Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api/firmware/messages/antiklepto.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions api/firmware/messages/backup_commands.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions api/firmware/messages/bitbox02_system.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions api/firmware/messages/bluetooth.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

298 changes: 234 additions & 64 deletions api/firmware/messages/btc.pb.go

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions api/firmware/messages/btc.proto
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,22 @@ message BTCPaymentRequestRequest {
message TextMemo {
string note = 1;
}
message CoinPurchaseMemo {
uint32 coin_type = 1; // SLIP-44 coin type
string amount = 2; // Human-readable amount (e.g. "0.25 ETH")
string address = 3; // Address to send the purchased coins to
// Derivation info for verifying address ownership.
// NOT part of the SLIP-24 sighash.
message EthAddressDerivation {
repeated uint32 keypath = 1; // Keypath to the address
}
oneof address_derivation {
EthAddressDerivation eth = 4;
}
}
oneof memo {
TextMemo text_memo = 1;
CoinPurchaseMemo coin_purchase_memo = 2;
}
}

Expand Down
4 changes: 2 additions & 2 deletions api/firmware/messages/cardano.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions api/firmware/messages/common.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions api/firmware/messages/eth.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions api/firmware/messages/hww.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions api/firmware/messages/keystore.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions api/firmware/messages/mnemonic.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions api/firmware/messages/perform_attestation.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions api/firmware/messages/system.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions api/firmware/paymentrequests.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ func ComputePaymentRequestSighash(
case *messages.BTCPaymentRequestRequest_Memo_TextMemo_:
_ = binary.Write(sighash, binary.LittleEndian, uint32(1))
hashDataLenPrefixed(sighash, []byte(m.TextMemo.Note))
case *messages.BTCPaymentRequestRequest_Memo_CoinPurchaseMemo_:
// CoinPurchaseMemo type = 3 in SLIP-24 (not the protobuf field number!)
_ = binary.Write(sighash, binary.LittleEndian, uint32(3))
// Hash the SLIP-24 fields: coin_type, amount, address
_ = binary.Write(sighash, binary.LittleEndian, m.CoinPurchaseMemo.CoinType)
hashDataLenPrefixed(sighash, []byte(m.CoinPurchaseMemo.Amount))
hashDataLenPrefixed(sighash, []byte(m.CoinPurchaseMemo.Address))
// Note: address_derivation field is NOT hashed.
default:
return nil, errors.New("unsupported memo type")
}
Expand Down
48 changes: 48 additions & 0 deletions api/firmware/paymentrequests_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package firmware
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

License header missing


import (
"encoding/hex"
"testing"

"github.com/BitBoxSwiss/bitbox02-api-go/api/firmware/messages"
"github.com/stretchr/testify/require"
)

// TODO: Add integration test for CoinPurchaseMemo once the firmware UI is implemented.
// potentially in psbt_test.go
Comment on lines +11 to +12
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please no TODOs in code, they very often get missed or stay forever. Keep track of TODOs in issue trackers instead.

In this case it might be most practical to wait with review&merge of this PR until this can be addressed.


func TestComputePaymentRequestSighash_CoinPurchaseMemo(t *testing.T) {
// This test verifies that our Go sighash computation matches the firmware's Rust implementation.
// The expected hash comes from a firmware test.
paymentRequest := &messages.BTCPaymentRequestRequest{
RecipientName: "Merchant",
Memos: []*messages.BTCPaymentRequestRequest_Memo{
{
Memo: &messages.BTCPaymentRequestRequest_Memo_CoinPurchaseMemo_{
CoinPurchaseMemo: &messages.BTCPaymentRequestRequest_Memo_CoinPurchaseMemo{
CoinType: 60, // Ethereum
Amount: "0.25 ETH",
Address: "0xabc1234567890",
// address_derivation is intentionally nil, since it's not part of the sighash
},
},
},
},
Nonce: []byte{},
TotalAmount: 123456,
Signature: []byte{},
}

sighash, err := ComputePaymentRequestSighash(
paymentRequest,
1, // SLIP-44 coin type for Bitcoin Testnet
123456,
"tb1q2q0j6gmfxynj40p0kxsr9jkagcvgpuqvqynnup",
)
require.NoError(t, err)

expectedHash := "1806caf7c518aad69eb38f25fd418d507c6a3e01719a7d77be94cd50a2790872"
actualHash := hex.EncodeToString(sighash)

require.Equal(t, expectedHash, actualHash, "Sighash mismatch: Go implementation doesn't match firmware")
}
Loading