├── .github └── workflows │ ├── lint.yml │ └── main.yml ├── .gitignore ├── .golangci.yml ├── LICENSE-APACHE ├── LICENSE-MIT ├── Makefile ├── README.md ├── data.go ├── db.go ├── db ├── memory │ ├── memory.go │ └── memory_test.go ├── pgx │ ├── go.mod │ ├── go.sum │ ├── schema.sql │ ├── sql.go │ ├── sql_test.go │ └── v5 │ │ ├── go.mod │ │ ├── go.sum │ │ ├── sql.go │ │ └── sql_test.go ├── sql │ ├── go.mod │ ├── go.sum │ ├── schema.sql │ ├── sql.go │ └── sql_test.go └── test │ └── test.go ├── elembytes.go ├── entry.go ├── go.mod ├── go.sum ├── hash.go ├── hash_test.go ├── merkletree.go ├── node.go ├── proof.go ├── proof_test.go └── utils.go /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | on: [ push, pull_request ] 3 | jobs: 4 | lint: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v3 8 | - uses: actions/setup-go@v3 9 | with: 10 | go-version: 1.20.2 11 | - uses: golangci/golangci-lint-action@v3 12 | with: 13 | version: v1.52.1 14 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: [push, pull_request] 3 | jobs: 4 | test: 5 | # matrix strategy from: https://github.com/mvdan/github-actions-golang/blob/master/.github/workflows/test.yml 6 | strategy: 7 | matrix: 8 | go-version: 9 | - 1.18.10 10 | - 1.19.7 11 | - 1.20.2 12 | platform: [ubuntu-latest] 13 | runs-on: ${{ matrix.platform }} 14 | steps: 15 | - name: Install Go 16 | uses: actions/setup-go@v4 17 | with: 18 | go-version: ${{ matrix.go-version }} 19 | - name: Checkout code 20 | uses: actions/checkout@v3 21 | - name: Run tests 22 | run: go test -race ./... 23 | sql-test-18: 24 | strategy: 25 | matrix: 26 | containers: 27 | - 1.18.10-bullseye 28 | runs-on: ubuntu-latest 29 | container: golang:${{ matrix.containers }} 30 | env: 31 | PGPASSWORD: pgpwd 32 | PGHOST: postgres 33 | PGUSER: postgres 34 | steps: 35 | - name: Checkout code 36 | uses: actions/checkout@v3 37 | - uses: actions/cache@v3 38 | with: 39 | path: | 40 | ~/.cache/go-build 41 | /go/pkg/mod 42 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 43 | restore-keys: | 44 | ${{ runner.os }}-go- 45 | - name: Run sqlx driver tests 46 | run: cd db/sql && go test -race ./... 47 | - name: Run pgx driver tests 48 | run: cd db/pgx && go test -race ./... 49 | services: 50 | postgres: 51 | image: postgres:13.3 52 | env: 53 | POSTGRES_PASSWORD: pgpwd 54 | sql-test-19: 55 | strategy: 56 | matrix: 57 | containers: 58 | - 1.19.7-bullseye 59 | - 1.20.2-bullseye 60 | runs-on: ubuntu-latest 61 | container: golang:${{ matrix.containers }} 62 | env: 63 | PGPASSWORD: pgpwd 64 | PGHOST: postgres 65 | PGUSER: postgres 66 | steps: 67 | - name: Checkout code 68 | uses: actions/checkout@v3 69 | - uses: actions/cache@v3 70 | with: 71 | path: | 72 | ~/.cache/go-build 73 | /go/pkg/mod 74 | key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} 75 | restore-keys: | 76 | ${{ runner.os }}-go- 77 | - name: Run sqlx driver tests 78 | run: cd db/sql && go test -race ./... 79 | - name: Run pgx driver tests 80 | run: cd db/pgx && go test -race ./... 81 | - name: Run pgx/v5 driver tests 82 | run: cd db/pgx/v5 && go test -race ./... 83 | services: 84 | postgres: 85 | image: postgres:13.3 86 | env: 87 | POSTGRES_PASSWORD: pgpwd 88 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | issues: 2 | max-same-issues: 0 3 | exclude-use-default: false 4 | linters: 5 | enable: 6 | - whitespace 7 | - gosec 8 | - gci 9 | - misspell 10 | - gofmt 11 | - goimports 12 | - lll 13 | # - revive 14 | linters-settings: 15 | lll: 16 | line-length: 100 17 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2023 0kims Association 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright 2023 0kims Association. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Unit test 2 | test: 3 | go test -v -race -timeout=60s -count=1 ./... 4 | 5 | # Linter 6 | lint: 7 | golangci-lint --config .golangci.yml run 8 | 9 | # Fix linter 10 | fix-lint: 11 | golangci-lint --config .golangci.yml run --fix 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # go-merkletree-sql [![GoDoc](https://godoc.org/github.com/iden3/go-merkletree-sql/v2?status.svg)](https://godoc.org/github.com/iden3/go-merkletree-sql/v2) [![Go Report Card](https://goreportcard.com/badge/github.com/iden3/go-merkletree-sql/v2)](https://goreportcard.com/report/github.com/iden3/go-merkletree-sql/v2) [![Test](https://github.com/iden3/go-merkletree-sql/v2/workflows/Test/badge.svg)](https://github.com/iden3/go-merkletree-sql/v2/actions?query=workflow%3ATest) 2 | 3 | MerkleTree compatible with version from [circomlib](https://github.com/iden3/circomlib). 4 | 5 | Adaptation of the merkletree from https://github.com/iden3/go-iden3-core/tree/v0.0.8 with several changes and more functionalities. 6 | 7 | ## Usage 8 | More detailed examples can be found at the [tests](https://github.com/iden3/go-merkletree-sql/v2/blob/master/merkletree_test.go), and in the [documentation](https://godoc.org/github.com/iden3/go-merkletree-sql/v2). 9 | 10 | ```go 11 | import ( 12 | "context" 13 | "math/big" 14 | "testing" 15 | 16 | "github.com/iden3/go-merkletree-sql/v2" 17 | "github.com/iden3/go-merkletree-sql/v2/db/memory" 18 | sql "github.com/iden3/go-merkletree-sql/v2/db/pgx" 19 | "github.com/stretchr/testify/require" 20 | ) 21 | 22 | func TestMT(t *testing.T) { 23 | mtDepth := 40 // maximum depth of the tree 24 | mtId := uint64(1) // id of tree in sql database, you can have multiple trees with different ids 25 | ctx := context.Background() 26 | 27 | var treeStorage merkletree.Storage 28 | 29 | // setup pgxConn here 30 | treeStorage = sql.NewSqlStorage(pgxConn, mtId) 31 | // OR 32 | treeStorage = memory.NewMemoryStorage() 33 | 34 | mt, err := merkletree.NewMerkleTree(ctx, treeStorage, mtDepth) 35 | require.NoError(t, err) 36 | 37 | err = mt.Add(ctx, big.NewInt(1), big.NewInt(2)) 38 | require.NoError(t, err) 39 | 40 | proof, _, err := mt.GenerateProof(ctx, big.NewInt(1), mt.Root()) 41 | require.NoError(t, err) 42 | 43 | valid := merkletree.VerifyProof(mt.Root(), proof, big.NewInt(1), big.NewInt(2)) 44 | require.True(t, valid) 45 | } 46 | ``` 47 | 48 | ## Contributing 49 | 50 | Unless you explicitly state otherwise, any contribution intentionally submitted 51 | for inclusion in the work by you, as defined in the Apache-2.0 license, shall be 52 | dual licensed as below, without any additional terms or conditions. 53 | 54 | ## License 55 | 56 | Copyright 2023 0kims Association 57 | 58 | This project is licensed under either of 59 | 60 | - [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) ([`LICENSE-APACHE`](LICENSE-APACHE)) 61 | - [MIT license](https://opensource.org/licenses/MIT) ([`LICENSE-MIT`](LICENSE-MIT)) 62 | 63 | at your option. 64 | -------------------------------------------------------------------------------- /data.go: -------------------------------------------------------------------------------- 1 | package merkletree 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "fmt" 7 | ) 8 | 9 | // Data is the type used to represent the data stored in an entry of the MT. 10 | // It consists of 8 elements: e0, e1, e2, e3, ...; 11 | // where v = [e0,e1], index = [e2,e3]. 12 | type Data [DataLen]ElemBytes 13 | 14 | func (d *Data) String() string { 15 | return fmt.Sprintf("%s%s%s%s", hex.EncodeToString(d[0][:]), hex.EncodeToString(d[1][:]), 16 | hex.EncodeToString(d[2][:]), hex.EncodeToString(d[3][:])) 17 | } 18 | 19 | func (d *Data) Bytes() (b [ElemBytesLen * DataLen]byte) { 20 | for i := 0; i < DataLen; i++ { 21 | copy(b[i*ElemBytesLen:(i+1)*ElemBytesLen], d[i][:]) 22 | } 23 | return b 24 | } 25 | 26 | func (d1 *Data) Equal(d2 *Data) bool { 27 | return bytes.Equal(d1[0][:], d2[0][:]) && bytes.Equal(d1[1][:], d2[1][:]) && 28 | bytes.Equal(d1[2][:], d2[2][:]) && bytes.Equal(d1[3][:], d2[3][:]) 29 | } 30 | 31 | func (d Data) MarshalText() ([]byte, error) { 32 | dataBytes := d.Bytes() 33 | return []byte(hex.EncodeToString(dataBytes[:])), nil 34 | } 35 | 36 | func (d *Data) UnmarshalText(text []byte) error { 37 | var dataBytes [ElemBytesLen * DataLen]byte 38 | _, err := hex.Decode(dataBytes[:], text) 39 | if err != nil { 40 | return err 41 | } 42 | *d = *NewDataFromBytes(dataBytes) 43 | return nil 44 | } 45 | 46 | func NewDataFromBytes(b [ElemBytesLen * DataLen]byte) *Data { 47 | d := &Data{} 48 | for i := 0; i < DataLen; i++ { 49 | copy(d[i][:], b[i*ElemBytesLen : (i+1)*ElemBytesLen][:]) 50 | } 51 | return d 52 | } 53 | -------------------------------------------------------------------------------- /db.go: -------------------------------------------------------------------------------- 1 | package merkletree 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "crypto/sha256" 7 | "errors" 8 | ) 9 | 10 | // ErrNotFound is used by the implementations of the interface db.Storage for 11 | // when a key is not found in the storage 12 | var ErrNotFound = errors.New("key not found") 13 | 14 | // Storage is the interface that defines the methods for the storage used in 15 | // the merkletree. Examples of the interface implementation can be found at 16 | // db/memory and db/leveldb directories. 17 | type Storage interface { 18 | Get(context.Context, []byte) (*Node, error) 19 | Put(ctx context.Context, k []byte, v *Node) error 20 | GetRoot(context.Context) (*Hash, error) 21 | SetRoot(context.Context, *Hash) error 22 | } 23 | 24 | // KV contains a key (K) and a value (V) 25 | type KV struct { 26 | K []byte 27 | V Node 28 | } 29 | 30 | // KvMap is a key-value map between a sha256 byte array hash, and a KV struct 31 | type KvMap map[[sha256.Size]byte]KV 32 | 33 | // Get retrieves the value respective to a key from the KvMap 34 | func (m KvMap) Get(k []byte) (Node, bool) { 35 | v, ok := m[sha256.Sum256(k)] 36 | return v.V, ok 37 | } 38 | 39 | // Put stores a key and a value in the KvMap 40 | func (m KvMap) Put(k []byte, v Node) { 41 | m[sha256.Sum256(k)] = KV{k, v} 42 | } 43 | 44 | // Concat concatenates arrays of bytes 45 | func Concat(vs ...[]byte) []byte { 46 | var b bytes.Buffer 47 | for _, v := range vs { 48 | b.Write(v) 49 | } 50 | return b.Bytes() 51 | } 52 | 53 | // Clone clones a byte array into a new byte array 54 | func Clone(b0 []byte) []byte { 55 | b1 := make([]byte, len(b0)) 56 | copy(b1, b0) 57 | return b1 58 | } 59 | -------------------------------------------------------------------------------- /db/memory/memory.go: -------------------------------------------------------------------------------- 1 | package memory 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/iden3/go-merkletree-sql/v2" 7 | ) 8 | 9 | // Storage implements the db.Storage interface 10 | type Storage struct { 11 | prefix []byte 12 | kv merkletree.KvMap 13 | currentRoot *merkletree.Hash 14 | } 15 | 16 | // NewMemoryStorage returns a new Storage 17 | func NewMemoryStorage() *Storage { 18 | kvmap := make(merkletree.KvMap) 19 | return &Storage{[]byte{}, kvmap, nil} 20 | } 21 | 22 | // Get retrieves a value from a key in the db.Storage 23 | func (m *Storage) Get(_ context.Context, key []byte) (*merkletree.Node, error) { 24 | if v, ok := m.kv.Get(merkletree.Concat(m.prefix, key[:])); ok { 25 | return &v, nil 26 | } 27 | return nil, merkletree.ErrNotFound 28 | } 29 | 30 | // Put inserts new node into merkletree 31 | func (m *Storage) Put(_ context.Context, key []byte, 32 | node *merkletree.Node) error { 33 | m.kv.Put(merkletree.Concat(m.prefix, key), *node) 34 | return nil 35 | } 36 | 37 | // GetRoot returns current merkletree root 38 | func (m *Storage) GetRoot(_ context.Context) (*merkletree.Hash, error) { 39 | if m.currentRoot != nil { 40 | hash := merkletree.Hash{} 41 | copy(hash[:], m.currentRoot[:]) 42 | return &hash, nil 43 | } 44 | return nil, merkletree.ErrNotFound 45 | } 46 | 47 | // SetRoot updates current merkletree root 48 | func (m *Storage) SetRoot(_ context.Context, hash *merkletree.Hash) error { 49 | root := &merkletree.Hash{} 50 | copy(root[:], hash[:]) 51 | m.currentRoot = root 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /db/memory/memory_test.go: -------------------------------------------------------------------------------- 1 | package memory 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/iden3/go-merkletree-sql/v2" 7 | "github.com/iden3/go-merkletree-sql/v2/db/test" 8 | "github.com/stretchr/testify/require" 9 | ) 10 | 11 | func TestMemoryStorageInterface(t *testing.T) { 12 | db := NewMemoryStorage() 13 | require.NotNil(t, db) 14 | } 15 | 16 | type MemoryStorageBuilder struct{} 17 | 18 | func (builder *MemoryStorageBuilder) NewStorage(t *testing.T) merkletree.Storage { 19 | return NewMemoryStorage() 20 | } 21 | 22 | func TestAll(t *testing.T) { 23 | builder := &MemoryStorageBuilder{} 24 | test.TestAll(t, builder) 25 | } 26 | -------------------------------------------------------------------------------- /db/pgx/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/iden3/go-merkletree-sql/db/pgx/v2 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/iden3/go-merkletree-sql/v2 v2.0.4 7 | github.com/jackc/pgconn v1.14.0 8 | github.com/jackc/pgx/v4 v4.15.0 9 | github.com/olomix/go-test-pg v1.0.2 10 | github.com/stretchr/testify v1.8.2 11 | ) 12 | 13 | require ( 14 | github.com/davecgh/go-spew v1.1.1 // indirect 15 | github.com/iden3/go-iden3-crypto v0.0.15 // indirect 16 | github.com/jackc/chunkreader/v2 v2.0.1 // indirect 17 | github.com/jackc/pgio v1.0.0 // indirect 18 | github.com/jackc/pgpassfile v1.0.0 // indirect 19 | github.com/jackc/pgproto3/v2 v2.3.2 // indirect 20 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect 21 | github.com/jackc/pgtype v1.10.0 // indirect 22 | github.com/jackc/puddle v1.2.1 // indirect 23 | github.com/pkg/errors v0.8.1 // indirect 24 | github.com/pmezard/go-difflib v1.0.0 // indirect 25 | golang.org/x/crypto v0.7.0 // indirect 26 | golang.org/x/sys v0.6.0 // indirect 27 | golang.org/x/text v0.8.0 // indirect 28 | gopkg.in/yaml.v3 v3.0.1 // indirect 29 | ) 30 | -------------------------------------------------------------------------------- /db/pgx/go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= 3 | github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= 4 | github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= 5 | github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= 6 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 7 | github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 8 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 9 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 11 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 12 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 13 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 14 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 15 | github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= 16 | github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 17 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 18 | github.com/iden3/go-iden3-crypto v0.0.15 h1:4MJYlrot1l31Fzlo2sF56u7EVFeHHJkxGXXZCtESgK4= 19 | github.com/iden3/go-iden3-crypto v0.0.15/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= 20 | github.com/iden3/go-merkletree-sql/v2 v2.0.4 h1:Dp089P3YNX1BE8+T1tKQHWTtnk84Y/Kr7ZAGTqwscoY= 21 | github.com/iden3/go-merkletree-sql/v2 v2.0.4/go.mod h1:kRhHKYpui5DUsry5RpveP6IC4XMe6iApdV9VChRYuEk= 22 | github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= 23 | github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 24 | github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= 25 | github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 26 | github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= 27 | github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= 28 | github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= 29 | github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= 30 | github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= 31 | github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= 32 | github.com/jackc/pgconn v1.11.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= 33 | github.com/jackc/pgconn v1.14.0 h1:vrbA9Ud87g6JdFWkHTJXppVce58qPIdP7N8y0Ml/A7Q= 34 | github.com/jackc/pgconn v1.14.0/go.mod h1:9mBNlny0UvkgJdCDvdVHYSjI+8tD2rnKK69Wz8ti++E= 35 | github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= 36 | github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= 37 | github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= 38 | github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= 39 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= 40 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= 41 | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= 42 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 43 | github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= 44 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= 45 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= 46 | github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 47 | github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 48 | github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 49 | github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 50 | github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 51 | github.com/jackc/pgproto3/v2 v2.3.2 h1:7eY55bdBeCz1F2fTzSz69QC+pG46jYq9/jtSPiJ5nn0= 52 | github.com/jackc/pgproto3/v2 v2.3.2/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 53 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= 54 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= 55 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= 56 | github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= 57 | github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= 58 | github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= 59 | github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= 60 | github.com/jackc/pgtype v1.10.0 h1:ILnBWrRMSXGczYvmkYD6PsYyVFUNLTnIUJHHDLmqk38= 61 | github.com/jackc/pgtype v1.10.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= 62 | github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= 63 | github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= 64 | github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= 65 | github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= 66 | github.com/jackc/pgx/v4 v4.15.0 h1:B7dTkXsdILD3MF987WGGCcg+tvLW6bZJdEcqVFeU//w= 67 | github.com/jackc/pgx/v4 v4.15.0/go.mod h1:D/zyOyXiaM1TmVWnOM18p0xdDtdakRBa0RsVGI3U3bw= 68 | github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 69 | github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 70 | github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 71 | github.com/jackc/puddle v1.2.1 h1:gI8os0wpRXFd4FiAY2dWiqRK037tjj3t7rKFeO4X5iw= 72 | github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 73 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 74 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 75 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 76 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 77 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 78 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 79 | github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= 80 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 81 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 82 | github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= 83 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 84 | github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 85 | github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 86 | github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= 87 | github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 88 | github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= 89 | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 90 | github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 91 | github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 92 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 93 | github.com/olomix/go-test-pg v1.0.2 h1:4ey3mFBhPx93PdgyshOJI1WrQzqzkWEnb0wL/7UbFMI= 94 | github.com/olomix/go-test-pg v1.0.2/go.mod h1:rHMame/S99rnU5YhVYFa3rr0riKqBYe8xsMDP4YzeHA= 95 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 96 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 97 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 98 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 99 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 100 | github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= 101 | github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= 102 | github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= 103 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 104 | github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= 105 | github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= 106 | github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 107 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 108 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 109 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 110 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 111 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 112 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 113 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 114 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 115 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 116 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 117 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 118 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 119 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 120 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 121 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 122 | github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= 123 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 124 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 125 | github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= 126 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 127 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 128 | go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 129 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 130 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 131 | go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= 132 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= 133 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 134 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 135 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 136 | go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= 137 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 138 | golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 139 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 140 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 141 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 142 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 143 | golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 144 | golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 145 | golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 146 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 147 | golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= 148 | golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= 149 | golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= 150 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 151 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 152 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 153 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 154 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 155 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 156 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 157 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 158 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 159 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 160 | golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 161 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 162 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 163 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 164 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 165 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 166 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 167 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 168 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 169 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 170 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 171 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 172 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 173 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 174 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 175 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 176 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 177 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 178 | golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= 179 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 180 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 181 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 182 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 183 | golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= 184 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 185 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 186 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 187 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 188 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 189 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 190 | golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= 191 | golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= 192 | golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 193 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 194 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 195 | golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 196 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 197 | golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 198 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 199 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 200 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 201 | golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 202 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 203 | golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 204 | golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 205 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 206 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 207 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 208 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 209 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 210 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 211 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 212 | gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= 213 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 214 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 215 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 216 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 217 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 218 | -------------------------------------------------------------------------------- /db/pgx/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE mt_nodes ( 2 | mt_id BIGINT, 3 | key BYTEA, 4 | type SMALLINT NOT NULL, 5 | child_l BYTEA, 6 | child_r BYTEA, 7 | entry BYTEA, 8 | created_at BIGINT, 9 | deleted_at BIGINT, 10 | PRIMARY KEY(mt_id, key) 11 | ); 12 | 13 | CREATE TABLE mt_roots ( 14 | mt_id BIGINT PRIMARY KEY, 15 | key BYTEA, 16 | created_at BIGINT, 17 | deleted_at BIGINT 18 | ); 19 | -------------------------------------------------------------------------------- /db/pgx/sql.go: -------------------------------------------------------------------------------- 1 | package sql 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | 7 | "github.com/iden3/go-merkletree-sql/v2" 8 | "github.com/jackc/pgconn" 9 | pgx "github.com/jackc/pgx/v4" 10 | ) 11 | 12 | // TODO: upsert or insert? 13 | const upsertStmt = `INSERT INTO mt_nodes (mt_id, key, type, child_l, child_r, entry) VALUES ($1, $2, $3, $4, $5, $6) ` + 14 | `ON CONFLICT (mt_id, key) DO UPDATE SET type = $3, child_l = $4, child_r = $5, entry = $6` 15 | 16 | const updateRootStmt = `INSERT INTO mt_roots (mt_id, key) VALUES ($1, $2) ` + 17 | `ON CONFLICT (mt_id) DO UPDATE SET key = $2` 18 | 19 | type DB interface { 20 | Exec(ctx context.Context, sql string, arguments ...interface{}) (pgconn.CommandTag, error) 21 | Query(ctx context.Context, sql string, args ...interface{}) (pgx.Rows, error) 22 | QueryRow(ctx context.Context, sql string, args ...interface{}) pgx.Row 23 | } 24 | 25 | // Storage implements the db.Storage interface 26 | type Storage struct { 27 | db DB 28 | mtId uint64 29 | currentVersion uint64 30 | currentRoot *merkletree.Hash 31 | } 32 | 33 | type NodeItem struct { 34 | MTId uint64 `db:"mt_id"` 35 | Key []byte `db:"key"` 36 | // Type is the type of node in the tree. 37 | Type byte `db:"type"` 38 | // ChildL is the left child of a middle node. 39 | ChildL []byte `db:"child_l"` 40 | // ChildR is the right child of a middle node. 41 | ChildR []byte `db:"child_r"` 42 | // Entry is the data stored in a leaf node. 43 | Entry []byte `db:"entry"` 44 | CreatedAt *uint64 `db:"created_at"` 45 | DeletedAt *uint64 `db:"deleted_at"` 46 | } 47 | 48 | type RootItem struct { 49 | MTId uint64 `db:"mt_id"` 50 | Key []byte `db:"key"` 51 | CreatedAt *uint64 `db:"created_at"` 52 | DeletedAt *uint64 `db:"deleted_at"` 53 | } 54 | 55 | // NewSqlStorage returns a new Storage 56 | func NewSqlStorage(db DB, mtId uint64) *Storage { 57 | return &Storage{db: db, mtId: mtId} 58 | } 59 | 60 | // Get retrieves a value from a key in the db.Storage 61 | func (s *Storage) Get(ctx context.Context, 62 | key []byte) (*merkletree.Node, error) { 63 | item := NodeItem{} 64 | row := s.db.QueryRow(ctx, `SELECT mt_id, key, type, child_l, child_r, entry, created_at, deleted_at 65 | FROM mt_nodes WHERE mt_id = $1 AND key = $2`, s.mtId, key) 66 | err := row.Scan(&item.MTId, 67 | &item.Key, 68 | &item.Type, 69 | &item.ChildL, 70 | &item.ChildR, 71 | &item.Entry, 72 | &item.CreatedAt, 73 | &item.DeletedAt) 74 | if err != nil && errors.Is(err, pgx.ErrNoRows) { 75 | return nil, merkletree.ErrNotFound 76 | } else if err != nil { 77 | return nil, err 78 | } 79 | 80 | node, err := item.Node() 81 | if err != nil { 82 | return nil, err 83 | } 84 | return node, nil 85 | } 86 | 87 | func (s *Storage) Put(ctx context.Context, key []byte, 88 | node *merkletree.Node) error { 89 | 90 | var childL []byte 91 | if node.ChildL != nil { 92 | childL = append(childL, node.ChildL[:]...) 93 | } 94 | 95 | var childR []byte 96 | if node.ChildR != nil { 97 | childR = append(childR, node.ChildR[:]...) 98 | } 99 | 100 | var entry []byte 101 | if node.Entry[0] != nil && node.Entry[1] != nil { 102 | entry = append(node.Entry[0][:], node.Entry[1][:]...) 103 | } 104 | 105 | _, err := s.db.Exec(ctx, upsertStmt, s.mtId, key[:], node.Type, 106 | childL, childR, entry) 107 | return err 108 | } 109 | 110 | // GetRoot retrieves a merkle tree root hash in the interface db.Tx 111 | func (s *Storage) GetRoot(ctx context.Context) (*merkletree.Hash, error) { 112 | var root merkletree.Hash 113 | var err error 114 | 115 | if s.currentRoot != nil { 116 | copy(root[:], s.currentRoot[:]) 117 | return &root, nil 118 | } 119 | 120 | item := RootItem{} 121 | row := s.db.QueryRow(ctx, 122 | "SELECT mt_id, key, created_at, deleted_at FROM mt_roots WHERE mt_id = $1", s.mtId) 123 | err = row.Scan(&item.MTId, &item.Key, &item.CreatedAt, &item.DeletedAt) 124 | if err != nil && errors.Is(err, pgx.ErrNoRows) { 125 | return nil, merkletree.ErrNotFound 126 | } else if err != nil { 127 | return nil, err 128 | } 129 | 130 | if s.currentRoot == nil { 131 | s.currentRoot = &merkletree.Hash{} 132 | } 133 | copy(s.currentRoot[:], item.Key[:]) 134 | copy(root[:], s.currentRoot[:]) 135 | return &root, nil 136 | } 137 | 138 | func (s *Storage) SetRoot(ctx context.Context, hash *merkletree.Hash) error { 139 | if s.currentRoot == nil { 140 | s.currentRoot = &merkletree.Hash{} 141 | } 142 | copy(s.currentRoot[:], hash[:]) 143 | _, err := s.db.Exec(ctx, updateRootStmt, s.mtId, s.currentRoot[:]) 144 | if err != nil { 145 | err = newErr(err, "failed to update current root hash") 146 | } 147 | return err 148 | } 149 | 150 | func (item *NodeItem) Node() (*merkletree.Node, error) { 151 | node := merkletree.Node{ 152 | Type: merkletree.NodeType(item.Type), 153 | } 154 | if item.ChildL != nil { 155 | node.ChildL = &merkletree.Hash{} 156 | copy(node.ChildL[:], item.ChildL[:]) 157 | } 158 | if item.ChildR != nil { 159 | node.ChildR = &merkletree.Hash{} 160 | copy(node.ChildR[:], item.ChildR[:]) 161 | } 162 | if len(item.Entry) > 0 { 163 | if len(item.Entry) != 2*merkletree.ElemBytesLen { 164 | return nil, merkletree.ErrNodeBytesBadSize 165 | } 166 | node.Entry = [2]*merkletree.Hash{{}, {}} 167 | copy(node.Entry[0][:], item.Entry[0:32]) 168 | copy(node.Entry[1][:], item.Entry[32:64]) 169 | } 170 | return &node, nil 171 | } 172 | 173 | // KV contains a key (K) and a value (V) 174 | type KV struct { 175 | MTId uint64 176 | K []byte 177 | V merkletree.Node 178 | } 179 | 180 | type storageError struct { 181 | err error 182 | msg string 183 | } 184 | 185 | func (err storageError) Error() string { 186 | return err.msg + ": " + err.err.Error() 187 | } 188 | 189 | func (err storageError) Unwrap() error { 190 | return err.err 191 | } 192 | 193 | func newErr(err error, msg string) error { 194 | return storageError{err, msg} 195 | } 196 | -------------------------------------------------------------------------------- /db/pgx/sql_test.go: -------------------------------------------------------------------------------- 1 | package sql 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | "sync/atomic" 7 | "testing" 8 | 9 | "github.com/iden3/go-merkletree-sql/v2" 10 | "github.com/iden3/go-merkletree-sql/v2/db/test" 11 | go_test_pg "github.com/olomix/go-test-pg" 12 | "github.com/stretchr/testify/require" 13 | ) 14 | 15 | var maxMTId uint64 = 0 16 | var dbPool = go_test_pg.Pgpool{ 17 | BaseName: "merkletree_sql", 18 | SchemaFile: "./schema.sql", 19 | Skip: false, 20 | } 21 | 22 | type SqlStorageBuilder struct{} 23 | 24 | func (builder *SqlStorageBuilder) NewStorage(t *testing.T) merkletree.Storage { 25 | // Note: Use ENV vars to set database configuration. 26 | // See https://www.postgresql.org/docs/11/libpq-envars.html for details. 27 | db := dbPool.WithEmpty(t) 28 | 29 | mtId := atomic.AddUint64(&maxMTId, 1) 30 | 31 | return NewSqlStorage(db, mtId) 32 | } 33 | 34 | func TestSql(t *testing.T) { 35 | builder := &SqlStorageBuilder{} 36 | test.TestAll(t, builder) 37 | } 38 | 39 | func TestErrors(t *testing.T) { 40 | err := storageError{ 41 | err: io.EOF, 42 | msg: "storage error", 43 | } 44 | require.EqualError(t, err, "storage error: EOF") 45 | require.Equal(t, io.EOF, errors.Unwrap(err)) 46 | } 47 | -------------------------------------------------------------------------------- /db/pgx/v5/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/iden3/go-merkletree-sql/db/pgx/v5 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/iden3/go-merkletree-sql/v2 v2.0.4 7 | github.com/jackc/pgx/v5 v5.3.1 8 | github.com/olomix/go-test-pg/v2 v2.0.1 9 | github.com/stretchr/testify v1.8.2 10 | ) 11 | 12 | require ( 13 | github.com/davecgh/go-spew v1.1.1 // indirect 14 | github.com/iden3/go-iden3-crypto v0.0.15 // indirect 15 | github.com/jackc/pgpassfile v1.0.0 // indirect 16 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect 17 | github.com/jackc/puddle/v2 v2.2.0 // indirect 18 | github.com/kr/text v0.1.0 // indirect 19 | github.com/pkg/errors v0.9.1 // indirect 20 | github.com/pmezard/go-difflib v1.0.0 // indirect 21 | github.com/rogpeppe/go-internal v1.9.0 // indirect 22 | golang.org/x/crypto v0.7.0 // indirect 23 | golang.org/x/sync v0.1.0 // indirect 24 | golang.org/x/sys v0.6.0 // indirect 25 | golang.org/x/text v0.8.0 // indirect 26 | gopkg.in/yaml.v3 v3.0.1 // indirect 27 | ) 28 | -------------------------------------------------------------------------------- /db/pgx/v5/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/iden3/go-iden3-crypto v0.0.15 h1:4MJYlrot1l31Fzlo2sF56u7EVFeHHJkxGXXZCtESgK4= 5 | github.com/iden3/go-iden3-crypto v0.0.15/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= 6 | github.com/iden3/go-merkletree-sql/v2 v2.0.4 h1:Dp089P3YNX1BE8+T1tKQHWTtnk84Y/Kr7ZAGTqwscoY= 7 | github.com/iden3/go-merkletree-sql/v2 v2.0.4/go.mod h1:kRhHKYpui5DUsry5RpveP6IC4XMe6iApdV9VChRYuEk= 8 | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= 9 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 10 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= 11 | github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= 12 | github.com/jackc/pgx/v5 v5.3.1 h1:Fcr8QJ1ZeLi5zsPZqQeUZhNhxfkkKBOgJuYkJHoBOtU= 13 | github.com/jackc/pgx/v5 v5.3.1/go.mod h1:t3JDKnCBlYIc0ewLF0Q7B8MXmoIaBOZj/ic7iHozM/8= 14 | github.com/jackc/puddle/v2 v2.2.0 h1:RdcDk92EJBuBS55nQMMYFXTxwstHug4jkhT5pq8VxPk= 15 | github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= 16 | github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= 17 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 18 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 19 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 20 | github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= 21 | github.com/olomix/go-test-pg/v2 v2.0.1 h1:jAeayLRCwZk0mP9SKU2GswwOPvlpqYeG3K2vhV2JZtU= 22 | github.com/olomix/go-test-pg/v2 v2.0.1/go.mod h1:5+lNpbMM6Aj+tG1NHhvpCNdDfxAzW90tpIZvzg0iuGo= 23 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 24 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 25 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 26 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 27 | github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= 28 | github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= 29 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 30 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 31 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 32 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 33 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 34 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 35 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 36 | github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= 37 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 38 | golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= 39 | golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= 40 | golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= 41 | golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 42 | golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= 43 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 44 | golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= 45 | golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 46 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 47 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= 48 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 49 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 50 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 51 | -------------------------------------------------------------------------------- /db/pgx/v5/sql.go: -------------------------------------------------------------------------------- 1 | package sql 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | 7 | "github.com/iden3/go-merkletree-sql/v2" 8 | "github.com/jackc/pgx/v5" 9 | "github.com/jackc/pgx/v5/pgconn" 10 | ) 11 | 12 | const upsertStmt = ` 13 | INSERT INTO mt_nodes (mt_id, key, type, child_l, child_r, entry) 14 | VALUES ($1, $2, $3, $4, $5, $6) 15 | ON CONFLICT (mt_id, key) DO UPDATE 16 | SET type = $3, child_l = $4, child_r = $5, entry = $6` 17 | 18 | const updateRootStmt = ` 19 | INSERT INTO mt_roots (mt_id, key) VALUES ($1, $2) 20 | ON CONFLICT (mt_id) DO UPDATE SET key = $2` 21 | 22 | type DB interface { 23 | Exec(ctx context.Context, sql string, 24 | arguments ...interface{}) (pgconn.CommandTag, error) 25 | Query(ctx context.Context, sql string, 26 | args ...interface{}) (pgx.Rows, error) 27 | QueryRow(ctx context.Context, sql string, args ...interface{}) pgx.Row 28 | } 29 | 30 | // Storage implements the db.Storage interface 31 | type Storage struct { 32 | db DB 33 | mtId uint64 34 | currentVersion uint64 35 | currentRoot *merkletree.Hash 36 | } 37 | 38 | type NodeItem struct { 39 | MTId uint64 `db:"mt_id"` 40 | Key []byte `db:"key"` 41 | // Type is the type of node in the tree. 42 | Type byte `db:"type"` 43 | // ChildL is the left child of a middle node. 44 | ChildL []byte `db:"child_l"` 45 | // ChildR is the right child of a middle node. 46 | ChildR []byte `db:"child_r"` 47 | // Entry is the data stored in a leaf node. 48 | Entry []byte `db:"entry"` 49 | CreatedAt *uint64 `db:"created_at"` 50 | DeletedAt *uint64 `db:"deleted_at"` 51 | } 52 | 53 | type RootItem struct { 54 | MTId uint64 `db:"mt_id"` 55 | Key []byte `db:"key"` 56 | CreatedAt *uint64 `db:"created_at"` 57 | DeletedAt *uint64 `db:"deleted_at"` 58 | } 59 | 60 | // NewSqlStorage returns a new Storage 61 | func NewSqlStorage(db DB, mtId uint64) *Storage { 62 | return &Storage{db: db, mtId: mtId} 63 | } 64 | 65 | // Get retrieves a value from a key in the db.Storage 66 | func (s *Storage) Get(ctx context.Context, 67 | key []byte) (*merkletree.Node, error) { 68 | item := NodeItem{} 69 | row := s.db.QueryRow(ctx, 70 | ` 71 | SELECT mt_id, key, type, child_l, child_r, entry, created_at, deleted_at 72 | FROM mt_nodes WHERE mt_id = $1 AND key = $2`, 73 | s.mtId, key) 74 | err := row.Scan(&item.MTId, &item.Key, &item.Type, &item.ChildL, 75 | &item.ChildR, &item.Entry, &item.CreatedAt, &item.DeletedAt) 76 | if err != nil && errors.Is(err, pgx.ErrNoRows) { 77 | return nil, merkletree.ErrNotFound 78 | } else if err != nil { 79 | return nil, err 80 | } 81 | 82 | node, err := item.Node() 83 | if err != nil { 84 | return nil, err 85 | } 86 | return node, nil 87 | } 88 | 89 | func (s *Storage) Put(ctx context.Context, key []byte, 90 | node *merkletree.Node) error { 91 | 92 | var childL []byte 93 | if node.ChildL != nil { 94 | childL = append(childL, node.ChildL[:]...) 95 | } 96 | 97 | var childR []byte 98 | if node.ChildR != nil { 99 | childR = append(childR, node.ChildR[:]...) 100 | } 101 | 102 | var entry []byte 103 | if node.Entry[0] != nil && node.Entry[1] != nil { 104 | entry = append(node.Entry[0][:], node.Entry[1][:]...) 105 | } 106 | 107 | _, err := s.db.Exec(ctx, upsertStmt, s.mtId, key[:], node.Type, 108 | childL, childR, entry) 109 | return err 110 | } 111 | 112 | // GetRoot retrieves a merkle tree root hash in the interface db.Tx 113 | func (s *Storage) GetRoot(ctx context.Context) (*merkletree.Hash, error) { 114 | var root merkletree.Hash 115 | var err error 116 | 117 | if s.currentRoot != nil { 118 | copy(root[:], s.currentRoot[:]) 119 | return &root, nil 120 | } 121 | 122 | item := RootItem{} 123 | row := s.db.QueryRow(ctx, 124 | ` 125 | SELECT mt_id, key, created_at, deleted_at FROM mt_roots WHERE mt_id = $1`, 126 | s.mtId) 127 | err = row.Scan(&item.MTId, &item.Key, &item.CreatedAt, &item.DeletedAt) 128 | if err != nil && errors.Is(err, pgx.ErrNoRows) { 129 | return nil, merkletree.ErrNotFound 130 | } else if err != nil { 131 | return nil, err 132 | } 133 | 134 | if s.currentRoot == nil { 135 | s.currentRoot = &merkletree.Hash{} 136 | } 137 | copy(s.currentRoot[:], item.Key[:]) 138 | copy(root[:], s.currentRoot[:]) 139 | return &root, nil 140 | } 141 | 142 | func (s *Storage) SetRoot(ctx context.Context, hash *merkletree.Hash) error { 143 | if s.currentRoot == nil { 144 | s.currentRoot = &merkletree.Hash{} 145 | } 146 | copy(s.currentRoot[:], hash[:]) 147 | _, err := s.db.Exec(ctx, updateRootStmt, s.mtId, s.currentRoot[:]) 148 | if err != nil { 149 | err = newErr(err, "failed to update current root hash") 150 | } 151 | return err 152 | } 153 | 154 | func (item *NodeItem) Node() (*merkletree.Node, error) { 155 | node := merkletree.Node{ 156 | Type: merkletree.NodeType(item.Type), 157 | } 158 | if item.ChildL != nil { 159 | node.ChildL = &merkletree.Hash{} 160 | copy(node.ChildL[:], item.ChildL[:]) 161 | } 162 | if item.ChildR != nil { 163 | node.ChildR = &merkletree.Hash{} 164 | copy(node.ChildR[:], item.ChildR[:]) 165 | } 166 | if len(item.Entry) > 0 { 167 | if len(item.Entry) != 2*merkletree.ElemBytesLen { 168 | return nil, merkletree.ErrNodeBytesBadSize 169 | } 170 | node.Entry = [2]*merkletree.Hash{{}, {}} 171 | copy(node.Entry[0][:], item.Entry[0:32]) 172 | copy(node.Entry[1][:], item.Entry[32:64]) 173 | } 174 | return &node, nil 175 | } 176 | 177 | // KV contains a key (K) and a value (V) 178 | type KV struct { 179 | MTId uint64 180 | K []byte 181 | V merkletree.Node 182 | } 183 | 184 | type storageError struct { 185 | err error 186 | msg string 187 | } 188 | 189 | func (err storageError) Error() string { 190 | return err.msg + ": " + err.err.Error() 191 | } 192 | 193 | func (err storageError) Unwrap() error { 194 | return err.err 195 | } 196 | 197 | func newErr(err error, msg string) error { 198 | return storageError{err, msg} 199 | } 200 | -------------------------------------------------------------------------------- /db/pgx/v5/sql_test.go: -------------------------------------------------------------------------------- 1 | package sql 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | "sync/atomic" 7 | "testing" 8 | 9 | "github.com/iden3/go-merkletree-sql/v2" 10 | "github.com/iden3/go-merkletree-sql/v2/db/test" 11 | go_test_pg "github.com/olomix/go-test-pg/v2" 12 | "github.com/stretchr/testify/require" 13 | ) 14 | 15 | var maxMTId uint64 = 0 16 | var dbPool = go_test_pg.Pgpool{ 17 | BaseName: "merkletree_sql", 18 | SchemaFile: "../schema.sql", 19 | Skip: false, 20 | } 21 | 22 | type SqlStorageBuilder struct{} 23 | 24 | func (builder *SqlStorageBuilder) NewStorage(t *testing.T) merkletree.Storage { 25 | // Note: Use ENV vars to set database configuration. 26 | // See https://www.postgresql.org/docs/11/libpq-envars.html for details. 27 | db := dbPool.WithEmpty(t) 28 | 29 | mtId := atomic.AddUint64(&maxMTId, 1) 30 | 31 | return NewSqlStorage(db, mtId) 32 | } 33 | 34 | func TestSql(t *testing.T) { 35 | builder := &SqlStorageBuilder{} 36 | test.TestAll(t, builder) 37 | } 38 | 39 | func TestErrors(t *testing.T) { 40 | err := storageError{ 41 | err: io.EOF, 42 | msg: "storage error", 43 | } 44 | require.EqualError(t, err, "storage error: EOF") 45 | require.Equal(t, io.EOF, errors.Unwrap(err)) 46 | } 47 | -------------------------------------------------------------------------------- /db/sql/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/iden3/go-merkletree-sql/db/sql/v2 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/iden3/go-merkletree-sql/v2 v2.0.4 7 | github.com/jmoiron/sqlx v1.3.5 8 | github.com/olomix/go-test-pg v1.0.2 9 | github.com/stretchr/testify v1.8.2 10 | ) 11 | 12 | require ( 13 | github.com/davecgh/go-spew v1.1.1 // indirect 14 | github.com/iden3/go-iden3-crypto v0.0.15 // indirect 15 | github.com/jackc/chunkreader/v2 v2.0.1 // indirect 16 | github.com/jackc/pgconn v1.11.0 // indirect 17 | github.com/jackc/pgio v1.0.0 // indirect 18 | github.com/jackc/pgpassfile v1.0.0 // indirect 19 | github.com/jackc/pgproto3/v2 v2.2.0 // indirect 20 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect 21 | github.com/jackc/pgtype v1.10.0 // indirect 22 | github.com/jackc/pgx/v4 v4.15.0 // indirect 23 | github.com/jackc/puddle v1.2.1 // indirect 24 | github.com/pkg/errors v0.8.1 // indirect 25 | github.com/pmezard/go-difflib v1.0.0 // indirect 26 | golang.org/x/crypto v0.7.0 // indirect 27 | golang.org/x/sys v0.6.0 // indirect 28 | golang.org/x/text v0.8.0 // indirect 29 | gopkg.in/yaml.v3 v3.0.1 // indirect 30 | ) 31 | -------------------------------------------------------------------------------- /db/sql/go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= 3 | github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= 4 | github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= 5 | github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= 6 | github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 7 | github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= 8 | github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 9 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 10 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 11 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 12 | github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= 13 | github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= 14 | github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= 15 | github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= 16 | github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= 17 | github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= 18 | github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 19 | github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= 20 | github.com/iden3/go-iden3-crypto v0.0.15 h1:4MJYlrot1l31Fzlo2sF56u7EVFeHHJkxGXXZCtESgK4= 21 | github.com/iden3/go-iden3-crypto v0.0.15/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= 22 | github.com/iden3/go-merkletree-sql/v2 v2.0.4 h1:Dp089P3YNX1BE8+T1tKQHWTtnk84Y/Kr7ZAGTqwscoY= 23 | github.com/iden3/go-merkletree-sql/v2 v2.0.4/go.mod h1:kRhHKYpui5DUsry5RpveP6IC4XMe6iApdV9VChRYuEk= 24 | github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= 25 | github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 26 | github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= 27 | github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= 28 | github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= 29 | github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= 30 | github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= 31 | github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= 32 | github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= 33 | github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= 34 | github.com/jackc/pgconn v1.11.0 h1:HiHArx4yFbwl91X3qqIHtUFoiIfLNJXCQRsnzkiwwaQ= 35 | github.com/jackc/pgconn v1.11.0/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= 36 | github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= 37 | github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= 38 | github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= 39 | github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= 40 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= 41 | github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= 42 | github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= 43 | github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= 44 | github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= 45 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= 46 | github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= 47 | github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 48 | github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= 49 | github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 50 | github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 51 | github.com/jackc/pgproto3/v2 v2.2.0 h1:r7JypeP2D3onoQTCxWdTpCtJ4D+qpKr0TxvoyMhZ5ns= 52 | github.com/jackc/pgproto3/v2 v2.2.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= 53 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= 54 | github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= 55 | github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= 56 | github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= 57 | github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= 58 | github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= 59 | github.com/jackc/pgtype v1.10.0 h1:ILnBWrRMSXGczYvmkYD6PsYyVFUNLTnIUJHHDLmqk38= 60 | github.com/jackc/pgtype v1.10.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= 61 | github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= 62 | github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= 63 | github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= 64 | github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= 65 | github.com/jackc/pgx/v4 v4.15.0 h1:B7dTkXsdILD3MF987WGGCcg+tvLW6bZJdEcqVFeU//w= 66 | github.com/jackc/pgx/v4 v4.15.0/go.mod h1:D/zyOyXiaM1TmVWnOM18p0xdDtdakRBa0RsVGI3U3bw= 67 | github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 68 | github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 69 | github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 70 | github.com/jackc/puddle v1.2.1 h1:gI8os0wpRXFd4FiAY2dWiqRK037tjj3t7rKFeO4X5iw= 71 | github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= 72 | github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= 73 | github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= 74 | github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 75 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 76 | github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 77 | github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 78 | github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 79 | github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= 80 | github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= 81 | github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 82 | github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 83 | github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= 84 | github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 85 | github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 86 | github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= 87 | github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= 88 | github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 89 | github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= 90 | github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= 91 | github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 92 | github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 93 | github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= 94 | github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= 95 | github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= 96 | github.com/olomix/go-test-pg v1.0.2 h1:4ey3mFBhPx93PdgyshOJI1WrQzqzkWEnb0wL/7UbFMI= 97 | github.com/olomix/go-test-pg v1.0.2/go.mod h1:rHMame/S99rnU5YhVYFa3rr0riKqBYe8xsMDP4YzeHA= 98 | github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= 99 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 100 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 101 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 102 | github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= 103 | github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= 104 | github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= 105 | github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= 106 | github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= 107 | github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= 108 | github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= 109 | github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= 110 | github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= 111 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 112 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 113 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 114 | github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= 115 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 116 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 117 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 118 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 119 | github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= 120 | github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= 121 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 122 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 123 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 124 | github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= 125 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 126 | github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= 127 | go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 128 | go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= 129 | go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 130 | go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= 131 | go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= 132 | go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= 133 | go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= 134 | go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= 135 | go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 136 | go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= 137 | go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= 138 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 139 | golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= 140 | golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 141 | golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 142 | golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= 143 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 144 | golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= 145 | golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 146 | golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 147 | golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= 148 | golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= 149 | golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 150 | golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= 151 | golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 152 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 153 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 154 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 155 | golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 156 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 157 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 158 | golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 159 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 160 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 161 | golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 162 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 163 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 164 | golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 165 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 166 | golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 167 | golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 168 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 169 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 170 | golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= 171 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 172 | golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= 173 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 174 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 175 | golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= 176 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 177 | golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 178 | golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 179 | golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= 180 | golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= 181 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 182 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 183 | golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 184 | golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 185 | golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 186 | golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 187 | golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 188 | golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 189 | golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 190 | golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 191 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 192 | golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 193 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 194 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 195 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 196 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 197 | gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= 198 | gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= 199 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 200 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 201 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 202 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 203 | honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= 204 | -------------------------------------------------------------------------------- /db/sql/schema.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE mt_nodes ( 2 | mt_id BIGINT, 3 | key BYTEA, 4 | type SMALLINT NOT NULL, 5 | child_l BYTEA, 6 | child_r BYTEA, 7 | entry BYTEA, 8 | created_at BIGINT, 9 | deleted_at BIGINT, 10 | PRIMARY KEY(mt_id, key) 11 | ); 12 | 13 | CREATE TABLE mt_roots ( 14 | mt_id BIGINT PRIMARY KEY, 15 | key BYTEA, 16 | created_at BIGINT, 17 | deleted_at BIGINT 18 | ); 19 | -------------------------------------------------------------------------------- /db/sql/sql.go: -------------------------------------------------------------------------------- 1 | package sql 2 | 3 | import ( 4 | "context" 5 | "database/sql" 6 | "github.com/iden3/go-merkletree-sql/v2" 7 | ) 8 | 9 | // TODO: upsert or insert? 10 | const upsertStmt = `INSERT INTO mt_nodes (mt_id, key, type, child_l, child_r, entry) VALUES ($1, $2, $3, $4, $5, $6) ` + 11 | `ON CONFLICT (mt_id, key) DO UPDATE SET type = $3, child_l = $4, child_r = $5, entry = $6` 12 | 13 | const updateRootStmt = `INSERT INTO mt_roots (mt_id, key) VALUES ($1, $2) ` + 14 | `ON CONFLICT (mt_id) DO UPDATE SET key = $2` 15 | 16 | type DB interface { 17 | ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) 18 | GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error 19 | SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error 20 | } 21 | 22 | // Storage implements the db.Storage interface 23 | type Storage struct { 24 | db DB 25 | mtId uint64 26 | currentVersion uint64 27 | currentRoot *merkletree.Hash 28 | } 29 | 30 | type NodeItem struct { 31 | MTId uint64 `db:"mt_id"` 32 | Key []byte `db:"key"` 33 | // Type is the type of node in the tree. 34 | Type byte `db:"type"` 35 | // ChildL is the left child of a middle node. 36 | ChildL []byte `db:"child_l"` 37 | // ChildR is the right child of a middle node. 38 | ChildR []byte `db:"child_r"` 39 | // Entry is the data stored in a leaf node. 40 | Entry []byte `db:"entry"` 41 | CreatedAt *uint64 `db:"created_at"` 42 | DeletedAt *uint64 `db:"deleted_at"` 43 | } 44 | 45 | type RootItem struct { 46 | MTId uint64 `db:"mt_id"` 47 | Key []byte `db:"key"` 48 | CreatedAt *uint64 `db:"created_at"` 49 | DeletedAt *uint64 `db:"deleted_at"` 50 | } 51 | 52 | // NewSqlStorage returns a new Storage 53 | func NewSqlStorage(db DB, mtId uint64) *Storage { 54 | return &Storage{db: db, mtId: mtId} 55 | } 56 | 57 | // Get retrieves a value from a key in the db.Storage 58 | func (s *Storage) Get(ctx context.Context, 59 | key []byte) (*merkletree.Node, error) { 60 | item := NodeItem{} 61 | err := s.db.GetContext(ctx, &item, 62 | "SELECT * FROM mt_nodes WHERE mt_id = $1 AND key = $2", s.mtId, key) 63 | if err == sql.ErrNoRows { 64 | return nil, merkletree.ErrNotFound 65 | } 66 | if err != nil { 67 | return nil, err 68 | } 69 | node, err := item.Node() 70 | if err != nil { 71 | return nil, err 72 | } 73 | return node, nil 74 | } 75 | 76 | func (s *Storage) Put(ctx context.Context, key []byte, 77 | node *merkletree.Node) error { 78 | 79 | var childL []byte 80 | if node.ChildL != nil { 81 | childL = append(childL, node.ChildL[:]...) 82 | } 83 | 84 | var childR []byte 85 | if node.ChildR != nil { 86 | childR = append(childR, node.ChildR[:]...) 87 | } 88 | 89 | var entry []byte 90 | if node.Entry[0] != nil && node.Entry[1] != nil { 91 | entry = append(node.Entry[0][:], node.Entry[1][:]...) 92 | } 93 | 94 | _, err := s.db.ExecContext(ctx, upsertStmt, s.mtId, key[:], node.Type, 95 | childL, childR, entry) 96 | return err 97 | } 98 | 99 | // GetRoot retrieves a merkle tree root hash in the interface db.Tx 100 | func (s *Storage) GetRoot(ctx context.Context) (*merkletree.Hash, error) { 101 | var root merkletree.Hash 102 | var err error 103 | 104 | if s.currentRoot != nil { 105 | copy(root[:], s.currentRoot[:]) 106 | return &root, nil 107 | } 108 | 109 | item := RootItem{} 110 | err = s.db.GetContext(ctx, &item, 111 | "SELECT * FROM mt_roots WHERE mt_id = $1", s.mtId) 112 | if err == sql.ErrNoRows { 113 | return nil, merkletree.ErrNotFound 114 | } 115 | if err != nil { 116 | return nil, err 117 | } 118 | if s.currentRoot == nil { 119 | s.currentRoot = &merkletree.Hash{} 120 | } 121 | copy(s.currentRoot[:], item.Key[:]) 122 | copy(root[:], s.currentRoot[:]) 123 | return &root, nil 124 | } 125 | 126 | func (s *Storage) SetRoot(ctx context.Context, hash *merkletree.Hash) error { 127 | if s.currentRoot == nil { 128 | s.currentRoot = &merkletree.Hash{} 129 | } 130 | copy(s.currentRoot[:], hash[:]) 131 | _, err := s.db.ExecContext(ctx, updateRootStmt, s.mtId, s.currentRoot[:]) 132 | if err != nil { 133 | err = newErr(err, "failed to update current root hash") 134 | } 135 | return err 136 | } 137 | 138 | func (item *NodeItem) Node() (*merkletree.Node, error) { 139 | node := merkletree.Node{ 140 | Type: merkletree.NodeType(item.Type), 141 | } 142 | if item.ChildL != nil { 143 | node.ChildL = &merkletree.Hash{} 144 | copy(node.ChildL[:], item.ChildL[:]) 145 | } 146 | if item.ChildR != nil { 147 | node.ChildR = &merkletree.Hash{} 148 | copy(node.ChildR[:], item.ChildR[:]) 149 | } 150 | if len(item.Entry) > 0 { 151 | if len(item.Entry) != 2*merkletree.ElemBytesLen { 152 | return nil, merkletree.ErrNodeBytesBadSize 153 | } 154 | node.Entry = [2]*merkletree.Hash{{}, {}} 155 | copy(node.Entry[0][:], item.Entry[0:32]) 156 | copy(node.Entry[1][:], item.Entry[32:64]) 157 | } 158 | return &node, nil 159 | } 160 | 161 | // KV contains a key (K) and a value (V) 162 | type KV struct { 163 | MTId uint64 164 | K []byte 165 | V merkletree.Node 166 | } 167 | 168 | type storageError struct { 169 | err error 170 | msg string 171 | } 172 | 173 | func (err storageError) Error() string { 174 | return err.msg + ": " + err.err.Error() 175 | } 176 | 177 | func (err storageError) Unwrap() error { 178 | return err.err 179 | } 180 | 181 | func newErr(err error, msg string) error { 182 | return storageError{err, msg} 183 | } 184 | -------------------------------------------------------------------------------- /db/sql/sql_test.go: -------------------------------------------------------------------------------- 1 | package sql 2 | 3 | import ( 4 | "errors" 5 | "io" 6 | "sync/atomic" 7 | "testing" 8 | 9 | "github.com/iden3/go-merkletree-sql/v2" 10 | "github.com/iden3/go-merkletree-sql/v2/db/test" 11 | "github.com/jmoiron/sqlx" 12 | go_test_pg "github.com/olomix/go-test-pg" 13 | "github.com/stretchr/testify/require" 14 | ) 15 | 16 | var maxMTId uint64 = 0 17 | var dbPool = go_test_pg.Pgpool{ 18 | BaseName: "merkletree_sql", 19 | SchemaFile: "./schema.sql", 20 | Skip: false, 21 | } 22 | 23 | type SqlStorageBuilder struct{} 24 | 25 | func (builder *SqlStorageBuilder) NewStorage(t *testing.T) merkletree.Storage { 26 | // Note: Use ENV vars to set database configuration. 27 | // See https://www.postgresql.org/docs/11/libpq-envars.html for details. 28 | db := dbPool.WithStdEmpty(t) 29 | dbx := sqlx.NewDb(db, "pgx") 30 | 31 | mtId := atomic.AddUint64(&maxMTId, 1) 32 | 33 | return NewSqlStorage(dbx, mtId) 34 | } 35 | 36 | func TestSql(t *testing.T) { 37 | builder := &SqlStorageBuilder{} 38 | test.TestAll(t, builder) 39 | } 40 | 41 | func TestErrors(t *testing.T) { 42 | err := storageError{ 43 | err: io.EOF, 44 | msg: "storage error", 45 | } 46 | require.EqualError(t, err, "storage error: EOF") 47 | require.Equal(t, io.EOF, errors.Unwrap(err)) 48 | } 49 | -------------------------------------------------------------------------------- /db/test/test.go: -------------------------------------------------------------------------------- 1 | //nolint:golint 2 | package test 3 | 4 | import ( 5 | "bytes" 6 | "context" 7 | "encoding/hex" 8 | "encoding/json" 9 | "fmt" 10 | "math/big" 11 | "testing" 12 | 13 | "github.com/iden3/go-iden3-crypto/constants" 14 | "github.com/iden3/go-iden3-crypto/poseidon" 15 | "github.com/iden3/go-merkletree-sql/v2" 16 | "github.com/stretchr/testify/assert" 17 | "github.com/stretchr/testify/require" 18 | ) 19 | 20 | var debug = false 21 | 22 | func newTestingMerkle(t *testing.T, sto merkletree.Storage, 23 | numLevels int) *merkletree.MerkleTree { 24 | mt, err := merkletree.NewMerkleTree(context.Background(), sto, numLevels) 25 | require.NoError(t, err) 26 | return mt 27 | } 28 | 29 | type StorageBuilder interface { 30 | NewStorage(t *testing.T) merkletree.Storage 31 | } 32 | 33 | func TestAll(t *testing.T, sb StorageBuilder) { 34 | t.Run("TestReturnKnownErrIfNotExists", func(t *testing.T) { 35 | TestReturnKnownErrIfNotExists(t, sb.NewStorage(t)) 36 | }) 37 | t.Run("TestStorageInsertGet", func(t *testing.T) { 38 | TestStorageInsertGet(t, sb.NewStorage(t)) 39 | }) 40 | t.Run("TestNewTree", func(t *testing.T) { 41 | TestNewTree(t, sb.NewStorage(t)) 42 | }) 43 | t.Run("TestTreeRootWithOneNode", func(t *testing.T) { 44 | TestTreeRootWithOneNode(t, sb.NewStorage(t)) 45 | }) 46 | t.Run("TestAddDifferentOrder", func(t *testing.T) { 47 | TestAddDifferentOrder(t, sb.NewStorage(t), sb.NewStorage(t)) 48 | }) 49 | t.Run("TestAddRepeatedIndex", func(t *testing.T) { 50 | TestAddRepeatedIndex(t, sb.NewStorage(t)) 51 | }) 52 | t.Run("TestGet", func(t *testing.T) { 53 | TestGet(t, sb.NewStorage(t)) 54 | }) 55 | t.Run("TestUpdate", func(t *testing.T) { 56 | TestUpdate(t, sb.NewStorage(t)) 57 | }) 58 | t.Run("TestUpdate2", func(t *testing.T) { 59 | TestUpdate2(t, sb.NewStorage(t)) 60 | }) 61 | t.Run("TestGenerateAndVerifyProof128", func(t *testing.T) { 62 | TestGenerateAndVerifyProof128(t, sb.NewStorage(t)) 63 | }) 64 | t.Run("TestTreeLimit", func(t *testing.T) { 65 | TestTreeLimit(t, sb.NewStorage(t)) 66 | }) 67 | t.Run("TestSiblingsFromProof", func(t *testing.T) { 68 | TestSiblingsFromProof(t, sb.NewStorage(t)) 69 | }) 70 | t.Run("TestVerifyProofCases", func(t *testing.T) { 71 | TestVerifyProofCases(t, sb.NewStorage(t)) 72 | }) 73 | t.Run("TestVerifyProofFalse", func(t *testing.T) { 74 | TestVerifyProofFalse(t, sb.NewStorage(t)) 75 | }) 76 | t.Run("TestGraphViz", func(t *testing.T) { 77 | TestGraphViz(t, sb.NewStorage(t)) 78 | }) 79 | t.Run("TestDelete", func(t *testing.T) { 80 | TestDelete(t, sb.NewStorage(t)) 81 | }) 82 | t.Run("TestDelete2", func(t *testing.T) { 83 | TestDelete2(t, sb.NewStorage(t), sb.NewStorage(t)) 84 | }) 85 | t.Run("TestDelete3", func(t *testing.T) { 86 | TestDelete3(t, sb.NewStorage(t), sb.NewStorage(t)) 87 | }) 88 | t.Run("TestDelete4", func(t *testing.T) { 89 | TestDelete4(t, sb.NewStorage(t), sb.NewStorage(t)) 90 | }) 91 | t.Run("TestDelete5", func(t *testing.T) { 92 | TestDelete5(t, sb.NewStorage(t), sb.NewStorage(t)) 93 | }) 94 | t.Run("TestDeleteNonExistingKeys", func(t *testing.T) { 95 | TestDeleteNonExistingKeys(t, sb.NewStorage(t)) 96 | }) 97 | t.Run("TestDumpLeafsImportLeafs", func(t *testing.T) { 98 | TestDumpLeafsImportLeafs(t, sb.NewStorage(t), sb.NewStorage(t)) 99 | }) 100 | t.Run("TestAddAndGetCircomProof", func(t *testing.T) { 101 | TestAddAndGetCircomProof(t, sb.NewStorage(t)) 102 | }) 103 | t.Run("TestUpdateCircomProcessorProof", func(t *testing.T) { 104 | TestUpdateCircomProcessorProof(t, sb.NewStorage(t)) 105 | }) 106 | t.Run("TestSmtVerifier", func(t *testing.T) { 107 | TestSmtVerifier(t, sb.NewStorage(t)) 108 | }) 109 | t.Run("TestTypesMarshalers", func(t *testing.T) { 110 | TestTypesMarshalers(t, sb.NewStorage(t)) 111 | }) 112 | t.Run("TestDeleteLeafNearMiddleNodeRightBranch", func(t *testing.T) { 113 | TestDeleteLeafNearMiddleNodeRightBranch(t, sb.NewStorage(t)) 114 | }) 115 | t.Run("TestDeleteLeafNearMiddleNodeRightBranchDeep", func(t *testing.T) { 116 | TestDeleteLeafNearMiddleNodeRightBranchDeep(t, sb.NewStorage(t)) 117 | }) 118 | t.Run("TeseDeleteLeafNearMiddleLeftBranch", func(t *testing.T) { 119 | TeseDeleteLeafNearMiddleNodeLeftBranch(t, sb.NewStorage(t)) 120 | }) 121 | t.Run("TeseDeleteLeafNearMiddleLeftBranchDeep", func(t *testing.T) { 122 | TeseDeleteLeafNearMiddleNodeLeftBranchDeep(t, sb.NewStorage(t)) 123 | }) 124 | t.Run("TestUpToRootAfterDeleteRightBranch", func(t *testing.T) { 125 | TestUpToRootAfterDeleteRightBranch(t, sb.NewStorage(t)) 126 | }) 127 | t.Run("TestUpToRootAfterDeleteLeftBranch", func(t *testing.T) { 128 | TestUpToRootAfterDeleteLeftBranch(t, sb.NewStorage(t)) 129 | }) 130 | t.Run("TestCalculatingOfNewRootRightBranch", func(t *testing.T) { 131 | TestCalculatingOfNewRootRightBranch(t, sb.NewStorage(t)) 132 | }) 133 | t.Run("TestCalculatingOfNewRootLeftBranch", func(t *testing.T) { 134 | TestCalculatingOfNewRootLeftBranch(t, sb.NewStorage(t)) 135 | }) 136 | t.Run("TestInsertNodeAfterDelete", func(t *testing.T) { 137 | TestInsertNodeAfterDelete(t, sb.NewStorage(t)) 138 | }) 139 | t.Run("TestInsertDeletedNodeThenUpdateItRightBranch", func(t *testing.T) { 140 | TestInsertDeletedNodeThenUpdateItRightBranch(t, sb.NewStorage(t)) 141 | }) 142 | t.Run("TestInsertDeletedNodeThenUpdateItLeftBranch", func(t *testing.T) { 143 | TestInsertDeletedNodeThenUpdateItLeftBranch(t, sb.NewStorage(t)) 144 | }) 145 | t.Run("TestPushLeafAlreadyExistsRightBranch", func(t *testing.T) { 146 | TestPushLeafAlreadyExistsRightBranch(t, sb.NewStorage(t)) 147 | }) 148 | t.Run("TestPushLeafAlreadyExistsLeftBranch", func(t *testing.T) { 149 | TestPushLeafAlreadyExistsLeftBranch(t, sb.NewStorage(t)) 150 | }) 151 | t.Run("TestUpNodesToTwoLevelsRightBranch", func(t *testing.T) { 152 | TestUpNodesToTwoLevelsRightBranch(t, sb.NewStorage(t)) 153 | }) 154 | t.Run("TestUpNodesToTwoLevelsLeftBranch", func(t *testing.T) { 155 | TestUpNodesToTwoLevelsLeftBranch(t, sb.NewStorage(t)) 156 | }) 157 | } 158 | 159 | // TestReturnKnownErrIfNotExists checks that the implementation of the 160 | // db.Storage interface returns the expected error in the case that the value 161 | // is not found 162 | func TestReturnKnownErrIfNotExists(t *testing.T, sto merkletree.Storage) { 163 | k := []byte("key") 164 | _, err := sto.Get(context.Background(), k) 165 | assert.EqualError(t, err, merkletree.ErrNotFound.Error()) 166 | } 167 | 168 | // TestStorageInsertGet checks that the implementation of the db.Storage 169 | // interface behaves as expected 170 | func TestStorageInsertGet(t *testing.T, sto merkletree.Storage) { 171 | value := merkletree.Hash{1, 1, 1, 1} 172 | 173 | node := merkletree.NewNodeMiddle(&value, &value) 174 | key, err := node.Key() 175 | assert.NoError(t, err) 176 | ctx := context.Background() 177 | err = sto.Put(ctx, key[:], node) 178 | assert.NoError(t, err) 179 | v, err := sto.Get(ctx, key[:]) 180 | assert.NoError(t, err) 181 | assert.Equal(t, value, *v.ChildL) 182 | assert.Equal(t, value, *v.ChildR) 183 | 184 | v, err = sto.Get(ctx, key[:]) 185 | assert.NoError(t, err) 186 | require.NotNil(t, v) 187 | assert.Equal(t, value, *v.ChildL) 188 | assert.Equal(t, value, *v.ChildR) 189 | } 190 | 191 | // 192 | // TODO: Add tests for each storage 193 | // 194 | 195 | func TestNewTree(t *testing.T, sto merkletree.Storage) { 196 | ctx := context.Background() 197 | mt, err := merkletree.NewMerkleTree(ctx, sto, 10) 198 | assert.Nil(t, err) 199 | assert.Equal(t, "0", mt.Root().String()) 200 | 201 | // test vectors generated using https://github.com/iden3/circomlib smt.js 202 | err = mt.Add(ctx, big.NewInt(1), big.NewInt(2)) 203 | assert.Nil(t, err) 204 | assert.Equal(t, 205 | "13578938674299138072471463694055224830892726234048532520316387704878000008795", 206 | mt.Root().BigInt().String()) 207 | 208 | err = mt.Add(ctx, big.NewInt(33), big.NewInt(44)) 209 | assert.Nil(t, err) 210 | assert.Equal(t, 211 | "5412393676474193513566895793055462193090331607895808993925969873307089394741", 212 | mt.Root().BigInt().String()) 213 | 214 | err = mt.Add(ctx, big.NewInt(1234), big.NewInt(9876)) 215 | assert.Nil(t, err) 216 | assert.Equal(t, 217 | "14204494359367183802864593755198662203838502594566452929175967972147978322084", 218 | mt.Root().BigInt().String()) 219 | 220 | dbRoot, err := sto.GetRoot(ctx) 221 | require.Nil(t, err) 222 | assert.Equal(t, mt.Root(), dbRoot) 223 | 224 | proof, v, err := mt.GenerateProof(ctx, big.NewInt(33), nil) 225 | assert.Nil(t, err) 226 | assert.Equal(t, big.NewInt(44), v) 227 | 228 | assert.True(t, merkletree.VerifyProof( 229 | mt.Root(), proof, big.NewInt(33), big.NewInt(44))) 230 | assert.True(t, !merkletree.VerifyProof( 231 | mt.Root(), proof, big.NewInt(33), big.NewInt(45))) 232 | } 233 | 234 | func TestTreeRootWithOneNode(t *testing.T, sto merkletree.Storage) { 235 | ctx := context.Background() 236 | mt, err := merkletree.NewMerkleTree(ctx, sto, 10) 237 | assert.Nil(t, err) 238 | assert.Equal(t, "0", mt.Root().String()) 239 | 240 | err = mt.Add(ctx, big.NewInt(100), big.NewInt(200)) 241 | assert.Nil(t, err) 242 | assert.Equal(t, 243 | "798876344175601936808542466911896801961231313012372360729165540443724338832", 244 | mt.Root().BigInt().String()) 245 | 246 | inputs := []*big.Int{ 247 | big.NewInt(100), // key 248 | big.NewInt(200), // value 249 | big.NewInt(1), 250 | } 251 | res, _ := poseidon.Hash(inputs) 252 | assert.Equal(t, mt.Root().BigInt().String(), res.String()) 253 | } 254 | 255 | func TestAddDifferentOrder(t *testing.T, sto merkletree.Storage, 256 | sto2 merkletree.Storage) { 257 | ctx := context.Background() 258 | 259 | mt1 := newTestingMerkle(t, sto, 140) 260 | for i := 0; i < 16; i++ { 261 | k := big.NewInt(int64(i)) 262 | v := big.NewInt(0) 263 | if err := mt1.Add(ctx, k, v); err != nil { 264 | t.Fatal(err) 265 | } 266 | } 267 | 268 | mt2 := newTestingMerkle(t, sto2, 140) 269 | for i := 16 - 1; i >= 0; i-- { 270 | k := big.NewInt(int64(i)) 271 | v := big.NewInt(0) 272 | if err := mt2.Add(ctx, k, v); err != nil { 273 | t.Fatal(err) 274 | } 275 | } 276 | 277 | assert.Equal(t, mt1.Root().Hex(), mt2.Root().Hex()) 278 | assert.Equal(t, 279 | "3b89100bec24da9275c87bc188740389e1d5accfc7d88ba5688d7fa96a00d82f", 280 | mt1.Root().Hex()) 281 | } 282 | 283 | func TestAddRepeatedIndex(t *testing.T, sto merkletree.Storage) { 284 | mt := newTestingMerkle(t, sto, 140) 285 | k := big.NewInt(int64(3)) 286 | v := big.NewInt(int64(12)) 287 | ctx := context.Background() 288 | if err := mt.Add(ctx, k, v); err != nil { 289 | t.Fatal(err) 290 | } 291 | err := mt.Add(ctx, k, v) 292 | assert.NotNil(t, err) 293 | assert.Equal(t, err, merkletree.ErrEntryIndexAlreadyExists) 294 | } 295 | 296 | func TestGet(t *testing.T, sto merkletree.Storage) { 297 | mt := newTestingMerkle(t, sto, 140) 298 | 299 | ctx := context.Background() 300 | for i := 0; i < 16; i++ { 301 | k := big.NewInt(int64(i)) 302 | v := big.NewInt(int64(i * 2)) 303 | if err := mt.Add(ctx, k, v); err != nil { 304 | t.Fatal(err) 305 | } 306 | } 307 | k, v, _, err := mt.Get(ctx, big.NewInt(10)) 308 | assert.Nil(t, err) 309 | assert.Equal(t, big.NewInt(10), k) 310 | assert.Equal(t, big.NewInt(20), v) 311 | 312 | k, v, _, err = mt.Get(ctx, big.NewInt(15)) 313 | assert.Nil(t, err) 314 | assert.Equal(t, big.NewInt(15), k) 315 | assert.Equal(t, big.NewInt(30), v) 316 | 317 | k, v, _, err = mt.Get(ctx, big.NewInt(16)) 318 | assert.NotNil(t, err) 319 | assert.Equal(t, merkletree.ErrKeyNotFound, err) 320 | assert.Equal(t, "0", k.String()) 321 | assert.Equal(t, "0", v.String()) 322 | } 323 | 324 | func TestUpdate(t *testing.T, sto merkletree.Storage) { 325 | mt := newTestingMerkle(t, sto, 140) 326 | 327 | ctx := context.Background() 328 | 329 | for i := 0; i < 16; i++ { 330 | k := big.NewInt(int64(i)) 331 | v := big.NewInt(int64(i * 2)) 332 | if err := mt.Add(ctx, k, v); err != nil { 333 | t.Fatal(err) 334 | } 335 | } 336 | _, v, _, err := mt.Get(ctx, big.NewInt(10)) 337 | assert.Nil(t, err) 338 | assert.Equal(t, big.NewInt(20), v) 339 | 340 | _, err = mt.Update(ctx, big.NewInt(10), big.NewInt(1024)) 341 | assert.Nil(t, err) 342 | _, v, _, err = mt.Get(ctx, big.NewInt(10)) 343 | assert.Nil(t, err) 344 | assert.Equal(t, big.NewInt(1024), v) 345 | 346 | _, err = mt.Update(ctx, big.NewInt(1000), big.NewInt(1024)) 347 | assert.Equal(t, merkletree.ErrKeyNotFound, err) 348 | 349 | dbRoot, err := sto.GetRoot(ctx) 350 | require.Nil(t, err) 351 | assert.Equal(t, mt.Root(), dbRoot) 352 | } 353 | 354 | func TestUpdate2(t *testing.T, sto merkletree.Storage) { 355 | mt1 := newTestingMerkle(t, sto, 140) 356 | mt2 := newTestingMerkle(t, sto, 140) 357 | 358 | ctx := context.Background() 359 | 360 | err := mt1.Add(ctx, big.NewInt(1), big.NewInt(119)) 361 | assert.Nil(t, err) 362 | err = mt1.Add(ctx, big.NewInt(2), big.NewInt(229)) 363 | assert.Nil(t, err) 364 | err = mt1.Add(ctx, big.NewInt(9876), big.NewInt(6789)) 365 | assert.Nil(t, err) 366 | 367 | err = mt2.Add(ctx, big.NewInt(1), big.NewInt(11)) 368 | assert.Nil(t, err) 369 | err = mt2.Add(ctx, big.NewInt(2), big.NewInt(22)) 370 | assert.Nil(t, err) 371 | err = mt2.Add(ctx, big.NewInt(9876), big.NewInt(10)) 372 | assert.Nil(t, err) 373 | 374 | _, err = mt1.Update(ctx, big.NewInt(1), big.NewInt(11)) 375 | assert.Nil(t, err) 376 | _, err = mt1.Update(ctx, big.NewInt(2), big.NewInt(22)) 377 | assert.Nil(t, err) 378 | _, err = mt2.Update(ctx, big.NewInt(9876), big.NewInt(6789)) 379 | assert.Nil(t, err) 380 | 381 | assert.Equal(t, mt1.Root(), mt2.Root()) 382 | } 383 | 384 | func TestGenerateAndVerifyProof128(t *testing.T, sto merkletree.Storage) { 385 | ctx := context.Background() 386 | mt, err := merkletree.NewMerkleTree(ctx, sto, 140) 387 | require.Nil(t, err) 388 | 389 | for i := 0; i < 128; i++ { 390 | k := big.NewInt(int64(i)) 391 | v := big.NewInt(0) 392 | if err := mt.Add(ctx, k, v); err != nil { 393 | t.Fatal(err) 394 | } 395 | } 396 | proof, v, err := mt.GenerateProof(ctx, big.NewInt(42), nil) 397 | assert.Nil(t, err) 398 | assert.Equal(t, "0", v.String()) 399 | assert.True(t, merkletree.VerifyProof( 400 | mt.Root(), proof, big.NewInt(42), big.NewInt(0))) 401 | } 402 | 403 | func TestTreeLimit(t *testing.T, sto merkletree.Storage) { 404 | ctx := context.Background() 405 | mt, err := merkletree.NewMerkleTree(ctx, sto, 5) 406 | require.Nil(t, err) 407 | 408 | for i := 0; i < 16; i++ { 409 | err = mt.Add(ctx, big.NewInt(int64(i)), big.NewInt(int64(i))) 410 | assert.Nil(t, err) 411 | } 412 | 413 | // here the tree is full, should not allow to add more data as reaches the maximum number of levels 414 | err = mt.Add(ctx, big.NewInt(int64(16)), big.NewInt(int64(16))) 415 | assert.NotNil(t, err) 416 | assert.Equal(t, merkletree.ErrReachedMaxLevel, err) 417 | } 418 | 419 | func TestSiblingsFromProof(t *testing.T, sto merkletree.Storage) { 420 | ctx := context.Background() 421 | mt, err := merkletree.NewMerkleTree(ctx, sto, 140) 422 | require.Nil(t, err) 423 | 424 | for i := 0; i < 64; i++ { 425 | k := big.NewInt(int64(i)) 426 | v := big.NewInt(0) 427 | if err := mt.Add(ctx, k, v); err != nil { 428 | t.Fatal(err) 429 | } 430 | } 431 | 432 | proof, _, err := mt.GenerateProof(ctx, big.NewInt(4), nil) 433 | if err != nil { 434 | t.Fatal(err) 435 | } 436 | 437 | siblings := merkletree.SiblingsFromProof(proof) 438 | assert.Equal(t, 6, len(siblings)) 439 | assert.Equal(t, 440 | "d6e368bda90c5ee3e910222c1fc1c0d9e23f2d350dbc47f4a92de30f1be3c60b", 441 | siblings[0].Hex()) 442 | assert.Equal(t, 443 | "9dbd03b1bcd580e0f3e6668d80d55288f04464126feb1624ec8ee30be8df9c16", 444 | siblings[1].Hex()) 445 | assert.Equal(t, 446 | "de866af9545dcd1c5bb7811e7f27814918e037eb9fead40919e8f19525896e27", 447 | siblings[2].Hex()) 448 | assert.Equal(t, 449 | "5f4182212a84741d1174ba7c42e369f2e3ad8ade7d04eea2d0f98e3ed8b7a317", 450 | siblings[3].Hex()) 451 | assert.Equal(t, 452 | "77639098d513f7aef9730fdb1d1200401af5fe9da91b61772f4dd142ac89a122", 453 | siblings[4].Hex()) 454 | assert.Equal(t, 455 | "943ee501f4ba2137c79b54af745dfc5f105f539fcc449cd2a356eb5c030e3c07", 456 | siblings[5].Hex()) 457 | } 458 | 459 | func TestVerifyProofCases(t *testing.T, sto merkletree.Storage) { 460 | mt := newTestingMerkle(t, sto, 140) 461 | 462 | ctx := context.Background() 463 | for i := 0; i < 8; i++ { 464 | if err := mt.Add(ctx, big.NewInt(int64(i)), big.NewInt(0)); err != nil { 465 | t.Fatal(err) 466 | } 467 | } 468 | 469 | // Existence proof 470 | proof, _, err := mt.GenerateProof(ctx, big.NewInt(4), nil) 471 | if err != nil { 472 | t.Fatal(err) 473 | } 474 | assert.Equal(t, proof.Existence, true) 475 | assert.True(t, 476 | merkletree.VerifyProof(mt.Root(), proof, big.NewInt(4), big.NewInt(0))) 477 | assert.Equal(t, 478 | "0003000000000000000000000000000000000000000000000000000000000007529cbedbda2bdd25fd6455551e55245fa6dc11a9d0c27dc0cd38fca44c17e40344ad686a18ba78b502c0b6f285c5c8393bde2f7a3e2abe586515e4d84533e3037b062539bde2d80749746986cf8f0001fd2cdbf9a89fcbf981a769daef49df06", //nolint:lll 479 | hex.EncodeToString(proof.Bytes())) 480 | 481 | for i := 8; i < 32; i++ { 482 | proof, _, err = mt.GenerateProof(ctx, big.NewInt(int64(i)), nil) 483 | assert.Nil(t, err) 484 | if debug { 485 | fmt.Println(i, proof) 486 | } 487 | } 488 | // Non-existence proof, empty aux 489 | proof, _, err = mt.GenerateProof(ctx, big.NewInt(12), nil) 490 | if err != nil { 491 | t.Fatal(err) 492 | } 493 | assert.Equal(t, proof.Existence, false) 494 | // assert.True(t, proof.nodeAux == nil) 495 | assert.True(t, 496 | merkletree.VerifyProof(mt.Root(), proof, big.NewInt(12), big.NewInt(0))) 497 | assert.Equal(t, 498 | "0303000000000000000000000000000000000000000000000000000000000007529cbedbda2bdd25fd6455551e55245fa6dc11a9d0c27dc0cd38fca44c17e40344ad686a18ba78b502c0b6f285c5c8393bde2f7a3e2abe586515e4d84533e3037b062539bde2d80749746986cf8f0001fd2cdbf9a89fcbf981a769daef49df0604000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", //nolint:lll 499 | hex.EncodeToString(proof.Bytes())) 500 | 501 | // Non-existence proof, diff. node aux 502 | proof, _, err = mt.GenerateProof(ctx, big.NewInt(10), nil) 503 | if err != nil { 504 | t.Fatal(err) 505 | } 506 | assert.Equal(t, proof.Existence, false) 507 | assert.True(t, proof.NodeAux != nil) 508 | assert.True(t, 509 | merkletree.VerifyProof(mt.Root(), proof, big.NewInt(10), big.NewInt(0))) 510 | assert.Equal(t, 511 | "0303000000000000000000000000000000000000000000000000000000000007529cbedbda2bdd25fd6455551e55245fa6dc11a9d0c27dc0cd38fca44c17e4030acfcdd2617df9eb5aef744c5f2e03eb8c92c61f679007dc1f2707fd908ea41a9433745b469c101edca814c498e7f388100d497b24f1d2ac935bced3572f591d02000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", //nolint:lll 512 | hex.EncodeToString(proof.Bytes())) 513 | } 514 | 515 | func TestVerifyProofFalse(t *testing.T, sto merkletree.Storage) { 516 | mt := newTestingMerkle(t, sto, 140) 517 | 518 | ctx := context.Background() 519 | for i := 0; i < 8; i++ { 520 | if err := mt.Add(ctx, big.NewInt(int64(i)), big.NewInt(0)); err != nil { 521 | t.Fatal(err) 522 | } 523 | } 524 | 525 | // Invalid existence proof (node used for verification doesn't 526 | // correspond to node in the proof) 527 | proof, _, err := mt.GenerateProof(ctx, big.NewInt(int64(4)), nil) 528 | if err != nil { 529 | t.Fatal(err) 530 | } 531 | assert.Equal(t, proof.Existence, true) 532 | assert.True(t, !merkletree.VerifyProof(mt.Root(), proof, 533 | big.NewInt(int64(5)), big.NewInt(int64(5)))) 534 | 535 | // Invalid non-existence proof (Non-existence proof, diff. node aux) 536 | proof, _, err = mt.GenerateProof(ctx, big.NewInt(int64(4)), nil) 537 | if err != nil { 538 | t.Fatal(err) 539 | } 540 | assert.Equal(t, proof.Existence, true) 541 | // Now we change the proof from existence to non-existence, and add e's 542 | // data as auxiliary node. 543 | proof.Existence = false 544 | proof.NodeAux = &merkletree.NodeAux{ 545 | Key: hashFromInt(big.NewInt(int64(4))), 546 | Value: hashFromInt(big.NewInt(4))} 547 | assert.True(t, 548 | !merkletree.VerifyProof(mt.Root(), proof, big.NewInt(int64(4)), 549 | big.NewInt(0))) 550 | } 551 | 552 | func hashFromInt(in *big.Int) *merkletree.Hash { 553 | h, err := merkletree.NewHashFromBigInt(in) 554 | if err != nil { 555 | panic(err) 556 | } 557 | return h 558 | } 559 | 560 | func TestGraphViz(t *testing.T, sto merkletree.Storage) { 561 | ctx := context.Background() 562 | mt, err := merkletree.NewMerkleTree(ctx, sto, 10) 563 | assert.Nil(t, err) 564 | 565 | _ = mt.Add(ctx, big.NewInt(1), big.NewInt(0)) 566 | _ = mt.Add(ctx, big.NewInt(2), big.NewInt(0)) 567 | _ = mt.Add(ctx, big.NewInt(3), big.NewInt(0)) 568 | _ = mt.Add(ctx, big.NewInt(4), big.NewInt(0)) 569 | _ = mt.Add(ctx, big.NewInt(5), big.NewInt(0)) 570 | _ = mt.Add(ctx, big.NewInt(100), big.NewInt(0)) 571 | 572 | // mt.PrintGraphViz(nil) 573 | 574 | expected := `digraph hierarchy { 575 | node [fontname=Monospace,fontsize=10,shape=box] 576 | "56332309..." -> {"18483622..." "20902180..."} 577 | "18483622..." -> {"75768243..." "16893244..."} 578 | "75768243..." -> {"empty0" "21857056..."} 579 | "empty0" [style=dashed,label=0]; 580 | "21857056..." -> {"51072523..." "empty1"} 581 | "empty1" [style=dashed,label=0]; 582 | "51072523..." -> {"17311038..." "empty2"} 583 | "empty2" [style=dashed,label=0]; 584 | "17311038..." -> {"69499803..." "21008290..."} 585 | "69499803..." [style=filled]; 586 | "21008290..." [style=filled]; 587 | "16893244..." [style=filled]; 588 | "20902180..." -> {"12496585..." "18055627..."} 589 | "12496585..." -> {"19374975..." "15739329..."} 590 | "19374975..." [style=filled]; 591 | "15739329..." [style=filled]; 592 | "18055627..." [style=filled]; 593 | } 594 | ` 595 | w := bytes.NewBufferString("") 596 | err = mt.GraphViz(ctx, w, nil) 597 | assert.Nil(t, err) 598 | assert.Equal(t, []byte(expected), w.Bytes()) 599 | } 600 | 601 | func TestDelete(t *testing.T, sto merkletree.Storage) { 602 | mt, err := merkletree.NewMerkleTree(context.Background(), sto, 10) 603 | assert.Nil(t, err) 604 | assert.Equal(t, "0", mt.Root().String()) 605 | ctx := context.Background() 606 | 607 | // test vectors generated using https://github.com/iden3/circomlib smt.js 608 | err = mt.Add(ctx, big.NewInt(1), big.NewInt(2)) 609 | assert.Nil(t, err) 610 | assert.Equal(t, 611 | "13578938674299138072471463694055224830892726234048532520316387704878000008795", 612 | mt.Root().BigInt().String()) 613 | 614 | err = mt.Add(ctx, big.NewInt(33), big.NewInt(44)) 615 | assert.Nil(t, err) 616 | assert.Equal(t, 617 | "5412393676474193513566895793055462193090331607895808993925969873307089394741", 618 | mt.Root().BigInt().String()) 619 | 620 | err = mt.Add(ctx, big.NewInt(1234), big.NewInt(9876)) 621 | assert.Nil(t, err) 622 | assert.Equal(t, 623 | "14204494359367183802864593755198662203838502594566452929175967972147978322084", 624 | mt.Root().BigInt().String()) 625 | 626 | // mt.PrintGraphViz(nil) 627 | 628 | err = mt.Delete(ctx, big.NewInt(33)) 629 | // mt.PrintGraphViz(nil) 630 | assert.Nil(t, err) 631 | assert.Equal(t, 632 | "15550352095346187559699212771793131433118240951738528922418613687814377955591", 633 | mt.Root().BigInt().String()) 634 | 635 | err = mt.Delete(ctx, big.NewInt(1234)) 636 | assert.Nil(t, err) 637 | err = mt.Delete(ctx, big.NewInt(1)) 638 | assert.Nil(t, err) 639 | assert.Equal(t, "0", mt.Root().String()) 640 | 641 | dbRoot, err := sto.GetRoot(ctx) 642 | require.Nil(t, err) 643 | assert.Equal(t, mt.Root(), dbRoot) 644 | } 645 | 646 | func TestDelete2(t *testing.T, sto merkletree.Storage, 647 | sto2 merkletree.Storage) { 648 | ctx := context.Background() 649 | mt := newTestingMerkle(t, sto, 140) 650 | for i := 0; i < 8; i++ { 651 | k := big.NewInt(int64(i)) 652 | v := big.NewInt(0) 653 | if err := mt.Add(ctx, k, v); err != nil { 654 | t.Fatal(err) 655 | } 656 | } 657 | 658 | expectedRoot := mt.Root() 659 | 660 | k := big.NewInt(8) 661 | v := big.NewInt(0) 662 | err := mt.Add(ctx, k, v) 663 | require.Nil(t, err) 664 | 665 | err = mt.Delete(ctx, big.NewInt(8)) 666 | assert.Nil(t, err) 667 | assert.Equal(t, expectedRoot, mt.Root()) 668 | 669 | mt2 := newTestingMerkle(t, sto2, 140) 670 | for i := 0; i < 8; i++ { 671 | k := big.NewInt(int64(i)) 672 | v := big.NewInt(0) 673 | if err := mt2.Add(ctx, k, v); err != nil { 674 | t.Fatal(err) 675 | } 676 | } 677 | assert.Equal(t, mt2.Root(), mt.Root()) 678 | } 679 | 680 | func TestDelete3(t *testing.T, sto merkletree.Storage, 681 | sto2 merkletree.Storage) { 682 | mt := newTestingMerkle(t, sto, 140) 683 | 684 | ctx := context.Background() 685 | err := mt.Add(ctx, big.NewInt(1), big.NewInt(1)) 686 | assert.Nil(t, err) 687 | 688 | err = mt.Add(ctx, big.NewInt(2), big.NewInt(2)) 689 | assert.Nil(t, err) 690 | 691 | assert.Equal(t, 692 | "19060075022714027595905950662613111880864833370144986660188929919683258088314", 693 | mt.Root().BigInt().String()) 694 | err = mt.Delete(ctx, big.NewInt(1)) 695 | assert.Nil(t, err) 696 | assert.Equal(t, 697 | "849831128489032619062850458217693666094013083866167024127442191257793527951", 698 | mt.Root().BigInt().String()) 699 | 700 | mt2 := newTestingMerkle(t, sto2, 140) 701 | err = mt2.Add(ctx, big.NewInt(2), big.NewInt(2)) 702 | assert.Nil(t, err) 703 | assert.Equal(t, mt2.Root(), mt.Root()) 704 | } 705 | 706 | func TestDelete4(t *testing.T, sto merkletree.Storage, 707 | sto2 merkletree.Storage) { 708 | mt := newTestingMerkle(t, sto, 140) 709 | 710 | ctx := context.Background() 711 | err := mt.Add(ctx, big.NewInt(1), big.NewInt(1)) 712 | assert.Nil(t, err) 713 | 714 | err = mt.Add(ctx, big.NewInt(2), big.NewInt(2)) 715 | assert.Nil(t, err) 716 | 717 | err = mt.Add(ctx, big.NewInt(3), big.NewInt(3)) 718 | assert.Nil(t, err) 719 | 720 | assert.Equal(t, 721 | "14109632483797541575275728657193822866549917334388996328141438956557066918117", 722 | mt.Root().BigInt().String()) 723 | err = mt.Delete(ctx, big.NewInt(1)) 724 | assert.Nil(t, err) 725 | assert.Equal(t, 726 | "159935162486187606489815340465698714590556679404589449576549073038844694972", 727 | mt.Root().BigInt().String()) 728 | 729 | mt2 := newTestingMerkle(t, sto2, 140) 730 | err = mt2.Add(ctx, big.NewInt(2), big.NewInt(2)) 731 | assert.Nil(t, err) 732 | err = mt2.Add(ctx, big.NewInt(3), big.NewInt(3)) 733 | assert.Nil(t, err) 734 | assert.Equal(t, mt2.Root(), mt.Root()) 735 | } 736 | 737 | func TestDelete5(t *testing.T, sto merkletree.Storage, 738 | sto2 merkletree.Storage) { 739 | ctx := context.Background() 740 | mt, err := merkletree.NewMerkleTree(ctx, sto, 10) 741 | assert.Nil(t, err) 742 | 743 | err = mt.Add(ctx, big.NewInt(1), big.NewInt(2)) 744 | assert.Nil(t, err) 745 | err = mt.Add(ctx, big.NewInt(33), big.NewInt(44)) 746 | assert.Nil(t, err) 747 | assert.Equal(t, 748 | "5412393676474193513566895793055462193090331607895808993925969873307089394741", 749 | mt.Root().BigInt().String()) 750 | 751 | err = mt.Delete(ctx, big.NewInt(1)) 752 | assert.Nil(t, err) 753 | assert.Equal(t, 754 | "18869260084287237667925661423624848342947598951870765316380602291081195309822", 755 | mt.Root().BigInt().String()) 756 | 757 | mt2 := newTestingMerkle(t, sto2, 140) 758 | err = mt2.Add(ctx, big.NewInt(33), big.NewInt(44)) 759 | assert.Nil(t, err) 760 | assert.Equal(t, mt2.Root(), mt.Root()) 761 | } 762 | 763 | func TestDeleteNonExistingKeys(t *testing.T, sto merkletree.Storage) { 764 | ctx := context.Background() 765 | mt, err := merkletree.NewMerkleTree(ctx, sto, 10) 766 | assert.Nil(t, err) 767 | 768 | err = mt.Add(ctx, big.NewInt(1), big.NewInt(2)) 769 | assert.Nil(t, err) 770 | err = mt.Add(ctx, big.NewInt(33), big.NewInt(44)) 771 | assert.Nil(t, err) 772 | 773 | err = mt.Delete(ctx, big.NewInt(33)) 774 | assert.Nil(t, err) 775 | err = mt.Delete(ctx, big.NewInt(33)) 776 | assert.Equal(t, merkletree.ErrKeyNotFound, err) 777 | 778 | err = mt.Delete(ctx, big.NewInt(1)) 779 | assert.Nil(t, err) 780 | 781 | assert.Equal(t, "0", mt.Root().String()) 782 | 783 | err = mt.Delete(ctx, big.NewInt(33)) 784 | assert.Equal(t, merkletree.ErrKeyNotFound, err) 785 | } 786 | 787 | func TestDumpLeafsImportLeafs(t *testing.T, sto merkletree.Storage, 788 | sto2 merkletree.Storage) { 789 | ctx := context.Background() 790 | mt, err := merkletree.NewMerkleTree(ctx, sto, 140) 791 | require.Nil(t, err) 792 | 793 | q1 := new(big.Int).Sub(constants.Q, big.NewInt(1)) 794 | for i := 0; i < 10; i++ { 795 | // use numbers near under Q 796 | k := new(big.Int).Sub(q1, big.NewInt(int64(i))) 797 | v := big.NewInt(0) 798 | err = mt.Add(ctx, k, v) 799 | require.Nil(t, err) 800 | 801 | // use numbers near above 0 802 | k = big.NewInt(int64(i)) 803 | err = mt.Add(ctx, k, v) 804 | require.Nil(t, err) 805 | } 806 | 807 | d, err := mt.DumpLeafs(ctx, nil) 808 | assert.Nil(t, err) 809 | 810 | mt2, err := merkletree.NewMerkleTree(ctx, sto2, 140) 811 | require.Nil(t, err) 812 | err = mt2.ImportDumpedLeafs(ctx, d) 813 | assert.Nil(t, err) 814 | 815 | assert.Equal(t, mt.Root(), mt2.Root()) 816 | } 817 | 818 | func TestAddAndGetCircomProof(t *testing.T, sto merkletree.Storage) { 819 | ctx := context.Background() 820 | mt, err := merkletree.NewMerkleTree(ctx, sto, 10) 821 | assert.Nil(t, err) 822 | assert.Equal(t, "0", mt.Root().String()) 823 | 824 | // test vectors generated using https://github.com/iden3/circomlib smt.js 825 | cpp, err := mt.AddAndGetCircomProof(ctx, big.NewInt(1), big.NewInt(2)) 826 | assert.Nil(t, err) 827 | assert.Equal(t, "0", cpp.OldRoot.String()) 828 | assert.Equal(t, "13578938...", cpp.NewRoot.String()) 829 | assert.Equal(t, "0", cpp.OldKey.String()) 830 | assert.Equal(t, "0", cpp.OldValue.String()) 831 | assert.Equal(t, "1", cpp.NewKey.String()) 832 | assert.Equal(t, "2", cpp.NewValue.String()) 833 | assert.Equal(t, true, cpp.IsOld0) 834 | assert.Equal(t, "[0 0 0 0 0 0 0 0 0 0 0]", fmt.Sprintf("%v", cpp.Siblings)) 835 | assert.Equal(t, mt.MaxLevels()+1, len(cpp.Siblings)) 836 | 837 | cpp, err = mt.AddAndGetCircomProof(ctx, big.NewInt(33), big.NewInt(44)) 838 | assert.Nil(t, err) 839 | assert.Equal(t, "13578938...", cpp.OldRoot.String()) 840 | assert.Equal(t, "54123936...", cpp.NewRoot.String()) 841 | assert.Equal(t, "1", cpp.OldKey.String()) 842 | assert.Equal(t, "2", cpp.OldValue.String()) 843 | assert.Equal(t, "33", cpp.NewKey.String()) 844 | assert.Equal(t, "44", cpp.NewValue.String()) 845 | assert.Equal(t, false, cpp.IsOld0) 846 | assert.Equal(t, "[0 0 0 0 0 0 0 0 0 0 0]", fmt.Sprintf("%v", cpp.Siblings)) 847 | assert.Equal(t, mt.MaxLevels()+1, len(cpp.Siblings)) 848 | 849 | cpp, err = mt.AddAndGetCircomProof(ctx, big.NewInt(55), big.NewInt(66)) 850 | assert.Nil(t, err) 851 | assert.Equal(t, "54123936...", cpp.OldRoot.String()) 852 | assert.Equal(t, "50943640...", cpp.NewRoot.String()) 853 | assert.Equal(t, "0", cpp.OldKey.String()) 854 | assert.Equal(t, "0", cpp.OldValue.String()) 855 | assert.Equal(t, "55", cpp.NewKey.String()) 856 | assert.Equal(t, "66", cpp.NewValue.String()) 857 | assert.Equal(t, true, cpp.IsOld0) 858 | assert.Equal(t, "[0 21312042... 0 0 0 0 0 0 0 0 0]", 859 | fmt.Sprintf("%v", cpp.Siblings)) 860 | assert.Equal(t, mt.MaxLevels()+1, len(cpp.Siblings)) 861 | } 862 | 863 | func TestUpdateCircomProcessorProof(t *testing.T, sto merkletree.Storage) { 864 | ctx := context.Background() 865 | mt := newTestingMerkle(t, sto, 10) 866 | 867 | for i := 0; i < 16; i++ { 868 | k := big.NewInt(int64(i)) 869 | v := big.NewInt(int64(i * 2)) 870 | if err := mt.Add(ctx, k, v); err != nil { 871 | t.Fatal(err) 872 | } 873 | } 874 | _, v, _, err := mt.Get(ctx, big.NewInt(10)) 875 | assert.Nil(t, err) 876 | assert.Equal(t, big.NewInt(20), v) 877 | 878 | // test vectors generated using https://github.com/iden3/circomlib smt.js 879 | cpp, err := mt.Update(ctx, big.NewInt(10), big.NewInt(1024)) 880 | assert.Nil(t, err) 881 | assert.Equal(t, "39010880...", cpp.OldRoot.String()) 882 | assert.Equal(t, "18587862...", cpp.NewRoot.String()) 883 | assert.Equal(t, "10", cpp.OldKey.String()) 884 | assert.Equal(t, "20", cpp.OldValue.String()) 885 | assert.Equal(t, "10", cpp.NewKey.String()) 886 | assert.Equal(t, "1024", cpp.NewValue.String()) 887 | assert.Equal(t, false, cpp.IsOld0) 888 | assert.Equal(t, 889 | "[34930557... 20201609... 18790542... 15930030... 0 0 0 0 0 0 0]", 890 | fmt.Sprintf("%v", cpp.Siblings)) 891 | } 892 | 893 | func TestSmtVerifier(t *testing.T, sto merkletree.Storage) { 894 | ctx := context.Background() 895 | mt, err := merkletree.NewMerkleTree(ctx, sto, 4) 896 | assert.Nil(t, err) 897 | 898 | err = mt.Add(ctx, big.NewInt(1), big.NewInt(11)) 899 | assert.Nil(t, err) 900 | 901 | cvp, err := mt.GenerateSCVerifierProof(ctx, big.NewInt(1), nil) 902 | assert.Nil(t, err) 903 | jCvp, err := json.Marshal(cvp) 904 | assert.Nil(t, err) 905 | // expect siblings to be '[]', instead of 'null' 906 | expected := `{"root":"6525056641794203554583616941316772618766382307684970171204065038799368146416","siblings":[],"oldKey":"0","oldValue":"0","isOld0":false,"key":"1","value":"11","fnc":0}` //nolint:lll 907 | 908 | assert.Equal(t, expected, string(jCvp)) 909 | err = mt.Add(ctx, big.NewInt(2), big.NewInt(22)) 910 | assert.Nil(t, err) 911 | err = mt.Add(ctx, big.NewInt(3), big.NewInt(33)) 912 | assert.Nil(t, err) 913 | err = mt.Add(ctx, big.NewInt(4), big.NewInt(44)) 914 | assert.Nil(t, err) 915 | 916 | cvp, err = mt.GenerateCircomVerifierProof(ctx, big.NewInt(2), nil) 917 | assert.Nil(t, err) 918 | 919 | jCvp, err = json.Marshal(cvp) 920 | assert.Nil(t, err) 921 | // Test vectors generated using https://github.com/iden3/circomlib smt.js 922 | // Expect siblings with the extra 0 that the circom circuits need 923 | expected = `{"root":"13558168455220559042747853958949063046226645447188878859760119761585093422436","siblings":["11620130507635441932056895853942898236773847390796721536119314875877874016518","5158240518874928563648144881543092238925265313977134167935552944620041388700","0","0","0"],"oldKey":"0","oldValue":"0","isOld0":false,"key":"2","value":"22","fnc":0}` //nolint:lll 924 | assert.Equal(t, expected, string(jCvp)) 925 | 926 | cvp, err = mt.GenerateSCVerifierProof(ctx, big.NewInt(2), nil) 927 | assert.Nil(t, err) 928 | 929 | jCvp, err = json.Marshal(cvp) 930 | assert.Nil(t, err) 931 | // Test vectors generated using https://github.com/iden3/circomlib smt.js 932 | // Without the extra 0 that the circom circuits need, but that are not 933 | // needed at a smart contract verification 934 | expected = `{"root":"13558168455220559042747853958949063046226645447188878859760119761585093422436","siblings":["11620130507635441932056895853942898236773847390796721536119314875877874016518","5158240518874928563648144881543092238925265313977134167935552944620041388700"],"oldKey":"0","oldValue":"0","isOld0":false,"key":"2","value":"22","fnc":0}` //nolint:lll 935 | assert.Equal(t, expected, string(jCvp)) 936 | } 937 | 938 | func TestTypesMarshalers(t *testing.T, sto merkletree.Storage) { 939 | // test Hash marshalers 940 | h, err := merkletree.NewHashFromString("42") 941 | assert.Nil(t, err) 942 | s, err := json.Marshal(h) 943 | assert.Nil(t, err) 944 | var h2 *merkletree.Hash 945 | err = json.Unmarshal(s, &h2) 946 | assert.Nil(t, err) 947 | assert.Equal(t, h, h2) 948 | 949 | ctx := context.Background() 950 | 951 | // create CircomProcessorProof 952 | mt := newTestingMerkle(t, sto, 10) 953 | for i := 0; i < 16; i++ { 954 | k := big.NewInt(int64(i)) 955 | v := big.NewInt(int64(i * 2)) 956 | if err := mt.Add(ctx, k, v); err != nil { 957 | t.Fatal(err) 958 | } 959 | } 960 | _, v, _, err := mt.Get(ctx, big.NewInt(10)) 961 | assert.Nil(t, err) 962 | assert.Equal(t, big.NewInt(20), v) 963 | cpp, err := mt.Update(ctx, big.NewInt(10), big.NewInt(1024)) 964 | assert.Nil(t, err) 965 | 966 | // test CircomProcessorProof marshalers 967 | b, err := json.Marshal(&cpp) 968 | assert.Nil(t, err) 969 | 970 | var cpp2 *merkletree.CircomProcessorProof 971 | err = json.Unmarshal(b, &cpp2) 972 | assert.Nil(t, err) 973 | assert.Equal(t, cpp, cpp2) 974 | } 975 | 976 | func TestDeleteLeafNearMiddleNodeRightBranch(t *testing.T, sto merkletree.Storage) { 977 | ctx := context.Background() 978 | mt, err := merkletree.NewMerkleTree(ctx, sto, 140) 979 | require.Nil(t, err) 980 | 981 | values := []*big.Int{big.NewInt(7), big.NewInt(1), big.NewInt(5)} 982 | 983 | expectedSiblings := map[string][]*big.Int{ 984 | "7": {}, 985 | "1": { 986 | big.NewInt(0), 987 | newBigIntFromString(t, 988 | "3968539605503372859924195689353752825000692947459401078008697788408142999740"), 989 | }, 990 | "5": { 991 | big.NewInt(0), 992 | newBigIntFromString(t, 993 | "3968539605503372859924195689353752825000692947459401078008697788408142999740"), 994 | newBigIntFromString(t, 995 | "1243904711429961858774220647610724273798918457991486031567244100767259239747"), 996 | }, 997 | } 998 | 999 | for _, v := range values { 1000 | err = mt.Add(ctx, v, v) 1001 | require.NoError(t, err) 1002 | existProof, _, err := mt.GenerateProof(ctx, v, mt.Root()) 1003 | require.NoError(t, err) 1004 | require.True(t, existProof.Existence) 1005 | compareSiblings(t, 1006 | expectedSiblings[v.String()], existProof.AllSiblings()) 1007 | } 1008 | 1009 | expectedSiblingsNonExist := map[string][]*big.Int{ 1010 | "7": { 1011 | big.NewInt(0), 1012 | newBigIntFromString(t, 1013 | "4274876798241152869364032215387952876266736406919374878317677138322903129320"), 1014 | }, 1015 | "1": {}, 1016 | "5": {}, 1017 | } 1018 | for _, v := range values { 1019 | err = mt.Delete(ctx, v) 1020 | require.NoError(t, err) 1021 | existProof, _, err := mt.GenerateProof(ctx, v, mt.Root()) 1022 | require.NoError(t, err) 1023 | require.False(t, existProof.Existence) 1024 | compareSiblings(t, 1025 | expectedSiblingsNonExist[v.String()], existProof.AllSiblings()) 1026 | } 1027 | } 1028 | 1029 | func TestDeleteLeafNearMiddleNodeRightBranchDeep(t *testing.T, sto merkletree.Storage) { 1030 | ctx := context.Background() 1031 | mt, err := merkletree.NewMerkleTree(ctx, sto, 140) 1032 | require.Nil(t, err) 1033 | 1034 | values := []*big.Int{big.NewInt(3), big.NewInt(7), big.NewInt(15)} 1035 | 1036 | expectedSiblings := map[string][]*big.Int{ 1037 | "3": {}, 1038 | "7": { 1039 | big.NewInt(0), 1040 | big.NewInt(0), 1041 | newBigIntFromString(t, 1042 | "14218827602097913497782608311388761513660285528499590827800641410537362569671"), 1043 | }, 1044 | "15": { 1045 | big.NewInt(0), 1046 | big.NewInt(0), 1047 | newBigIntFromString(t, 1048 | "14218827602097913497782608311388761513660285528499590827800641410537362569671"), 1049 | newBigIntFromString(t, 1050 | "3968539605503372859924195689353752825000692947459401078008697788408142999740"), 1051 | }, 1052 | } 1053 | 1054 | for _, v := range values { 1055 | err = mt.Add(ctx, v, v) 1056 | require.NoError(t, err) 1057 | existProof, _, err := mt.GenerateProof(ctx, v, mt.Root()) 1058 | require.NoError(t, err) 1059 | require.True(t, existProof.Existence) 1060 | compareSiblings(t, 1061 | expectedSiblings[v.String()], existProof.AllSiblings()) 1062 | } 1063 | 1064 | expectedSiblingsNonExist := map[string][]*big.Int{ 1065 | "3": { 1066 | big.NewInt(0), 1067 | big.NewInt(0), 1068 | newBigIntFromString(t, 1069 | "10179745751648650481317481301133564568831136415508833815669215270622331305772"), 1070 | }, 1071 | "7": {}, 1072 | "15": {}, 1073 | } 1074 | for _, v := range values { 1075 | err = mt.Delete(ctx, v) 1076 | require.NoError(t, err) 1077 | existProof, _, err := mt.GenerateProof(ctx, v, mt.Root()) 1078 | require.NoError(t, err) 1079 | require.False(t, existProof.Existence) 1080 | compareSiblings(t, 1081 | expectedSiblingsNonExist[v.String()], existProof.AllSiblings()) 1082 | } 1083 | } 1084 | 1085 | func TeseDeleteLeafNearMiddleNodeLeftBranch(t *testing.T, sto merkletree.Storage) { 1086 | ctx := context.Background() 1087 | mt, err := merkletree.NewMerkleTree(ctx, sto, 140) 1088 | require.NoError(t, err) 1089 | 1090 | // 110 / 6 1091 | // 100 / 4 1092 | // 010 / 2 1093 | values := []*big.Int{big.NewInt(6), big.NewInt(4), big.NewInt(2)} 1094 | 1095 | expectedSiblings := map[string][]*big.Int{ 1096 | "6": {}, 1097 | "4": { 1098 | big.NewInt(0), 1099 | newBigIntFromString(t, 1100 | "8281804442553804052634892902276241371362897230229887706643673501401618941157"), 1101 | }, 1102 | "2": { 1103 | big.NewInt(0), 1104 | newBigIntFromString(t, 1105 | "9054077202653694725190129562729426419405710792276939073869944863201489138082"), 1106 | newBigIntFromString(t, 1107 | "8281804442553804052634892902276241371362897230229887706643673501401618941157"), 1108 | }, 1109 | } 1110 | 1111 | for _, v := range values { 1112 | err = mt.Add(ctx, v, v) 1113 | require.NoError(t, err) 1114 | existProof, _, err := mt.GenerateProof(ctx, v, mt.Root()) 1115 | require.NoError(t, err) 1116 | require.True(t, existProof.Existence) 1117 | compareSiblings(t, 1118 | expectedSiblings[v.String()], existProof.AllSiblings()) 1119 | } 1120 | 1121 | expectedSiblingsNonExist := map[string][]*big.Int{ 1122 | "6": { 1123 | big.NewInt(0), 1124 | newBigIntFromString(t, 1125 | "9054077202653694725190129562729426419405710792276939073869944863201489138082"), 1126 | }, 1127 | "4": {}, 1128 | "2": {}, 1129 | } 1130 | for _, v := range values { 1131 | err = mt.Delete(ctx, v) 1132 | require.NoError(t, err) 1133 | existProof, _, err := mt.GenerateProof(ctx, v, mt.Root()) 1134 | require.NoError(t, err) 1135 | require.False(t, existProof.Existence) 1136 | compareSiblings(t, 1137 | expectedSiblingsNonExist[v.String()], existProof.AllSiblings()) 1138 | } 1139 | } 1140 | 1141 | func TeseDeleteLeafNearMiddleNodeLeftBranchDeep(t *testing.T, sto merkletree.Storage) { 1142 | ctx := context.Background() 1143 | mt, err := merkletree.NewMerkleTree(ctx, sto, 140) 1144 | require.Nil(t, err) 1145 | 1146 | values := []*big.Int{big.NewInt(4), big.NewInt(8), big.NewInt(16)} 1147 | 1148 | expectedSiblings := map[string][]*big.Int{ 1149 | "4": {}, 1150 | "8": { 1151 | big.NewInt(0), 1152 | big.NewInt(0), 1153 | newBigIntFromString(t, 1154 | "9054077202653694725190129562729426419405710792276939073869944863201489138082"), 1155 | }, 1156 | "16": { 1157 | big.NewInt(0), 1158 | big.NewInt(0), 1159 | newBigIntFromString(t, 1160 | "9054077202653694725190129562729426419405710792276939073869944863201489138082"), 1161 | newBigIntFromString(t, 1162 | "16390924951002018924619640791777477120654009069056735603697729984158734051481"), 1163 | }, 1164 | } 1165 | 1166 | for _, v := range values { 1167 | err = mt.Add(ctx, v, v) 1168 | require.NoError(t, err) 1169 | existProof, _, err := mt.GenerateProof(ctx, v, mt.Root()) 1170 | require.NoError(t, err) 1171 | require.True(t, existProof.Existence) 1172 | compareSiblings(t, 1173 | expectedSiblings[v.String()], existProof.AllSiblings()) 1174 | } 1175 | 1176 | expectedSiblingsNonExist := map[string][]*big.Int{ 1177 | "4": { 1178 | big.NewInt(0), 1179 | big.NewInt(0), 1180 | newBigIntFromString(t, 1181 | "999617652929602377745081623447845927693004638040169919261337791961364573823"), 1182 | }, 1183 | "8": {}, 1184 | "16": {}, 1185 | } 1186 | for _, v := range values { 1187 | err = mt.Delete(ctx, v) 1188 | require.NoError(t, err) 1189 | existProof, _, err := mt.GenerateProof(ctx, v, mt.Root()) 1190 | require.NoError(t, err) 1191 | require.False(t, existProof.Existence) 1192 | compareSiblings(t, 1193 | expectedSiblingsNonExist[v.String()], existProof.AllSiblings()) 1194 | } 1195 | } 1196 | 1197 | // Checking whether the last leaf will be moved to the root position 1198 | // 1199 | // root 1200 | // / \ 1201 | // 0 MiddleNode 1202 | // / \ 1203 | // 01 11 1204 | // 1205 | // Up to: 1206 | // 1207 | // root(11) 1208 | func TestUpToRootAfterDeleteRightBranch(t *testing.T, sto merkletree.Storage) { 1209 | ctx := context.Background() 1210 | mt, err := merkletree.NewMerkleTree(ctx, sto, 140) 1211 | require.NoError(t, err) 1212 | 1213 | err = mt.Add(ctx, big.NewInt(1), big.NewInt(1)) 1214 | require.NoError(t, err) 1215 | err = mt.Add(ctx, big.NewInt(3), big.NewInt(3)) 1216 | require.NoError(t, err) 1217 | 1218 | err = mt.Delete(ctx, big.NewInt(1)) 1219 | require.NoError(t, err) 1220 | 1221 | leaf, err := mt.GetNode(ctx, mt.Root()) 1222 | require.NoError(t, err) 1223 | require.Equal(t, merkletree.NodeTypeLeaf, leaf.Type) 1224 | 1225 | require.Equal(t, big.NewInt(3), leaf.Entry[0].BigInt()) 1226 | } 1227 | 1228 | // Checking whether the last leaf will be moved to the root position 1229 | // 1230 | // root 1231 | // / \ 1232 | // MiddleNode 0 1233 | // / \ 1234 | // 100 010 1235 | // 1236 | // Up to: 1237 | // 1238 | // root(100) 1239 | func TestUpToRootAfterDeleteLeftBranch(t *testing.T, sto merkletree.Storage) { 1240 | ctx := context.Background() 1241 | mt, err := merkletree.NewMerkleTree(ctx, sto, 140) 1242 | require.NoError(t, err) 1243 | 1244 | err = mt.Add(ctx, big.NewInt(2), big.NewInt(2)) 1245 | require.NoError(t, err) 1246 | err = mt.Add(ctx, big.NewInt(4), big.NewInt(4)) 1247 | require.NoError(t, err) 1248 | 1249 | err = mt.Delete(ctx, big.NewInt(2)) 1250 | require.NoError(t, err) 1251 | 1252 | leaf, err := mt.GetNode(ctx, mt.Root()) 1253 | require.NoError(t, err) 1254 | require.Equal(t, merkletree.NodeTypeLeaf, leaf.Type) 1255 | 1256 | require.Equal(t, big.NewInt(4), leaf.Entry[0].BigInt()) 1257 | } 1258 | 1259 | // Checking whether the new root will be calculated from to leafs 1260 | // 1261 | // root 1262 | // / \ 1263 | // 10 MiddleNode 1264 | // / \ 1265 | // 01 11 1266 | // 1267 | // Up to: 1268 | // 1269 | // root 1270 | // / \ 1271 | // 10 11 1272 | func TestCalculatingOfNewRootRightBranch(t *testing.T, sto merkletree.Storage) { 1273 | ctx := context.Background() 1274 | mt, err := merkletree.NewMerkleTree(ctx, sto, 140) 1275 | require.NoError(t, err) 1276 | 1277 | err = mt.Add(ctx, big.NewInt(1), big.NewInt(1)) 1278 | require.NoError(t, err) 1279 | err = mt.Add(ctx, big.NewInt(3), big.NewInt(3)) 1280 | require.NoError(t, err) 1281 | err = mt.Add(ctx, big.NewInt(2), big.NewInt(2)) 1282 | require.NoError(t, err) 1283 | 1284 | err = mt.Delete(ctx, big.NewInt(1)) 1285 | require.NoError(t, err) 1286 | 1287 | root, err := mt.GetNode(ctx, mt.Root()) 1288 | require.NoError(t, err) 1289 | 1290 | lLeaf, err := mt.GetNode(ctx, root.ChildL) 1291 | require.NoError(t, err) 1292 | rLeaf, err := mt.GetNode(ctx, root.ChildR) 1293 | require.NoError(t, err) 1294 | 1295 | require.Equal(t, big.NewInt(2), lLeaf.Entry[0].BigInt()) 1296 | require.Equal(t, big.NewInt(3), rLeaf.Entry[0].BigInt()) 1297 | } 1298 | 1299 | // Checking whether the new root will be calculated from to leafs 1300 | // 1301 | // root 1302 | // / \ 1303 | // MiddleNode 01 1304 | // / \ 1305 | // 100 010 1306 | // 1307 | // Up to: 1308 | // 1309 | // root 1310 | // / \ 1311 | // 100 001 1312 | func TestCalculatingOfNewRootLeftBranch(t *testing.T, sto merkletree.Storage) { 1313 | ctx := context.Background() 1314 | mt, err := merkletree.NewMerkleTree(ctx, sto, 140) 1315 | require.NoError(t, err) 1316 | 1317 | err = mt.Add(ctx, big.NewInt(1), big.NewInt(1)) 1318 | require.NoError(t, err) 1319 | err = mt.Add(ctx, big.NewInt(2), big.NewInt(2)) 1320 | require.NoError(t, err) 1321 | err = mt.Add(ctx, big.NewInt(4), big.NewInt(4)) 1322 | require.NoError(t, err) 1323 | 1324 | err = mt.Delete(ctx, big.NewInt(2)) 1325 | require.NoError(t, err) 1326 | 1327 | root, err := mt.GetNode(ctx, mt.Root()) 1328 | require.NoError(t, err) 1329 | 1330 | lLeaf, err := mt.GetNode(ctx, root.ChildL) 1331 | require.NoError(t, err) 1332 | rLeaf, err := mt.GetNode(ctx, root.ChildR) 1333 | require.NoError(t, err) 1334 | 1335 | require.Equal(t, big.NewInt(4), lLeaf.Entry[0].BigInt()) 1336 | require.Equal(t, big.NewInt(1), rLeaf.Entry[0].BigInt()) 1337 | } 1338 | 1339 | // https://github.com/iden3/go-merkletree-sql/issues/23 1340 | func TestInsertNodeAfterDelete(t *testing.T, sto merkletree.Storage) { 1341 | ctx := context.Background() 1342 | mt, err := merkletree.NewMerkleTree(ctx, sto, 40) 1343 | require.NoError(t, err) 1344 | 1345 | values := []*big.Int{big.NewInt(1), big.NewInt(5), big.NewInt(7)} 1346 | for _, v := range values { 1347 | err = mt.Add(ctx, v, v) 1348 | require.NoError(t, err) 1349 | } 1350 | 1351 | expectedSiblings := []*big.Int{ 1352 | big.NewInt(0), 1353 | newBigIntFromString(t, 1354 | "4274876798241152869364032215387952876266736406919374878317677138322903129320"), 1355 | } 1356 | 1357 | err = mt.Delete(ctx, big.NewInt(7)) 1358 | require.NoError(t, err) 1359 | proof, _, err := mt.GenerateProof(ctx, big.NewInt(7), mt.Root()) 1360 | require.NoError(t, err) 1361 | require.False(t, proof.Existence) 1362 | compareSiblings(t, expectedSiblings, proof.AllSiblings()) 1363 | 1364 | err = mt.Add(ctx, big.NewInt(7), big.NewInt(7)) 1365 | require.NoError(t, err) 1366 | proof, _, err = mt.GenerateProof(ctx, big.NewInt(7), mt.Root()) 1367 | require.NoError(t, err) 1368 | require.True(t, proof.Existence) 1369 | compareSiblings(t, expectedSiblings, proof.AllSiblings()) 1370 | } 1371 | 1372 | func TestInsertDeletedNodeThenUpdateItRightBranch(t *testing.T, sto merkletree.Storage) { 1373 | ctx := context.Background() 1374 | mt, err := merkletree.NewMerkleTree(ctx, sto, 40) 1375 | require.NoError(t, err) 1376 | 1377 | values := []*big.Int{big.NewInt(1), big.NewInt(5), big.NewInt(7)} 1378 | for _, v := range values { 1379 | err = mt.Add(ctx, v, v) 1380 | require.NoError(t, err) 1381 | } 1382 | 1383 | expectedSiblings := []*big.Int{ 1384 | big.NewInt(0), 1385 | newBigIntFromString(t, 1386 | "4274876798241152869364032215387952876266736406919374878317677138322903129320"), 1387 | } 1388 | 1389 | err = mt.Delete(ctx, big.NewInt(7)) 1390 | require.NoError(t, err) 1391 | proof, _, err := mt.GenerateProof(ctx, big.NewInt(7), mt.Root()) 1392 | require.NoError(t, err) 1393 | require.False(t, proof.Existence) 1394 | compareSiblings(t, expectedSiblings, proof.AllSiblings()) 1395 | 1396 | err = mt.Add(ctx, big.NewInt(7), big.NewInt(7)) 1397 | require.NoError(t, err) 1398 | proof, _, err = mt.GenerateProof(ctx, big.NewInt(7), mt.Root()) 1399 | require.NoError(t, err) 1400 | require.True(t, proof.Existence) 1401 | compareSiblings(t, expectedSiblings, proof.AllSiblings()) 1402 | 1403 | _, err = mt.Update(ctx, big.NewInt(7), big.NewInt(100)) 1404 | require.NoError(t, err) 1405 | key, value, _, err := mt.Get(ctx, big.NewInt(7)) 1406 | require.NoError(t, err) 1407 | require.Equal(t, key, big.NewInt(7)) 1408 | require.Equal(t, value, big.NewInt(100)) 1409 | } 1410 | 1411 | func TestInsertDeletedNodeThenUpdateItLeftBranch(t *testing.T, sto merkletree.Storage) { 1412 | ctx := context.Background() 1413 | mt, err := merkletree.NewMerkleTree(ctx, sto, 40) 1414 | require.NoError(t, err) 1415 | 1416 | values := []*big.Int{big.NewInt(6), big.NewInt(2), big.NewInt(4)} 1417 | for _, v := range values { 1418 | err = mt.Add(ctx, v, v) 1419 | require.NoError(t, err) 1420 | } 1421 | 1422 | expectedSiblings := []*big.Int{ 1423 | big.NewInt(0), 1424 | newBigIntFromString(t, 1425 | "8485562453225409715331824380162827639878522662998299574537757078697535221073"), 1426 | } 1427 | 1428 | err = mt.Delete(ctx, big.NewInt(4)) 1429 | require.NoError(t, err) 1430 | proof, _, err := mt.GenerateProof(ctx, big.NewInt(4), mt.Root()) 1431 | require.NoError(t, err) 1432 | require.False(t, proof.Existence) 1433 | compareSiblings(t, expectedSiblings, proof.AllSiblings()) 1434 | 1435 | err = mt.Add(ctx, big.NewInt(4), big.NewInt(4)) 1436 | require.NoError(t, err) 1437 | proof, _, err = mt.GenerateProof(ctx, big.NewInt(4), mt.Root()) 1438 | require.NoError(t, err) 1439 | require.True(t, proof.Existence) 1440 | compareSiblings(t, expectedSiblings, proof.AllSiblings()) 1441 | 1442 | _, err = mt.Update(ctx, big.NewInt(4), big.NewInt(100)) 1443 | require.NoError(t, err) 1444 | key, value, _, err := mt.Get(ctx, big.NewInt(4)) 1445 | require.NoError(t, err) 1446 | require.Equal(t, key, big.NewInt(4)) 1447 | require.Equal(t, value, big.NewInt(100)) 1448 | } 1449 | 1450 | func TestPushLeafAlreadyExistsRightBranch(t *testing.T, sto merkletree.Storage) { 1451 | ctx := context.Background() 1452 | mt, err := merkletree.NewMerkleTree(ctx, sto, 40) 1453 | require.NoError(t, err) 1454 | 1455 | values := []*big.Int{big.NewInt(1), big.NewInt(5), big.NewInt(7), big.NewInt(3)} 1456 | for _, v := range values { 1457 | err = mt.Add(ctx, v, v) 1458 | require.NoError(t, err) 1459 | } 1460 | 1461 | expectedSiblings := []*big.Int{ 1462 | big.NewInt(0), 1463 | newBigIntFromString(t, 1464 | "4274876798241152869364032215387952876266736406919374878317677138322903129320"), 1465 | } 1466 | 1467 | err = mt.Delete(ctx, big.NewInt(3)) 1468 | require.NoError(t, err) 1469 | proof, _, err := mt.GenerateProof(ctx, big.NewInt(3), mt.Root()) 1470 | require.NoError(t, err) 1471 | require.False(t, proof.Existence) 1472 | compareSiblings(t, expectedSiblings, proof.AllSiblings()) 1473 | 1474 | expectedSiblingsExist := []*big.Int{ 1475 | big.NewInt(0), 1476 | newBigIntFromString(t, 1477 | "4274876798241152869364032215387952876266736406919374878317677138322903129320"), 1478 | newBigIntFromString(t, 1479 | "3968539605503372859924195689353752825000692947459401078008697788408142999740"), 1480 | } 1481 | 1482 | err = mt.Add(ctx, big.NewInt(3), big.NewInt(3)) 1483 | require.NoError(t, err) 1484 | proof, _, err = mt.GenerateProof(ctx, big.NewInt(3), mt.Root()) 1485 | require.NoError(t, err) 1486 | require.True(t, proof.Existence) 1487 | compareSiblings(t, expectedSiblingsExist, proof.AllSiblings()) 1488 | } 1489 | 1490 | func TestPushLeafAlreadyExistsLeftBranch(t *testing.T, sto merkletree.Storage) { 1491 | ctx := context.Background() 1492 | mt, err := merkletree.NewMerkleTree(ctx, sto, 40) 1493 | require.NoError(t, err) 1494 | 1495 | values := []*big.Int{big.NewInt(6), big.NewInt(2), big.NewInt(4), big.NewInt(8)} 1496 | for _, v := range values { 1497 | err = mt.Add(ctx, v, v) 1498 | require.NoError(t, err) 1499 | } 1500 | 1501 | expectedSiblings := []*big.Int{ 1502 | big.NewInt(0), 1503 | newBigIntFromString(t, 1504 | "8485562453225409715331824380162827639878522662998299574537757078697535221073"), 1505 | } 1506 | 1507 | err = mt.Delete(ctx, big.NewInt(8)) 1508 | require.NoError(t, err) 1509 | proof, _, err := mt.GenerateProof(ctx, big.NewInt(8), mt.Root()) 1510 | require.NoError(t, err) 1511 | require.False(t, proof.Existence) 1512 | compareSiblings(t, expectedSiblings, proof.AllSiblings()) 1513 | 1514 | expectedSiblingsExist := []*big.Int{ 1515 | big.NewInt(0), 1516 | newBigIntFromString(t, 1517 | "8485562453225409715331824380162827639878522662998299574537757078697535221073"), 1518 | newBigIntFromString(t, 1519 | "9054077202653694725190129562729426419405710792276939073869944863201489138082"), 1520 | } 1521 | 1522 | err = mt.Add(ctx, big.NewInt(8), big.NewInt(8)) 1523 | require.NoError(t, err) 1524 | proof, _, err = mt.GenerateProof(ctx, big.NewInt(8), mt.Root()) 1525 | require.NoError(t, err) 1526 | require.True(t, proof.Existence) 1527 | compareSiblings(t, expectedSiblingsExist, proof.AllSiblings()) 1528 | } 1529 | 1530 | func TestUpNodesToTwoLevelsRightBranch(t *testing.T, sto merkletree.Storage) { 1531 | ctx := context.Background() 1532 | mt, err := merkletree.NewMerkleTree(ctx, sto, 40) 1533 | require.NoError(t, err) 1534 | 1535 | values := []*big.Int{big.NewInt(1), big.NewInt(7), big.NewInt(15)} 1536 | for _, v := range values { 1537 | err = mt.Add(ctx, v, v) 1538 | require.NoError(t, err) 1539 | } 1540 | err = mt.Delete(ctx, big.NewInt(15)) 1541 | require.NoError(t, err) 1542 | 1543 | proof, _, err := mt.GenerateProof(ctx, big.NewInt(15), mt.Root()) 1544 | require.NoError(t, err) 1545 | require.False(t, proof.Existence) 1546 | compareSiblings(t, []*big.Int{ 1547 | big.NewInt(0), 1548 | newBigIntFromString(t, 1549 | "1243904711429961858774220647610724273798918457991486031567244100767259239747"), 1550 | }, proof.AllSiblings()) 1551 | } 1552 | 1553 | func TestUpNodesToTwoLevelsLeftBranch(t *testing.T, sto merkletree.Storage) { 1554 | ctx := context.Background() 1555 | mt, err := merkletree.NewMerkleTree(ctx, sto, 40) 1556 | require.NoError(t, err) 1557 | 1558 | values := []*big.Int{big.NewInt(2), big.NewInt(8), big.NewInt(16)} 1559 | for _, v := range values { 1560 | err = mt.Add(ctx, v, v) 1561 | require.NoError(t, err) 1562 | } 1563 | err = mt.Delete(ctx, big.NewInt(16)) 1564 | require.NoError(t, err) 1565 | 1566 | proof, _, err := mt.GenerateProof(ctx, big.NewInt(16), mt.Root()) 1567 | require.NoError(t, err) 1568 | require.False(t, proof.Existence) 1569 | compareSiblings(t, []*big.Int{ 1570 | big.NewInt(0), 1571 | newBigIntFromString(t, 1572 | "849831128489032619062850458217693666094013083866167024127442191257793527951"), 1573 | }, proof.AllSiblings()) 1574 | } 1575 | 1576 | func newBigIntFromString(t *testing.T, str string) *big.Int { 1577 | bi, ok := big.NewInt(0).SetString(str, 10) 1578 | require.True(t, ok) 1579 | return bi 1580 | } 1581 | 1582 | func compareSiblings(t *testing.T, 1583 | expectedSiblings []*big.Int, actualSiblings []*merkletree.Hash) { 1584 | require.Equal( 1585 | t, 1586 | len(expectedSiblings), len(actualSiblings), 1587 | ) 1588 | for i := range expectedSiblings { 1589 | require.Equal(t, expectedSiblings[i].String(), actualSiblings[i].BigInt().String()) 1590 | } 1591 | } 1592 | -------------------------------------------------------------------------------- /elembytes.go: -------------------------------------------------------------------------------- 1 | package merkletree 2 | 3 | import ( 4 | "encoding/hex" 5 | "fmt" 6 | "math/big" 7 | ) 8 | 9 | const ( 10 | // ElemBytesLen is the length of the Hash byte array 11 | ElemBytesLen = 32 12 | ) 13 | 14 | // ElemBytes is the basic type used to store data in the MT. ElemBytes 15 | // corresponds to the serialization of an element from mimc7. 16 | type ElemBytes [ElemBytesLen]byte 17 | 18 | func NewElemBytesFromBigInt(v *big.Int) (e ElemBytes) { 19 | bs := SwapEndianness(v.Bytes()) 20 | copy(e[:], bs) 21 | return e 22 | } 23 | 24 | func (e *ElemBytes) BigInt() *big.Int { 25 | return new(big.Int).SetBytes(SwapEndianness(e[:])) 26 | } 27 | 28 | // String returns the first 4 bytes of ElemBytes in hex. 29 | func (e *ElemBytes) String() string { 30 | return fmt.Sprintf("%v...", hex.EncodeToString(e[:4])) 31 | } 32 | 33 | // ElemBytesToBytes serializes an array of ElemBytes to []byte. 34 | func ElemBytesToBytes(es []ElemBytes) []byte { 35 | bs := make([]byte, len(es)*ElemBytesLen) 36 | for i := 0; i < len(es); i++ { 37 | copy(bs[i*ElemBytesLen:(i+1)*ElemBytesLen], es[i][:]) 38 | } 39 | return bs 40 | } 41 | 42 | // ElemBytesToBigInts serializes an array of ElemBytes to []byte. 43 | func ElemBytesToBigInts(es []ElemBytes) []*big.Int { 44 | bs := make([]*big.Int, len(es)) 45 | for i := 0; i < len(es); i++ { 46 | bs[i] = es[i].BigInt() 47 | } 48 | return bs 49 | } 50 | -------------------------------------------------------------------------------- /entry.go: -------------------------------------------------------------------------------- 1 | package merkletree 2 | 3 | import ( 4 | "encoding/hex" 5 | 6 | cryptoUtils "github.com/iden3/go-iden3-crypto/utils" 7 | ) 8 | 9 | // Entry is the generic type that is stored in the MT. The entry should not be 10 | // modified after creating because the cached hIndex and hValue won't be 11 | // updated. 12 | type Entry struct { 13 | Data Data 14 | // hIndex is a cache used to avoid recalculating hIndex 15 | hIndex *Hash 16 | // hValue is a cache used to avoid recalculating hValue 17 | hValue *Hash 18 | } 19 | 20 | type Entrier interface { 21 | Entry() *Entry 22 | } 23 | 24 | func (e *Entry) Index() []ElemBytes { 25 | return e.Data[:IndexLen] 26 | } 27 | 28 | func (e *Entry) Value() []ElemBytes { 29 | return e.Data[IndexLen:] 30 | } 31 | 32 | // HIndex calculates the hash of the Index of the Entry, used to find the path 33 | // from the root to the leaf in the MT. 34 | func (e *Entry) HIndex() (*Hash, error) { 35 | var err error 36 | if e.hIndex == nil { // Cache the hIndex. 37 | hIndex, err := HashElems(ElemBytesToBigInts(e.Index())...) 38 | if err != nil { 39 | return nil, err 40 | } 41 | e.hIndex = hIndex 42 | } 43 | return e.hIndex, err 44 | } 45 | 46 | // HValue calculates the hash of the Value of the Entry 47 | func (e *Entry) HValue() (*Hash, error) { 48 | var err error 49 | if e.hValue == nil { // Cache the hValue. 50 | hValue, err := HashElems(ElemBytesToBigInts(e.Value())...) 51 | if err != nil { 52 | return nil, err 53 | } 54 | e.hValue = hValue 55 | } 56 | return e.hValue, err 57 | } 58 | 59 | // HiHv returns the HIndex and HValue of the Entry 60 | func (e *Entry) HiHv() (*Hash, *Hash, error) { 61 | hi, err := e.HIndex() 62 | if err != nil { 63 | return nil, nil, err 64 | } 65 | hv, err := e.HValue() 66 | if err != nil { 67 | return nil, nil, err 68 | } 69 | 70 | return hi, hv, nil 71 | } 72 | 73 | func (e *Entry) Bytes() []byte { 74 | b := e.Data.Bytes() 75 | return b[:] 76 | } 77 | 78 | func (e1 *Entry) Equal(e2 *Entry) bool { 79 | return e1.Data.Equal(&e2.Data) 80 | } 81 | 82 | func (e Entry) MarshalText() ([]byte, error) { 83 | return []byte(hex.EncodeToString(e.Bytes())), nil 84 | } 85 | 86 | func (e *Entry) UnmarshalText(text []byte) error { 87 | return e.Data.UnmarshalText(text) 88 | } 89 | 90 | func (e *Entry) Clone() *Entry { 91 | data := NewDataFromBytes(e.Data.Bytes()) 92 | return &Entry{Data: *data} 93 | } 94 | 95 | func CheckEntryInField(e Entry) bool { 96 | bigints := ElemBytesToBigInts(e.Data[:]) 97 | ok := cryptoUtils.CheckBigIntArrayInField(bigints) 98 | return ok 99 | } 100 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/iden3/go-merkletree-sql/v2 2 | 3 | go 1.18 4 | 5 | require ( 6 | github.com/iden3/go-iden3-crypto v0.0.15 7 | github.com/stretchr/testify v1.8.2 8 | ) 9 | 10 | require ( 11 | github.com/davecgh/go-spew v1.1.1 // indirect 12 | github.com/pmezard/go-difflib v1.0.0 // indirect 13 | golang.org/x/sys v0.6.0 // indirect 14 | gopkg.in/yaml.v3 v3.0.1 // indirect 15 | ) 16 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 3 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/iden3/go-iden3-crypto v0.0.15 h1:4MJYlrot1l31Fzlo2sF56u7EVFeHHJkxGXXZCtESgK4= 5 | github.com/iden3/go-iden3-crypto v0.0.15/go.mod h1:dLpM4vEPJ3nDHzhWFXDjzkn1qHoBeOT/3UEhXsEsP3E= 6 | github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c= 7 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 8 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 9 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 10 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 11 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 12 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 13 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 14 | github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= 15 | github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 16 | golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= 17 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 18 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 19 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 20 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 21 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 22 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 23 | -------------------------------------------------------------------------------- /hash.go: -------------------------------------------------------------------------------- 1 | package merkletree 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "errors" 7 | "fmt" 8 | "math/big" 9 | "strings" 10 | 11 | cryptoUtils "github.com/iden3/go-iden3-crypto/utils" 12 | ) 13 | 14 | var ( 15 | // HashZero is used at Empty nodes 16 | HashZero = Hash{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 18 | ) 19 | 20 | // Hash is the generic type stored in the MerkleTree 21 | type Hash [32]byte 22 | 23 | // MarshalText implements the marshaler for the Hash type 24 | func (h Hash) MarshalText() ([]byte, error) { 25 | return []byte(h.BigInt().String()), nil 26 | } 27 | 28 | // UnmarshalText implements the unmarshaler for the Hash type 29 | func (h *Hash) UnmarshalText(b []byte) error { 30 | ha, err := NewHashFromString(string(b)) 31 | if err != nil { 32 | return err 33 | } 34 | copy(h[:], ha[:]) 35 | return nil 36 | } 37 | 38 | // String returns decimal representation in string format of the Hash 39 | func (h Hash) String() string { 40 | s := h.BigInt().String() 41 | if len(s) < numCharPrint { 42 | return s 43 | } 44 | return s[0:numCharPrint] + "..." 45 | } 46 | 47 | // Hex returns the hexadecimal representation of the Hash 48 | func (h Hash) Hex() string { 49 | return hex.EncodeToString(h[:]) 50 | // alternatively equivalent, but with too extra steps: 51 | // bRaw := h.BigInt().Bytes() 52 | // b := [32]byte{} 53 | // copy(b[:], SwapEndianness(bRaw[:])) 54 | // return hex.EncodeToString(b[:]) 55 | } 56 | 57 | // BigInt returns the *big.Int representation of the *Hash 58 | func (h *Hash) BigInt() *big.Int { 59 | if new(big.Int).SetBytes(SwapEndianness(h[:])) == nil { 60 | return big.NewInt(0) 61 | } 62 | return new(big.Int).SetBytes(SwapEndianness(h[:])) 63 | } 64 | 65 | func (h *Hash) Equals(h2 *Hash) bool { 66 | return bytes.Equal(h[:], h2[:]) 67 | } 68 | 69 | // NewBigIntFromHashBytes returns a *big.Int from a byte array, swapping the 70 | // endianness in the process. This is the intended method to get a *big.Int 71 | // from a byte array that previously has ben generated by the Hash.Bytes() 72 | // method. 73 | func NewBigIntFromHashBytes(b []byte) (*big.Int, error) { 74 | if len(b) != ElemBytesLen { 75 | return nil, fmt.Errorf("Expected 32 bytes, found %d bytes", len(b)) 76 | } 77 | bi := new(big.Int).SetBytes(b[:ElemBytesLen]) 78 | if !cryptoUtils.CheckBigIntInField(bi) { 79 | return nil, fmt.Errorf("NewBigIntFromHashBytes: Value not inside the Finite Field") 80 | } 81 | return bi, nil 82 | } 83 | 84 | // NewHashFromBigInt returns a *Hash representation of the given *big.Int 85 | func NewHashFromBigInt(b *big.Int) (*Hash, error) { 86 | if !cryptoUtils.CheckBigIntInField(b) { 87 | return nil, errors.New( 88 | "NewHashFromBigInt: Value not inside the Finite Field") 89 | } 90 | r := &Hash{} 91 | copy(r[:], SwapEndianness(b.Bytes())) 92 | return r, nil 93 | } 94 | 95 | // NewHashFromHex returns a *Hash representation of the given hex string 96 | func NewHashFromHex(h string) (*Hash, error) { 97 | h = strings.TrimPrefix(h, "0x") 98 | b, err := hex.DecodeString(h) 99 | if err != nil { 100 | return nil, err 101 | } 102 | var hash Hash 103 | if len(b) != len(hash) { 104 | return nil, errors.New("invalid hash length") 105 | } 106 | copy(hash[:], b) 107 | return &hash, nil 108 | } 109 | 110 | // NewHashFromString returns a *Hash representation of the given decimal string 111 | func NewHashFromString(s string) (*Hash, error) { 112 | bi, ok := new(big.Int).SetString(s, 10) 113 | if !ok { 114 | return nil, fmt.Errorf("Can not parse string to Hash") 115 | } 116 | return NewHashFromBigInt(bi) 117 | } 118 | -------------------------------------------------------------------------------- /hash_test.go: -------------------------------------------------------------------------------- 1 | package merkletree 2 | 3 | import ( 4 | "math/big" 5 | "testing" 6 | 7 | "github.com/iden3/go-iden3-crypto/constants" 8 | cryptoUtils "github.com/iden3/go-iden3-crypto/utils" 9 | "github.com/stretchr/testify/assert" 10 | "github.com/stretchr/testify/require" 11 | ) 12 | 13 | func TestHashParsers(t *testing.T) { 14 | h0, err := NewHashFromBigInt(big.NewInt(0)) 15 | require.NoError(t, err) 16 | assert.Equal(t, "0", h0.String()) 17 | h1, err := NewHashFromBigInt(big.NewInt(1)) 18 | require.NoError(t, err) 19 | assert.Equal(t, "1", h1.String()) 20 | h10, err := NewHashFromBigInt(big.NewInt(10)) 21 | require.NoError(t, err) 22 | assert.Equal(t, "10", h10.String()) 23 | 24 | h7l, err := NewHashFromBigInt(big.NewInt(1234567)) 25 | require.NoError(t, err) 26 | assert.Equal(t, "1234567", h7l.String()) 27 | h8l, err := NewHashFromBigInt(big.NewInt(12345678)) 28 | require.NoError(t, err) 29 | assert.Equal(t, "12345678...", h8l.String()) 30 | 31 | b, ok := new(big.Int).SetString( 32 | "4932297968297298434239270129193057052722409868268166443802652458940273154854", //nolint:lll 33 | 10) 34 | assert.True(t, ok) 35 | h, err := NewHashFromBigInt(b) 36 | require.NoError(t, err) 37 | assert.Equal(t, 38 | "4932297968297298434239270129193057052722409868268166443802652458940273154854", 39 | h.BigInt().String()) //nolint:lll 40 | assert.Equal(t, "49322979...", h.String()) 41 | assert.Equal(t, 42 | "265baaf161e875c372d08e50f52abddc01d32efc93e90290bb8b3d9ceb94e70a", 43 | h.Hex()) 44 | 45 | b1, err := NewBigIntFromHashBytes(b.Bytes()) 46 | assert.Nil(t, err) 47 | assert.Equal(t, new(big.Int).SetBytes(b.Bytes()).String(), b1.String()) 48 | 49 | h2, err := NewHashFromHex(h.Hex()) 50 | assert.Nil(t, err) 51 | assert.Equal(t, h, h2) 52 | _, err = NewHashFromHex("0x12") 53 | assert.NotNil(t, err) 54 | 55 | // check limits 56 | a := new(big.Int).Sub(constants.Q, big.NewInt(1)) 57 | testHashParsers(t, a) 58 | a = big.NewInt(int64(1)) 59 | testHashParsers(t, a) 60 | } 61 | 62 | func testHashParsers(t *testing.T, a *big.Int) { 63 | require.True(t, cryptoUtils.CheckBigIntInField(a)) 64 | h, err := NewHashFromBigInt(a) 65 | require.NoError(t, err) 66 | assert.Equal(t, a, h.BigInt()) 67 | hFromHex, err := NewHashFromHex(h.Hex()) 68 | assert.Nil(t, err) 69 | assert.Equal(t, h, hFromHex) 70 | } 71 | -------------------------------------------------------------------------------- /merkletree.go: -------------------------------------------------------------------------------- 1 | package merkletree 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "errors" 7 | "fmt" 8 | "io" 9 | "math/big" 10 | "sync" 11 | 12 | cryptoUtils "github.com/iden3/go-iden3-crypto/utils" 13 | ) 14 | 15 | const ( 16 | // proofFlagsLen is the byte length of the flags in the proof header 17 | // (first 32 bytes). 18 | proofFlagsLen = 2 19 | 20 | numCharPrint = 8 21 | 22 | // IndexLen indicates how many elements are used for the index. 23 | IndexLen = 4 24 | // DataLen indicates how many elements are used for the data. 25 | DataLen = 8 26 | ) 27 | 28 | var ( 29 | // ErrNodeKeyAlreadyExists is used when a node key already exists. 30 | ErrNodeKeyAlreadyExists = errors.New("key already exists") 31 | // ErrKeyNotFound is used when a key is not found in the MerkleTree. 32 | ErrKeyNotFound = errors.New("Key not found in the MerkleTree") 33 | // ErrNodeBytesBadSize is used when the data of a node has an incorrect 34 | // size and can't be parsed. 35 | ErrNodeBytesBadSize = errors.New("node data has incorrect size in the DB") 36 | // ErrReachedMaxLevel is used when a traversal of the MT reaches the 37 | // maximum level. 38 | ErrReachedMaxLevel = errors.New("reached maximum level of the merkle tree") 39 | // ErrInvalidNodeFound is used when an invalid node is found and can't 40 | // be parsed. 41 | ErrInvalidNodeFound = errors.New("found an invalid node in the DB") 42 | // ErrInvalidProofBytes is used when a serialized proof is invalid. 43 | ErrInvalidProofBytes = errors.New("the serialized proof is invalid") 44 | // ErrInvalidDBValue is used when a value in the key value DB is 45 | // invalid (for example, it doen't contain a byte header and a []byte 46 | // body of at least len=1. 47 | ErrInvalidDBValue = errors.New("the value in the DB is invalid") 48 | // ErrEntryIndexAlreadyExists is used when the entry index already 49 | // exists in the tree. 50 | ErrEntryIndexAlreadyExists = errors.New("the entry index already exists in the tree") 51 | // ErrNotWritable is used when the MerkleTree is not writable and a 52 | // write function is called 53 | ErrNotWritable = errors.New("Merkle Tree not writable") 54 | ) 55 | 56 | // MerkleTree is the struct with the main elements of the MerkleTree 57 | type MerkleTree struct { 58 | sync.RWMutex 59 | db Storage 60 | rootKey *Hash 61 | writable bool 62 | maxLevels int 63 | } 64 | 65 | // NewMerkleTree loads a new MerkleTree. If in the storage already exists one 66 | // will open that one, if not, will create a new one. 67 | func NewMerkleTree(ctx context.Context, storage Storage, 68 | maxLevels int) (*MerkleTree, error) { 69 | mt := MerkleTree{db: storage, maxLevels: maxLevels, writable: true} 70 | 71 | root, err := mt.db.GetRoot(ctx) 72 | if err == ErrNotFound { 73 | mt.rootKey = &HashZero 74 | err = mt.db.SetRoot(ctx, mt.rootKey) 75 | if err != nil { 76 | return nil, err 77 | } 78 | return &mt, nil 79 | } else if err != nil { 80 | return nil, err 81 | } 82 | mt.rootKey = root 83 | return &mt, nil 84 | } 85 | 86 | // Root returns the MerkleRoot 87 | func (mt *MerkleTree) Root() *Hash { 88 | return mt.rootKey 89 | } 90 | 91 | // MaxLevels returns the MT maximum level 92 | func (mt *MerkleTree) MaxLevels() int { 93 | return mt.maxLevels 94 | } 95 | 96 | // Snapshot returns a read-only copy of the MerkleTree 97 | func (mt *MerkleTree) Snapshot( 98 | ctx context.Context, rootKey *Hash) (*MerkleTree, error) { 99 | mt.RLock() 100 | defer mt.RUnlock() 101 | _, err := mt.GetNode(ctx, rootKey) 102 | if err != nil { 103 | return nil, err 104 | } 105 | return &MerkleTree{ 106 | db: mt.db, 107 | maxLevels: mt.maxLevels, 108 | rootKey: rootKey, 109 | writable: false}, nil 110 | } 111 | 112 | // Add adds a Key & Value into the MerkleTree. Where the `k` determines the 113 | // path from the Root to the Leaf. 114 | func (mt *MerkleTree) Add(ctx context.Context, k, v *big.Int) error { 115 | // verify that the MerkleTree is writable 116 | if !mt.writable { 117 | return ErrNotWritable 118 | } 119 | 120 | kHash, err := NewHashFromBigInt(k) 121 | if err != nil { 122 | return fmt.Errorf("can't create hash from Key: %w", err) 123 | } 124 | vHash, err := NewHashFromBigInt(v) 125 | if err != nil { 126 | return fmt.Errorf("can't create hash from Value: %w", err) 127 | } 128 | 129 | mt.Lock() 130 | defer mt.Unlock() 131 | 132 | newNodeLeaf := NewNodeLeaf(kHash, vHash) 133 | path := getPath(mt.maxLevels, kHash[:]) 134 | 135 | newRootKey, err := mt.addLeaf(ctx, newNodeLeaf, mt.rootKey, 0, path) 136 | if err != nil { 137 | return err 138 | } 139 | mt.rootKey = newRootKey 140 | return mt.db.SetRoot(ctx, mt.rootKey) 141 | } 142 | 143 | // AddEntry adds the Entry to the MerkleTree 144 | func (mt *MerkleTree) AddEntry(ctx context.Context, e *Entry) error { 145 | // verify that the MerkleTree is writable 146 | if !mt.writable { 147 | return ErrNotWritable 148 | } 149 | // verify that the ElemBytes are valid and fit inside the mimc7 field. 150 | if !CheckEntryInField(*e) { 151 | return errors.New("Elements not inside the Finite Field over R") 152 | } 153 | 154 | mt.Lock() 155 | defer mt.Unlock() 156 | 157 | hIndex, err := e.HIndex() 158 | if err != nil { 159 | return err 160 | } 161 | hValue, err := e.HValue() 162 | if err != nil { 163 | return err 164 | } 165 | newNodeLeaf := NewNodeLeaf(hIndex, hValue) 166 | path := getPath(mt.maxLevels, hIndex[:]) 167 | 168 | newRootKey, err := mt.addLeaf(ctx, newNodeLeaf, mt.rootKey, 0, path) 169 | if err != nil { 170 | return err 171 | } 172 | mt.rootKey = newRootKey 173 | return mt.db.SetRoot(ctx, mt.rootKey) 174 | } 175 | 176 | // AddAndGetCircomProof does an Add, and returns a CircomProcessorProof 177 | func (mt *MerkleTree) AddAndGetCircomProof(ctx context.Context, 178 | k, v *big.Int) (*CircomProcessorProof, error) { 179 | var cp CircomProcessorProof 180 | cp.Fnc = 2 181 | cp.OldRoot = mt.rootKey 182 | gotK, gotV, _, err := mt.Get(ctx, k) 183 | if err != nil && err != ErrKeyNotFound { 184 | return nil, err 185 | } 186 | cp.OldKey, err = NewHashFromBigInt(gotK) 187 | if err != nil { 188 | return nil, err 189 | } 190 | cp.OldValue, err = NewHashFromBigInt(gotV) 191 | if err != nil { 192 | return nil, err 193 | } 194 | if bytes.Equal(cp.OldKey[:], HashZero[:]) { 195 | cp.IsOld0 = true 196 | } 197 | _, _, siblings, err := mt.Get(ctx, k) 198 | if err != nil && err != ErrKeyNotFound { 199 | return nil, err 200 | } 201 | cp.Siblings = CircomSiblingsFromSiblings(siblings, mt.maxLevels) 202 | 203 | err = mt.Add(ctx, k, v) 204 | if err != nil { 205 | return nil, err 206 | } 207 | 208 | cp.NewKey, err = NewHashFromBigInt(k) 209 | if err != nil { 210 | return nil, err 211 | } 212 | cp.NewValue, err = NewHashFromBigInt(v) 213 | if err != nil { 214 | return nil, err 215 | } 216 | cp.NewRoot = mt.rootKey 217 | 218 | return &cp, nil 219 | } 220 | 221 | // pushLeaf recursively pushes an existing oldLeaf down until its path diverges 222 | // from newLeaf, at which point both leafs are stored, all while updating the 223 | // path. 224 | func (mt *MerkleTree) pushLeaf(ctx context.Context, newLeaf *Node, 225 | oldLeaf *Node, lvl int, pathNewLeaf []bool, 226 | pathOldLeaf []bool) (*Hash, error) { 227 | if lvl > mt.maxLevels-2 { 228 | return nil, ErrReachedMaxLevel 229 | } 230 | var newNodeMiddle *Node 231 | if pathNewLeaf[lvl] == pathOldLeaf[lvl] { // We need to go deeper! 232 | nextKey, err := mt.pushLeaf(ctx, newLeaf, oldLeaf, lvl+1, 233 | pathNewLeaf, pathOldLeaf) 234 | if err != nil { 235 | return nil, err 236 | } 237 | if pathNewLeaf[lvl] { // go right 238 | newNodeMiddle = NewNodeMiddle(&HashZero, nextKey) 239 | } else { // go left 240 | newNodeMiddle = NewNodeMiddle(nextKey, &HashZero) 241 | } 242 | return mt.addNode(context.TODO(), newNodeMiddle) 243 | } 244 | oldLeafKey, err := oldLeaf.Key() 245 | if err != nil { 246 | return nil, err 247 | } 248 | newLeafKey, err := newLeaf.Key() 249 | if err != nil { 250 | return nil, err 251 | } 252 | 253 | if pathNewLeaf[lvl] { 254 | newNodeMiddle = NewNodeMiddle(oldLeafKey, newLeafKey) 255 | } else { 256 | newNodeMiddle = NewNodeMiddle(newLeafKey, oldLeafKey) 257 | } 258 | // We can add newLeaf now. We don't need to add oldLeaf because it's 259 | // already in the tree. 260 | _, err = mt.addNode(ctx, newLeaf) 261 | if err != nil { 262 | return nil, err 263 | } 264 | return mt.addNode(ctx, newNodeMiddle) 265 | } 266 | 267 | // addLeaf recursively adds a newLeaf in the MT while updating the path. 268 | func (mt *MerkleTree) addLeaf(ctx context.Context, newLeaf *Node, key *Hash, 269 | lvl int, path []bool) (*Hash, error) { 270 | var err error 271 | var nextKey *Hash 272 | if lvl > mt.maxLevels-1 { 273 | return nil, ErrReachedMaxLevel 274 | } 275 | n, err := mt.GetNode(ctx, key) 276 | if err != nil { 277 | return nil, err 278 | } 279 | switch n.Type { 280 | case NodeTypeEmpty: 281 | // We can add newLeaf now 282 | return mt.addNode(ctx, newLeaf) 283 | case NodeTypeLeaf: 284 | nKey := n.Entry[0] 285 | // Check if leaf node found contains the leaf node we are 286 | // trying to add 287 | newLeafKey := newLeaf.Entry[0] 288 | if bytes.Equal(nKey[:], newLeafKey[:]) { 289 | return nil, ErrEntryIndexAlreadyExists 290 | } 291 | pathOldLeaf := getPath(mt.maxLevels, nKey[:]) 292 | // We need to push newLeaf down until its path diverges from 293 | // n's path 294 | return mt.pushLeaf(ctx, newLeaf, n, lvl, path, pathOldLeaf) 295 | case NodeTypeMiddle: 296 | // We need to go deeper, continue traversing the tree, left or 297 | // right depending on path 298 | var newNodeMiddle *Node 299 | if path[lvl] { // go right 300 | nextKey, err = mt.addLeaf(ctx, newLeaf, n.ChildR, lvl+1, path) 301 | newNodeMiddle = NewNodeMiddle(n.ChildL, nextKey) 302 | } else { // go left 303 | nextKey, err = mt.addLeaf(ctx, newLeaf, n.ChildL, lvl+1, path) 304 | newNodeMiddle = NewNodeMiddle(nextKey, n.ChildR) 305 | } 306 | if err != nil { 307 | return nil, err 308 | } 309 | // Update the node to reflect the modified child 310 | return mt.addNode(ctx, newNodeMiddle) 311 | default: 312 | return nil, ErrInvalidNodeFound 313 | } 314 | } 315 | 316 | // addNode adds a node into the MT. Empty nodes are not stored in the tree; 317 | // they are all the same and assumed to always exist. 318 | func (mt *MerkleTree) addNode(ctx context.Context, n *Node) (*Hash, error) { 319 | // verify that the MerkleTree is writable 320 | if !mt.writable { 321 | return nil, ErrNotWritable 322 | } 323 | if n.Type == NodeTypeEmpty { 324 | return n.Key() 325 | } 326 | k, err := n.Key() 327 | if err != nil { 328 | return nil, err 329 | } 330 | //v := n.Value() 331 | // Check that the node key doesn't already exist 332 | if _, err := mt.db.Get(ctx, k[:]); err == nil { 333 | return k, nil 334 | } 335 | return k, mt.db.Put(ctx, k[:], n) 336 | } 337 | 338 | // updateNode updates an existing node in the MT. Empty nodes are not stored 339 | // in the tree; they are all the same and assumed to always exist. 340 | func (mt *MerkleTree) updateNode(ctx context.Context, n *Node) (*Hash, error) { 341 | // verify that the MerkleTree is writable 342 | if !mt.writable { 343 | return nil, ErrNotWritable 344 | } 345 | if n.Type == NodeTypeEmpty { 346 | return n.Key() 347 | } 348 | k, err := n.Key() 349 | if err != nil { 350 | return nil, err 351 | } 352 | //v := n.Value() 353 | err = mt.db.Put(ctx, k[:], n) 354 | return k, err 355 | } 356 | 357 | // Get returns the value of the leaf for the given key 358 | func (mt *MerkleTree) Get(ctx context.Context, 359 | k *big.Int) (*big.Int, *big.Int, []*Hash, error) { 360 | kHash, err := NewHashFromBigInt(k) 361 | if err != nil { 362 | return nil, nil, nil, fmt.Errorf("can't create hash from Key: %w", err) 363 | } 364 | path := getPath(mt.maxLevels, kHash[:]) 365 | 366 | nextKey := mt.rootKey 367 | siblings := []*Hash{} 368 | for i := 0; i < mt.maxLevels; i++ { 369 | n, err := mt.GetNode(ctx, nextKey) 370 | if err != nil { 371 | return nil, nil, nil, err 372 | } 373 | switch n.Type { 374 | case NodeTypeEmpty: 375 | return big.NewInt(0), big.NewInt(0), siblings, ErrKeyNotFound 376 | case NodeTypeLeaf: 377 | if bytes.Equal(kHash[:], n.Entry[0][:]) { 378 | return n.Entry[0].BigInt(), n.Entry[1].BigInt(), siblings, nil 379 | } 380 | return n.Entry[0].BigInt(), n.Entry[1].BigInt(), siblings, ErrKeyNotFound 381 | case NodeTypeMiddle: 382 | if path[i] { 383 | nextKey = n.ChildR 384 | siblings = append(siblings, n.ChildL) 385 | } else { 386 | nextKey = n.ChildL 387 | siblings = append(siblings, n.ChildR) 388 | } 389 | default: 390 | return nil, nil, nil, ErrInvalidNodeFound 391 | } 392 | } 393 | 394 | return nil, nil, nil, ErrReachedMaxLevel 395 | } 396 | 397 | // Update updates the value of a specified key in the MerkleTree, and updates 398 | // the path from the leaf to the Root with the new values. Returns the 399 | // CircomProcessorProof. 400 | func (mt *MerkleTree) Update(ctx context.Context, 401 | k, v *big.Int) (*CircomProcessorProof, error) { 402 | // verify that the MerkleTree is writable 403 | if !mt.writable { 404 | return nil, ErrNotWritable 405 | } 406 | 407 | // verify that k & v are valid and fit inside the Finite Field. 408 | if !cryptoUtils.CheckBigIntInField(k) { 409 | return nil, errors.New("Key not inside the Finite Field") 410 | } 411 | if !cryptoUtils.CheckBigIntInField(v) { 412 | return nil, errors.New("Key not inside the Finite Field") 413 | } 414 | 415 | mt.Lock() 416 | defer mt.Unlock() 417 | 418 | kHash, err := NewHashFromBigInt(k) 419 | if err != nil { 420 | return nil, err 421 | } 422 | vHash, err := NewHashFromBigInt(v) 423 | if err != nil { 424 | return nil, err 425 | } 426 | path := getPath(mt.maxLevels, kHash[:]) 427 | 428 | var cp CircomProcessorProof 429 | cp.Fnc = 1 430 | cp.OldRoot = mt.rootKey 431 | cp.OldKey = kHash 432 | cp.NewKey = kHash 433 | cp.NewValue = vHash 434 | 435 | nextKey := mt.rootKey 436 | siblings := []*Hash{} 437 | for i := 0; i < mt.maxLevels; i++ { 438 | n, err := mt.GetNode(ctx, nextKey) 439 | if err != nil { 440 | return nil, err 441 | } 442 | switch n.Type { 443 | case NodeTypeEmpty: 444 | return nil, ErrKeyNotFound 445 | case NodeTypeLeaf: 446 | if bytes.Equal(kHash[:], n.Entry[0][:]) { 447 | cp.OldValue = n.Entry[1] 448 | cp.Siblings = CircomSiblingsFromSiblings(siblings, mt.maxLevels) 449 | // update leaf and upload to the root 450 | newNodeLeaf := NewNodeLeaf(kHash, vHash) 451 | _, err := mt.updateNode(ctx, newNodeLeaf) 452 | if err != nil { 453 | return nil, err 454 | } 455 | newRootKey, err := 456 | mt.recalculatePathUntilRoot(path, newNodeLeaf, siblings) 457 | if err != nil { 458 | return nil, err 459 | } 460 | mt.rootKey = newRootKey 461 | err = mt.db.SetRoot(ctx, mt.rootKey) 462 | if err != nil { 463 | return nil, err 464 | } 465 | cp.NewRoot = newRootKey 466 | return &cp, nil 467 | } 468 | return nil, ErrKeyNotFound 469 | case NodeTypeMiddle: 470 | if path[i] { 471 | nextKey = n.ChildR 472 | siblings = append(siblings, n.ChildL) 473 | } else { 474 | nextKey = n.ChildL 475 | siblings = append(siblings, n.ChildR) 476 | } 477 | default: 478 | return nil, ErrInvalidNodeFound 479 | } 480 | } 481 | 482 | return nil, ErrKeyNotFound 483 | } 484 | 485 | // Delete removes the specified Key from the MerkleTree and updates the path 486 | // from the deleted key to the Root with the new values. This method removes 487 | // the key from the MerkleTree, but does not remove the old nodes from the 488 | // key-value database; this means that if the tree is accessed by an old Root 489 | // where the key was not deleted yet, the key will still exist. If is desired 490 | // to remove the key-values from the database that are not under the current 491 | // Root, an option could be to dump all the leaves (using mt.DumpLeafs) and 492 | // import them in a new MerkleTree in a new database (using 493 | // mt.ImportDumpedLeafs), but this will loose all the Root history of the 494 | // MerkleTree 495 | func (mt *MerkleTree) Delete(ctx context.Context, k *big.Int) error { 496 | // verify that the MerkleTree is writable 497 | if !mt.writable { 498 | return ErrNotWritable 499 | } 500 | 501 | mt.Lock() 502 | defer mt.Unlock() 503 | 504 | kHash, err := NewHashFromBigInt(k) 505 | if err != nil { 506 | return err 507 | } 508 | path := getPath(mt.maxLevels, kHash[:]) 509 | 510 | nextKey := mt.rootKey 511 | siblings := []*Hash{} 512 | for i := 0; i < mt.maxLevels; i++ { 513 | n, err := mt.GetNode(ctx, nextKey) 514 | if err != nil { 515 | return err 516 | } 517 | switch n.Type { 518 | case NodeTypeEmpty: 519 | return ErrKeyNotFound 520 | case NodeTypeLeaf: 521 | if bytes.Equal(kHash[:], n.Entry[0][:]) { 522 | // remove and go up with the sibling 523 | err = mt.rmAndUpload(ctx, path, kHash, siblings) 524 | return err 525 | } 526 | return ErrKeyNotFound 527 | case NodeTypeMiddle: 528 | if path[i] { 529 | nextKey = n.ChildR 530 | siblings = append(siblings, n.ChildL) 531 | } else { 532 | nextKey = n.ChildL 533 | siblings = append(siblings, n.ChildR) 534 | } 535 | default: 536 | return ErrInvalidNodeFound 537 | } 538 | } 539 | 540 | return ErrKeyNotFound 541 | } 542 | 543 | // rmAndUpload removes the key, and goes up until the root updating all the 544 | // nodes with the new values. 545 | func (mt *MerkleTree) rmAndUpload(ctx context.Context, path []bool, kHash *Hash, 546 | siblings []*Hash) error { 547 | if len(siblings) == 0 { 548 | mt.rootKey = &HashZero 549 | err := mt.db.SetRoot(ctx, mt.rootKey) 550 | return err 551 | } 552 | 553 | toUpload := siblings[len(siblings)-1] 554 | if len(siblings) < 2 { 555 | mt.rootKey = siblings[0] 556 | err := mt.db.SetRoot(ctx, mt.rootKey) 557 | if err != nil { 558 | return err 559 | } 560 | } 561 | 562 | //When deleting a leaf node that is on the same level as middleNode, 563 | //need to nullify the leaf node instead of removing it from the tree. 564 | nearestSibling, err := mt.db.Get(ctx, toUpload[:]) 565 | if err != nil { 566 | return err 567 | } 568 | if nearestSibling.Type == NodeTypeMiddle { 569 | var newNode *Node 570 | if path[len(siblings)-1] { 571 | newNode = NewNodeMiddle(toUpload, &HashZero) 572 | } else { 573 | newNode = NewNodeMiddle(&HashZero, toUpload) 574 | } 575 | _, err = mt.addNode(ctx, newNode) 576 | if err != nil { 577 | return err 578 | } 579 | newRootKey, err := mt.recalculatePathUntilRoot(path, newNode, 580 | siblings[:len(siblings)-1]) 581 | if err != nil { 582 | return err 583 | } 584 | mt.rootKey = newRootKey 585 | err = mt.db.SetRoot(ctx, mt.rootKey) 586 | if err != nil { 587 | return err 588 | } 589 | return nil 590 | } 591 | 592 | for i := len(siblings) - 2; i >= 0; i-- { 593 | if !bytes.Equal(siblings[i][:], HashZero[:]) { 594 | var newNode *Node 595 | if path[i] { 596 | newNode = NewNodeMiddle(siblings[i], toUpload) 597 | } else { 598 | newNode = NewNodeMiddle(toUpload, siblings[i]) 599 | } 600 | _, err := mt.addNode(context.TODO(), newNode) 601 | if err != nil { 602 | return err 603 | } 604 | // go up until the root 605 | newRootKey, err := mt.recalculatePathUntilRoot(path, newNode, 606 | siblings[:i]) 607 | if err != nil { 608 | return err 609 | } 610 | mt.rootKey = newRootKey 611 | err = mt.db.SetRoot(ctx, mt.rootKey) 612 | if err != nil { 613 | return err 614 | } 615 | break 616 | } 617 | // if i==0 (root position), stop and store the sibling of the 618 | // deleted leaf as root 619 | if i == 0 { 620 | mt.rootKey = toUpload 621 | err := mt.db.SetRoot(ctx, mt.rootKey) 622 | if err != nil { 623 | return err 624 | } 625 | break 626 | } 627 | } 628 | 629 | return nil 630 | } 631 | 632 | // recalculatePathUntilRoot recalculates the nodes until the Root 633 | func (mt *MerkleTree) recalculatePathUntilRoot(path []bool, node *Node, 634 | siblings []*Hash) (*Hash, error) { 635 | for i := len(siblings) - 1; i >= 0; i-- { 636 | nodeKey, err := node.Key() 637 | if err != nil { 638 | return nil, err 639 | } 640 | if path[i] { 641 | node = NewNodeMiddle(siblings[i], nodeKey) 642 | } else { 643 | node = NewNodeMiddle(nodeKey, siblings[i]) 644 | } 645 | _, err = mt.addNode(context.TODO(), node) 646 | if err != nil { 647 | return nil, err 648 | } 649 | } 650 | 651 | // return last node added, which is the root 652 | nodeKey, err := node.Key() 653 | return nodeKey, err 654 | } 655 | 656 | // GetNode gets a node by key from the MT. Empty nodes are not stored in the 657 | // tree; they are all the same and assumed to always exist. 658 | func (mt *MerkleTree) GetNode(ctx context.Context, key *Hash) (*Node, error) { 659 | if bytes.Equal(key[:], HashZero[:]) { 660 | return NewNodeEmpty(), nil 661 | } 662 | n, err := mt.db.Get(ctx, key[:]) 663 | if err != nil { 664 | return nil, err 665 | } 666 | return n, nil 667 | } 668 | 669 | // getPath returns the binary path, from the root to the leaf. 670 | func getPath(numLevels int, k []byte) []bool { 671 | path := make([]bool, numLevels) 672 | for n := 0; n < numLevels; n++ { 673 | path[n] = TestBit(k[:], uint(n)) 674 | } 675 | return path 676 | } 677 | 678 | // NodeAux contains the auxiliary node used in a non-existence proof. 679 | type NodeAux struct { 680 | Key *Hash `json:"key"` 681 | Value *Hash `json:"value"` 682 | } 683 | 684 | // CircomSiblingsFromSiblings returns the full siblings compatible with circom 685 | func CircomSiblingsFromSiblings(siblings []*Hash, levels int) []*Hash { 686 | // Add the rest of empty levels to the siblings 687 | for i := len(siblings); i < levels+1; i++ { 688 | siblings = append(siblings, &HashZero) 689 | } 690 | return siblings 691 | } 692 | 693 | // CircomProcessorProof defines the ProcessorProof compatible with circom. Is 694 | // the data of the proof between the transition from one state to another. 695 | type CircomProcessorProof struct { 696 | OldRoot *Hash `json:"oldRoot"` 697 | NewRoot *Hash `json:"newRoot"` 698 | Siblings []*Hash `json:"siblings"` 699 | OldKey *Hash `json:"oldKey"` 700 | OldValue *Hash `json:"oldValue"` 701 | NewKey *Hash `json:"newKey"` 702 | NewValue *Hash `json:"newValue"` 703 | IsOld0 bool `json:"isOld0"` 704 | // 0: NOP, 1: Update, 2: Insert, 3: Delete 705 | Fnc int `json:"fnc"` 706 | } 707 | 708 | // String returns a human readable string representation of the 709 | // CircomProcessorProof 710 | func (p CircomProcessorProof) String() string { 711 | buf := bytes.NewBufferString("{") 712 | fmt.Fprintf(buf, " OldRoot: %v,\n", p.OldRoot) 713 | fmt.Fprintf(buf, " NewRoot: %v,\n", p.NewRoot) 714 | fmt.Fprintf(buf, " Siblings: [\n ") 715 | for _, s := range p.Siblings { 716 | fmt.Fprintf(buf, "%v, ", s) 717 | } 718 | fmt.Fprintf(buf, "\n ],\n") 719 | fmt.Fprintf(buf, " OldKey: %v,\n", p.OldKey) 720 | fmt.Fprintf(buf, " OldValue: %v,\n", p.OldValue) 721 | fmt.Fprintf(buf, " NewKey: %v,\n", p.NewKey) 722 | fmt.Fprintf(buf, " NewValue: %v,\n", p.NewValue) 723 | fmt.Fprintf(buf, " IsOld0: %v,\n", p.IsOld0) 724 | fmt.Fprintf(buf, "}\n") 725 | 726 | return buf.String() 727 | } 728 | 729 | // CircomVerifierProof defines the VerifierProof compatible with circom. Is the 730 | // data of the proof that a certain leaf exists in the MerkleTree. 731 | type CircomVerifierProof struct { 732 | Root *Hash `json:"root"` 733 | Siblings []*Hash `json:"siblings"` 734 | OldKey *Hash `json:"oldKey"` 735 | OldValue *Hash `json:"oldValue"` 736 | IsOld0 bool `json:"isOld0"` 737 | Key *Hash `json:"key"` 738 | Value *Hash `json:"value"` 739 | Fnc int `json:"fnc"` // 0: inclusion, 1: non inclusion 740 | } 741 | 742 | // GenerateCircomVerifierProof returns the CircomVerifierProof for a certain 743 | // key in the MerkleTree. If the rootKey is nil, the current merkletree root 744 | // is used. 745 | func (mt *MerkleTree) GenerateCircomVerifierProof(ctx context.Context, 746 | k *big.Int, rootKey *Hash) (*CircomVerifierProof, error) { 747 | cp, err := mt.GenerateSCVerifierProof(ctx, k, rootKey) 748 | if err != nil { 749 | return nil, err 750 | } 751 | cp.Siblings = CircomSiblingsFromSiblings(cp.Siblings, mt.maxLevels) 752 | return cp, nil 753 | } 754 | 755 | // GenerateSCVerifierProof returns the CircomVerifierProof for a certain key in 756 | // the MerkleTree with the Siblings without the extra 0 needed at the circom 757 | // circuits, which makes it straight forward to verifiy inside a Smart 758 | // Contract. If the rootKey is nil, the current merkletree root is used. 759 | func (mt *MerkleTree) GenerateSCVerifierProof(ctx context.Context, k *big.Int, 760 | rootKey *Hash) (*CircomVerifierProof, error) { 761 | if rootKey == nil { 762 | rootKey = mt.Root() 763 | } 764 | p, v, err := mt.GenerateProof(ctx, k, rootKey) 765 | if err != nil && err != ErrKeyNotFound { 766 | return nil, err 767 | } 768 | var cp CircomVerifierProof 769 | cp.Root = rootKey 770 | cp.Siblings = p.AllSiblings() 771 | if p.NodeAux != nil { 772 | cp.OldKey = p.NodeAux.Key 773 | cp.OldValue = p.NodeAux.Value 774 | } else { 775 | cp.OldKey = &HashZero 776 | cp.OldValue = &HashZero 777 | } 778 | cp.Key, err = NewHashFromBigInt(k) 779 | if err != nil { 780 | return nil, err 781 | } 782 | cp.Value, err = NewHashFromBigInt(v) 783 | if err != nil { 784 | return nil, err 785 | } 786 | if p.Existence { 787 | cp.Fnc = 0 // inclusion 788 | } else { 789 | cp.Fnc = 1 // non inclusion 790 | } 791 | 792 | return &cp, nil 793 | } 794 | 795 | // GenerateProof generates the proof of existence (or non-existence) of an 796 | // Entry's hash Index for a Merkle Tree given the root. 797 | // If the rootKey is nil, the current merkletree root is used 798 | func (mt *MerkleTree) GenerateProof(ctx context.Context, k *big.Int, 799 | rootKey *Hash) (*Proof, *big.Int, error) { 800 | p := &Proof{} 801 | var siblingKey *Hash 802 | 803 | kHash, err := NewHashFromBigInt(k) 804 | if err != nil { 805 | return nil, nil, err 806 | } 807 | path := getPath(mt.maxLevels, kHash[:]) 808 | if rootKey == nil { 809 | rootKey = mt.Root() 810 | } 811 | nextKey := rootKey 812 | for p.depth = 0; p.depth < uint(mt.maxLevels); p.depth++ { 813 | n, err := mt.GetNode(ctx, nextKey) 814 | if err != nil { 815 | return nil, nil, err 816 | } 817 | switch n.Type { 818 | case NodeTypeEmpty: 819 | return p, big.NewInt(0), nil 820 | case NodeTypeLeaf: 821 | if bytes.Equal(kHash[:], n.Entry[0][:]) { 822 | p.Existence = true 823 | return p, n.Entry[1].BigInt(), nil 824 | } 825 | // We found a leaf whose entry didn't match hIndex 826 | p.NodeAux = &NodeAux{Key: n.Entry[0], Value: n.Entry[1]} 827 | return p, n.Entry[1].BigInt(), nil 828 | case NodeTypeMiddle: 829 | if path[p.depth] { 830 | nextKey = n.ChildR 831 | siblingKey = n.ChildL 832 | } else { 833 | nextKey = n.ChildL 834 | siblingKey = n.ChildR 835 | } 836 | default: 837 | return nil, nil, ErrInvalidNodeFound 838 | } 839 | if !bytes.Equal(siblingKey[:], HashZero[:]) { 840 | SetBitBigEndian(p.notempties[:], p.depth) 841 | p.siblings = append(p.siblings, siblingKey) 842 | } 843 | } 844 | return nil, nil, ErrKeyNotFound 845 | } 846 | 847 | // walk is a helper recursive function to iterate over all tree branches 848 | func (mt *MerkleTree) walk(ctx context.Context, 849 | key *Hash, f func(*Node)) error { 850 | n, err := mt.GetNode(ctx, key) 851 | if err != nil { 852 | return err 853 | } 854 | switch n.Type { 855 | case NodeTypeEmpty: 856 | f(n) 857 | case NodeTypeLeaf: 858 | f(n) 859 | case NodeTypeMiddle: 860 | f(n) 861 | if err := mt.walk(ctx, n.ChildL, f); err != nil { 862 | return err 863 | } 864 | if err := mt.walk(ctx, n.ChildR, f); err != nil { 865 | return err 866 | } 867 | default: 868 | return ErrInvalidNodeFound 869 | } 870 | return nil 871 | } 872 | 873 | // Walk iterates over all the branches of a MerkleTree with the given rootKey 874 | // if rootKey is nil, it will get the current RootKey of the current state of 875 | // the MerkleTree. For each node, it calls the f function given in the 876 | // parameters. See some examples of the Walk function usage in the 877 | // merkletree.go and merkletree_test.go 878 | func (mt *MerkleTree) Walk(ctx context.Context, rootKey *Hash, 879 | f func(*Node)) error { 880 | if rootKey == nil { 881 | rootKey = mt.Root() 882 | } 883 | err := mt.walk(ctx, rootKey, f) 884 | return err 885 | } 886 | 887 | // GraphViz uses Walk function to generate a string GraphViz representation of 888 | // the tree and writes it to w 889 | func (mt *MerkleTree) GraphViz(ctx context.Context, w io.Writer, 890 | rootKey *Hash) error { 891 | fmt.Fprintf(w, `digraph hierarchy { 892 | node [fontname=Monospace,fontsize=10,shape=box] 893 | `) 894 | cnt := 0 895 | var errIn error 896 | err := mt.Walk(ctx, rootKey, func(n *Node) { 897 | k, err := n.Key() 898 | if err != nil { 899 | errIn = err 900 | } 901 | switch n.Type { 902 | case NodeTypeEmpty: 903 | case NodeTypeLeaf: 904 | fmt.Fprintf(w, "\"%v\" [style=filled];\n", k.String()) 905 | case NodeTypeMiddle: 906 | lr := [2]string{n.ChildL.String(), n.ChildR.String()} 907 | emptyNodes := "" 908 | for i := range lr { 909 | if lr[i] == "0" { 910 | lr[i] = fmt.Sprintf("empty%v", cnt) 911 | emptyNodes += fmt.Sprintf("\"%v\" [style=dashed,label=0];\n", 912 | lr[i]) 913 | cnt++ 914 | } 915 | } 916 | fmt.Fprintf(w, "\"%v\" -> {\"%v\" \"%v\"}\n", k.String(), lr[0], 917 | lr[1]) 918 | fmt.Fprint(w, emptyNodes) 919 | default: 920 | } 921 | }) 922 | fmt.Fprintf(w, "}\n") 923 | if errIn != nil { 924 | return errIn 925 | } 926 | return err 927 | } 928 | 929 | // PrintGraphViz prints directly the GraphViz() output 930 | func (mt *MerkleTree) PrintGraphViz(ctx context.Context, rootKey *Hash) error { 931 | if rootKey == nil { 932 | rootKey = mt.Root() 933 | } 934 | w := bytes.NewBufferString("") 935 | fmt.Fprintf(w, 936 | "--------\nGraphViz of the MerkleTree with RootKey "+rootKey.BigInt().String()+"\n") 937 | err := mt.GraphViz(ctx, w, nil) 938 | if err != nil { 939 | return err 940 | } 941 | fmt.Fprintf(w, 942 | "End of GraphViz of the MerkleTree with RootKey "+rootKey.BigInt().String()+"\n--------\n") 943 | 944 | fmt.Println(w) 945 | return nil 946 | } 947 | 948 | // DumpLeafs returns all the Leafs that exist under the given Root. If no Root 949 | // is given (nil), it uses the current Root of the MerkleTree. 950 | func (mt *MerkleTree) DumpLeafs(ctx context.Context, 951 | rootKey *Hash) ([]byte, error) { 952 | var buf bytes.Buffer 953 | err := mt.Walk(ctx, rootKey, func(n *Node) { 954 | if n.Type == NodeTypeLeaf { 955 | buf.Grow(len(n.Entry[0]) + len(n.Entry[1])) 956 | buf.Write(n.Entry[0][:]) 957 | buf.Write(n.Entry[1][:]) 958 | } 959 | }) 960 | return buf.Bytes(), err 961 | } 962 | 963 | // ImportDumpedLeafs parses and adds to the MerkleTree the dumped list of leafs 964 | // from the DumpLeafs function. 965 | func (mt *MerkleTree) ImportDumpedLeafs(ctx context.Context, b []byte) error { 966 | hashLn := len(Hash{}) 967 | nodeLn := hashLn * 2 968 | if len(b)%nodeLn != 0 { 969 | return errors.New("invalid input length") 970 | } 971 | for i := 0; i < len(b); i += nodeLn { 972 | var leftHash, rightHash Hash 973 | copy(leftHash[:], b[i:i+hashLn]) 974 | copy(rightHash[:], b[i+hashLn:i+(hashLn*2)]) 975 | 976 | err := mt.Add(ctx, leftHash.BigInt(), rightHash.BigInt()) 977 | if err != nil { 978 | return err 979 | } 980 | } 981 | return nil 982 | } 983 | -------------------------------------------------------------------------------- /node.go: -------------------------------------------------------------------------------- 1 | package merkletree 2 | 3 | import ( 4 | "fmt" 5 | "math/big" 6 | ) 7 | 8 | // NodeType defines the type of node in the MT. 9 | type NodeType byte 10 | 11 | const ( 12 | // NodeTypeMiddle indicates the type of middle Node that has children. 13 | NodeTypeMiddle NodeType = 0 14 | // NodeTypeLeaf indicates the type of a leaf Node that contains a key & 15 | // value. 16 | NodeTypeLeaf NodeType = 1 17 | // NodeTypeEmpty indicates the type of an empty Node. 18 | NodeTypeEmpty NodeType = 2 19 | 20 | // DBEntryTypeRoot indicates a type of DB entry that indicates the 21 | // current Root of a MerkleTree 22 | DBEntryTypeRoot NodeType = 3 23 | ) 24 | 25 | // Node is the struct that represents a node in the MT. The node should not be 26 | // modified after creation because the cached key won't be updated. 27 | type Node struct { 28 | // Type is the type of node in the tree. 29 | Type NodeType 30 | // ChildL is the left child of a middle node. 31 | ChildL *Hash 32 | // ChildR is the right child of a middle node. 33 | ChildR *Hash 34 | // Entry is the data stored in a leaf node. 35 | Entry [2]*Hash 36 | // key is a cache used to avoid recalculating key 37 | key *Hash 38 | } 39 | 40 | // NewNodeLeaf creates a new leaf node. 41 | func NewNodeLeaf(k, v *Hash) *Node { 42 | return &Node{Type: NodeTypeLeaf, Entry: [2]*Hash{k, v}} 43 | } 44 | 45 | // NewNodeMiddle creates a new middle node. 46 | func NewNodeMiddle(childL *Hash, childR *Hash) *Node { 47 | return &Node{Type: NodeTypeMiddle, ChildL: childL, ChildR: childR} 48 | } 49 | 50 | // NewNodeEmpty creates a new empty node. 51 | func NewNodeEmpty() *Node { 52 | return &Node{Type: NodeTypeEmpty} 53 | } 54 | 55 | // NewNodeFromBytes creates a new node by parsing the input []byte. 56 | func NewNodeFromBytes(b []byte) (*Node, error) { 57 | if len(b) < 1 { 58 | return nil, ErrNodeBytesBadSize 59 | } 60 | n := Node{Type: NodeType(b[0])} 61 | b = b[1:] 62 | switch n.Type { 63 | case NodeTypeMiddle: 64 | if len(b) != 2*ElemBytesLen { 65 | return nil, ErrNodeBytesBadSize 66 | } 67 | n.ChildL, n.ChildR = &Hash{}, &Hash{} 68 | copy(n.ChildL[:], b[:ElemBytesLen]) 69 | copy(n.ChildR[:], b[ElemBytesLen:ElemBytesLen*2]) 70 | case NodeTypeLeaf: 71 | if len(b) != 2*ElemBytesLen { 72 | return nil, ErrNodeBytesBadSize 73 | } 74 | n.Entry = [2]*Hash{{}, {}} 75 | copy(n.Entry[0][:], b[0:32]) 76 | copy(n.Entry[1][:], b[32:64]) 77 | case NodeTypeEmpty: 78 | break 79 | default: 80 | return nil, ErrInvalidNodeFound 81 | } 82 | return &n, nil 83 | } 84 | 85 | // LeafKey computes the key of a leaf node given the hIndex and hValue of the 86 | // entry of the leaf. 87 | func LeafKey(k, v *Hash) (*Hash, error) { 88 | return HashElemsKey(big.NewInt(1), k.BigInt(), v.BigInt()) 89 | } 90 | 91 | // Key computes the key of the node by hashing the content in a specific way 92 | // for each type of node. This key is used as the hash of the merkle tree for 93 | // each node. 94 | func (n *Node) Key() (*Hash, error) { 95 | if n.key == nil { // Cache the key to avoid repeated hash computations. 96 | // NOTE: We are not using the type to calculate the hash! 97 | switch n.Type { 98 | case NodeTypeMiddle: // H(ChildL || ChildR) 99 | var err error 100 | n.key, err = HashElems(n.ChildL.BigInt(), n.ChildR.BigInt()) 101 | if err != nil { 102 | return nil, err 103 | } 104 | case NodeTypeLeaf: 105 | var err error 106 | n.key, err = LeafKey(n.Entry[0], n.Entry[1]) 107 | if err != nil { 108 | return nil, err 109 | } 110 | case NodeTypeEmpty: // Zero 111 | n.key = &HashZero 112 | default: 113 | n.key = &HashZero 114 | } 115 | } 116 | return n.key, nil 117 | } 118 | 119 | // Value returns the value of the node. This is the content that is stored in 120 | // the backend database. 121 | func (n *Node) Value() []byte { 122 | switch n.Type { 123 | case NodeTypeMiddle: // {Type || ChildL || ChildR} 124 | return append([]byte{byte(n.Type)}, append(n.ChildL[:], n.ChildR[:]...)...) 125 | case NodeTypeLeaf: // {Type || Data...} 126 | return append([]byte{byte(n.Type)}, append(n.Entry[0][:], n.Entry[1][:]...)...) 127 | case NodeTypeEmpty: // {} 128 | return []byte{} 129 | default: 130 | return []byte{} 131 | } 132 | } 133 | 134 | // String outputs a string representation of a node (different for each type). 135 | func (n *Node) String() string { 136 | switch n.Type { 137 | case NodeTypeMiddle: // {Type || ChildL || ChildR} 138 | return fmt.Sprintf("Middle L:%s R:%s", n.ChildL, n.ChildR) 139 | case NodeTypeLeaf: // {Type || Data...} 140 | return fmt.Sprintf("Leaf I:%v D:%v", n.Entry[0], n.Entry[1]) 141 | case NodeTypeEmpty: // {} 142 | return "Empty" 143 | default: 144 | return "Invalid Node" 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /proof.go: -------------------------------------------------------------------------------- 1 | package merkletree 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "fmt" 7 | "math/big" 8 | ) 9 | 10 | // Proof defines the required elements for a MT proof of existence or 11 | // non-existence. 12 | type Proof struct { 13 | // existence indicates whether this is a proof of existence or 14 | // non-existence 15 | Existence bool 16 | // depth indicates how deep in the tree the proof goes 17 | depth uint 18 | // notempties is a bitmap of non-empty siblings found in siblings 19 | notempties [ElemBytesLen - proofFlagsLen]byte 20 | // siblings is a list of non-empty sibling keys 21 | siblings []*Hash 22 | // Auxiliary node if needed 23 | NodeAux *NodeAux 24 | } 25 | 26 | // proofJSON defines the required elements for a MT proof in json serializable structure 27 | type proofJSON struct { 28 | // existence indicates whether this is a proof of existence or 29 | // non-existence 30 | Existence bool `json:"existence"` 31 | // Siblings is a list of all sibling keys 32 | Siblings []*Hash `json:"siblings"` 33 | // Auxiliary node if needed 34 | NodeAux *NodeAux `json:"node_aux,omitempty"` 35 | } 36 | 37 | // NewProofFromBytes parses a byte array into a Proof 38 | func NewProofFromBytes(bs []byte) (*Proof, error) { 39 | if len(bs) < ElemBytesLen { 40 | return nil, ErrInvalidProofBytes 41 | } 42 | p := &Proof{} 43 | if (bs[0] & 0x01) == 0 { 44 | p.Existence = true 45 | } 46 | p.depth = uint(bs[1]) 47 | copy(p.notempties[:], bs[proofFlagsLen:ElemBytesLen]) 48 | siblingBytes := bs[ElemBytesLen:] 49 | sibIdx := 0 50 | for i := uint(0); i < p.depth; i++ { 51 | if TestBitBigEndian(p.notempties[:], i) { 52 | if len(siblingBytes) < (sibIdx+1)*ElemBytesLen { 53 | return nil, ErrInvalidProofBytes 54 | } 55 | var sib Hash 56 | copy(sib[:], 57 | siblingBytes[sibIdx*ElemBytesLen:(sibIdx+1)*ElemBytesLen]) 58 | p.siblings = append(p.siblings, &sib) 59 | sibIdx++ 60 | } 61 | } 62 | 63 | if !p.Existence && ((bs[0] & 0x02) != 0) { 64 | p.NodeAux = &NodeAux{Key: &Hash{}, Value: &Hash{}} 65 | nodeAuxBytes := siblingBytes[len(p.siblings)*ElemBytesLen:] 66 | if len(nodeAuxBytes) != 2*ElemBytesLen { 67 | return nil, ErrInvalidProofBytes 68 | } 69 | copy(p.NodeAux.Key[:], nodeAuxBytes[:ElemBytesLen]) 70 | copy(p.NodeAux.Value[:], nodeAuxBytes[ElemBytesLen:2*ElemBytesLen]) 71 | } 72 | return p, nil 73 | } 74 | 75 | // NewProofFromData reconstructs proof from siblings and auxiliary node 76 | func NewProofFromData(existence bool, 77 | allSiblings []*Hash, 78 | nodeAux *NodeAux) (*Proof, error) { 79 | var p Proof 80 | p.Existence = existence 81 | p.NodeAux = nodeAux 82 | var siblings []*Hash 83 | p.depth = 0 84 | for lvl, sibling := range allSiblings { 85 | if !sibling.Equals(&HashZero) { 86 | SetBitBigEndian(p.notempties[:], uint(lvl)) 87 | siblings = append(siblings, sibling) 88 | p.depth = uint(lvl) + 1 89 | } 90 | } 91 | p.siblings = siblings 92 | return &p, nil 93 | } 94 | 95 | // Bytes serializes a Proof into a byte array. 96 | func (p *Proof) Bytes() []byte { 97 | bsLen := proofFlagsLen + len(p.notempties) + ElemBytesLen*len(p.siblings) 98 | if p.NodeAux != nil { 99 | bsLen += 2 * ElemBytesLen 100 | } 101 | bs := make([]byte, bsLen) 102 | 103 | if !p.Existence { 104 | bs[0] |= 0x01 105 | } 106 | bs[1] = byte(p.depth) 107 | copy(bs[proofFlagsLen:len(p.notempties)+proofFlagsLen], p.notempties[:]) 108 | siblingsBytes := bs[len(p.notempties)+proofFlagsLen:] 109 | for i, k := range p.siblings { 110 | copy(siblingsBytes[i*ElemBytesLen:(i+1)*ElemBytesLen], k[:]) 111 | } 112 | if p.NodeAux != nil { 113 | bs[0] |= 0x02 114 | copy(bs[len(bs)-2*ElemBytesLen:], p.NodeAux.Key[:]) 115 | copy(bs[len(bs)-1*ElemBytesLen:], p.NodeAux.Value[:]) 116 | } 117 | return bs 118 | } 119 | 120 | // AllSiblings returns all the siblings of the proof. 121 | func (p *Proof) AllSiblings() []*Hash { 122 | return SiblingsFromProof(p) 123 | } 124 | 125 | // MarshalJSON implements json.Marshaler interface 126 | func (p Proof) MarshalJSON() ([]byte, error) { 127 | obj := proofJSON{ 128 | Existence: p.Existence, 129 | Siblings: p.AllSiblings(), 130 | NodeAux: p.NodeAux, 131 | } 132 | return json.Marshal(obj) 133 | } 134 | 135 | // UnmarshalJSON implements json.Unmarshaler interface 136 | func (p *Proof) UnmarshalJSON(data []byte) error { 137 | var obj proofJSON 138 | err := json.Unmarshal(data, &obj) 139 | if err != nil { 140 | return err 141 | } 142 | 143 | proof, err := NewProofFromData(obj.Existence, obj.Siblings, obj.NodeAux) 144 | if err != nil { 145 | return err 146 | } 147 | 148 | p.siblings = proof.siblings 149 | p.Existence = proof.Existence 150 | p.NodeAux = proof.NodeAux 151 | p.notempties = proof.notempties 152 | p.depth = proof.depth 153 | 154 | return nil 155 | } 156 | 157 | // SiblingsFromProof returns all the siblings of the proof. 158 | func SiblingsFromProof(proof *Proof) []*Hash { 159 | sibIdx := 0 160 | siblings := []*Hash{} 161 | for lvl := 0; lvl < int(proof.depth); lvl++ { 162 | if TestBitBigEndian(proof.notempties[:], uint(lvl)) { 163 | siblings = append(siblings, proof.siblings[sibIdx]) 164 | sibIdx++ 165 | } else { 166 | siblings = append(siblings, &HashZero) 167 | } 168 | } 169 | return siblings 170 | } 171 | 172 | // VerifyProof verifies the Merkle Proof for the entry and root. 173 | func VerifyProof(rootKey *Hash, proof *Proof, k, v *big.Int) bool { 174 | rootFromProof, err := RootFromProof(proof, k, v) 175 | if err != nil { 176 | return false 177 | } 178 | return bytes.Equal(rootKey[:], rootFromProof[:]) 179 | } 180 | 181 | // RootFromProof calculates the root that would correspond to a tree whose 182 | // siblings are the ones in the proof with the leaf hashing to hIndex and 183 | // hValue. 184 | func RootFromProof(proof *Proof, k, v *big.Int) (*Hash, error) { 185 | kHash, err := NewHashFromBigInt(k) 186 | if err != nil { 187 | return nil, fmt.Errorf("can't create hash from Key: %w", err) 188 | } 189 | vHash, err := NewHashFromBigInt(v) 190 | if err != nil { 191 | return nil, fmt.Errorf("can't create hash from Value: %w", err) 192 | } 193 | sibIdx := len(proof.siblings) - 1 194 | var midKey *Hash 195 | if proof.Existence { 196 | midKey, err = LeafKey(kHash, vHash) 197 | if err != nil { 198 | return nil, err 199 | } 200 | } else { 201 | if proof.NodeAux == nil { 202 | midKey = &HashZero 203 | } else { 204 | if bytes.Equal(kHash[:], proof.NodeAux.Key[:]) { 205 | return nil, 206 | fmt.Errorf("Non-existence proof being checked against hIndex equal to nodeAux") 207 | } 208 | midKey, err = LeafKey(proof.NodeAux.Key, proof.NodeAux.Value) 209 | if err != nil { 210 | return nil, err 211 | } 212 | } 213 | } 214 | path := getPath(int(proof.depth), kHash[:]) 215 | var siblingKey *Hash 216 | for lvl := int(proof.depth) - 1; lvl >= 0; lvl-- { 217 | if TestBitBigEndian(proof.notempties[:], uint(lvl)) { 218 | siblingKey = proof.siblings[sibIdx] 219 | sibIdx-- 220 | } else { 221 | siblingKey = &HashZero 222 | } 223 | if path[lvl] { 224 | midKey, err = NewNodeMiddle(siblingKey, midKey).Key() 225 | if err != nil { 226 | return nil, err 227 | } 228 | } else { 229 | midKey, err = NewNodeMiddle(midKey, siblingKey).Key() 230 | if err != nil { 231 | return nil, err 232 | } 233 | } 234 | } 235 | return midKey, nil 236 | } 237 | -------------------------------------------------------------------------------- /proof_test.go: -------------------------------------------------------------------------------- 1 | package merkletree_test 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "math/big" 7 | "testing" 8 | 9 | "github.com/iden3/go-merkletree-sql/v2" 10 | "github.com/iden3/go-merkletree-sql/v2/db/memory" 11 | "github.com/stretchr/testify/assert" 12 | "github.com/stretchr/testify/require" 13 | ) 14 | 15 | func TestProof_MarshalJSON(t *testing.T) { 16 | db := memory.NewMemoryStorage() 17 | ctx := context.Background() 18 | mt, err := merkletree.NewMerkleTree(ctx, db, 40) 19 | require.NoError(t, err) 20 | 21 | _ = mt.Add(ctx, big.NewInt(0x0001), big.NewInt(2)) 22 | _ = mt.Add(ctx, big.NewInt(0x0011), big.NewInt(8)) 23 | proof, _, err := mt.GenerateProof(ctx, big.NewInt(1), mt.Root()) 24 | require.NoError(t, err) 25 | 26 | expected := `{"existence":true,"siblings":["0","0","0","0","13167809686468103484252970188077542812117386492167015186848701688893624465068"]}` //nolint:lll 27 | 28 | jsonProof, err := proof.MarshalJSON() 29 | require.NoError(t, err) 30 | assert.JSONEq(t, expected, string(jsonProof)) 31 | 32 | jsonProof2, err := json.Marshal(proof) 33 | require.NoError(t, err) 34 | assert.JSONEq(t, expected, string(jsonProof2)) 35 | 36 | var p merkletree.Proof 37 | err = json.Unmarshal(jsonProof, &p) 38 | require.NoError(t, err) 39 | 40 | assert.Equal(t, proof.AllSiblings(), p.AllSiblings()) 41 | assert.Equal(t, proof.NodeAux, p.NodeAux) 42 | assert.Equal(t, proof.Existence, p.Existence) 43 | 44 | valid := merkletree.VerifyProof(mt.Root(), proof, big.NewInt(1), big.NewInt(2)) 45 | assert.True(t, valid) 46 | 47 | valid = merkletree.VerifyProof(mt.Root(), &p, big.NewInt(1), big.NewInt(2)) 48 | assert.True(t, valid) 49 | } 50 | 51 | func TestProof_MarshalJSON_NonInclusionProofWithoutNodeAux(t *testing.T) { 52 | db := memory.NewMemoryStorage() 53 | ctx := context.Background() 54 | mt, err := merkletree.NewMerkleTree(ctx, db, 40) 55 | require.NoError(t, err) 56 | 57 | _ = mt.Add(ctx, big.NewInt(1), big.NewInt(2)) 58 | _ = mt.Add(ctx, big.NewInt(2), big.NewInt(8)) 59 | _ = mt.Add(ctx, big.NewInt(3), big.NewInt(8)) 60 | _ = mt.Add(ctx, big.NewInt(17), big.NewInt(8)) 61 | _ = mt.Add(ctx, big.NewInt(18), big.NewInt(8)) 62 | _ = mt.Add(ctx, big.NewInt(19), big.NewInt(8)) 63 | 64 | expected := `{"existence":false,"siblings":["11445591970430686524669302036672429838422356071483318076578901368167305782934","0","19623034175990655567331847335376057032468128626960956120127301863642129702078"]}` //nolint:lll 65 | 66 | proof, _, err := mt.GenerateProof(ctx, big.NewInt(6), mt.Root()) 67 | require.NoError(t, err) 68 | jsonProof, err := proof.MarshalJSON() 69 | require.NoError(t, err) 70 | assert.JSONEq(t, expected, string(jsonProof)) 71 | 72 | // gives the same proof 73 | proof, _, err = mt.GenerateProof(ctx, big.NewInt(14), mt.Root()) 74 | require.NoError(t, err) 75 | jsonProof, err = proof.MarshalJSON() 76 | require.NoError(t, err) 77 | assert.JSONEq(t, expected, string(jsonProof)) 78 | 79 | // gives the same proof 80 | proof, _, err = mt.GenerateProof(ctx, big.NewInt(22), mt.Root()) 81 | require.NoError(t, err) 82 | jsonProof, err = proof.MarshalJSON() 83 | require.NoError(t, err) 84 | assert.JSONEq(t, expected, string(jsonProof)) 85 | 86 | // gives the same proof 87 | proof, _, err = mt.GenerateProof(ctx, big.NewInt(30), mt.Root()) 88 | require.NoError(t, err) 89 | jsonProof, err = proof.MarshalJSON() 90 | require.NoError(t, err) 91 | assert.JSONEq(t, expected, string(jsonProof)) 92 | 93 | // gives the same proof 94 | proof, _, err = mt.GenerateProof(ctx, big.NewInt(38), mt.Root()) 95 | require.NoError(t, err) 96 | jsonProof, err = proof.MarshalJSON() 97 | require.NoError(t, err) 98 | assert.JSONEq(t, expected, string(jsonProof)) 99 | 100 | // gives the same proof 101 | proof, _, err = mt.GenerateProof(ctx, big.NewInt(46), mt.Root()) 102 | require.NoError(t, err) 103 | jsonProof, err = proof.MarshalJSON() 104 | require.NoError(t, err) 105 | assert.JSONEq(t, expected, string(jsonProof)) 106 | 107 | //fmt.Println(string(jsonProof)) 108 | 109 | jsonProof2, err := json.Marshal(proof) 110 | require.NoError(t, err) 111 | assert.JSONEq(t, expected, string(jsonProof2)) 112 | 113 | var p merkletree.Proof 114 | err = json.Unmarshal(jsonProof, &p) 115 | require.NoError(t, err) 116 | 117 | assert.Equal(t, proof.AllSiblings(), p.AllSiblings()) 118 | assert.Equal(t, proof.NodeAux, p.NodeAux) 119 | assert.Equal(t, proof.Existence, p.Existence) 120 | 121 | valid := merkletree.VerifyProof(mt.Root(), proof, big.NewInt(6), big.NewInt(0)) 122 | assert.True(t, valid) 123 | 124 | valid = merkletree.VerifyProof(mt.Root(), &p, big.NewInt(6), big.NewInt(0)) 125 | assert.True(t, valid) 126 | } 127 | 128 | func TestProof_MarshalJSON_NonInclusionProofWithNodeAux(t *testing.T) { 129 | db := memory.NewMemoryStorage() 130 | ctx := context.Background() 131 | mt, err := merkletree.NewMerkleTree(ctx, db, 40) 132 | require.NoError(t, err) 133 | 134 | _ = mt.Add(ctx, big.NewInt(1), big.NewInt(2)) // 1 0b000001 135 | _ = mt.Add(ctx, big.NewInt(3), big.NewInt(8)) // 3 0b000011 136 | _ = mt.Add(ctx, big.NewInt(7), big.NewInt(8)) // 7 0b000111 137 | _ = mt.Add(ctx, big.NewInt(9), big.NewInt(8)) // 9 0b001001 138 | 139 | //nolint:lll 140 | expected := `{"existence":false,"siblings":["0","12166698708103333637493481507263348370172773813051235807348785759284762677336","7750564177398573185975752951631372712868228752107043582052272719841058100111"],"node_aux":{"key":"3","value":"8"}}` 141 | 142 | proof, _, err := mt.GenerateProof(ctx, big.NewInt(11), mt.Root()) // 11 0b001011 143 | require.NoError(t, err) 144 | jsonProof, err := proof.MarshalJSON() 145 | require.NoError(t, err) 146 | assert.JSONEq(t, expected, string(jsonProof)) 147 | 148 | //fmt.Println(string(jsonProof)) 149 | 150 | jsonProof2, err := json.Marshal(proof) 151 | require.NoError(t, err) 152 | assert.JSONEq(t, expected, string(jsonProof2)) 153 | 154 | var p merkletree.Proof 155 | err = json.Unmarshal(jsonProof, &p) 156 | require.NoError(t, err) 157 | 158 | assert.Equal(t, proof.AllSiblings(), p.AllSiblings()) 159 | assert.Equal(t, proof.NodeAux, p.NodeAux) 160 | assert.Equal(t, proof.Existence, p.Existence) 161 | 162 | valid := merkletree.VerifyProof(mt.Root(), proof, big.NewInt(11), big.NewInt(0)) 163 | assert.True(t, valid) 164 | 165 | valid = merkletree.VerifyProof(mt.Root(), &p, big.NewInt(11), big.NewInt(0)) 166 | assert.True(t, valid) 167 | } 168 | 169 | func TestProof_UnmarshalJSON_NonInclusionProofWithNodeAuxAllSiblings(t *testing.T) { 170 | db := memory.NewMemoryStorage() 171 | ctx := context.Background() 172 | mt, err := merkletree.NewMerkleTree(ctx, db, 40) 173 | require.NoError(t, err) 174 | 175 | _ = mt.Add(ctx, big.NewInt(1), big.NewInt(2)) // 1 0b000001 176 | _ = mt.Add(ctx, big.NewInt(3), big.NewInt(8)) // 3 0b000011 177 | _ = mt.Add(ctx, big.NewInt(7), big.NewInt(8)) // 7 0b000111 178 | _ = mt.Add(ctx, big.NewInt(9), big.NewInt(8)) // 9 0b001001 179 | 180 | //nolint:lll 181 | given := `{ "existence": false, "siblings": [ "0", "12166698708103333637493481507263348370172773813051235807348785759284762677336", "7750564177398573185975752951631372712868228752107043582052272719841058100111", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0", "0" ], "node_aux": { "key": "3", "value": "8" }}` 182 | 183 | proof, _, err := mt.GenerateProof(ctx, big.NewInt(11), mt.Root()) // 11 0b001011 184 | require.NoError(t, err) 185 | 186 | var p merkletree.Proof 187 | err = json.Unmarshal([]byte(given), &p) 188 | require.NoError(t, err) 189 | 190 | assert.Equal(t, proof.AllSiblings(), p.AllSiblings()) 191 | assert.Equal(t, proof.NodeAux, p.NodeAux) 192 | assert.Equal(t, proof.Existence, p.Existence) 193 | 194 | valid := merkletree.VerifyProof(mt.Root(), proof, big.NewInt(11), big.NewInt(0)) 195 | assert.True(t, valid) 196 | 197 | valid = merkletree.VerifyProof(mt.Root(), &p, big.NewInt(11), big.NewInt(0)) 198 | assert.True(t, valid) 199 | } 200 | -------------------------------------------------------------------------------- /utils.go: -------------------------------------------------------------------------------- 1 | package merkletree 2 | 3 | import ( 4 | "encoding/binary" 5 | "math/big" 6 | 7 | "github.com/iden3/go-iden3-crypto/poseidon" 8 | ) 9 | 10 | // HashElems performs a poseidon hash over the array of ElemBytes, currently we 11 | // are using 2 elements. Uses poseidon.Hash to be compatible with the circom 12 | // circuits implementations. 13 | func HashElems(elems ...*big.Int) (*Hash, error) { 14 | poseidonHash, err := poseidon.Hash(elems) 15 | if err != nil { 16 | return nil, err 17 | } 18 | return NewHashFromBigInt(poseidonHash) 19 | } 20 | 21 | // HashElemsKey performs a poseidon hash over the array of ElemBytes, currently 22 | // we are using 2 elements. 23 | func HashElemsKey(key *big.Int, elems ...*big.Int) (*Hash, error) { 24 | if key == nil { 25 | key = new(big.Int).SetInt64(0) 26 | } 27 | bi := make([]*big.Int, 3) 28 | copy(bi[:], elems) 29 | bi[2] = key 30 | poseidonHash, err := poseidon.Hash(bi) 31 | if err != nil { 32 | return nil, err 33 | } 34 | return NewHashFromBigInt(poseidonHash) 35 | } 36 | 37 | // SetBitBigEndian sets the bit n in the bitmap to 1, in Big Endian. 38 | func SetBitBigEndian(bitmap []byte, n uint) { 39 | bitmap[uint(len(bitmap))-n/8-1] |= 1 << (n % 8) 40 | } 41 | 42 | // TestBit tests whether the bit n in bitmap is 1. 43 | func TestBit(bitmap []byte, n uint) bool { 44 | return bitmap[n/8]&(1<<(n%8)) != 0 45 | } 46 | 47 | // TestBitBigEndian tests whether the bit n in bitmap is 1, in Big Endian. 48 | func TestBitBigEndian(bitmap []byte, n uint) bool { 49 | return bitmap[uint(len(bitmap))-n/8-1]&(1<<(n%8)) != 0 50 | } 51 | 52 | // SwapEndianness swaps the order of the bytes in the slice. 53 | func SwapEndianness(b []byte) []byte { 54 | o := make([]byte, len(b)) 55 | for i := range b { 56 | o[len(b)-1-i] = b[i] 57 | } 58 | return o 59 | } 60 | 61 | // Uint16ToBytes returns a byte array from a uint16 62 | func Uint16ToBytes(u uint16) []byte { 63 | var b [2]byte 64 | binary.LittleEndian.PutUint16(b[:], u) 65 | return b[:] 66 | } 67 | 68 | // BytesToUint16 returns a uint16 from a byte array 69 | func BytesToUint16(b []byte) uint16 { 70 | return binary.LittleEndian.Uint16(b[:2]) 71 | } 72 | --------------------------------------------------------------------------------