Skip to content

Commit 9eeea4b

Browse files
committed
common: add product strings for BitBox02Plus
Allows the BitBoxApp to detect the product. These might be placeholder values to be renamed later. The existing product names are prefixed with BitBox02 for disambiguation. Standard is renamed to Multi, as that's what the product is actually named. HID is renamed to Device, as the string is not only used in HID descriptors, but also in the Bluetooth characteristic.
1 parent 0e6a62c commit 9eeea4b

File tree

10 files changed

+88
-33
lines changed

10 files changed

+88
-33
lines changed

api/bootloader/device.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,10 @@ const (
4444
)
4545

4646
var sigDataMagic = map[common.Product]uint32{
47-
common.ProductBitBox02Multi: 0x653f362b,
48-
common.ProductBitBox02BTCOnly: 0x11233B0B,
47+
common.ProductBitBox02Multi: 0x653f362b,
48+
common.ProductBitBox02BTCOnly: 0x11233B0B,
49+
common.ProductBitBox02PlusMulti: 0x5b648ceb,
50+
common.ProductBitBox02PlusBTCOnly: 0x48714774,
4951
}
5052

5153
// Communication contains functions needed to communicate with the device.

api/bootloader/device_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ func testConfigurations(t *testing.T, run func(*testing.T, *testEnv)) {
5858
for _, product := range []common.Product{
5959
common.ProductBitBox02Multi,
6060
common.ProductBitBox02BTCOnly,
61+
common.ProductBitBox02PlusMulti,
62+
common.ProductBitBox02PlusBTCOnly,
6163
} {
6264
var env testEnv
6365
env.product = product

api/common/common.go

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// Copyright 2018-2019 Shift Cryptosecurity AG
2+
// Copyright 2025 Shift Crypto AG
23
//
34
// Licensed under the Apache License, Version 2.0 (the "License");
45
// you may not use this file except in compliance with the License.
@@ -27,28 +28,57 @@ const (
2728
// ProductBitBox02BTCOnly is the btc-only edition of the BitBox02, restricting functionality to
2829
// Bitcoin.
2930
ProductBitBox02BTCOnly Product = "bitbox02-btconly"
31+
32+
// ProductBitBox02PlusMulti is the multi edition of the BitBox02 Plus.
33+
ProductBitBox02PlusMulti Product = "bitbox02-plus-multi"
34+
// ProductBitBox02PlusBTCOnly is the btc-only edition of the BitBox02 Plus, restricting
35+
// functionality to Bitcoin.
36+
ProductBitBox02PlusBTCOnly Product = "bitbox02-plus-btconly"
3037
)
3138

3239
const (
33-
// FirmwareHIDProductStringStandard is the hid product string of the standard edition firmware.
34-
FirmwareHIDProductStringStandard = "BitBox02"
35-
// FirmwareHIDProductStringBTCOnly is the hid product string of the btc-only edition firmware.
36-
FirmwareHIDProductStringBTCOnly = "BitBox02BTC"
37-
38-
// BootloaderHIDProductStringStandard is the hid product string of the standard edition bootloader.
39-
BootloaderHIDProductStringStandard = "bb02-bootloader"
40-
// BootloaderHIDProductStringBTCOnly is the hid product string of the btc-only edition bootloader.
41-
BootloaderHIDProductStringBTCOnly = "bb02btc-bootloader"
40+
// FirmwareDeviceProductStringBitBox02Multi is the product string of the BitBox02 multi edition
41+
// firmware. It appears in the HID descriptor.
42+
FirmwareDeviceProductStringBitBox02Multi = "BitBox02"
43+
// FirmwareDeviceProductStringBitBox02BTCOnly is the product string of the BitBox02 btc-only
44+
// edition firmware. It appears in the HID descriptor.
45+
FirmwareDeviceProductStringBitBox02BTCOnly = "BitBox02BTC"
46+
47+
// BootloaderDeviceProductStringBitBox02Multi is the product string of the BitBox02 multi
48+
// edition bootloader. It appears in the HID descriptor.
49+
BootloaderDeviceProductStringBitBox02Multi = "bb02-bootloader"
50+
// BootloaderDeviceProductStringBitBox02BTCOnly is the product string of the BitBox02 btc-only
51+
// edition bootloader. It appears in the HID descriptor.
52+
BootloaderDeviceProductStringBitBox02BTCOnly = "bb02btc-bootloader"
53+
54+
// FirmwareDeviceProductStringBitBox02PlusMulti the product string of the "BitBox02 Plus" multi
55+
// edition firmware. It appears in the HID descriptor and the Bluetooth characteristic.
56+
FirmwareDeviceProductStringBitBox02PlusMulti = "bb02p-multi"
57+
// FirmwareDeviceProductStringBitBox02PlusBTCOnly is the product string of the "BitBox02 Plus"
58+
// btc-only edition firmware. It appears in the HID descriptor and the Bluetooth characteristic.
59+
FirmwareDeviceProductStringBitBox02PlusBTCOnly = "bb02p-btconly"
60+
61+
// BootloaderDeviceProductStringBitBox02Multi is the product string of the "BitBox02 Plus" multi
62+
// edition bootloader. It appears in the HID descriptor and the Bluetooth characteristic.
63+
BootloaderDeviceProductStringBitBox02PlusMulti = "bb02p-bl-multi"
64+
// BootloaderDeviceProductStringBitBox02BTCOnly is the product string of the "BitBox02 Plus"
65+
// btc-only edition bootloader. It appears in the HID descriptor and the Bluetooth
66+
// characteristic.
67+
BootloaderDeviceProductStringBitBox02PlusBTCOnly = "bb02p-bl-btconly"
4268
)
4369

44-
// ProductFromHIDProductString returns the firmware or bootloader product based on the usb HID
70+
// ProductFromDeviceProductString returns the firmware or bootloader product based on the usb Device
4571
// product string. Returns an error for an invalid/unrecognized product string.
46-
func ProductFromHIDProductString(productString string) (Product, error) {
72+
func ProductFromDeviceProductString(productString string) (Product, error) {
4773
switch productString {
48-
case FirmwareHIDProductStringStandard, BootloaderHIDProductStringStandard:
74+
case FirmwareDeviceProductStringBitBox02Multi, BootloaderDeviceProductStringBitBox02Multi:
4975
return ProductBitBox02Multi, nil
50-
case FirmwareHIDProductStringBTCOnly, BootloaderHIDProductStringBTCOnly:
76+
case FirmwareDeviceProductStringBitBox02BTCOnly, BootloaderDeviceProductStringBitBox02BTCOnly:
5177
return ProductBitBox02BTCOnly, nil
78+
case FirmwareDeviceProductStringBitBox02PlusMulti, BootloaderDeviceProductStringBitBox02PlusMulti:
79+
return ProductBitBox02PlusMulti, nil
80+
case FirmwareDeviceProductStringBitBox02PlusBTCOnly, BootloaderDeviceProductStringBitBox02PlusBTCOnly:
81+
return ProductBitBox02PlusBTCOnly, nil
5282
default:
5383
return "", errp.New("unrecognized product")
5484
}

api/firmware/device.go

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,16 @@ func (device *Device) info() (*semver.SemVer, common.Product, bool, error) {
167167
platformByte, response := response[0], response[1:]
168168
editionByte, response := response[0], response[1:]
169169
const platformBitBox02 = 0x00
170+
const platformBitBox02Plus = 0x02
170171
products := map[byte]map[byte]common.Product{
171172
platformBitBox02: {
172173
0x00: common.ProductBitBox02Multi,
173174
0x01: common.ProductBitBox02BTCOnly,
174175
},
176+
platformBitBox02Plus: {
177+
0x00: common.ProductBitBox02PlusMulti,
178+
0x01: common.ProductBitBox02PlusBTCOnly,
179+
},
175180
}
176181
editions, ok := products[platformByte]
177182
if !ok {
@@ -211,8 +216,8 @@ func (device *Device) inferVersionAndProduct() error {
211216
if device.version == nil {
212217
version, product, _, err := device.info()
213218
if err != nil {
214-
return errp.New(
215-
"OP_INFO unavailable; need to provide version and product via the USB HID descriptor")
219+
return errp.Newf(
220+
"OP_INFO unavailable; need to provide version and product via the USB HID descriptor.")
216221
}
217222
device.log.Info(fmt.Sprintf("OP_INFO: version=%s, product=%s", version, product))
218223

@@ -326,9 +331,13 @@ func (device *Device) Product() common.Product {
326331
return *device.product
327332
}
328333

334+
func (device *Device) isMultiEdition() bool {
335+
return *device.product == common.ProductBitBox02Multi || *device.product == common.ProductBitBox02PlusMulti
336+
}
337+
329338
// SupportsETH returns true if ETH is supported by the device api.
330339
func (device *Device) SupportsETH(chainID uint64) bool {
331-
if *device.product != common.ProductBitBox02Multi {
340+
if !device.isMultiEdition() {
332341
return false
333342
}
334343
if device.version.AtLeast(semver.NewSemVer(9, 10, 0)) {
@@ -348,7 +357,7 @@ func (device *Device) SupportsETH(chainID uint64) bool {
348357
// For now, this list only contains tokens relevant to the BitBoxApp, otherwise the bitbox02-api-js
349358
// library size would blow up. TODO: move this to the bitbox-wallet-app repo.
350359
func (device *Device) SupportsERC20(contractAddress string) bool {
351-
if *device.product != common.ProductBitBox02Multi {
360+
if !device.isMultiEdition() {
352361
return false
353362
}
354363
if device.version.AtLeast(semver.NewSemVer(4, 0, 0)) {
@@ -384,5 +393,5 @@ func (device *Device) SupportsERC20(contractAddress string) bool {
384393

385394
// SupportsLTC returns true if LTC is supported by the device api.
386395
func (device *Device) SupportsLTC() bool {
387-
return *device.product == common.ProductBitBox02Multi
396+
return device.isMultiEdition()
388397
}

api/firmware/device_test.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,10 @@ func newDevice(
371371

372372
{ // Test upgrade required and actual upgrade, which for the firmware only means to reboot into the bootloader.
373373
lowestSupported := map[common.Product]*semver.SemVer{
374-
common.ProductBitBox02Multi: lowestSupportedFirmwareVersion,
375-
common.ProductBitBox02BTCOnly: lowestSupportedFirmwareVersionBTCOnly,
374+
common.ProductBitBox02Multi: lowestSupportedFirmwareVersion,
375+
common.ProductBitBox02BTCOnly: lowestSupportedFirmwareVersionBTCOnly,
376+
common.ProductBitBox02PlusMulti: lowestSupportedFirmwareVersion,
377+
common.ProductBitBox02PlusBTCOnly: lowestSupportedFirmwareVersionBTCOnly,
376378
}
377379
lowestSupportedFirmwareVersion, ok := lowestSupported[product]
378380
require.True(t, ok)
@@ -453,6 +455,8 @@ func testConfigurations(t *testing.T, run func(*testing.T, *testEnv)) {
453455
products := []common.Product{
454456
common.ProductBitBox02Multi,
455457
common.ProductBitBox02BTCOnly,
458+
common.ProductBitBox02PlusMulti,
459+
common.ProductBitBox02PlusBTCOnly,
456460
}
457461
for _, version := range versions {
458462
for _, product := range products {

api/firmware/pairing.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,9 @@ func (device *Device) ChannelHashVerify(ok bool) {
157157
_ = device.config.AddDeviceStaticPubkey(device.deviceNoiseStaticPubkey)
158158
requireUpgrade := false
159159
switch *device.product {
160-
case common.ProductBitBox02Multi:
160+
case common.ProductBitBox02Multi, common.ProductBitBox02PlusMulti:
161161
requireUpgrade = !device.version.AtLeast(lowestSupportedFirmwareVersion)
162-
case common.ProductBitBox02BTCOnly:
162+
case common.ProductBitBox02BTCOnly, common.ProductBitBox02PlusBTCOnly:
163163
requireUpgrade = !device.version.AtLeast(lowestSupportedFirmwareVersionBTCOnly)
164164
default:
165165
device.log.Error(fmt.Sprintf("unrecognized product: %s", *device.product), nil)

cmd/bootloader/main.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,10 @@ func errpanic(err error) {
4242
}
4343

4444
func isBitBox02Bootloader(deviceInfo *hid.DeviceInfo) bool {
45-
return (deviceInfo.Product == common.BootloaderHIDProductStringStandard ||
46-
deviceInfo.Product == common.BootloaderHIDProductStringBTCOnly) &&
45+
return (deviceInfo.Product == common.BootloaderDeviceProductStringBitBox02Multi ||
46+
deviceInfo.Product == common.BootloaderDeviceProductStringBitBox02BTCOnly ||
47+
deviceInfo.Product == common.BootloaderDeviceProductStringBitBox02PlusMulti ||
48+
deviceInfo.Product == common.BootloaderDeviceProductStringBitBox02PlusBTCOnly) &&
4749
deviceInfo.VendorID == bitbox02VendorID &&
4850
deviceInfo.ProductID == bitbox02ProductID &&
4951
(deviceInfo.UsagePage == 0xffff || deviceInfo.Interface == 0)
@@ -84,7 +86,7 @@ func main() {
8486
comm := u2fhid.NewCommunication(hidDevice, bitbox02BootloaderCMD)
8587
version, err := parseVersion(deviceInfo.Serial)
8688
errpanic(err)
87-
product, err := common.ProductFromHIDProductString(deviceInfo.Product)
89+
product, err := common.ProductFromDeviceProductString(deviceInfo.Product)
8890
errpanic(err)
8991
device := bootloader.NewDevice(version, product, comm, func(*bootloader.Status) {})
9092
firmwareVersion, signingPubkeysVersion, err := device.Versions()

cmd/miniscript/main.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,10 @@ func errpanic(err error) {
5656
}
5757

5858
func isBitBox02(deviceInfo *hid.DeviceInfo) bool {
59-
return (deviceInfo.Product == common.FirmwareHIDProductStringStandard ||
60-
deviceInfo.Product == common.FirmwareHIDProductStringBTCOnly) &&
59+
return (deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02Multi ||
60+
deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02BTCOnly ||
61+
deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02PlusMulti ||
62+
deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02PlusBTCOnly) &&
6163
deviceInfo.VendorID == bitbox02VendorID &&
6264
deviceInfo.ProductID == bitbox02ProductID &&
6365
(deviceInfo.UsagePage == 0xffff || deviceInfo.Interface == 0)

cmd/paymentrequest/main.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,10 @@ func errpanic(err error) {
5858
}
5959

6060
func isBitBox02(deviceInfo *hid.DeviceInfo) bool {
61-
return (deviceInfo.Product == common.FirmwareHIDProductStringStandard ||
62-
deviceInfo.Product == common.FirmwareHIDProductStringBTCOnly) &&
61+
return (deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02Multi ||
62+
deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02BTCOnly ||
63+
deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02PlusMulti ||
64+
deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02PlusBTCOnly) &&
6365
deviceInfo.VendorID == bitbox02VendorID &&
6466
deviceInfo.ProductID == bitbox02ProductID &&
6567
(deviceInfo.UsagePage == 0xffff || deviceInfo.Interface == 0)

cmd/playground/main.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,10 @@ func errpanic(err error) {
4646
}
4747

4848
func isBitBox02(deviceInfo *hid.DeviceInfo) bool {
49-
return (deviceInfo.Product == common.FirmwareHIDProductStringStandard ||
50-
deviceInfo.Product == common.FirmwareHIDProductStringBTCOnly) &&
49+
return (deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02Multi ||
50+
deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02BTCOnly ||
51+
deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02PlusMulti ||
52+
deviceInfo.Product == common.FirmwareDeviceProductStringBitBox02PlusBTCOnly) &&
5153
deviceInfo.VendorID == bitbox02VendorID &&
5254
deviceInfo.ProductID == bitbox02ProductID &&
5355
(deviceInfo.UsagePage == 0xffff || deviceInfo.Interface == 0)

0 commit comments

Comments
 (0)