diff --git a/api/firmware/bluetooth.go b/api/firmware/bluetooth.go new file mode 100644 index 0000000..ff2464b --- /dev/null +++ b/api/firmware/bluetooth.go @@ -0,0 +1,84 @@ +// Copyright 2025 Shift Crypto AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package firmware + +import ( + "github.com/BitBoxSwiss/bitbox02-api-go/api/firmware/messages" + "github.com/BitBoxSwiss/bitbox02-api-go/util/errp" +) + +// queryBluetooth is like query, but nested one level deeper for Bluetooth. +func (device *Device) queryBluetooth(request *messages.BluetoothRequest) (*messages.BluetoothResponse, error) { + if !device.SupportsBluetooth() { + return nil, errp.New("this device does not support Bluetooth") + } + response, err := device.query(&messages.Request{ + Request: &messages.Request_Bluetooth{ + Bluetooth: request, + }, + }) + if err != nil { + return nil, err + } + bluetoothResponse, ok := response.Response.(*messages.Response_Bluetooth) + if !ok { + return nil, errp.New("unexpected reply") + } + return bluetoothResponse.Bluetooth, nil +} + +// BluetoothUpgrade attempts an upgrade of the Bluetooth firmware. +func (device *Device) BluetoothUpgrade(firmware []byte) error { + // Send initial upgrade request + initReq := &messages.BluetoothUpgradeInitRequest{ + FirmwareLength: uint32(len(firmware)), + } + req := &messages.BluetoothRequest{ + Request: &messages.BluetoothRequest_UpgradeInit{ + UpgradeInit: initReq, + }, + } + + currentResponse, err := device.queryBluetooth(req) + if err != nil { + return err + } + + for { + switch resp := currentResponse.Response.(type) { + case *messages.BluetoothResponse_RequestChunk: + chunkReq := resp.RequestChunk + chunkData := firmware[chunkReq.Offset : chunkReq.Offset+chunkReq.Length] + + currentResponse, err = device.queryBluetooth(&messages.BluetoothRequest{ + Request: &messages.BluetoothRequest_Chunk{ + Chunk: &messages.BluetoothChunkRequest{ + Data: chunkData, + }, + }, + }) + if err != nil { + return err + } + + case *messages.BluetoothResponse_Success: + // Upgrade complete + return nil + + default: + return errp.New("unexpected response type during bluetooth upgrade") + } + } +} diff --git a/api/firmware/device.go b/api/firmware/device.go index 2869523..cc9c9c1 100644 --- a/api/firmware/device.go +++ b/api/firmware/device.go @@ -352,6 +352,11 @@ func (device *Device) SupportsETH(chainID uint64) bool { return false } +// SupportsBluetooth returns true if this device supports Bluetooth. +func (device *Device) SupportsBluetooth() bool { + return *device.product == common.ProductBitBox02PlusMulti || *device.product == common.ProductBitBox02PlusBTCOnly +} + // SupportsERC20 returns true if an ERC20 token is supported by the device api. // // For now, this list only contains tokens relevant to the BitBoxApp, otherwise the bitbox02-api-js diff --git a/api/firmware/messages/bluetooth.pb.go b/api/firmware/messages/bluetooth.pb.go new file mode 100644 index 0000000..25fe0b0 --- /dev/null +++ b/api/firmware/messages/bluetooth.pb.go @@ -0,0 +1,570 @@ +// Copyright 2025 Shift Crypto AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.2 +// protoc v3.21.12 +// source: bluetooth.proto + +package messages + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type BluetoothUpgradeInitRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FirmwareLength uint32 `protobuf:"varint,1,opt,name=firmware_length,json=firmwareLength,proto3" json:"firmware_length,omitempty"` +} + +func (x *BluetoothUpgradeInitRequest) Reset() { + *x = BluetoothUpgradeInitRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_bluetooth_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BluetoothUpgradeInitRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BluetoothUpgradeInitRequest) ProtoMessage() {} + +func (x *BluetoothUpgradeInitRequest) ProtoReflect() protoreflect.Message { + mi := &file_bluetooth_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BluetoothUpgradeInitRequest.ProtoReflect.Descriptor instead. +func (*BluetoothUpgradeInitRequest) Descriptor() ([]byte, []int) { + return file_bluetooth_proto_rawDescGZIP(), []int{0} +} + +func (x *BluetoothUpgradeInitRequest) GetFirmwareLength() uint32 { + if x != nil { + return x.FirmwareLength + } + return 0 +} + +type BluetoothChunkRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` +} + +func (x *BluetoothChunkRequest) Reset() { + *x = BluetoothChunkRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_bluetooth_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BluetoothChunkRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BluetoothChunkRequest) ProtoMessage() {} + +func (x *BluetoothChunkRequest) ProtoReflect() protoreflect.Message { + mi := &file_bluetooth_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BluetoothChunkRequest.ProtoReflect.Descriptor instead. +func (*BluetoothChunkRequest) Descriptor() ([]byte, []int) { + return file_bluetooth_proto_rawDescGZIP(), []int{1} +} + +func (x *BluetoothChunkRequest) GetData() []byte { + if x != nil { + return x.Data + } + return nil +} + +type BluetoothSuccess struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *BluetoothSuccess) Reset() { + *x = BluetoothSuccess{} + if protoimpl.UnsafeEnabled { + mi := &file_bluetooth_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BluetoothSuccess) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BluetoothSuccess) ProtoMessage() {} + +func (x *BluetoothSuccess) ProtoReflect() protoreflect.Message { + mi := &file_bluetooth_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BluetoothSuccess.ProtoReflect.Descriptor instead. +func (*BluetoothSuccess) Descriptor() ([]byte, []int) { + return file_bluetooth_proto_rawDescGZIP(), []int{2} +} + +type BluetoothRequestChunkResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Offset uint32 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + Length uint32 `protobuf:"varint,2,opt,name=length,proto3" json:"length,omitempty"` +} + +func (x *BluetoothRequestChunkResponse) Reset() { + *x = BluetoothRequestChunkResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_bluetooth_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BluetoothRequestChunkResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BluetoothRequestChunkResponse) ProtoMessage() {} + +func (x *BluetoothRequestChunkResponse) ProtoReflect() protoreflect.Message { + mi := &file_bluetooth_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BluetoothRequestChunkResponse.ProtoReflect.Descriptor instead. +func (*BluetoothRequestChunkResponse) Descriptor() ([]byte, []int) { + return file_bluetooth_proto_rawDescGZIP(), []int{3} +} + +func (x *BluetoothRequestChunkResponse) GetOffset() uint32 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *BluetoothRequestChunkResponse) GetLength() uint32 { + if x != nil { + return x.Length + } + return 0 +} + +type BluetoothRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Request: + // + // *BluetoothRequest_UpgradeInit + // *BluetoothRequest_Chunk + Request isBluetoothRequest_Request `protobuf_oneof:"request"` +} + +func (x *BluetoothRequest) Reset() { + *x = BluetoothRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_bluetooth_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BluetoothRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BluetoothRequest) ProtoMessage() {} + +func (x *BluetoothRequest) ProtoReflect() protoreflect.Message { + mi := &file_bluetooth_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BluetoothRequest.ProtoReflect.Descriptor instead. +func (*BluetoothRequest) Descriptor() ([]byte, []int) { + return file_bluetooth_proto_rawDescGZIP(), []int{4} +} + +func (m *BluetoothRequest) GetRequest() isBluetoothRequest_Request { + if m != nil { + return m.Request + } + return nil +} + +func (x *BluetoothRequest) GetUpgradeInit() *BluetoothUpgradeInitRequest { + if x, ok := x.GetRequest().(*BluetoothRequest_UpgradeInit); ok { + return x.UpgradeInit + } + return nil +} + +func (x *BluetoothRequest) GetChunk() *BluetoothChunkRequest { + if x, ok := x.GetRequest().(*BluetoothRequest_Chunk); ok { + return x.Chunk + } + return nil +} + +type isBluetoothRequest_Request interface { + isBluetoothRequest_Request() +} + +type BluetoothRequest_UpgradeInit struct { + UpgradeInit *BluetoothUpgradeInitRequest `protobuf:"bytes,1,opt,name=upgrade_init,json=upgradeInit,proto3,oneof"` +} + +type BluetoothRequest_Chunk struct { + Chunk *BluetoothChunkRequest `protobuf:"bytes,2,opt,name=chunk,proto3,oneof"` +} + +func (*BluetoothRequest_UpgradeInit) isBluetoothRequest_Request() {} + +func (*BluetoothRequest_Chunk) isBluetoothRequest_Request() {} + +type BluetoothResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Response: + // + // *BluetoothResponse_Success + // *BluetoothResponse_RequestChunk + Response isBluetoothResponse_Response `protobuf_oneof:"response"` +} + +func (x *BluetoothResponse) Reset() { + *x = BluetoothResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_bluetooth_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *BluetoothResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*BluetoothResponse) ProtoMessage() {} + +func (x *BluetoothResponse) ProtoReflect() protoreflect.Message { + mi := &file_bluetooth_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use BluetoothResponse.ProtoReflect.Descriptor instead. +func (*BluetoothResponse) Descriptor() ([]byte, []int) { + return file_bluetooth_proto_rawDescGZIP(), []int{5} +} + +func (m *BluetoothResponse) GetResponse() isBluetoothResponse_Response { + if m != nil { + return m.Response + } + return nil +} + +func (x *BluetoothResponse) GetSuccess() *BluetoothSuccess { + if x, ok := x.GetResponse().(*BluetoothResponse_Success); ok { + return x.Success + } + return nil +} + +func (x *BluetoothResponse) GetRequestChunk() *BluetoothRequestChunkResponse { + if x, ok := x.GetResponse().(*BluetoothResponse_RequestChunk); ok { + return x.RequestChunk + } + return nil +} + +type isBluetoothResponse_Response interface { + isBluetoothResponse_Response() +} + +type BluetoothResponse_Success struct { + Success *BluetoothSuccess `protobuf:"bytes,1,opt,name=success,proto3,oneof"` +} + +type BluetoothResponse_RequestChunk struct { + RequestChunk *BluetoothRequestChunkResponse `protobuf:"bytes,2,opt,name=request_chunk,json=requestChunk,proto3,oneof"` +} + +func (*BluetoothResponse_Success) isBluetoothResponse_Response() {} + +func (*BluetoothResponse_RequestChunk) isBluetoothResponse_Response() {} + +var File_bluetooth_proto protoreflect.FileDescriptor + +var file_bluetooth_proto_rawDesc = []byte{ + 0x0a, 0x0f, 0x62, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x14, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, + 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x22, 0x46, 0x0a, 0x1b, 0x42, 0x6c, 0x75, 0x65, 0x74, + 0x6f, 0x6f, 0x74, 0x68, 0x55, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x27, 0x0a, 0x0f, 0x66, 0x69, 0x72, 0x6d, 0x77, 0x61, + 0x72, 0x65, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0e, 0x66, 0x69, 0x72, 0x6d, 0x77, 0x61, 0x72, 0x65, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x22, + 0x2b, 0x0a, 0x15, 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x43, 0x68, 0x75, 0x6e, + 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x12, 0x0a, 0x10, + 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x22, 0x4f, 0x0a, 0x1d, 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x65, 0x6e, + 0x67, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x6c, 0x65, 0x6e, 0x67, 0x74, + 0x68, 0x22, 0xba, 0x01, 0x0a, 0x10, 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x56, 0x0a, 0x0c, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, + 0x65, 0x5f, 0x69, 0x6e, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x73, + 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, + 0x78, 0x30, 0x32, 0x2e, 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x55, 0x70, 0x67, + 0x72, 0x61, 0x64, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, + 0x00, 0x52, 0x0b, 0x75, 0x70, 0x67, 0x72, 0x61, 0x64, 0x65, 0x49, 0x6e, 0x69, 0x74, 0x12, 0x43, + 0x0a, 0x05, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2b, 0x2e, + 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, + 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x43, 0x68, + 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x63, 0x68, + 0x75, 0x6e, 0x6b, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0xbf, + 0x01, 0x0a, 0x11, 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x42, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x42, 0x6c, 0x75, + 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, + 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x5a, 0x0a, 0x0d, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x5f, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x33, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, + 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x68, 0x75, 0x6e, 0x6b, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0c, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, + 0x68, 0x75, 0x6e, 0x6b, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_bluetooth_proto_rawDescOnce sync.Once + file_bluetooth_proto_rawDescData = file_bluetooth_proto_rawDesc +) + +func file_bluetooth_proto_rawDescGZIP() []byte { + file_bluetooth_proto_rawDescOnce.Do(func() { + file_bluetooth_proto_rawDescData = protoimpl.X.CompressGZIP(file_bluetooth_proto_rawDescData) + }) + return file_bluetooth_proto_rawDescData +} + +var file_bluetooth_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_bluetooth_proto_goTypes = []any{ + (*BluetoothUpgradeInitRequest)(nil), // 0: shiftcrypto.bitbox02.BluetoothUpgradeInitRequest + (*BluetoothChunkRequest)(nil), // 1: shiftcrypto.bitbox02.BluetoothChunkRequest + (*BluetoothSuccess)(nil), // 2: shiftcrypto.bitbox02.BluetoothSuccess + (*BluetoothRequestChunkResponse)(nil), // 3: shiftcrypto.bitbox02.BluetoothRequestChunkResponse + (*BluetoothRequest)(nil), // 4: shiftcrypto.bitbox02.BluetoothRequest + (*BluetoothResponse)(nil), // 5: shiftcrypto.bitbox02.BluetoothResponse +} +var file_bluetooth_proto_depIdxs = []int32{ + 0, // 0: shiftcrypto.bitbox02.BluetoothRequest.upgrade_init:type_name -> shiftcrypto.bitbox02.BluetoothUpgradeInitRequest + 1, // 1: shiftcrypto.bitbox02.BluetoothRequest.chunk:type_name -> shiftcrypto.bitbox02.BluetoothChunkRequest + 2, // 2: shiftcrypto.bitbox02.BluetoothResponse.success:type_name -> shiftcrypto.bitbox02.BluetoothSuccess + 3, // 3: shiftcrypto.bitbox02.BluetoothResponse.request_chunk:type_name -> shiftcrypto.bitbox02.BluetoothRequestChunkResponse + 4, // [4:4] is the sub-list for method output_type + 4, // [4:4] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_bluetooth_proto_init() } +func file_bluetooth_proto_init() { + if File_bluetooth_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_bluetooth_proto_msgTypes[0].Exporter = func(v any, i int) any { + switch v := v.(*BluetoothUpgradeInitRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bluetooth_proto_msgTypes[1].Exporter = func(v any, i int) any { + switch v := v.(*BluetoothChunkRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bluetooth_proto_msgTypes[2].Exporter = func(v any, i int) any { + switch v := v.(*BluetoothSuccess); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bluetooth_proto_msgTypes[3].Exporter = func(v any, i int) any { + switch v := v.(*BluetoothRequestChunkResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bluetooth_proto_msgTypes[4].Exporter = func(v any, i int) any { + switch v := v.(*BluetoothRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_bluetooth_proto_msgTypes[5].Exporter = func(v any, i int) any { + switch v := v.(*BluetoothResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_bluetooth_proto_msgTypes[4].OneofWrappers = []any{ + (*BluetoothRequest_UpgradeInit)(nil), + (*BluetoothRequest_Chunk)(nil), + } + file_bluetooth_proto_msgTypes[5].OneofWrappers = []any{ + (*BluetoothResponse_Success)(nil), + (*BluetoothResponse_RequestChunk)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_bluetooth_proto_rawDesc, + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_bluetooth_proto_goTypes, + DependencyIndexes: file_bluetooth_proto_depIdxs, + MessageInfos: file_bluetooth_proto_msgTypes, + }.Build() + File_bluetooth_proto = out.File + file_bluetooth_proto_rawDesc = nil + file_bluetooth_proto_goTypes = nil + file_bluetooth_proto_depIdxs = nil +} diff --git a/api/firmware/messages/bluetooth.proto b/api/firmware/messages/bluetooth.proto new file mode 100644 index 0000000..c165c19 --- /dev/null +++ b/api/firmware/messages/bluetooth.proto @@ -0,0 +1,46 @@ +// Copyright 2025 Shift Crypto AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; +package shiftcrypto.bitbox02; + +message BluetoothUpgradeInitRequest { + uint32 firmware_length = 1; +} + +message BluetoothChunkRequest { + bytes data = 1; +} + +message BluetoothSuccess { +} + +message BluetoothRequestChunkResponse { + uint32 offset = 1; + uint32 length = 2; +} + +message BluetoothRequest { + oneof request { + BluetoothUpgradeInitRequest upgrade_init = 1; + BluetoothChunkRequest chunk = 2; + } +} + +message BluetoothResponse { + oneof response { + BluetoothSuccess success = 1; + BluetoothRequestChunkResponse request_chunk = 2; + } +} diff --git a/api/firmware/messages/hww.pb.go b/api/firmware/messages/hww.pb.go index 891fc3b..9c778cf 100644 --- a/api/firmware/messages/hww.pb.go +++ b/api/firmware/messages/hww.pb.go @@ -160,6 +160,7 @@ type Request struct { // *Request_ElectrumEncryptionKey // *Request_Cardano // *Request_Bip85 + // *Request_Bluetooth Request isRequest_Request `protobuf_oneof:"request"` } @@ -384,6 +385,13 @@ func (x *Request) GetBip85() *BIP85Request { return nil } +func (x *Request) GetBluetooth() *BluetoothRequest { + if x, ok := x.GetRequest().(*Request_Bluetooth); ok { + return x.Bluetooth + } + return nil +} + type isRequest_Request interface { isRequest_Request() } @@ -494,6 +502,10 @@ type Request_Bip85 struct { Bip85 *BIP85Request `protobuf:"bytes,28,opt,name=bip85,proto3,oneof"` } +type Request_Bluetooth struct { + Bluetooth *BluetoothRequest `protobuf:"bytes,29,opt,name=bluetooth,proto3,oneof"` +} + func (*Request_DeviceName) isRequest_Request() {} func (*Request_DeviceLanguage) isRequest_Request() {} @@ -546,6 +558,8 @@ func (*Request_Cardano) isRequest_Request() {} func (*Request_Bip85) isRequest_Request() {} +func (*Request_Bluetooth) isRequest_Request() {} + type Response struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -568,6 +582,7 @@ type Response struct { // *Response_ElectrumEncryptionKey // *Response_Cardano // *Response_Bip85 + // *Response_Bluetooth Response isResponse_Response `protobuf_oneof:"response"` } @@ -715,6 +730,13 @@ func (x *Response) GetBip85() *BIP85Response { return nil } +func (x *Response) GetBluetooth() *BluetoothResponse { + if x, ok := x.GetResponse().(*Response_Bluetooth); ok { + return x.Bluetooth + } + return nil +} + type isResponse_Response interface { isResponse_Response() } @@ -780,6 +802,10 @@ type Response_Bip85 struct { Bip85 *BIP85Response `protobuf:"bytes,16,opt,name=bip85,proto3,oneof"` } +type Response_Bluetooth struct { + Bluetooth *BluetoothResponse `protobuf:"bytes,17,opt,name=bluetooth,proto3,oneof"` +} + func (*Response_Success) isResponse_Response() {} func (*Response_Error) isResponse_Response() {} @@ -810,6 +836,8 @@ func (*Response_Cardano) isResponse_Response() {} func (*Response_Bip85) isResponse_Response() {} +func (*Response_Bluetooth) isResponse_Response() {} + var File_hww_proto protoreflect.FileDescriptor var file_hww_proto_rawDesc = []byte{ @@ -818,223 +846,234 @@ var file_hww_proto_rawDesc = []byte{ 0x32, 0x1a, 0x0c, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, - 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x09, 0x62, - 0x74, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0d, 0x63, 0x61, 0x72, 0x64, 0x61, 0x6e, - 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x09, 0x65, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x1a, 0x0e, 0x6b, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x1a, 0x0e, 0x6d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x1a, 0x0c, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x1a, 0x19, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x35, 0x0a, 0x05, 0x45, - 0x72, 0x72, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x22, 0x09, 0x0a, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0xdf, 0x10, - 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4d, 0x0a, 0x0b, 0x64, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, - 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, - 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x53, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, - 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x64, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x59, 0x0a, 0x0f, 0x64, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x5f, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x2e, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, - 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x53, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, - 0x63, 0x65, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x48, 0x00, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x61, 0x6e, 0x67, 0x75, - 0x61, 0x67, 0x65, 0x12, 0x4a, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, - 0x66, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x48, 0x00, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x4d, 0x0a, 0x0c, 0x73, 0x65, 0x74, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, - 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x53, 0x65, 0x74, - 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, - 0x00, 0x52, 0x0b, 0x73, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x50, - 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, - 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x48, 0x00, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x12, 0x50, 0x0a, 0x0d, 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x6d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, - 0x63, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x53, - 0x68, 0x6f, 0x77, 0x4d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x68, 0x6f, 0x77, 0x4d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, - 0x69, 0x63, 0x12, 0x3e, 0x0a, 0x07, 0x62, 0x74, 0x63, 0x5f, 0x70, 0x75, 0x62, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x42, 0x54, 0x43, 0x50, 0x75, - 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x62, 0x74, 0x63, 0x50, - 0x75, 0x62, 0x12, 0x4e, 0x0a, 0x0d, 0x62, 0x74, 0x63, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x5f, 0x69, - 0x6e, 0x69, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x68, 0x69, 0x66, + 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0f, 0x62, + 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x09, + 0x62, 0x74, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0d, 0x63, 0x61, 0x72, 0x64, 0x61, + 0x6e, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x09, 0x65, 0x74, 0x68, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x0e, 0x6b, 0x65, 0x79, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x0e, 0x6d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x0c, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x1a, 0x19, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x35, 0x0a, 0x05, + 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x09, 0x0a, 0x07, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x22, 0xa7, + 0x11, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4d, 0x0a, 0x0b, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2a, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, + 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x53, 0x65, 0x74, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x64, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x59, 0x0a, 0x0f, 0x64, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x5f, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, + 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x53, 0x65, 0x74, 0x44, 0x65, 0x76, + 0x69, 0x63, 0x65, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x61, 0x6e, 0x67, + 0x75, 0x61, 0x67, 0x65, 0x12, 0x4a, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, + 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, - 0x2e, 0x42, 0x54, 0x43, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x62, 0x74, 0x63, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, - 0x69, 0x74, 0x12, 0x51, 0x0a, 0x0e, 0x62, 0x74, 0x63, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x5f, 0x69, - 0x6e, 0x70, 0x75, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x68, 0x69, + 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x48, 0x00, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x4d, 0x0a, 0x0c, 0x73, 0x65, 0x74, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x53, 0x65, + 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x48, 0x00, 0x52, 0x0b, 0x73, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, + 0x50, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x48, 0x00, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x12, 0x50, 0x0a, 0x0d, 0x73, 0x68, 0x6f, 0x77, 0x5f, 0x6d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, + 0x69, 0x63, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, + 0x53, 0x68, 0x6f, 0x77, 0x4d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x68, 0x6f, 0x77, 0x4d, 0x6e, 0x65, 0x6d, 0x6f, + 0x6e, 0x69, 0x63, 0x12, 0x3e, 0x0a, 0x07, 0x62, 0x74, 0x63, 0x5f, 0x70, 0x75, 0x62, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x42, 0x54, 0x43, 0x50, + 0x75, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x62, 0x74, 0x63, + 0x50, 0x75, 0x62, 0x12, 0x4e, 0x0a, 0x0d, 0x62, 0x74, 0x63, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x5f, + 0x69, 0x6e, 0x69, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, - 0x32, 0x2e, 0x42, 0x54, 0x43, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x62, 0x74, 0x63, 0x53, 0x69, 0x67, 0x6e, - 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x54, 0x0a, 0x0f, 0x62, 0x74, 0x63, 0x5f, 0x73, 0x69, 0x67, - 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, - 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, - 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x42, 0x54, 0x43, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x62, 0x74, - 0x63, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x63, 0x0a, 0x14, 0x69, - 0x6e, 0x73, 0x65, 0x72, 0x74, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x73, 0x64, 0x63, - 0x61, 0x72, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x68, 0x69, 0x66, - 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, - 0x2e, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x44, 0x43, - 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x12, 0x69, 0x6e, - 0x73, 0x65, 0x72, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x64, 0x63, 0x61, 0x72, 0x64, - 0x12, 0x4d, 0x0a, 0x0c, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x73, 0x64, 0x63, 0x61, 0x72, 0x64, - 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, - 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x43, 0x68, - 0x65, 0x63, 0x6b, 0x53, 0x44, 0x43, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x48, 0x00, 0x52, 0x0b, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x64, 0x63, 0x61, 0x72, 0x64, 0x12, - 0x82, 0x01, 0x0a, 0x1f, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, - 0x5f, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x5f, 0x65, 0x6e, 0x61, 0x62, - 0x6c, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x73, 0x68, 0x69, 0x66, - 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, - 0x2e, 0x53, 0x65, 0x74, 0x4d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x50, 0x61, 0x73, 0x73, - 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x1c, 0x73, 0x65, 0x74, 0x4d, 0x6e, 0x65, 0x6d, 0x6f, - 0x6e, 0x69, 0x63, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x45, 0x6e, 0x61, - 0x62, 0x6c, 0x65, 0x64, 0x12, 0x4d, 0x0a, 0x0c, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x62, 0x61, 0x63, - 0x6b, 0x75, 0x70, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x68, 0x69, + 0x32, 0x2e, 0x42, 0x54, 0x43, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x69, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x62, 0x74, 0x63, 0x53, 0x69, 0x67, 0x6e, 0x49, + 0x6e, 0x69, 0x74, 0x12, 0x51, 0x0a, 0x0e, 0x62, 0x74, 0x63, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x5f, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x68, + 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, + 0x30, 0x32, 0x2e, 0x42, 0x54, 0x43, 0x53, 0x69, 0x67, 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x62, 0x74, 0x63, 0x53, 0x69, 0x67, + 0x6e, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x12, 0x54, 0x0a, 0x0f, 0x62, 0x74, 0x63, 0x5f, 0x73, 0x69, + 0x67, 0x6e, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2a, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, + 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x42, 0x54, 0x43, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x75, + 0x74, 0x70, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x62, + 0x74, 0x63, 0x53, 0x69, 0x67, 0x6e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x12, 0x63, 0x0a, 0x14, + 0x69, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x5f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x5f, 0x73, 0x64, + 0x63, 0x61, 0x72, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, - 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x6c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, - 0x75, 0x70, 0x73, 0x12, 0x53, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x62, - 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x68, + 0x32, 0x2e, 0x49, 0x6e, 0x73, 0x65, 0x72, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x44, + 0x43, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x12, 0x69, + 0x6e, 0x73, 0x65, 0x72, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x53, 0x64, 0x63, 0x61, 0x72, + 0x64, 0x12, 0x4d, 0x0a, 0x0c, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x73, 0x64, 0x63, 0x61, 0x72, + 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x43, + 0x68, 0x65, 0x63, 0x6b, 0x53, 0x44, 0x43, 0x61, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x64, 0x63, 0x61, 0x72, 0x64, + 0x12, 0x82, 0x01, 0x0a, 0x1f, 0x73, 0x65, 0x74, 0x5f, 0x6d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, + 0x63, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x5f, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x39, 0x2e, 0x73, 0x68, 0x69, + 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, + 0x32, 0x2e, 0x53, 0x65, 0x74, 0x4d, 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x50, 0x61, 0x73, + 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x1c, 0x73, 0x65, 0x74, 0x4d, 0x6e, 0x65, 0x6d, + 0x6f, 0x6e, 0x69, 0x63, 0x50, 0x61, 0x73, 0x73, 0x70, 0x68, 0x72, 0x61, 0x73, 0x65, 0x45, 0x6e, + 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x4d, 0x0a, 0x0c, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x62, 0x61, + 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, - 0x30, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x74, 0x6f, - 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x70, 0x65, 0x72, 0x66, - 0x6f, 0x72, 0x6d, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, - 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x50, 0x65, 0x72, - 0x66, 0x6f, 0x72, 0x6d, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x12, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, - 0x6d, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3d, 0x0a, 0x06, - 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, + 0x30, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x6c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x73, 0x12, 0x53, 0x0a, 0x0e, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, + 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, - 0x78, 0x30, 0x32, 0x2e, 0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x12, 0x4d, 0x0a, 0x0c, 0x63, - 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x13, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, - 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x61, - 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x63, - 0x68, 0x65, 0x63, 0x6b, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x34, 0x0a, 0x03, 0x65, 0x74, - 0x68, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x45, - 0x54, 0x48, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x03, 0x65, 0x74, 0x68, - 0x12, 0x3a, 0x0a, 0x05, 0x72, 0x65, 0x73, 0x65, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x22, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, - 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x72, 0x65, 0x73, 0x65, 0x74, 0x12, 0x66, 0x0a, 0x15, - 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x6d, 0x6e, 0x65, - 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x73, 0x68, - 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, - 0x30, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x4d, 0x6e, - 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, - 0x13, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x4d, 0x6e, 0x65, 0x6d, - 0x6f, 0x6e, 0x69, 0x63, 0x12, 0x50, 0x0a, 0x0b, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, - 0x69, 0x6e, 0x74, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x73, 0x68, 0x69, 0x66, - 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, - 0x2e, 0x52, 0x6f, 0x6f, 0x74, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x66, 0x69, 0x6e, 0x67, 0x65, - 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x34, 0x0a, 0x03, 0x62, 0x74, 0x63, 0x18, 0x19, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x42, 0x54, 0x43, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x03, 0x62, 0x74, 0x63, 0x12, 0x6c, 0x0a, 0x17, - 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x75, 0x6d, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, + 0x78, 0x30, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, + 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x72, 0x65, 0x73, 0x74, + 0x6f, 0x72, 0x65, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x62, 0x0a, 0x13, 0x70, 0x65, 0x72, + 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x50, 0x65, + 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x12, 0x70, 0x65, 0x72, 0x66, 0x6f, + 0x72, 0x6d, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3d, 0x0a, + 0x06, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, - 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x45, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x75, 0x6d, 0x45, 0x6e, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x48, 0x00, 0x52, 0x15, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x75, 0x6d, 0x45, 0x6e, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x40, 0x0a, 0x07, 0x63, 0x61, - 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x68, - 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, - 0x30, 0x32, 0x2e, 0x43, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x48, 0x00, 0x52, 0x07, 0x63, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x12, 0x3a, 0x0a, 0x05, - 0x62, 0x69, 0x70, 0x38, 0x35, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x68, - 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, - 0x30, 0x32, 0x2e, 0x42, 0x49, 0x50, 0x38, 0x35, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, - 0x00, 0x52, 0x05, 0x62, 0x69, 0x70, 0x38, 0x35, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x17, 0x10, 0x18, 0x22, - 0xe6, 0x08, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x07, - 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, - 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x53, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, 0x07, - 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x33, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, - 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x45, 0x72, - 0x72, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x4b, 0x0a, 0x0b, - 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, - 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, - 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x64, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x35, 0x0a, 0x03, 0x70, 0x75, 0x62, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, - 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x50, 0x75, - 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x03, 0x70, 0x75, 0x62, - 0x12, 0x4f, 0x0a, 0x0d, 0x62, 0x74, 0x63, 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x5f, 0x6e, 0x65, 0x78, - 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x42, - 0x54, 0x43, 0x53, 0x69, 0x67, 0x6e, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x62, 0x74, 0x63, 0x53, 0x69, 0x67, 0x6e, 0x4e, 0x65, 0x78, - 0x74, 0x12, 0x4e, 0x0a, 0x0c, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x4c, - 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x6c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, - 0x73, 0x12, 0x4e, 0x0a, 0x0c, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x43, - 0x68, 0x65, 0x63, 0x6b, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x61, 0x63, 0x6b, 0x75, - 0x70, 0x12, 0x63, 0x0a, 0x13, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x61, 0x74, 0x74, - 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, + 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x12, 0x4d, 0x0a, 0x0c, + 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x13, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, + 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, + 0x61, 0x63, 0x6b, 0x75, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, + 0x63, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x34, 0x0a, 0x03, 0x65, + 0x74, 0x68, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, + 0x45, 0x54, 0x48, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x03, 0x65, 0x74, + 0x68, 0x12, 0x3a, 0x0a, 0x05, 0x72, 0x65, 0x73, 0x65, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x22, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, + 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x72, 0x65, 0x73, 0x65, 0x74, 0x12, 0x66, 0x0a, + 0x15, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x6d, 0x6e, + 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x73, + 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, + 0x78, 0x30, 0x32, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x4d, + 0x6e, 0x65, 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, + 0x52, 0x13, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x46, 0x72, 0x6f, 0x6d, 0x4d, 0x6e, 0x65, + 0x6d, 0x6f, 0x6e, 0x69, 0x63, 0x12, 0x50, 0x0a, 0x0b, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, + 0x72, 0x69, 0x6e, 0x74, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x73, 0x68, 0x69, + 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, + 0x32, 0x2e, 0x52, 0x6f, 0x6f, 0x74, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x66, 0x69, 0x6e, 0x67, + 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x34, 0x0a, 0x03, 0x62, 0x74, 0x63, 0x18, 0x19, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x42, 0x54, 0x43, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x03, 0x62, 0x74, 0x63, 0x12, 0x6c, 0x0a, + 0x17, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x75, 0x6d, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, - 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x41, 0x74, 0x74, - 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x48, 0x00, 0x52, 0x12, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x41, 0x74, 0x74, 0x65, 0x73, - 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x4e, 0x0a, 0x0c, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, - 0x73, 0x64, 0x63, 0x61, 0x72, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, + 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x45, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x75, 0x6d, 0x45, 0x6e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x48, 0x00, 0x52, 0x15, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x75, 0x6d, 0x45, 0x6e, + 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x40, 0x0a, 0x07, 0x63, + 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, - 0x78, 0x30, 0x32, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x44, 0x43, 0x61, 0x72, 0x64, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x63, 0x68, 0x65, 0x63, 0x6b, - 0x53, 0x64, 0x63, 0x61, 0x72, 0x64, 0x12, 0x35, 0x0a, 0x03, 0x65, 0x74, 0x68, 0x18, 0x0b, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x45, 0x54, 0x48, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x03, 0x65, 0x74, 0x68, 0x12, 0x51, 0x0a, - 0x0b, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x0c, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, - 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x52, 0x6f, 0x6f, 0x74, 0x46, 0x69, - 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x48, 0x00, 0x52, 0x0b, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, - 0x12, 0x35, 0x0a, 0x03, 0x62, 0x74, 0x63, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, - 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, - 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x42, 0x54, 0x43, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x48, 0x00, 0x52, 0x03, 0x62, 0x74, 0x63, 0x12, 0x6d, 0x0a, 0x17, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x72, 0x75, 0x6d, 0x5f, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, - 0x65, 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, - 0x45, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x75, 0x6d, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, - 0x15, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x75, 0x6d, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x12, 0x41, 0x0a, 0x07, 0x63, 0x61, 0x72, 0x64, 0x61, 0x6e, - 0x6f, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, - 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x43, - 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, - 0x52, 0x07, 0x63, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x12, 0x3b, 0x0a, 0x05, 0x62, 0x69, 0x70, - 0x38, 0x35, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, - 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, - 0x42, 0x49, 0x50, 0x38, 0x35, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, - 0x05, 0x62, 0x69, 0x70, 0x38, 0x35, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x78, 0x30, 0x32, 0x2e, 0x43, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x48, 0x00, 0x52, 0x07, 0x63, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x12, 0x3a, 0x0a, + 0x05, 0x62, 0x69, 0x70, 0x38, 0x35, 0x18, 0x1c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, + 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, + 0x78, 0x30, 0x32, 0x2e, 0x42, 0x49, 0x50, 0x38, 0x35, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x48, 0x00, 0x52, 0x05, 0x62, 0x69, 0x70, 0x38, 0x35, 0x12, 0x46, 0x0a, 0x09, 0x62, 0x6c, 0x75, + 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x18, 0x1d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x73, + 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, + 0x78, 0x30, 0x32, 0x2e, 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, + 0x68, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4a, 0x04, 0x08, 0x01, + 0x10, 0x02, 0x4a, 0x04, 0x08, 0x17, 0x10, 0x18, 0x22, 0xaf, 0x09, 0x0a, 0x08, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x53, 0x75, + 0x63, 0x63, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x12, 0x33, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, + 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x05, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x4b, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x68, 0x69, + 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, + 0x32, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, + 0x66, 0x6f, 0x12, 0x35, 0x0a, 0x03, 0x70, 0x75, 0x62, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x21, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, + 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x50, 0x75, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x48, 0x00, 0x52, 0x03, 0x70, 0x75, 0x62, 0x12, 0x4f, 0x0a, 0x0d, 0x62, 0x74, 0x63, + 0x5f, 0x73, 0x69, 0x67, 0x6e, 0x5f, 0x6e, 0x65, 0x78, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x29, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, + 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x42, 0x54, 0x43, 0x53, 0x69, 0x67, 0x6e, 0x4e, + 0x65, 0x78, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x62, + 0x74, 0x63, 0x53, 0x69, 0x67, 0x6e, 0x4e, 0x65, 0x78, 0x74, 0x12, 0x4e, 0x0a, 0x0c, 0x6c, 0x69, + 0x73, 0x74, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x29, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, + 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, + 0x75, 0x70, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x6c, + 0x69, 0x73, 0x74, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x73, 0x12, 0x4e, 0x0a, 0x0c, 0x63, 0x68, + 0x65, 0x63, 0x6b, 0x5f, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x29, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, + 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x42, 0x61, 0x63, + 0x6b, 0x75, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x63, + 0x68, 0x65, 0x63, 0x6b, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x63, 0x0a, 0x13, 0x70, 0x65, + 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x5f, 0x61, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x50, + 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x12, 0x70, 0x65, 0x72, + 0x66, 0x6f, 0x72, 0x6d, 0x41, 0x74, 0x74, 0x65, 0x73, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x4e, 0x0a, 0x0c, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x5f, 0x73, 0x64, 0x63, 0x61, 0x72, 0x64, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, + 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x53, 0x44, 0x43, 0x61, 0x72, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x48, 0x00, 0x52, 0x0b, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x64, 0x63, 0x61, 0x72, 0x64, 0x12, + 0x35, 0x0a, 0x03, 0x65, 0x74, 0x68, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, + 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, + 0x78, 0x30, 0x32, 0x2e, 0x45, 0x54, 0x48, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, + 0x00, 0x52, 0x03, 0x65, 0x74, 0x68, 0x12, 0x51, 0x0a, 0x0b, 0x66, 0x69, 0x6e, 0x67, 0x65, 0x72, + 0x70, 0x72, 0x69, 0x6e, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x73, 0x68, + 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, + 0x30, 0x32, 0x2e, 0x52, 0x6f, 0x6f, 0x74, 0x46, 0x69, 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x66, 0x69, + 0x6e, 0x67, 0x65, 0x72, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x12, 0x35, 0x0a, 0x03, 0x62, 0x74, 0x63, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, + 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x42, 0x54, + 0x43, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x03, 0x62, 0x74, 0x63, + 0x12, 0x6d, 0x0a, 0x17, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x75, 0x6d, 0x5f, 0x65, 0x6e, 0x63, + 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x0e, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x33, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, + 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x45, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x75, + 0x6d, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x15, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, + 0x75, 0x6d, 0x45, 0x6e, 0x63, 0x72, 0x79, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4b, 0x65, 0x79, 0x12, + 0x41, 0x0a, 0x07, 0x63, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x25, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, 0x62, + 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x43, 0x61, 0x72, 0x64, 0x61, 0x6e, 0x6f, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x07, 0x63, 0x61, 0x72, 0x64, 0x61, + 0x6e, 0x6f, 0x12, 0x3b, 0x0a, 0x05, 0x62, 0x69, 0x70, 0x38, 0x35, 0x18, 0x10, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x23, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, 0x2e, + 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x42, 0x49, 0x50, 0x38, 0x35, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x05, 0x62, 0x69, 0x70, 0x38, 0x35, 0x12, + 0x47, 0x0a, 0x09, 0x62, 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x18, 0x11, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x68, 0x69, 0x66, 0x74, 0x63, 0x72, 0x79, 0x70, 0x74, 0x6f, + 0x2e, 0x62, 0x69, 0x74, 0x62, 0x6f, 0x78, 0x30, 0x32, 0x2e, 0x42, 0x6c, 0x75, 0x65, 0x74, 0x6f, + 0x6f, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x09, 0x62, + 0x6c, 0x75, 0x65, 0x74, 0x6f, 0x6f, 0x74, 0x68, 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -1081,19 +1120,21 @@ var file_hww_proto_goTypes = []any{ (*ElectrumEncryptionKeyRequest)(nil), // 27: shiftcrypto.bitbox02.ElectrumEncryptionKeyRequest (*CardanoRequest)(nil), // 28: shiftcrypto.bitbox02.CardanoRequest (*BIP85Request)(nil), // 29: shiftcrypto.bitbox02.BIP85Request - (*DeviceInfoResponse)(nil), // 30: shiftcrypto.bitbox02.DeviceInfoResponse - (*PubResponse)(nil), // 31: shiftcrypto.bitbox02.PubResponse - (*BTCSignNextResponse)(nil), // 32: shiftcrypto.bitbox02.BTCSignNextResponse - (*ListBackupsResponse)(nil), // 33: shiftcrypto.bitbox02.ListBackupsResponse - (*CheckBackupResponse)(nil), // 34: shiftcrypto.bitbox02.CheckBackupResponse - (*PerformAttestationResponse)(nil), // 35: shiftcrypto.bitbox02.PerformAttestationResponse - (*CheckSDCardResponse)(nil), // 36: shiftcrypto.bitbox02.CheckSDCardResponse - (*ETHResponse)(nil), // 37: shiftcrypto.bitbox02.ETHResponse - (*RootFingerprintResponse)(nil), // 38: shiftcrypto.bitbox02.RootFingerprintResponse - (*BTCResponse)(nil), // 39: shiftcrypto.bitbox02.BTCResponse - (*ElectrumEncryptionKeyResponse)(nil), // 40: shiftcrypto.bitbox02.ElectrumEncryptionKeyResponse - (*CardanoResponse)(nil), // 41: shiftcrypto.bitbox02.CardanoResponse - (*BIP85Response)(nil), // 42: shiftcrypto.bitbox02.BIP85Response + (*BluetoothRequest)(nil), // 30: shiftcrypto.bitbox02.BluetoothRequest + (*DeviceInfoResponse)(nil), // 31: shiftcrypto.bitbox02.DeviceInfoResponse + (*PubResponse)(nil), // 32: shiftcrypto.bitbox02.PubResponse + (*BTCSignNextResponse)(nil), // 33: shiftcrypto.bitbox02.BTCSignNextResponse + (*ListBackupsResponse)(nil), // 34: shiftcrypto.bitbox02.ListBackupsResponse + (*CheckBackupResponse)(nil), // 35: shiftcrypto.bitbox02.CheckBackupResponse + (*PerformAttestationResponse)(nil), // 36: shiftcrypto.bitbox02.PerformAttestationResponse + (*CheckSDCardResponse)(nil), // 37: shiftcrypto.bitbox02.CheckSDCardResponse + (*ETHResponse)(nil), // 38: shiftcrypto.bitbox02.ETHResponse + (*RootFingerprintResponse)(nil), // 39: shiftcrypto.bitbox02.RootFingerprintResponse + (*BTCResponse)(nil), // 40: shiftcrypto.bitbox02.BTCResponse + (*ElectrumEncryptionKeyResponse)(nil), // 41: shiftcrypto.bitbox02.ElectrumEncryptionKeyResponse + (*CardanoResponse)(nil), // 42: shiftcrypto.bitbox02.CardanoResponse + (*BIP85Response)(nil), // 43: shiftcrypto.bitbox02.BIP85Response + (*BluetoothResponse)(nil), // 44: shiftcrypto.bitbox02.BluetoothResponse } var file_hww_proto_depIdxs = []int32{ 4, // 0: shiftcrypto.bitbox02.Request.device_name:type_name -> shiftcrypto.bitbox02.SetDeviceNameRequest @@ -1122,26 +1163,28 @@ var file_hww_proto_depIdxs = []int32{ 27, // 23: shiftcrypto.bitbox02.Request.electrum_encryption_key:type_name -> shiftcrypto.bitbox02.ElectrumEncryptionKeyRequest 28, // 24: shiftcrypto.bitbox02.Request.cardano:type_name -> shiftcrypto.bitbox02.CardanoRequest 29, // 25: shiftcrypto.bitbox02.Request.bip85:type_name -> shiftcrypto.bitbox02.BIP85Request - 1, // 26: shiftcrypto.bitbox02.Response.success:type_name -> shiftcrypto.bitbox02.Success - 0, // 27: shiftcrypto.bitbox02.Response.error:type_name -> shiftcrypto.bitbox02.Error - 30, // 28: shiftcrypto.bitbox02.Response.device_info:type_name -> shiftcrypto.bitbox02.DeviceInfoResponse - 31, // 29: shiftcrypto.bitbox02.Response.pub:type_name -> shiftcrypto.bitbox02.PubResponse - 32, // 30: shiftcrypto.bitbox02.Response.btc_sign_next:type_name -> shiftcrypto.bitbox02.BTCSignNextResponse - 33, // 31: shiftcrypto.bitbox02.Response.list_backups:type_name -> shiftcrypto.bitbox02.ListBackupsResponse - 34, // 32: shiftcrypto.bitbox02.Response.check_backup:type_name -> shiftcrypto.bitbox02.CheckBackupResponse - 35, // 33: shiftcrypto.bitbox02.Response.perform_attestation:type_name -> shiftcrypto.bitbox02.PerformAttestationResponse - 36, // 34: shiftcrypto.bitbox02.Response.check_sdcard:type_name -> shiftcrypto.bitbox02.CheckSDCardResponse - 37, // 35: shiftcrypto.bitbox02.Response.eth:type_name -> shiftcrypto.bitbox02.ETHResponse - 38, // 36: shiftcrypto.bitbox02.Response.fingerprint:type_name -> shiftcrypto.bitbox02.RootFingerprintResponse - 39, // 37: shiftcrypto.bitbox02.Response.btc:type_name -> shiftcrypto.bitbox02.BTCResponse - 40, // 38: shiftcrypto.bitbox02.Response.electrum_encryption_key:type_name -> shiftcrypto.bitbox02.ElectrumEncryptionKeyResponse - 41, // 39: shiftcrypto.bitbox02.Response.cardano:type_name -> shiftcrypto.bitbox02.CardanoResponse - 42, // 40: shiftcrypto.bitbox02.Response.bip85:type_name -> shiftcrypto.bitbox02.BIP85Response - 41, // [41:41] is the sub-list for method output_type - 41, // [41:41] is the sub-list for method input_type - 41, // [41:41] is the sub-list for extension type_name - 41, // [41:41] is the sub-list for extension extendee - 0, // [0:41] is the sub-list for field type_name + 30, // 26: shiftcrypto.bitbox02.Request.bluetooth:type_name -> shiftcrypto.bitbox02.BluetoothRequest + 1, // 27: shiftcrypto.bitbox02.Response.success:type_name -> shiftcrypto.bitbox02.Success + 0, // 28: shiftcrypto.bitbox02.Response.error:type_name -> shiftcrypto.bitbox02.Error + 31, // 29: shiftcrypto.bitbox02.Response.device_info:type_name -> shiftcrypto.bitbox02.DeviceInfoResponse + 32, // 30: shiftcrypto.bitbox02.Response.pub:type_name -> shiftcrypto.bitbox02.PubResponse + 33, // 31: shiftcrypto.bitbox02.Response.btc_sign_next:type_name -> shiftcrypto.bitbox02.BTCSignNextResponse + 34, // 32: shiftcrypto.bitbox02.Response.list_backups:type_name -> shiftcrypto.bitbox02.ListBackupsResponse + 35, // 33: shiftcrypto.bitbox02.Response.check_backup:type_name -> shiftcrypto.bitbox02.CheckBackupResponse + 36, // 34: shiftcrypto.bitbox02.Response.perform_attestation:type_name -> shiftcrypto.bitbox02.PerformAttestationResponse + 37, // 35: shiftcrypto.bitbox02.Response.check_sdcard:type_name -> shiftcrypto.bitbox02.CheckSDCardResponse + 38, // 36: shiftcrypto.bitbox02.Response.eth:type_name -> shiftcrypto.bitbox02.ETHResponse + 39, // 37: shiftcrypto.bitbox02.Response.fingerprint:type_name -> shiftcrypto.bitbox02.RootFingerprintResponse + 40, // 38: shiftcrypto.bitbox02.Response.btc:type_name -> shiftcrypto.bitbox02.BTCResponse + 41, // 39: shiftcrypto.bitbox02.Response.electrum_encryption_key:type_name -> shiftcrypto.bitbox02.ElectrumEncryptionKeyResponse + 42, // 40: shiftcrypto.bitbox02.Response.cardano:type_name -> shiftcrypto.bitbox02.CardanoResponse + 43, // 41: shiftcrypto.bitbox02.Response.bip85:type_name -> shiftcrypto.bitbox02.BIP85Response + 44, // 42: shiftcrypto.bitbox02.Response.bluetooth:type_name -> shiftcrypto.bitbox02.BluetoothResponse + 43, // [43:43] is the sub-list for method output_type + 43, // [43:43] is the sub-list for method input_type + 43, // [43:43] is the sub-list for extension type_name + 43, // [43:43] is the sub-list for extension extendee + 0, // [0:43] is the sub-list for field type_name } func init() { file_hww_proto_init() } @@ -1152,6 +1195,7 @@ func file_hww_proto_init() { file_common_proto_init() file_backup_commands_proto_init() file_bitbox02_system_proto_init() + file_bluetooth_proto_init() file_btc_proto_init() file_cardano_proto_init() file_eth_proto_init() @@ -1236,6 +1280,7 @@ func file_hww_proto_init() { (*Request_ElectrumEncryptionKey)(nil), (*Request_Cardano)(nil), (*Request_Bip85)(nil), + (*Request_Bluetooth)(nil), } file_hww_proto_msgTypes[3].OneofWrappers = []any{ (*Response_Success)(nil), @@ -1253,6 +1298,7 @@ func file_hww_proto_init() { (*Response_ElectrumEncryptionKey)(nil), (*Response_Cardano)(nil), (*Response_Bip85)(nil), + (*Response_Bluetooth)(nil), } type x struct{} out := protoimpl.TypeBuilder{ diff --git a/api/firmware/messages/hww.proto b/api/firmware/messages/hww.proto index 54c34f6..4088ae3 100644 --- a/api/firmware/messages/hww.proto +++ b/api/firmware/messages/hww.proto @@ -19,6 +19,7 @@ import "common.proto"; import "backup_commands.proto"; import "bitbox02_system.proto"; +import "bluetooth.proto"; import "btc.proto"; import "cardano.proto"; import "eth.proto"; @@ -67,6 +68,7 @@ message Request { ElectrumEncryptionKeyRequest electrum_encryption_key = 26; CardanoRequest cardano = 27; BIP85Request bip85 = 28; + BluetoothRequest bluetooth = 29; } } @@ -89,5 +91,6 @@ message Response { ElectrumEncryptionKeyResponse electrum_encryption_key = 14; CardanoResponse cardano = 15; BIP85Response bip85 = 16; + BluetoothResponse bluetooth = 17; } } diff --git a/cmd/bluetooth_upgrade/main.go b/cmd/bluetooth_upgrade/main.go new file mode 100644 index 0000000..9486478 --- /dev/null +++ b/cmd/bluetooth_upgrade/main.go @@ -0,0 +1,89 @@ +// Copyright 2025 Shift Crypto AG +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package main is a playground to play with the BitBox02 miniscript support. +package main + +import ( + "fmt" + "log" + "os" + + "github.com/BitBoxSwiss/bitbox02-api-go/api/common" + "github.com/BitBoxSwiss/bitbox02-api-go/api/firmware" + "github.com/BitBoxSwiss/bitbox02-api-go/api/firmware/mocks" + "github.com/BitBoxSwiss/bitbox02-api-go/communication/u2fhid" + "github.com/karalabe/hid" +) + +const ( + bitbox02VendorID = 0x03eb + bitbox02ProductID = 0x2403 + bitboxCMD = 0x80 + 0x40 + 0x01 + + HARDENED = 0x80000000 +) + +func errpanic(err error) { + if err != nil { + log.Fatalf("%+v", err) + } +} + +func isBitBox02(deviceInfo *hid.DeviceInfo) bool { + return (deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02Multi || + deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02BTCOnly || + deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02PlusMulti || + deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02PlusBTCOnly) && + deviceInfo.VendorID == bitbox02VendorID && + deviceInfo.ProductID == bitbox02ProductID && + (deviceInfo.UsagePage == 0xffff || deviceInfo.Interface == 0) +} + +func main() { + if len(os.Args) != 2 { + fmt.Println("Usage:", os.Args[0], "filename") + os.Exit(1) + } + filename := os.Args[1] + + firmwareBytes, err := os.ReadFile(filename) + errpanic(err) + + deviceInfo := func() *hid.DeviceInfo { + infos, err := hid.Enumerate(0, 0) + errpanic(err) + for idx := range infos { + di := &infos[idx] + if di.Serial == "" || di.Product == "" { + continue + } + if isBitBox02(di) { + return di + } + } + panic("could no find a bitbox02") + + }() + + hidDevice, err := deviceInfo.Open() + errpanic(err) + + comm := u2fhid.NewCommunication(hidDevice, bitboxCMD) + device := firmware.NewDevice(nil, nil, &mocks.Config{}, comm, &mocks.Logger{}) + errpanic(device.Init()) + device.ChannelHashVerify(true) + + errpanic(device.BluetoothUpgrade(firmwareBytes)) +}