diff --git a/cmd/kt-client/distinguished.go b/cmd/kt-client/distinguished.go index 3ea816b..faa981a 100644 --- a/cmd/kt-client/distinguished.go +++ b/cmd/kt-client/distinguished.go @@ -31,7 +31,7 @@ func handleDistinguished(client pb.KeyTransparencyQueryServiceClient) { if *configFile == "" { p.Printf("Verification skipped\n") } else { - if err := transparency.VerifySearch(newStore(), createTreeSearchRequest([]byte("distinguished")), createTreeSearchResponse(res.Distinguished, res.TreeHead)); err != nil { + if err := transparency.VerifySearch(newStore(), createTreeSearchRequest([]byte("distinguished"), nil), createTreeSearchResponse(res.Distinguished, res.TreeHead)); err != nil { p.Printf("Verification failed: %v\n", err) } else { p.Printf("Verification successful\n") diff --git a/cmd/kt-client/main.go b/cmd/kt-client/main.go index 2d256b1..6b867ee 100644 --- a/cmd/kt-client/main.go +++ b/cmd/kt-client/main.go @@ -32,11 +32,14 @@ var ( testServerAddr = flag.String("test-addr", "localhost:8081", "Address of test server.") configFile = flag.String("config", "", "(Optional) Location of server config file.") - usernameHash = flag.String("username-hash", "", "Base64url encoded username hash") - e164 = flag.String("e164", "", "E164-formatted phone number. Must be preceded with a '+'. E.g. +14155550101") - uak = flag.String("uak", "", "Standard base64 encoded unidentified access key") - timingNumSamples = flag.Int("num-samples", 5, "Number of samples to use for measuring timing of a query request") - timingSampleSize = flag.Int("sample-size", 100, "Number of requests per sample to use for measuring timing of a query request") + usernameHash = flag.String("username-hash", "", "Base64url encoded username hash") + e164 = flag.String("e164", "", "E164-formatted phone number. Must be preceded with a '+'. E.g. +14155550101") + uak = flag.String("uak", "", "Standard base64 encoded unidentified access key") + aciVersionStr = flag.String("aci-version", "", "Which version of the provided ACI to search for") + e164VersionStr = flag.String("e164-version", "", "Which version of the provided E164 to search for") + usernameHashVersionStr = flag.String("username-hash-version", "", "Which version of the provided username hash to search for") + timingNumSamples = flag.Int("num-samples", 5, "Number of samples to use for measuring timing of a query request") + timingSampleSize = flag.Int("sample-size", 100, "Number of requests per sample to use for measuring timing of a query request") last = flag.Int("last", -1, "(Optional) Size of tree when last observed, or -1 for none.") ) diff --git a/cmd/kt-client/search.go b/cmd/kt-client/search.go index f535572..60c0dec 100644 --- a/cmd/kt-client/search.go +++ b/cmd/kt-client/search.go @@ -7,6 +7,7 @@ package main import ( "context" + "encoding/base64" "github.com/signalapp/keytransparency/cmd/internal/util" "github.com/signalapp/keytransparency/cmd/kt-server/pb" @@ -20,15 +21,25 @@ func constructSearchRequest(args QueryArgs) *pb.SearchRequest { AciIdentityKey: args.AciIdentityKey, Consistency: consistency(last), } + + if args.AciVersion != nil { + req.AciVersion = args.AciVersion + } if args.E164 != "" { req.E164SearchRequest = &pb.E164SearchRequest{ E164: &args.E164, UnidentifiedAccessKey: args.UnidentifiedAccessKey, } + if args.E164Version != nil { + req.E164Version = args.E164Version + } } if args.UsernameHash != nil { req.UsernameHash = args.UsernameHash + if args.UsernameHashVersion != nil { + req.UsernameHashVersion = args.UsernameHashVersion + } } return req } @@ -40,25 +51,28 @@ func handleSearch(client pb.KeyTransparencyQueryServiceClient) { printFullTreeHead(res.TreeHead) p.Printf("ACI search response: \n") + p.Printf("VRF: %x\n\n", res.Aci.VrfProof) printSearchProof(res.Aci.Search) p.Printf("Opening: %x\n", res.Aci.Opening) - p.Printf("Value: %x\n\n", res.Aci.Value.Value) + p.Printf("Value: %s\n\n", base64.StdEncoding.EncodeToString(res.Aci.Value.Value[1:])) if res.E164 != nil { p.Printf("E164 search response: \n") + p.Printf("VRF: %x\n\n", res.E164.VrfProof) printSearchProof(res.E164.Search) p.Printf("Opening: %x\n", res.E164.Opening) - p.Printf("Value: %x\n\n", res.E164.Value.Value) + p.Printf("Value: %x\n\n", res.E164.Value.Value[1:]) } if res.UsernameHash != nil { p.Printf("Username hash search response: \n") + p.Printf("VRF: %x\n\n", res.UsernameHash.VrfProof) printSearchProof(res.UsernameHash.Search) p.Printf("Opening: %x\n", res.UsernameHash.Opening) - p.Printf("Value: %x\n\n", res.UsernameHash.Value.Value) + p.Printf("Value: %x\n\n", res.UsernameHash.Value.Value[1:]) } if *configFile == "" { @@ -74,20 +88,20 @@ func handleSearch(client pb.KeyTransparencyQueryServiceClient) { } allVerificationsSuccessful := true - if err := transparency.VerifySearch(newStore(), createIdentifierSearchRequest(util.AciPrefix, args.Aci), createTreeSearchResponse(res.Aci, res.TreeHead)); err != nil { + if err := transparency.VerifySearch(newStore(), createIdentifierSearchRequest(util.AciPrefix, args.Aci, args.AciVersion), createTreeSearchResponse(res.Aci, res.TreeHead)); err != nil { p.Printf("ACI verification failed: %v\n", err) allVerificationsSuccessful = false } if res.E164 != nil { - if err := transparency.VerifySearch(newStore(), createIdentifierSearchRequest(util.NumberPrefix, []byte(*e164)), createTreeSearchResponse(res.E164, res.TreeHead)); err != nil { + if err := transparency.VerifySearch(newStore(), createIdentifierSearchRequest(util.NumberPrefix, []byte(*e164), args.E164Version), createTreeSearchResponse(res.E164, res.TreeHead)); err != nil { p.Printf("E164 verification failed: %v\n", err) allVerificationsSuccessful = false } } if res.UsernameHash != nil { - if err := transparency.VerifySearch(newStore(), createIdentifierSearchRequest(util.UsernameHashPrefix, args.UsernameHash), createTreeSearchResponse(res.UsernameHash, res.TreeHead)); err != nil { + if err := transparency.VerifySearch(newStore(), createIdentifierSearchRequest(util.UsernameHashPrefix, args.UsernameHash, args.UsernameHashVersion), createTreeSearchResponse(res.UsernameHash, res.TreeHead)); err != nil { p.Printf("Username hash verification failed: %v\n", err) allVerificationsSuccessful = false } @@ -98,15 +112,19 @@ func handleSearch(client pb.KeyTransparencyQueryServiceClient) { } } -func createIdentifierSearchRequest(prefix byte, identifier []byte) *tpb.TreeSearchRequest { - return createTreeSearchRequest(append([]byte{prefix}, identifier...)) +func createIdentifierSearchRequest(prefix byte, identifier []byte, version *uint32) *tpb.TreeSearchRequest { + return createTreeSearchRequest(append([]byte{prefix}, identifier...), version) } -func createTreeSearchRequest(key []byte) *tpb.TreeSearchRequest { - return &tpb.TreeSearchRequest{ +func createTreeSearchRequest(key []byte, version *uint32) *tpb.TreeSearchRequest { + req := &tpb.TreeSearchRequest{ SearchKey: key, Consistency: consistency(last), } + if version != nil { + req.Version = version + } + return req } func createTreeSearchResponse(response *pb.CondensedTreeSearchResponse, treeHead *tpb.FullTreeHead) *tpb.TreeSearchResponse { diff --git a/cmd/kt-client/util.go b/cmd/kt-client/util.go index 1c23a2b..b4b680d 100644 --- a/cmd/kt-client/util.go +++ b/cmd/kt-client/util.go @@ -11,6 +11,7 @@ import ( "fmt" "log" "os" + "strconv" "time" "github.com/google/uuid" @@ -21,10 +22,13 @@ import ( type QueryArgs struct { Aci []byte + AciVersion *uint32 AciIdentityKey []byte E164 string + E164Version *uint32 UnidentifiedAccessKey []byte UsernameHash []byte + UsernameHashVersion *uint32 } func extractQueryArgs(command string) QueryArgs { @@ -57,12 +61,19 @@ func extractQueryArgs(command string) QueryArgs { checkErr("decoding base64url encoding for username hash", err) } + aciVersion := parseVersion(aciVersionStr, "aci version") + e164Version := parseVersion(e164VersionStr, "e164 version") + usernameHashVersion := parseVersion(usernameHashVersionStr, "usernameHash version") + return QueryArgs{ aciBytes, + aciVersion, aciIdentityKeyBytes, *e164, + e164Version, unidentifiedAccessKeyBytes, usernameHashBytes, + usernameHashVersion, } } @@ -143,3 +154,16 @@ func checkErr(context string, err error) { os.Exit(1) } } + +func parseVersion(versionStr *string, argName string) *uint32 { + var version *uint32 + if *versionStr != "" { + val, err := strconv.ParseUint(*versionStr, 10, 32) + if err != nil { + log.Fatalf("invalid %s: %v", argName, err) + } + v := uint32(val) + version = &v + } + return version +} diff --git a/cmd/kt-server/kt_query_handler.go b/cmd/kt-server/kt_query_handler.go index a471248..c6a0a3c 100644 --- a/cmd/kt-server/kt_query_handler.go +++ b/cmd/kt-server/kt_query_handler.go @@ -8,6 +8,7 @@ package main import ( "context" "crypto/subtle" + "fmt" "math/rand" "strings" "time" @@ -155,9 +156,16 @@ func aciSearch(req *pb.SearchRequest, tree *transparency.Tree) (*tpb.FullTreeHea aciResponse, err := tree.Search(&tpb.TreeSearchRequest{ SearchKey: append([]byte{util.AciPrefix}, req.Aci...), Consistency: consistency, + Version: req.AciVersion, }) + metrics.IncrCounterWithLabels([]string{"search_requests", "aci"}, 1, []metrics.Label{{Name: "hasVersion", Value: fmt.Sprint(req.AciVersion != nil)}, grpcStatusLabel(err)}) if err != nil { + // There's no use case for distinguishing "not found" vs "permission denied" + // and consolidating prevents information leakage. + if grpcError, _ := status.FromError(err); grpcError.Code() == codes.NotFound { + err = status.Error(codes.PermissionDenied, "provided value does not match expected value") + } return nil, nil, err } else if len(aciResponse.Value.Value) < 2 || aciResponse.Value.Value[0] != 0 { return nil, nil, status.Error(codes.Internal, "unexpected response value") @@ -175,10 +183,13 @@ func usernameHashSearch(req *pb.SearchRequest, tree *transparency.Tree) (*pb.Con if len(req.UsernameHash) == 0 { return nil, nil } + usernameHashResponse, responseErr := tree.Search(&tpb.TreeSearchRequest{ SearchKey: append([]byte{util.UsernameHashPrefix}, req.UsernameHash...), Consistency: &tpb.Consistency{}, + Version: req.UsernameHashVersion, }) + metrics.IncrCounterWithLabels([]string{"search_requests", "username_hash"}, 1, []metrics.Label{{Name: "hasVersion", Value: fmt.Sprint(req.UsernameHashVersion != nil)}, grpcStatusLabel(responseErr)}) if responseErr != nil { // A non-nil err should be returned except in the case where it's "not found". @@ -210,13 +221,16 @@ func (h *KtQueryHandler) phoneNumberSearch(req *pb.SearchRequest, tree *transpar if err != nil { return nil, err } + // A non-nil responseErr should be returned except in the case where it's "not found" for a phone number lookup. // This is to prevent short-circuiting and creating a timing difference between an account that doesn't exist // with the given phone number, and one that does but is undiscoverable. phoneNumberResponse, responseErr := tree.Search(&tpb.TreeSearchRequest{ SearchKey: append([]byte{util.NumberPrefix}, []byte(req.E164SearchRequest.GetE164())...), Consistency: &tpb.Consistency{}, + Version: req.E164Version, }) + metrics.IncrCounterWithLabels([]string{"search_requests", "e164"}, 1, []metrics.Label{{Name: "hasVersion", Value: fmt.Sprint(req.E164Version != nil)}, grpcStatusLabel(responseErr)}) var valueForComparison []byte if responseErr != nil { diff --git a/cmd/kt-server/kt_query_handler_test.go b/cmd/kt-server/kt_query_handler_test.go index 5ef935f..dd2cd6a 100644 --- a/cmd/kt-server/kt_query_handler_test.go +++ b/cmd/kt-server/kt_query_handler_test.go @@ -118,9 +118,9 @@ func TestSearch_AciNotFound(t *testing.T) { AciIdentityKey: validAciIdentityKey1, Consistency: &tpb.Consistency{}, }, tree) - if grpcError, ok := status.FromError(err); grpcError.Code() != codes.NotFound || !ok { + if grpcError, ok := status.FromError(err); grpcError.Code() != codes.PermissionDenied || !ok { t.Fatalf("Expected %v, got %v", - codes.NotFound, err) + codes.PermissionDenied, err) } else if resp != nil { t.Fatalf("Expected no search response") } diff --git a/cmd/kt-server/pb/key_transparency_query.pb.go b/cmd/kt-server/pb/key_transparency_query.pb.go index 48b259e..662fe72 100644 --- a/cmd/kt-server/pb/key_transparency_query.pb.go +++ b/cmd/kt-server/pb/key_transparency_query.pb.go @@ -134,11 +134,14 @@ type SearchRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Aci []byte `protobuf:"bytes,1,opt,name=aci,proto3" json:"aci,omitempty"` - AciIdentityKey []byte `protobuf:"bytes,2,opt,name=aci_identity_key,json=aciIdentityKey,proto3" json:"aci_identity_key,omitempty"` - UsernameHash []byte `protobuf:"bytes,3,opt,name=username_hash,json=usernameHash,proto3,oneof" json:"username_hash,omitempty"` - E164SearchRequest *E164SearchRequest `protobuf:"bytes,4,opt,name=e164_search_request,json=e164SearchRequest,proto3,oneof" json:"e164_search_request,omitempty"` - Consistency *pb.Consistency `protobuf:"bytes,5,opt,name=consistency,proto3" json:"consistency,omitempty"` + Aci []byte `protobuf:"bytes,1,opt,name=aci,proto3" json:"aci,omitempty"` + AciIdentityKey []byte `protobuf:"bytes,2,opt,name=aci_identity_key,json=aciIdentityKey,proto3" json:"aci_identity_key,omitempty"` + UsernameHash []byte `protobuf:"bytes,3,opt,name=username_hash,json=usernameHash,proto3,oneof" json:"username_hash,omitempty"` + E164SearchRequest *E164SearchRequest `protobuf:"bytes,4,opt,name=e164_search_request,json=e164SearchRequest,proto3,oneof" json:"e164_search_request,omitempty"` + Consistency *pb.Consistency `protobuf:"bytes,5,opt,name=consistency,proto3" json:"consistency,omitempty"` + AciVersion *uint32 `protobuf:"varint,6,opt,name=aci_version,json=aciVersion,proto3,oneof" json:"aci_version,omitempty"` + E164Version *uint32 `protobuf:"varint,7,opt,name=e164_version,json=e164Version,proto3,oneof" json:"e164_version,omitempty"` + UsernameHashVersion *uint32 `protobuf:"varint,8,opt,name=username_hash_version,json=usernameHashVersion,proto3,oneof" json:"username_hash_version,omitempty"` } func (x *SearchRequest) Reset() { @@ -206,6 +209,27 @@ func (x *SearchRequest) GetConsistency() *pb.Consistency { return nil } +func (x *SearchRequest) GetAciVersion() uint32 { + if x != nil && x.AciVersion != nil { + return *x.AciVersion + } + return 0 +} + +func (x *SearchRequest) GetE164Version() uint32 { + if x != nil && x.E164Version != nil { + return *x.E164Version + } + return 0 +} + +func (x *SearchRequest) GetUsernameHashVersion() uint32 { + if x != nil && x.UsernameHashVersion != nil { + return *x.UsernameHashVersion + } + return 0 +} + // E164SearchRequest contains the data that the user must provide when looking up an E164 type E164SearchRequest struct { state protoimpl.MessageState @@ -750,7 +774,7 @@ var file_key_transparency_query_proto_rawDesc = []byte{ 0x32, 0x25, 0x2e, 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x64, 0x54, 0x72, 0x65, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x0d, 0x64, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, - 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x22, 0xae, 0x02, 0x0a, 0x0d, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x22, 0xf0, 0x03, 0x0a, 0x0d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x61, 0x63, 0x69, 0x12, 0x28, 0x0a, 0x10, 0x61, 0x63, 0x69, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, @@ -766,130 +790,142 @@ var file_key_transparency_query_proto_rawDesc = []byte{ 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, - 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x42, 0x10, 0x0a, - 0x0e, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, - 0x16, 0x0a, 0x14, 0x5f, 0x65, 0x31, 0x36, 0x34, 0x5f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, - 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x6d, 0x0a, 0x11, 0x45, 0x31, 0x36, 0x34, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x04, - 0x65, 0x31, 0x36, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x65, 0x31, - 0x36, 0x34, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x17, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, - 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x66, 0x69, 0x65, 0x64, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x42, 0x07, 0x0a, - 0x05, 0x5f, 0x65, 0x31, 0x36, 0x34, 0x22, 0xb8, 0x01, 0x0a, 0x1b, 0x43, 0x6f, 0x6e, 0x64, 0x65, + 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x24, 0x0a, + 0x0b, 0x61, 0x63, 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0d, 0x48, 0x02, 0x52, 0x0a, 0x61, 0x63, 0x69, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x88, 0x01, 0x01, 0x12, 0x26, 0x0a, 0x0c, 0x65, 0x31, 0x36, 0x34, 0x5f, 0x76, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x03, 0x52, 0x0b, 0x65, 0x31, 0x36, + 0x34, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x37, 0x0a, 0x15, 0x75, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0d, 0x48, 0x04, 0x52, 0x13, 0x75, 0x73, + 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x48, 0x61, 0x73, 0x68, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x88, 0x01, 0x01, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x16, 0x0a, 0x14, 0x5f, 0x65, 0x31, 0x36, 0x34, 0x5f, + 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x0e, + 0x0a, 0x0c, 0x5f, 0x61, 0x63, 0x69, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x0f, + 0x0a, 0x0d, 0x5f, 0x65, 0x31, 0x36, 0x34, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, + 0x18, 0x0a, 0x16, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x68, 0x61, 0x73, + 0x68, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x6d, 0x0a, 0x11, 0x45, 0x31, 0x36, + 0x34, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, + 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, + 0x65, 0x31, 0x36, 0x34, 0x88, 0x01, 0x01, 0x12, 0x36, 0x0a, 0x17, 0x75, 0x6e, 0x69, 0x64, 0x65, + 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x75, 0x6e, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x64, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x42, + 0x07, 0x0a, 0x05, 0x5f, 0x65, 0x31, 0x36, 0x34, 0x22, 0xb8, 0x01, 0x0a, 0x1b, 0x43, 0x6f, 0x6e, + 0x64, 0x65, 0x6e, 0x73, 0x65, 0x64, 0x54, 0x72, 0x65, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x72, 0x66, 0x5f, + 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x76, 0x72, 0x66, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x31, 0x0a, 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, + 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x72, 0x6f, 0x6f, 0x66, + 0x52, 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x65, 0x6e, + 0x69, 0x6e, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x65, 0x6e, 0x69, + 0x6e, 0x67, 0x12, 0x2f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, + 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x22, 0xae, 0x02, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x09, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x68, + 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x54, 0x72, 0x65, + 0x65, 0x48, 0x65, 0x61, 0x64, 0x52, 0x08, 0x74, 0x72, 0x65, 0x65, 0x48, 0x65, 0x61, 0x64, 0x12, + 0x37, 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6b, + 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x65, 0x6e, 0x73, 0x65, + 0x64, 0x54, 0x72, 0x65, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x52, 0x03, 0x61, 0x63, 0x69, 0x12, 0x3e, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, + 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x64, 0x54, 0x72, 0x65, 0x65, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, + 0x04, 0x65, 0x31, 0x36, 0x34, 0x88, 0x01, 0x01, 0x12, 0x4f, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, + 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x25, 0x2e, 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x64, 0x54, 0x72, 0x65, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x72, 0x66, 0x5f, 0x70, 0x72, - 0x6f, 0x6f, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x76, 0x72, 0x66, 0x50, 0x72, - 0x6f, 0x6f, 0x66, 0x12, 0x31, 0x0a, 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, - 0x63, 0x79, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x06, - 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, - 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, - 0x12, 0x2f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x22, 0xae, 0x02, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x09, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x68, 0x65, 0x61, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, - 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x54, 0x72, 0x65, 0x65, 0x48, - 0x65, 0x61, 0x64, 0x52, 0x08, 0x74, 0x72, 0x65, 0x65, 0x48, 0x65, 0x61, 0x64, 0x12, 0x37, 0x0a, - 0x03, 0x61, 0x63, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6b, 0x74, 0x5f, - 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x64, 0x54, - 0x72, 0x65, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x52, 0x03, 0x61, 0x63, 0x69, 0x12, 0x3e, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, - 0x43, 0x6f, 0x6e, 0x64, 0x65, 0x6e, 0x73, 0x65, 0x64, 0x54, 0x72, 0x65, 0x65, 0x53, 0x65, 0x61, - 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x04, 0x65, - 0x31, 0x36, 0x34, 0x88, 0x01, 0x01, 0x12, 0x4f, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, - 0x6d, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, - 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x64, 0x65, 0x6e, 0x73, - 0x65, 0x64, 0x54, 0x72, 0x65, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x01, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, - 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x65, 0x31, 0x36, 0x34, - 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x68, 0x61, - 0x73, 0x68, 0x22, 0x9e, 0x02, 0x0a, 0x0e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x41, 0x63, - 0x69, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, - 0x03, 0x61, 0x63, 0x69, 0x12, 0x4e, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, - 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x6b, 0x74, - 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x48, - 0x61, 0x73, 0x68, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x48, 0x00, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x48, 0x61, 0x73, - 0x68, 0x88, 0x01, 0x01, 0x12, 0x35, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x45, 0x31, - 0x36, 0x34, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x48, 0x01, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x88, 0x01, 0x01, 0x12, 0x3b, 0x0a, 0x0b, 0x63, - 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, - 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, - 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x75, 0x73, 0x65, - 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x65, - 0x31, 0x36, 0x34, 0x22, 0x77, 0x0a, 0x11, 0x41, 0x63, 0x69, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, - 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x61, 0x63, 0x69, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x6e, - 0x74, 0x72, 0x79, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x0d, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, - 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x63, 0x6f, 0x6d, - 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x93, 0x01, 0x0a, - 0x1a, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x6f, 0x6e, - 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x75, - 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x48, 0x61, 0x73, 0x68, - 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x50, - 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x22, 0x88, 0x01, 0x0a, 0x12, 0x45, 0x31, 0x36, 0x34, 0x4d, 0x6f, 0x6e, 0x69, 0x74, - 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x04, 0x65, 0x31, 0x36, - 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x88, - 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x70, 0x6f, 0x73, 0x69, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x01, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, + 0x6d, 0x65, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x65, 0x31, + 0x36, 0x34, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, + 0x68, 0x61, 0x73, 0x68, 0x22, 0x9e, 0x02, 0x0a, 0x0e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x03, 0x61, 0x63, 0x69, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, + 0x41, 0x63, 0x69, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x52, 0x03, 0x61, 0x63, 0x69, 0x12, 0x4e, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, + 0x6d, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, + 0x65, 0x48, 0x61, 0x73, 0x68, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x48, + 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x35, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, + 0x45, 0x31, 0x36, 0x34, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x48, 0x01, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, 0x88, 0x01, 0x01, 0x12, 0x3b, 0x0a, + 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, + 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, + 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x75, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x07, 0x0a, 0x05, + 0x5f, 0x65, 0x31, 0x36, 0x34, 0x22, 0x77, 0x0a, 0x11, 0x41, 0x63, 0x69, 0x4d, 0x6f, 0x6e, 0x69, + 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x63, + 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x03, 0x61, 0x63, 0x69, 0x12, 0x25, 0x0a, 0x0e, + 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x6f, 0x73, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, + 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x93, + 0x01, 0x0a, 0x1a, 0x55, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x48, 0x61, 0x73, 0x68, 0x4d, + 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, + 0x0d, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0c, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x48, 0x61, + 0x73, 0x68, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x49, - 0x6e, 0x64, 0x65, 0x78, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x65, 0x31, 0x36, 0x34, 0x22, 0xac, 0x02, - 0x0a, 0x0f, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x37, 0x0a, 0x09, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x63, 0x79, 0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x54, 0x72, 0x65, 0x65, 0x48, 0x65, 0x61, 0x64, - 0x52, 0x08, 0x74, 0x72, 0x65, 0x65, 0x48, 0x65, 0x61, 0x64, 0x12, 0x2c, 0x0a, 0x03, 0x61, 0x63, - 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, - 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x72, - 0x6f, 0x6f, 0x66, 0x52, 0x03, 0x61, 0x63, 0x69, 0x12, 0x44, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, - 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x4d, - 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x48, 0x00, 0x52, 0x0c, 0x75, - 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, 0x12, 0x33, - 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, - 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, - 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x48, 0x01, 0x52, 0x04, 0x65, 0x31, 0x36, 0x34, - 0x88, 0x01, 0x01, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x05, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, - 0x6e, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x68, - 0x61, 0x73, 0x68, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x65, 0x31, 0x36, 0x34, 0x32, 0xf2, 0x01, 0x0a, - 0x1b, 0x4b, 0x65, 0x79, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x52, 0x0a, 0x0d, - 0x44, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x1e, 0x2e, - 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, - 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, - 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, - 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x3d, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x17, 0x2e, 0x6b, 0x74, 0x5f, - 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, - 0x40, 0x0a, 0x07, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x12, 0x18, 0x2e, 0x6b, 0x74, 0x5f, - 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, - 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x00, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x61, 0x70, 0x70, 0x2f, 0x6b, 0x65, 0x79, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x6b, 0x74, - 0x2d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x6e, 0x64, 0x65, 0x78, 0x22, 0x88, 0x01, 0x0a, 0x12, 0x45, 0x31, 0x36, 0x34, 0x4d, 0x6f, 0x6e, + 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x04, 0x65, + 0x31, 0x36, 0x34, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x65, 0x31, 0x36, + 0x34, 0x88, 0x01, 0x01, 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x65, 0x6e, + 0x74, 0x72, 0x79, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, + 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x65, 0x31, 0x36, 0x34, 0x22, + 0xac, 0x02, 0x0a, 0x0f, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x09, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x54, 0x72, 0x65, 0x65, 0x48, 0x65, + 0x61, 0x64, 0x52, 0x08, 0x74, 0x72, 0x65, 0x65, 0x48, 0x65, 0x61, 0x64, 0x12, 0x2c, 0x0a, 0x03, + 0x61, 0x63, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x03, 0x61, 0x63, 0x69, 0x12, 0x44, 0x0a, 0x0d, 0x75, 0x73, + 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, + 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x48, 0x00, 0x52, + 0x0c, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x48, 0x61, 0x73, 0x68, 0x88, 0x01, 0x01, + 0x12, 0x33, 0x0a, 0x04, 0x65, 0x31, 0x36, 0x34, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x4d, 0x6f, + 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x48, 0x01, 0x52, 0x04, 0x65, 0x31, + 0x36, 0x34, 0x88, 0x01, 0x01, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, + 0x69, 0x6f, 0x6e, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, + 0x5f, 0x68, 0x61, 0x73, 0x68, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x65, 0x31, 0x36, 0x34, 0x32, 0xf2, + 0x01, 0x0a, 0x1b, 0x4b, 0x65, 0x79, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x63, 0x79, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x52, + 0x0a, 0x0d, 0x44, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, + 0x1e, 0x2e, 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1f, 0x2e, 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x44, 0x69, 0x73, 0x74, 0x69, + 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x3d, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x17, 0x2e, 0x6b, + 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x40, 0x0a, 0x07, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x12, 0x18, 0x2e, 0x6b, + 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x6b, 0x74, 0x5f, 0x71, 0x75, 0x65, 0x72, + 0x79, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x00, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x61, 0x70, 0x70, 0x2f, 0x6b, 0x65, 0x79, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2f, 0x63, 0x6d, 0x64, 0x2f, + 0x6b, 0x74, 0x2d, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( diff --git a/cmd/kt-server/pb/key_transparency_query.proto b/cmd/kt-server/pb/key_transparency_query.proto index 384d4e5..9852a3a 100644 --- a/cmd/kt-server/pb/key_transparency_query.proto +++ b/cmd/kt-server/pb/key_transparency_query.proto @@ -48,6 +48,9 @@ message SearchRequest { optional bytes username_hash = 3; optional E164SearchRequest e164_search_request = 4; transparency.Consistency consistency = 5; + optional uint32 aci_version = 6; + optional uint32 e164_version = 7; + optional uint32 username_hash_version = 8; } // E164SearchRequest contains the data that the user must provide when looking up an E164 diff --git a/example/config.yaml b/example/config.yaml index c21b5fc..6c9b3a9 100644 --- a/example/config.yaml +++ b/example/config.yaml @@ -34,7 +34,9 @@ api: # fake: # count: 1 # interval: 10s - distinguished: 1m + # This distinguished value is intentionally large for local development purposes: it's easier to adjust this value down + # and re-run the local server than to find that the tree accidentally grew too big and start the entire log over again. + distinguished: 1000h auditors: example-auditor-1: abcdef1234abcdef1234abcdef1234abcdef1234abcdef1234abcdef1234abcd example-auditor-2: abcdef1234abcdef1234abcdef1234abcdef1234abcdef1234abcdef1234abcd diff --git a/tree/prefix/batch_test.go b/tree/prefix/batch_test.go index 0e52fdf..6383bc3 100644 --- a/tree/prefix/batch_test.go +++ b/tree/prefix/batch_test.go @@ -118,12 +118,12 @@ func TestLookupPattern(t *testing.T) { // Insert a bunch of random keys. var key []byte - for version := uint64(0); version < 300; version++ { + for treeSize := uint64(0); treeSize < 300; treeSize++ { temp := random() - _, _, err := tree.Insert(version, temp, make([]byte, 32), false) + _, _, err := tree.Insert(treeSize, temp, make([]byte, 32), false) if err != nil { t.Fatal(err) - } else if version == 9 { + } else if treeSize == 9 { key = temp } } @@ -131,7 +131,7 @@ func TestLookupPattern(t *testing.T) { for i := 0; i < 100; i++ { store.cache = make(map[uint64][]byte) - // Choose two random versions to do lookups in. + // Choose two random tree sizes to do lookups in. ver1 := uint64(mrand.Intn(290) + 10) ver2 := uint64(mrand.Intn(290) + 10) if ver1 == ver2 { diff --git a/tree/prefix/prefix.go b/tree/prefix/prefix.go index a37daec..4c8dd0c 100644 --- a/tree/prefix/prefix.go +++ b/tree/prefix/prefix.go @@ -25,10 +25,12 @@ import ( const IndexLength = 32 -// SearchResult is the output from executing a search in a given version of the prefix tree for an index. +// SearchResult is the output from executing a search in a specific prefix tree for an index. // // There are two use cases for searching the prefix tree: -// 1. ["Indexing"] To find the log entry position of the most recent update to an index, along with the first update position. +// 1. ["Indexing"] To find the log entry positions of: +// 1. the first update, and +// 2. the most recent update OR the update corresponding to the desired version. // This allows the server to conduct a more efficient binary search in the *log tree* for that log entry position. // In this use case, the server will always start out searching the latest log entry and will only use FirstUpdatePosition and LatestUpdatePosition // from the search result. @@ -40,14 +42,15 @@ type SearchResult struct { // FirstUpdatePosition returns the log entry position of the first occurrence of this index in the given prefix tree. FirstUpdatePosition uint64 // LatestUpdatePosition returns the log entry position of the most recent occurrence of the index in the given prefix tree. + // Note that the given prefix tree is not necessarily the one associated with latest log entry. LatestUpdatePosition uint64 - // Commitment returns the commitment associated with this version of the prefix - // tree. It may return nil if this version of the prefix tree was created by a fake update. + // Commitment returns the commitment associated with this prefix tree. + // It may return nil if this prefix tree was created by a fake update. Commitment []byte // Proof returns a proof of inclusion from the prefix tree leaf where the search terminated to the prefix tree root. Proof [][]byte - // Counter returns how many times the index has been updated in the given version of the prefix tree. + // Counter returns how many times the index has been updated in this prefix tree. Counter uint32 } @@ -66,13 +69,13 @@ func NewTree(aesKey []byte, tx db.PrefixStore) *Tree { } // BatchSearch returns an unexecuted search structure. -func (t *Tree) BatchSearch(version uint64, index []byte) (*Search, error) { - if version == 0 { +func (t *Tree) BatchSearch(treeSize uint64, index []byte) (*Search, error) { + if treeSize == 0 { return nil, errors.New("tree is empty") } else if len(index) != IndexLength { return nil, fmt.Errorf("index length must be %v bytes", IndexLength) } - return &Search{index: index, ptr: version - 1}, nil + return &Search{index: index, ptr: treeSize - 1}, nil } // BatchExec runs several searches in parallel, minimizing the number of @@ -100,9 +103,40 @@ func (t *Tree) BatchExec(searches []*Search) ([]*SearchResult, error) { return out, nil } -// Search executes a search for `index` in the requested version of the tree. -func (t *Tree) Search(version uint64, index []byte) (*SearchResult, error) { - search, err := t.BatchSearch(version, index) +// SearchForVersion executes a search in the tree of the given size for the index with a counter value +// equal to indexVersion. +// The SearchResult returns the latest update position *in the last tree size that was searched*, which is not necessarily +// the original treeSize. +func (t *Tree) SearchForVersion(treeSize uint64, index []byte, indexVersion uint32) (*SearchResult, error) { + var res *SearchResult + nextTreeSizeToSearch := treeSize + + // Search for the index with the requested indexVersion counter by recursively searching in earlier + // and earlier entries of the log for the most recent update to the given index, until we find the desired index version + // or we get back a "not found" error. + var err error + for { + res, err = t.Search(nextTreeSizeToSearch, index) + if err != nil { + return nil, fmt.Errorf("running versioned search: %w", err) + } + + if res.Counter != indexVersion { + // Tree size is one-indexed, but positions are zero-indexed. For example, + // if index A's latest update position is 8, that means that that update was the 9th entry in the tree. + // So in the next iteration, we want to search in the tree with 8 entries for the latest update to index A. + nextTreeSizeToSearch = res.LatestUpdatePosition + } else { + break + } + } + + return res, nil +} + +// Search executes a search for `index` in the requested tree. +func (t *Tree) Search(treeSize uint64, index []byte) (*SearchResult, error) { + search, err := t.BatchSearch(treeSize, index) if err != nil { return nil, fmt.Errorf("creating search: %w", err) } @@ -116,8 +150,8 @@ func (t *Tree) Search(version uint64, index []byte) (*SearchResult, error) { // Trace performs the same database lookups in the same order as Search, without // computing the intermediate hashes to produce a full search result. This is // used for populating caches. -func (t *Tree) Trace(version uint64, index []byte) error { - search, err := t.BatchSearch(version, index) +func (t *Tree) Trace(treeSize uint64, index []byte) error { + search, err := t.BatchSearch(treeSize, index) if err != nil { return fmt.Errorf("creating search: %w", err) } @@ -131,15 +165,15 @@ func (t *Tree) Trace(version uint64, index []byte) error { // InsertFake changes the tree like a random new entry was inserted, without // actually doing so. // -// The current tree version is given in `version`; after this method returns -// successfully, the tree may be used with `version+1`. -func (t *Tree) InsertFake(version uint64) ([]byte, error) { +// The current tree size is given in `treeSize`; after this method returns +// successfully, the tree may be used with `treeSize+1`. +func (t *Tree) InsertFake(treeSize uint64) ([]byte, error) { var entry *pb.LogEntry - if version == 0 { + if treeSize == 0 { // entry = &pb.LogEntry{ // Index: nil, // Copath: nil, - // Seed: version, + // Seed: treeSize, // } return nil, fmt.Errorf("can not do fake insert in an empty tree") } else { @@ -147,7 +181,7 @@ func (t *Tree) InsertFake(version uint64) ([]byte, error) { if _, err := rand.Read(index); err != nil { return nil, fmt.Errorf("getting randomness: %w", err) } - search, err := t.BatchSearch(version, index) + search, err := t.BatchSearch(treeSize, index) if err != nil { return nil, fmt.Errorf("creating search: %w", err) } @@ -163,7 +197,7 @@ func (t *Tree) InsertFake(version uint64) ([]byte, error) { entry = &pb.LogEntry{ Index: index[:cutoff], Copath: failed.copath, - FirstUpdatePosition: version, + FirstUpdatePosition: treeSize, } } @@ -174,7 +208,7 @@ func (t *Tree) InsertFake(version uint64) ([]byte, error) { if err != nil { return nil, err } - t.tx.Put(version, raw) + t.tx.Put(treeSize, raw) return cached.rollup(0), nil } @@ -185,9 +219,9 @@ type Entry struct { // sequence is a wrapper around sequencePart, that allows sequencing to happen // on many cores instead of just one. -func (t *Tree) sequence(version uint64, entries []Entry, fake bool) ([]*cachedLogEntry, error) { +func (t *Tree) sequence(treeSize uint64, entries []Entry, fake bool) ([]*cachedLogEntry, error) { if len(entries) < 64 { // Skip multi-threaded stuff for small batches. - return t.sequencePart(version, 0, entries, fake) + return t.sequencePart(treeSize, 0, entries, fake) } type sequenceResult struct { @@ -212,7 +246,7 @@ func (t *Tree) sequence(version uint64, entries []Entry, fake bool) ([]*cachedLo j = len(entries) } go func() { - part, err := t.sequencePart(version, i, entries[i:j], fake) + part, err := t.sequencePart(treeSize, i, entries[i:j], fake) ch <- sequenceResult{i, part, err} }() goroutines++ @@ -233,12 +267,12 @@ func (t *Tree) sequence(version uint64, entries []Entry, fake bool) ([]*cachedLo // sequencePart takes a subset of new entries to insert into the prefix tree and // returns a cachedLogEntry for each, corresponding to the log entry that would -// be stored if it were version+1 of the tree. +// be stored if the tree had treeSize+1 entries. // fake is whether the provided log entries are fake, which affects the data stored in the cachedLogEntry. -func (t *Tree) sequencePart(version uint64, offset int, entries []Entry, fake bool) ([]*cachedLogEntry, error) { +func (t *Tree) sequencePart(treeSize uint64, offset int, entries []Entry, fake bool) ([]*cachedLogEntry, error) { var searches []*Search for _, entry := range entries { - search, err := t.BatchSearch(version, entry.Index) + search, err := t.BatchSearch(treeSize, entry.Index) if err != nil { return nil, fmt.Errorf("creating search: %w", err) } @@ -261,7 +295,7 @@ func (t *Tree) sequencePart(version uint64, offset int, entries []Entry, fake bo temp := &cachedLogEntry{ inner: &pb.LogEntry{ Copath: res.copath, - FirstUpdatePosition: version + uint64(offset+i), + FirstUpdatePosition: treeSize + uint64(offset+i), }, aesKey: t.aesKey, } @@ -295,9 +329,9 @@ func (t *Tree) sequencePart(version uint64, offset int, entries []Entry, fake bo // of entries that already exist. It returns the new roots and a search result // for each entry. // -// The current tree version is given in `version`; after this method returns -// successfully, the tree may be used with `version+len(entries)`. -func (t *Tree) BatchInsert(version uint64, entries []Entry, fake bool) ([][]byte, []*SearchResult, error) { +// The current treeSize is given in `treeSize`; after this method returns +// successfully, the tree may be used with `treeSize+len(entries)`. +func (t *Tree) BatchInsert(treeSize uint64, entries []Entry, fake bool) ([][]byte, []*SearchResult, error) { if len(entries) == 0 { return nil, nil, errors.New("no entries to insert provided") } @@ -310,7 +344,7 @@ func (t *Tree) BatchInsert(version uint64, entries []Entry, fake bool) ([][]byte } var sequenced []*cachedLogEntry - if version == 0 { + if treeSize == 0 { // Do not insert fake entries into an empty tree if fake { return nil, nil, errors.New("cannot insert fake entries into an empty tree") @@ -320,7 +354,7 @@ func (t *Tree) BatchInsert(version uint64, entries []Entry, fake bool) ([][]byte inner: &pb.LogEntry{ Index: entry.Index, Copath: nil, - FirstUpdatePosition: version + uint64(i), + FirstUpdatePosition: treeSize + uint64(i), Leaf: &pb.LeafNode{Ctr: 0, Commitment: entry.Commitment}, }, aesKey: t.aesKey, @@ -328,16 +362,16 @@ func (t *Tree) BatchInsert(version uint64, entries []Entry, fake bool) ([][]byte } } else { var err error - sequenced, err = t.sequence(version, entries, fake) + sequenced, err = t.sequence(treeSize, entries, fake) if err != nil { return nil, nil, err } } // All the entries in the `sequenced` slice are constructed as if they're - // going to be version+1 of the tree. Update them so that they're in order. + // going to be treeSize+1 of the tree. Update them so that they're in order. for i := 1; i < len(sequenced); i++ { - search := &Search{index: sequenced[i].inner.Index, ptr: version - 1 + uint64(i)} + search := &Search{index: sequenced[i].inner.Index, ptr: treeSize - 1 + uint64(i)} ptr := i - 1 for { // Search the prefix tree of the log entry associated with `ptr`. @@ -347,8 +381,8 @@ func (t *Tree) BatchInsert(version uint64, entries []Entry, fake bool) ([][]byte case uint64: // If the next step of the search jumps to a previous entry in the sequencing batch, // we can grab that log entry from the `sequenced` slice and continue our search - if res >= version { - ptr = int(res - version) + if res >= treeSize { + ptr = int(res - treeSize) continue } // Otherwise, the search jumped to a log entry less than the starting log tree size before the batch update. @@ -396,7 +430,7 @@ func (t *Tree) BatchInsert(version uint64, entries []Entry, fake bool) ([][]byte if err != nil { return nil, nil, err } - t.tx.Put(version+uint64(i), raw) + t.tx.Put(treeSize+uint64(i), raw) roots = append(roots, entry.rollup(0)) @@ -407,7 +441,7 @@ func (t *Tree) BatchInsert(version uint64, entries []Entry, fake bool) ([][]byte Counter: entry.inner.Leaf.Ctr, FirstUpdatePosition: entry.inner.FirstUpdatePosition, - LatestUpdatePosition: version + uint64(i), + LatestUpdatePosition: treeSize + uint64(i), Commitment: entry.inner.Leaf.Commitment, }) } @@ -417,15 +451,15 @@ func (t *Tree) BatchInsert(version uint64, entries []Entry, fake bool) ([][]byte // Insert adds a new index to the tree or increments its counter if it already // exists, and returns the new root and search result. -func (t *Tree) Insert(version uint64, index, commitment []byte, fake bool) ([]byte, *SearchResult, error) { - roots, srs, err := t.BatchInsert(version, []Entry{{index, commitment}}, fake) +func (t *Tree) Insert(treeSize uint64, index, commitment []byte, fake bool) ([]byte, *SearchResult, error) { + roots, srs, err := t.BatchInsert(treeSize, []Entry{{index, commitment}}, fake) if err != nil { return nil, nil, err } return roots[0], srs[0], nil } -// LogEntries returns the stored log entries for the requested version range. +// LogEntries returns the stored log entries for the requested range. func (t *Tree) LogEntries(start, end uint64) ([]*pb.LogEntry, [][]byte, [][]byte, error) { var ids []uint64 for i := start; i < end; i++ { diff --git a/tree/prefix/prefix_test.go b/tree/prefix/prefix_test.go index 9dd6e08..0c77361 100644 --- a/tree/prefix/prefix_test.go +++ b/tree/prefix/prefix_test.go @@ -23,6 +23,58 @@ func random() []byte { return out } +func TestPrefixTreeSearchForVersion(t *testing.T) { + var ( + tree = NewTree(make([]byte, 16), db.NewMemoryTransparencyStore().PrefixStore()) + repeatKey = random() + // The i-th value is the update position for version i of repeatKey + versionPositions []uint64 + + randomKeys [][]byte + treeSize uint64 + ) + + for i := 0; i < 1000; i++ { + dice := mrand.Intn(4) + + if dice == 0 && len(versionPositions) > 0 { // Search for a random version of the key + version := uint32(mrand.Intn(len(versionPositions))) + + res, err := tree.SearchForVersion(treeSize, repeatKey, version) + if err != nil { + t.Fatal(err) + } else if res.Counter != version { + t.Fatal("unexpected value for version counter") + } else if res.FirstUpdatePosition != versionPositions[0] { + t.Fatal("unexpected value for first update position") + } else if res.LatestUpdatePosition != versionPositions[version] { + t.Fatal("unexpected value for version update position") + } + } else if dice == 1 && (len(randomKeys) > 0 || len(versionPositions) > 0) { // Insert a fake entry. + _, err := tree.InsertFake(treeSize) + if err != nil { + t.Fatal(err) + } + treeSize = treeSize + 1 + } else if dice == 2 { // Insert a new index. + randomKey := random() + _, _, err := tree.Insert(treeSize, randomKey, make([]byte, 32), false) + if err != nil { + t.Fatal(err) + } + randomKeys = append(randomKeys, randomKey) + treeSize = treeSize + 1 + } else if dice == 3 { // Insert repeatKey again + _, _, err := tree.Insert(treeSize, repeatKey, make([]byte, 32), false) + if err != nil { + t.Fatal(err) + } + versionPositions = append(versionPositions, treeSize) + treeSize = treeSize + 1 + } + } +} + func TestPrefixTree(t *testing.T) { var ( tree = NewTree(make([]byte, 16), db.NewMemoryTransparencyStore().PrefixStore()) @@ -32,8 +84,8 @@ func TestPrefixTree(t *testing.T) { firstUpdatePosition []uint64 latestUpdatePosition []uint64 - version uint64 - root []byte + treeSize uint64 + root []byte ) for i := 0; i < 1000; i++ { @@ -42,7 +94,7 @@ func TestPrefixTree(t *testing.T) { if dice == 0 && len(keys) > 0 { // Search for an existing index. k := mrand.Intn(len(keys)) - res, err := tree.Search(version, keys[k]) + res, err := tree.Search(treeSize, keys[k]) if err != nil { t.Fatal(err) } else if err = Verify(root, keys[k], firstUpdatePosition[k], res); err != nil { @@ -55,62 +107,62 @@ func TestPrefixTree(t *testing.T) { t.Fatal("unexpected value for latest update position") } } else if dice == 1 && len(keys) > 0 { // Insert a fake entry. - temp, err := tree.InsertFake(version) + temp, err := tree.InsertFake(treeSize) if err != nil { t.Fatal(err) } - version, root = version+1, temp + treeSize, root = treeSize+1, temp } else if dice == 2 { // Insert a new index. key := random() - temp, _, err := tree.Insert(version, key, make([]byte, 32), false) + temp, _, err := tree.Insert(treeSize, key, make([]byte, 32), false) if err != nil { t.Fatal(err) } keys = append(keys, key) ctr = append(ctr, 0) - firstUpdatePosition = append(firstUpdatePosition, version) - latestUpdatePosition = append(latestUpdatePosition, version) - version, root = version+1, temp + firstUpdatePosition = append(firstUpdatePosition, treeSize) + latestUpdatePosition = append(latestUpdatePosition, treeSize) + treeSize, root = treeSize+1, temp } else if dice == 3 && len(keys) > 0 { // Insert an existing index. k := mrand.Intn(len(keys)) - temp, _, err := tree.Insert(version, keys[k], make([]byte, 32), false) + temp, _, err := tree.Insert(treeSize, keys[k], make([]byte, 32), false) if err != nil { t.Fatal(err) } ctr[k] += 1 - latestUpdatePosition[k] = version - version, root = version+1, temp + latestUpdatePosition[k] = treeSize + treeSize, root = treeSize+1, temp } } } func TestBatchSearch(t *testing.T) { var ( - tree = NewTree(make([]byte, 16), db.NewMemoryTransparencyStore().PrefixStore()) - versions = []uint64{20, 50, 100, 200, 250} + tree = NewTree(make([]byte, 16), db.NewMemoryTransparencyStore().PrefixStore()) + treeSizes = []uint64{20, 50, 100, 200, 250} key []byte roots [][]byte commitments [][]byte ) - for version := uint64(0); version < 300; version++ { + for treeSize := uint64(0); treeSize < 300; treeSize++ { temp := random() - root, sr, err := tree.Insert(version, temp, make([]byte, 32), false) + root, sr, err := tree.Insert(treeSize, temp, make([]byte, 32), false) if err != nil { t.Fatal(err) } - if version == 10 { + if treeSize == 10 { key = temp - } else if slices.Contains(versions, version+1) { + } else if slices.Contains(treeSizes, treeSize+1) { roots = append(roots, root) commitments = append(commitments, sr.Commitment) } } searches := make([]*Search, 0) - for _, version := range versions { - search, err := tree.BatchSearch(version, key) + for _, treeSize := range treeSizes { + search, err := tree.BatchSearch(treeSize, key) if err != nil { t.Fatal(err) } @@ -126,7 +178,7 @@ func TestBatchSearch(t *testing.T) { } else if res.FirstUpdatePosition != 10 { t.Fatal("unexpected value for first update position") } else if res.LatestUpdatePosition != 10 { - t.Fatal("unexpected value for version position") + t.Fatal("unexpected value for latest update position") } else if !bytes.Equal(res.Commitment, commitments[i]) { t.Fatal("unexpected value for commitment") } diff --git a/tree/transparency/guide.go b/tree/transparency/guide.go index 23bc726..85f1c94 100644 --- a/tree/transparency/guide.go +++ b/tree/transparency/guide.go @@ -24,10 +24,21 @@ func (s idCtrSlice) Len() int { return len(s) } func (s idCtrSlice) Less(i, j int) bool { return s[i].id < s[j].id } func (s idCtrSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } -// proofGuide contains the data necessary to carry out a search of the implicit binary tree -// for a given index. -// The implicit binary tree is formed by arranging the log entries into a left-balanced binary search formation, +// proofGuide contains the data necessary to determine the search path through the implicit binary tree +// for the target log entry. It is used in two ways: for search proof generation and search proof verification. +// +// For context, the implicit binary tree is formed by arranging the log entries into a left-balanced binary search formation, // where each node contains an entry ID and a counter value that denotes which "version" of a given index exists in that entry. +// While an index can have versions greater than 1, for the purposes of generating a search proof, we only use two counter values: +// +// 0: Denotes that this entry occurred before the target log entry +// 1: Denotes that this entry is either the target log entry or occurred after it +// +// Unlike search proof generation, during search proof verification, we don't know the target log entry position. +// Instead, we have the supposed steps of the search path (as generated by the key transparency server), +// along with the version of the index at each step. We use the provided version(s) to determine how to +// traverse the implicit binary search tree as part of the verification process. +// // Unlike a typical binary search that would move left or right based on the entry ID alone, this search moves left and right // based on two criteria: // 1. The ctr value for each entry ID in the tree which is stored in the sorted field alongside the entry ID. @@ -61,6 +72,18 @@ func mostRecentProofGuide(firstUpdatePosition, treeSize uint64) *proofGuide { return &proofGuide{firstUpdatePosition: firstUpdatePosition, treeSize: treeSize, ids: frontier, frontier: true} } +// versionProofGuide initializes the data structure used to search for a specific version of an index. +// Unlike mostRecentProofGuide, it does not need to search the frontier nodes to determine targetCtr, and so it +// begins its search with only the root node. +func versionProofGuide(targetCtr uint32, firstUpdatePosition, treeSize uint64) *proofGuide { + return &proofGuide{ + firstUpdatePosition: firstUpdatePosition, + treeSize: treeSize, + targetCtr: targetCtr, + ids: []uint64{math.Root(firstUpdatePosition, treeSize)}, + } +} + // done returns true if the search proof is finished. // Otherwise, it looks up and stores the next entry ID to search. func (pg *proofGuide) done() (bool, error) { diff --git a/tree/transparency/guide_test.go b/tree/transparency/guide_test.go index a59b667..c500442 100644 --- a/tree/transparency/guide_test.go +++ b/tree/transparency/guide_test.go @@ -6,6 +6,7 @@ package transparency import ( + "slices" "testing" ) @@ -70,3 +71,17 @@ func TestMostRecentProofGuide(t *testing.T) { t.Fatal("wrong result returned") } } + +func TestVersionProofGuide(t *testing.T) { + guide := versionProofGuide(1, 1, 28) + ids := executeGuide(guide, 1, 28, 17) + if !slices.Equal([]uint64{15, 23, 19, 17, 16}, ids) { + t.Fatal("wrong result returned") + } + + guide = versionProofGuide(1, 1, 28) + ids = executeGuide(guide, 1, 28, 27) + if !slices.Equal([]uint64{15, 23, 27, 25, 26}, ids) { + t.Fatal("wrong result returned") + } +} diff --git a/tree/transparency/pb/transparency.pb.go b/tree/transparency/pb/transparency.pb.go index b31e9d7..152842e 100644 --- a/tree/transparency/pb/transparency.pb.go +++ b/tree/transparency/pb/transparency.pb.go @@ -625,6 +625,7 @@ type TreeSearchRequest struct { SearchKey []byte `protobuf:"bytes,1,opt,name=search_key,json=searchKey,proto3" json:"search_key,omitempty"` Consistency *Consistency `protobuf:"bytes,2,opt,name=consistency,proto3" json:"consistency,omitempty"` + Version *uint32 `protobuf:"varint,3,opt,name=version,proto3,oneof" json:"version,omitempty"` } func (x *TreeSearchRequest) Reset() { @@ -671,6 +672,13 @@ func (x *TreeSearchRequest) GetConsistency() *Consistency { return nil } +func (x *TreeSearchRequest) GetVersion() uint32 { + if x != nil && x.Version != nil { + return *x.Version + } + return 0 +} + // TreeSearchResponse is the output of executing a search on the tree. type TreeSearchResponse struct { state protoimpl.MessageState @@ -1531,45 +1539,18 @@ var file_pb_transparency_proto_rawDesc = []byte{ 0x67, 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x48, 0x01, 0x52, 0x0d, 0x64, 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x88, 0x01, 0x01, 0x42, 0x07, 0x0a, 0x05, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x64, - 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x22, 0x6f, 0x0a, 0x11, - 0x54, 0x72, 0x65, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, - 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, - 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, - 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x22, 0xe8, 0x01, - 0x0a, 0x12, 0x54, 0x72, 0x65, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x09, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x68, 0x65, 0x61, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, - 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x54, 0x72, 0x65, 0x65, 0x48, - 0x65, 0x61, 0x64, 0x52, 0x08, 0x74, 0x72, 0x65, 0x65, 0x48, 0x65, 0x61, 0x64, 0x12, 0x1b, 0x0a, - 0x09, 0x76, 0x72, 0x66, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x08, 0x76, 0x72, 0x66, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x31, 0x0a, 0x06, 0x73, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, - 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x18, 0x0a, - 0x07, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, - 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x12, 0x2f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, - 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xf2, 0x01, 0x0a, 0x0d, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, - 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, - 0x3b, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, - 0x6e, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x52, - 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x39, 0x0a, 0x19, - 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x65, 0x5f, 0x75, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x16, 0x65, 0x78, 0x70, 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x72, 0x65, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x65, 0x74, 0x75, 0x72, - 0x6e, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x14, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xb3, 0x01, - 0x0a, 0x0e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x69, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x75, 0x69, 0x73, 0x68, 0x65, 0x64, 0x22, 0x9a, 0x01, 0x0a, + 0x11, 0x54, 0x72, 0x65, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, + 0x79, 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, + 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x1d, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x48, + 0x00, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x42, 0x0a, 0x0a, + 0x08, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0xe8, 0x01, 0x0a, 0x12, 0x54, 0x72, + 0x65, 0x65, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x09, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x54, 0x72, 0x65, 0x65, 0x48, 0x65, 0x61, 0x64, 0x52, @@ -1580,76 +1561,106 @@ var file_pb_transparency_proto_rawDesc = []byte{ 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x65, 0x6e, - 0x69, 0x6e, 0x67, 0x22, 0x7d, 0x0a, 0x0a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x4b, 0x65, - 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, - 0x12, 0x25, 0x0a, 0x0e, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x50, - 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x69, - 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x0f, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x22, 0x7b, 0x0a, 0x0e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x2c, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, - 0x79, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x4b, 0x65, 0x79, 0x52, 0x04, 0x6b, 0x65, - 0x79, 0x73, 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, - 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, - 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, - 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x22, - 0x3d, 0x0a, 0x0c, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, - 0x2d, 0x0a, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, - 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x50, 0x72, - 0x6f, 0x6f, 0x66, 0x53, 0x74, 0x65, 0x70, 0x52, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x22, 0x9c, - 0x01, 0x0a, 0x0f, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x37, 0x0a, 0x09, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, - 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x54, 0x72, 0x65, 0x65, 0x48, 0x65, 0x61, - 0x64, 0x52, 0x08, 0x74, 0x72, 0x65, 0x65, 0x48, 0x65, 0x61, 0x64, 0x12, 0x32, 0x0a, 0x06, 0x70, - 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, - 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x12, - 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x0c, 0x52, 0x09, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x90, 0x03, - 0x0a, 0x0c, 0x41, 0x75, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x3f, - 0x0a, 0x08, 0x6e, 0x65, 0x77, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x22, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, - 0x41, 0x75, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x2e, 0x4e, 0x65, 0x77, - 0x54, 0x72, 0x65, 0x65, 0x48, 0x00, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x54, 0x72, 0x65, 0x65, 0x12, - 0x4e, 0x0a, 0x0d, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, - 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, - 0x6f, 0x66, 0x2e, 0x44, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x48, - 0x00, 0x52, 0x0c, 0x64, 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, - 0x3f, 0x0a, 0x08, 0x73, 0x61, 0x6d, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x22, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, - 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x2e, 0x53, 0x61, - 0x6d, 0x65, 0x4b, 0x65, 0x79, 0x48, 0x00, 0x52, 0x07, 0x73, 0x61, 0x6d, 0x65, 0x4b, 0x65, 0x79, - 0x1a, 0x09, 0x0a, 0x07, 0x4e, 0x65, 0x77, 0x54, 0x72, 0x65, 0x65, 0x1a, 0x41, 0x0a, 0x0c, 0x44, - 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x63, - 0x6f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6f, 0x70, - 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x6f, 0x6c, 0x64, 0x5f, 0x73, 0x65, 0x65, 0x64, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x6c, 0x64, 0x53, 0x65, 0x65, 0x64, 0x1a, 0x57, - 0x0a, 0x07, 0x53, 0x61, 0x6d, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x70, - 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6f, 0x70, 0x61, 0x74, - 0x68, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, - 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x70, - 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x07, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, - 0x22, 0x9f, 0x01, 0x0a, 0x0d, 0x41, 0x75, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x04, 0x72, 0x65, 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x12, 0x0a, 0x04, - 0x73, 0x65, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x73, 0x65, 0x65, 0x64, - 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, - 0x12, 0x30, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1a, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x41, - 0x75, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x05, 0x70, 0x72, 0x6f, - 0x6f, 0x66, 0x42, 0x3b, 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x61, 0x70, 0x70, 0x2f, 0x6b, 0x65, 0x79, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2f, 0x74, 0x72, 0x65, 0x65, 0x2f, - 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2f, 0x70, 0x62, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x6e, 0x67, 0x12, 0x2f, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, + 0x79, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x22, 0xf2, 0x01, 0x0a, 0x0d, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, + 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x09, 0x73, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x63, + 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, + 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, 0x63, 0x6f, 0x6e, + 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x12, 0x39, 0x0a, 0x19, 0x65, 0x78, 0x70, 0x65, + 0x63, 0x74, 0x65, 0x64, 0x5f, 0x70, 0x72, 0x65, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x16, 0x65, 0x78, 0x70, + 0x65, 0x63, 0x74, 0x65, 0x64, 0x50, 0x72, 0x65, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x5f, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x5f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x14, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xb3, 0x01, 0x0a, 0x0e, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x09, + 0x74, 0x72, 0x65, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x46, + 0x75, 0x6c, 0x6c, 0x54, 0x72, 0x65, 0x65, 0x48, 0x65, 0x61, 0x64, 0x52, 0x08, 0x74, 0x72, 0x65, + 0x65, 0x48, 0x65, 0x61, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x72, 0x66, 0x5f, 0x70, 0x72, 0x6f, + 0x6f, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x08, 0x76, 0x72, 0x66, 0x50, 0x72, 0x6f, + 0x6f, 0x66, 0x12, 0x31, 0x0a, 0x06, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, + 0x79, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x06, 0x73, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x70, 0x65, 0x6e, 0x69, 0x6e, 0x67, 0x22, + 0x7d, 0x0a, 0x0a, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, + 0x0a, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x09, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x0e, + 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0d, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x50, 0x6f, 0x73, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, + 0x74, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x63, + 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x7b, + 0x0a, 0x0e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x2c, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, + 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x4d, 0x6f, + 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x4b, 0x65, 0x79, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x3b, + 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, + 0x63, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x0b, + 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x22, 0x3d, 0x0a, 0x0c, 0x4d, + 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x2d, 0x0a, 0x05, 0x73, + 0x74, 0x65, 0x70, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x72, 0x61, + 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x53, + 0x74, 0x65, 0x70, 0x52, 0x05, 0x73, 0x74, 0x65, 0x70, 0x73, 0x22, 0x9c, 0x01, 0x0a, 0x0f, 0x4d, + 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, + 0x0a, 0x09, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x68, 0x65, 0x61, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, + 0x2e, 0x46, 0x75, 0x6c, 0x6c, 0x54, 0x72, 0x65, 0x65, 0x48, 0x65, 0x61, 0x64, 0x52, 0x08, 0x74, + 0x72, 0x65, 0x65, 0x48, 0x65, 0x61, 0x64, 0x12, 0x32, 0x0a, 0x06, 0x70, 0x72, 0x6f, 0x6f, 0x66, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, + 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x52, 0x06, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x69, + 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x09, + 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x90, 0x03, 0x0a, 0x0c, 0x41, 0x75, + 0x64, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x12, 0x3f, 0x0a, 0x08, 0x6e, 0x65, + 0x77, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x41, 0x75, 0x64, 0x69, + 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x2e, 0x4e, 0x65, 0x77, 0x54, 0x72, 0x65, 0x65, + 0x48, 0x00, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x54, 0x72, 0x65, 0x65, 0x12, 0x4e, 0x0a, 0x0d, 0x64, + 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, + 0x79, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x2e, 0x44, + 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x48, 0x00, 0x52, 0x0c, 0x64, + 0x69, 0x66, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x3f, 0x0a, 0x08, 0x73, + 0x61, 0x6d, 0x65, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, + 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x41, 0x75, 0x64, + 0x69, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x2e, 0x53, 0x61, 0x6d, 0x65, 0x4b, 0x65, + 0x79, 0x48, 0x00, 0x52, 0x07, 0x73, 0x61, 0x6d, 0x65, 0x4b, 0x65, 0x79, 0x1a, 0x09, 0x0a, 0x07, + 0x4e, 0x65, 0x77, 0x54, 0x72, 0x65, 0x65, 0x1a, 0x41, 0x0a, 0x0c, 0x44, 0x69, 0x66, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x70, 0x61, 0x74, + 0x68, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6f, 0x70, 0x61, 0x74, 0x68, 0x12, + 0x19, 0x0a, 0x08, 0x6f, 0x6c, 0x64, 0x5f, 0x73, 0x65, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x07, 0x6f, 0x6c, 0x64, 0x53, 0x65, 0x65, 0x64, 0x1a, 0x57, 0x0a, 0x07, 0x53, 0x61, + 0x6d, 0x65, 0x4b, 0x65, 0x79, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x6f, 0x70, 0x61, 0x74, 0x68, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x06, 0x63, 0x6f, 0x70, 0x61, 0x74, 0x68, 0x12, 0x18, 0x0a, + 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x70, 0x6f, 0x73, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x42, 0x07, 0x0a, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x9f, 0x01, 0x0a, + 0x0d, 0x41, 0x75, 0x64, 0x69, 0x74, 0x6f, 0x72, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x72, 0x65, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x72, 0x65, + 0x61, 0x6c, 0x12, 0x14, 0x0a, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x65, 0x65, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x73, 0x65, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, + 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x30, 0x0a, 0x05, + 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2e, 0x41, 0x75, 0x64, 0x69, 0x74, + 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x42, 0x3b, + 0x5a, 0x39, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x69, 0x67, + 0x6e, 0x61, 0x6c, 0x61, 0x70, 0x70, 0x2f, 0x6b, 0x65, 0x79, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x70, + 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2f, 0x74, 0x72, 0x65, 0x65, 0x2f, 0x74, 0x72, 0x61, 0x6e, + 0x73, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x2f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -1727,6 +1738,7 @@ func file_pb_transparency_proto_init() { } file_pb_transparency_proto_msgTypes[4].OneofWrappers = []any{} file_pb_transparency_proto_msgTypes[9].OneofWrappers = []any{} + file_pb_transparency_proto_msgTypes[10].OneofWrappers = []any{} file_pb_transparency_proto_msgTypes[18].OneofWrappers = []any{ (*AuditorProof_NewTree_)(nil), (*AuditorProof_DifferentKey_)(nil), diff --git a/tree/transparency/pb/transparency.proto b/tree/transparency/pb/transparency.proto index 1adec8a..8bfd633 100644 --- a/tree/transparency/pb/transparency.proto +++ b/tree/transparency/pb/transparency.proto @@ -82,6 +82,7 @@ message Consistency { message TreeSearchRequest { bytes search_key = 1; Consistency consistency = 2; + optional uint32 version = 3; } // TreeSearchResponse is the output of executing a search on the tree. diff --git a/tree/transparency/test/transparency_test.go b/tree/transparency/test/transparency_test.go index 7b93d21..6caa851 100644 --- a/tree/transparency/test/transparency_test.go +++ b/tree/transparency/test/transparency_test.go @@ -108,21 +108,24 @@ func TestTreeWithAuditorHeads(t *testing.T) { } } -func TestTree(t *testing.T) { +func TestTreeSearchForVersion(t *testing.T) { tree, store, _, _ := NewTree(t, transparency.ContactMonitoring) var ( - keys [][]byte - values [][]byte + repeatKey = random() + repeatKeyValues [][]byte + + randomKeys [][]byte + randomKeyValues [][]byte ) for i := 0; i < 100; i++ { - dice := mrand.Intn(4) + dice := mrand.Intn(5) - if dice == 0 && len(keys) > 0 { // Search for an existing key. - i := mrand.Intn(len(keys)) + if dice == 0 && len(randomKeys) > 0 { // Search for an existing random key, most recent version. + i := mrand.Intn(len(randomKeys)) req := &pb.TreeSearchRequest{ - SearchKey: keys[i], + SearchKey: randomKeys[i], Consistency: Last(store), } res, err := tree.Search(req) @@ -130,10 +133,25 @@ func TestTree(t *testing.T) { t.Fatal(err) } else if err := transparency.VerifySearch(store, req, res); err != nil { t.Fatal(err) - } else if !bytes.Equal(res.Value.Value, values[i]) { + } else if !bytes.Equal(res.Value.Value, randomKeyValues[i]) { t.Fatal("unexpected value returned") } - } else if dice == 1 { // Add a new key. + } else if dice == 1 && len(repeatKeyValues) > 0 { // Search for a specific version of the repeat key + version := uint32(mrand.Intn(len(repeatKeyValues))) + req := &pb.TreeSearchRequest{ + SearchKey: repeatKey, + Consistency: Last(store), + Version: &version, + } + res, err := tree.Search(req) + if err != nil { + t.Fatal(err) + } else if err := transparency.VerifySearch(store, req, res); err != nil { + t.Fatal(err) + } else if !bytes.Equal(res.Value.Value, repeatKeyValues[version]) { + t.Fatal("unexpected value returned") + } + } else if dice == 2 { // Add a new random key. key, value := random(), random() req := &pb.UpdateRequest{ SearchKey: key, @@ -146,11 +164,11 @@ func TestTree(t *testing.T) { } else if err := transparency.VerifyUpdate(store, req, res); err != nil { t.Fatal(err) } - keys, values = append(keys, key), append(values, value) - } else if dice == 2 && len(keys) > 0 { // Update an existing key. - i, value := mrand.Intn(len(keys)), random() + randomKeys, randomKeyValues = append(randomKeys, key), append(randomKeyValues, value) + } else if dice == 3 && len(randomKeys) > 0 { // Update the repeat key + value := random() req := &pb.UpdateRequest{ - SearchKey: keys[i], + SearchKey: repeatKey, Value: value, Consistency: Last(store), } @@ -160,8 +178,8 @@ func TestTree(t *testing.T) { } else if err := transparency.VerifyUpdate(store, req, res); err != nil { t.Fatal(err) } - values[i] = value - } else if dice == 3 && len(keys) > 0 { // Add some fake updates. + repeatKeyValues = append(repeatKeyValues, value) + } else if dice == 4 && (len(randomKeys) > 0 || len(repeatKeyValues) > 0) { // Add some fake updates. if err := tree.BatchUpdateFake(5); err != nil { t.Fatal(err) } diff --git a/tree/transparency/transparency.go b/tree/transparency/transparency.go index ca1565c..ca70cdb 100644 --- a/tree/transparency/transparency.go +++ b/tree/transparency/transparency.go @@ -238,9 +238,9 @@ func (t *Tree) updatedAuditorHeads(treeSize uint64) (map[string]*db.AuditorTreeH return auditors, nil } -func (t *Tree) search(index [32]byte, firstUpdatePosition, latestUpdatePosition uint64) (*pb.SearchProof, error) { +func (t *Tree) search(index [32]byte, firstUpdatePosition, latestUpdatePosition uint64, mostRecent bool) (*pb.SearchProof, error) { // Determine the path of our binary search. - ids, err := searchPath(firstUpdatePosition, latestUpdatePosition, t.latest.TreeSize) + ids, err := searchPath(firstUpdatePosition, latestUpdatePosition, t.latest.TreeSize, mostRecent) if err != nil { return nil, err } @@ -294,20 +294,27 @@ func (t *Tree) Search(req *pb.TreeSearchRequest) (*pb.TreeSearchResponse, error) index, vrfProof := t.config.VrfKey.ECVRFProve(req.SearchKey) // Find the position of the first occurrence of the index in the log, and the - // position of the most recent occurrence of the index in the log. - var firstUpdatePosition, latestUpdatePosition uint64 - res, err := t.prefixTree.Search(t.latest.TreeSize, index[:]) + // position of the most recent occurrence of the index in the log OR the + // position corresponding to the requested version. + var res *prefix.SearchResult + var err error + if req.Version == nil { + res, err = t.prefixTree.Search(t.latest.TreeSize, index[:]) + } else { + res, err = t.prefixTree.SearchForVersion(t.latest.TreeSize, index[:], *req.Version) + } if err != nil { return nil, err } - firstUpdatePosition, latestUpdatePosition = res.FirstUpdatePosition, res.LatestUpdatePosition + + firstUpdatePosition, updatePosition := res.FirstUpdatePosition, res.LatestUpdatePosition // Fetch the search proof and the update value. - searchProof, err := t.search(index, firstUpdatePosition, latestUpdatePosition) + searchProof, err := t.search(index, firstUpdatePosition, updatePosition, req.Version == nil) if err != nil { return nil, err } - raw, err := t.tx.Get(latestUpdatePosition) + raw, err := t.tx.Get(updatePosition) if err != nil { return nil, err } @@ -326,7 +333,7 @@ func (t *Tree) Search(req *pb.TreeSearchRequest) (*pb.TreeSearchResponse, error) VrfProof: vrfProof, Search: searchProof, - Opening: computeOpening(t.config.OpeningKey, latestUpdatePosition), + Opening: computeOpening(t.config.OpeningKey, updatePosition), Value: value, }, nil } @@ -378,7 +385,7 @@ func (t *Tree) PostUpdate(state *PostUpdateState) (*pb.UpdateResponse, error) { t.latest = state.head // Build a search proof for the newly-added value. - searchProof, err := t.search(state.pre.index, state.sr.FirstUpdatePosition, state.sr.LatestUpdatePosition) + searchProof, err := t.search(state.pre.index, state.sr.FirstUpdatePosition, state.sr.LatestUpdatePosition, true) if err != nil { return nil, err } @@ -902,14 +909,24 @@ func (t *Tree) SetAuditorHead(head *pb.AuditorTreeHead, auditorName string) erro } // searchPath returns the set of ids that will be accessed by a binary search -// through the transparency tree. `firstUpdatePosition` is the position of the first -// occurrence of the index in the tree, `latestUpdatePosition` is the position of the most recent occurrence -// of the index in the tree, and `treeSize` is the current size of the tree. -func searchPath(firstUpdatePosition, latestUpdatePosition, treeSize uint64) ([]uint64, error) { +// through the transparency tree for the entry associated with `latestUpdatePosition`. +// `firstUpdatePosition` is the position of the first occurrence of the index in the tree, +// `latestUpdatePosition` is the position of the most recent occurrence of the index in the tree, and +// `treeSize` is the current size of the tree. +func searchPath(firstUpdatePosition, latestUpdatePosition, treeSize uint64, mostRecent bool) ([]uint64, error) { var ids []uint64 var guide *proofGuide - guide = mostRecentProofGuide(firstUpdatePosition, treeSize) + + if mostRecent { + // The target counter is always 1, but the proof guide for the most recent version has to "prove" this by + // first searching the frontier nodes of the implicit binary search tree instead of hardcoding it like + // the versioned proof guide. + guide = mostRecentProofGuide(firstUpdatePosition, treeSize) + } else { + guide = versionProofGuide(1, firstUpdatePosition, treeSize) + } + for { done, err := guide.done() if err != nil { diff --git a/tree/transparency/verify.go b/tree/transparency/verify.go index da26621..40b1af0 100644 --- a/tree/transparency/verify.go +++ b/tree/transparency/verify.go @@ -178,7 +178,11 @@ func verifySearch(storage ClientStorage, req *pb.TreeSearchRequest, res *pb.Tree stepMap := make(map[uint64]*pb.ProofStep) var guide *proofGuide - guide = mostRecentProofGuide(res.Search.Pos, treeSize) + if req.Version == nil { + guide = mostRecentProofGuide(res.Search.Pos, treeSize) + } else { + guide = versionProofGuide(*req.Version, res.Search.Pos, treeSize) + } for { done, err := guide.done() if err != nil { @@ -190,6 +194,8 @@ func verifySearch(storage ClientStorage, req *pb.TreeSearchRequest, res *pb.Tree } id := guide.next() step := res.Search.Steps[i] + + // Unlike during search proof generation, we use the actual version of the index during search proof verification. guide.insert(id, step.Prefix.Counter) // Evaluate the prefix proof and combine it with the commitment to get