github.com/google/trillian-examples@v0.0.0-20240520080811-0d40d35cef0e/clone/internal/verify/verify_test.go (about)

     1  // Copyright 2021 Google LLC. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package verify
    16  
    17  import (
    18  	"context"
    19  	"database/sql"
    20  	"encoding/base64"
    21  	"fmt"
    22  	"testing"
    23  
    24  	"github.com/google/trillian-examples/clone/logdb"
    25  	_ "github.com/mattn/go-sqlite3" // Load drivers for sqlite3
    26  	"github.com/transparency-dev/merkle/rfc6962"
    27  )
    28  
    29  func TestRootFromScratch(t *testing.T) {
    30  	db, close, err := NewInMemoryDatabase()
    31  	if err != nil {
    32  		t.Fatalf("NewDatabase(): %v", err)
    33  	}
    34  	defer close()
    35  
    36  	leaves := make([][]byte, 64)
    37  	for i := range leaves {
    38  		leaves[i] = []byte(fmt.Sprintf("leaf %d", i))
    39  	}
    40  	if err := db.WriteLeaves(context.Background(), 0, leaves); err != nil {
    41  		t.Fatalf("Failed to initialize database with leaves")
    42  	}
    43  
    44  	h := rfc6962.DefaultHasher
    45  	lh := func(_ uint64, preimage []byte) []byte {
    46  		return h.HashLeaf(preimage)
    47  	}
    48  
    49  	for _, test := range []struct {
    50  		desc     string
    51  		count    uint64
    52  		wantRoot string
    53  		wantErr  bool
    54  	}{{
    55  		desc:     "one leaf",
    56  		count:    1,
    57  		wantRoot: "G7l9zCFjXUfiZj79/QoXRobZjdcBNS3SzQbotD/T0wU",
    58  	}, {
    59  		desc:     "16 leaves",
    60  		count:    16,
    61  		wantRoot: "cUopKYyn2GQ5dRAFaUmcIwnoOm8vlwkC3EbvMuvBsA8",
    62  	}, {
    63  		desc:     "17 leaves",
    64  		count:    17,
    65  		wantRoot: "Ru8bykxkgM1l5Q4pzBw3XbNnEc1QJF7NPmsxDG4qOD8",
    66  	}, {
    67  		desc:     "all leaves",
    68  		count:    64,
    69  		wantRoot: "8mHiNpLZeP2sP9lJ21SVlApDeuZxuabd6aphGNADZS8",
    70  	}, {
    71  		desc:    "too many leaves",
    72  		count:   65,
    73  		wantErr: true,
    74  	},
    75  	} {
    76  		t.Run(test.desc, func(t *testing.T) {
    77  			v := NewLogVerifier(db, lh, h.HashChildren)
    78  			got, _, err := v.MerkleRoot(context.Background(), test.count)
    79  			if gotErr := err != nil; test.wantErr != gotErr {
    80  				t.Errorf("expected err (%t) but got: %q", test.wantErr, err)
    81  			}
    82  			if !test.wantErr {
    83  				gotb64 := base64.RawStdEncoding.EncodeToString(got)
    84  				if gotb64 != test.wantRoot {
    85  					t.Errorf("got %q but wanted root %q", gotb64, test.wantRoot)
    86  				}
    87  			}
    88  		})
    89  	}
    90  }
    91  
    92  func TestPartialRoot(t *testing.T) {
    93  	db, close, err := NewInMemoryDatabase()
    94  	if err != nil {
    95  		t.Fatalf("NewDatabase(): %v", err)
    96  	}
    97  	defer close()
    98  
    99  	leaves := make([][]byte, 64)
   100  	for i := range leaves {
   101  		leaves[i] = []byte(fmt.Sprintf("leaf %d", i))
   102  	}
   103  	if err := db.WriteLeaves(context.Background(), 0, leaves); err != nil {
   104  		t.Fatalf("Failed to initialize database with leaves: %v", err)
   105  	}
   106  	cr, err := base64.RawStdEncoding.DecodeString("cUopKYyn2GQ5dRAFaUmcIwnoOm8vlwkC3EbvMuvBsA8")
   107  	if err != nil {
   108  		t.Fatalf("Failed to decode base64: %v", err)
   109  	}
   110  	if err := db.WriteCheckpoint(context.Background(), 16, []byte("root"), [][]byte{cr}); err != nil {
   111  		t.Fatalf("Failed to init db with checkpoint: %v", err)
   112  	}
   113  
   114  	h := rfc6962.DefaultHasher
   115  	lh := func(_ uint64, preimage []byte) []byte {
   116  		return h.HashLeaf(preimage)
   117  	}
   118  
   119  	for _, test := range []struct {
   120  		desc     string
   121  		count    uint64
   122  		wantRoot string
   123  		wantErr  bool
   124  	}{{
   125  		desc:     "one leaf",
   126  		count:    1,
   127  		wantRoot: "G7l9zCFjXUfiZj79/QoXRobZjdcBNS3SzQbotD/T0wU",
   128  	}, {
   129  		desc:     "16 leaves",
   130  		count:    16,
   131  		wantRoot: "cUopKYyn2GQ5dRAFaUmcIwnoOm8vlwkC3EbvMuvBsA8",
   132  	}, {
   133  		desc:     "17 leaves",
   134  		count:    17,
   135  		wantRoot: "Ru8bykxkgM1l5Q4pzBw3XbNnEc1QJF7NPmsxDG4qOD8",
   136  	}, {
   137  		desc:     "all leaves",
   138  		count:    64,
   139  		wantRoot: "8mHiNpLZeP2sP9lJ21SVlApDeuZxuabd6aphGNADZS8",
   140  	}, {
   141  		desc:    "too many leaves",
   142  		count:   65,
   143  		wantErr: true,
   144  	},
   145  	} {
   146  		t.Run(test.desc, func(t *testing.T) {
   147  			v := NewLogVerifier(db, lh, h.HashChildren)
   148  			got, _, err := v.MerkleRoot(context.Background(), test.count)
   149  			if gotErr := err != nil; test.wantErr != gotErr {
   150  				t.Errorf("expected err (%t) but got: %q", test.wantErr, err)
   151  			}
   152  			if !test.wantErr {
   153  				gotb64 := base64.RawStdEncoding.EncodeToString(got)
   154  				if gotb64 != test.wantRoot {
   155  					t.Errorf("got %q but wanted root %q", gotb64, test.wantRoot)
   156  				}
   157  			}
   158  		})
   159  	}
   160  }
   161  
   162  func NewInMemoryDatabase() (*logdb.Database, func(), error) {
   163  	sqlitedb, err := sql.Open("sqlite3", ":memory:")
   164  	if err != nil {
   165  		return nil, nil, fmt.Errorf("failed to open temporary in-memory DB: %v", err)
   166  	}
   167  	db, err := logdb.NewDatabaseDirect(sqlitedb)
   168  	return db, func() { _ = sqlitedb.Close }, err
   169  }