Skip to content

Commit 4fcd611

Browse files
committed
cmd/paymentrequet: dynamically sign the payment request
Easier to mess with the example.
1 parent 383ad4b commit 4fcd611

File tree

1 file changed

+59
-3
lines changed

1 file changed

+59
-3
lines changed

cmd/paymentrequest/main.go

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,22 @@
1616
package main
1717

1818
import (
19+
"crypto/sha256"
20+
"encoding/binary"
1921
"encoding/hex"
22+
"errors"
2023
"fmt"
24+
"hash"
2125
"log"
2226

2327
"github.com/BitBoxSwiss/bitbox02-api-go/api/common"
2428
"github.com/BitBoxSwiss/bitbox02-api-go/api/firmware"
2529
"github.com/BitBoxSwiss/bitbox02-api-go/api/firmware/messages"
2630
"github.com/BitBoxSwiss/bitbox02-api-go/api/firmware/mocks"
2731
"github.com/BitBoxSwiss/bitbox02-api-go/communication/u2fhid"
32+
"github.com/btcsuite/btcd/btcec/v2"
33+
"github.com/btcsuite/btcd/btcec/v2/ecdsa"
34+
"github.com/btcsuite/btcd/wire"
2835
"github.com/karalabe/usb"
2936
)
3037

@@ -58,6 +65,47 @@ func isBitBox02(deviceInfo *usb.DeviceInfo) bool {
5865
(deviceInfo.UsagePage == 0xffff || deviceInfo.Interface == 0)
5966
}
6067

68+
func hashDataLenPrefixed(hasher hash.Hash, data []byte) {
69+
_ = wire.WriteVarInt(hasher, 0, uint64(len(data)))
70+
hasher.Write(data)
71+
}
72+
73+
func computeSighash(paymentRequest *messages.BTCPaymentRequestRequest, slip44 uint32, outputValue uint64, outputAddress string) ([]byte, error) {
74+
sighash := sha256.New()
75+
76+
// versionMagic
77+
sighash.Write([]byte("SL\x00\x24"))
78+
79+
// nonce
80+
hashDataLenPrefixed(sighash, paymentRequest.Nonce)
81+
82+
// recipientName
83+
hashDataLenPrefixed(sighash, []byte(paymentRequest.RecipientName))
84+
85+
// memos
86+
_ = wire.WriteVarInt(sighash, 0, uint64(len(paymentRequest.Memos)))
87+
for _, memo := range paymentRequest.Memos {
88+
switch m := memo.Memo.(type) {
89+
case *messages.BTCPaymentRequestRequest_Memo_TextMemo_:
90+
_ = binary.Write(sighash, binary.LittleEndian, uint32(1))
91+
hashDataLenPrefixed(sighash, []byte(m.TextMemo.Note))
92+
default:
93+
return nil, errors.New("unsupported memo type")
94+
}
95+
}
96+
97+
// coinType
98+
_ = binary.Write(sighash, binary.LittleEndian, slip44)
99+
100+
// outputsHash (only one output for now)
101+
outputHasher := sha256.New()
102+
_ = binary.Write(outputHasher, binary.LittleEndian, outputValue)
103+
hashDataLenPrefixed(outputHasher, []byte(outputAddress))
104+
sighash.Write(outputHasher.Sum(nil))
105+
106+
return sighash.Sum(nil), nil
107+
}
108+
61109
func main() {
62110
deviceInfo := func() *usb.DeviceInfo {
63111
infos, err := usb.EnumerateHid(0, 0)
@@ -90,7 +138,7 @@ func main() {
90138
value := uint64(123456)
91139
paymentRequestIndex := uint32(0)
92140

93-
// Manually created. To test with a real device, modify and compile/use a firmware where "Test
141+
// To test with a real device, modify and compile/use a firmware where "Test
94142
// Merchant" (private key "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") is included in the identities in
95143
// payment_request.rs.
96144
paymentRequest := &messages.BTCPaymentRequestRequest{
@@ -99,16 +147,24 @@ func main() {
99147
{
100148
Memo: &messages.BTCPaymentRequestRequest_Memo_TextMemo_{
101149
TextMemo: &messages.BTCPaymentRequestRequest_Memo_TextMemo{
102-
Note: "TextMemo",
150+
Note: "TextMemo line1\nTextMemo line2",
103151
},
104152
},
105153
},
106154
},
107155
Nonce: nil,
108156
TotalAmount: value,
109-
Signature: unhex("b719cf98cc8a0f9191d4be1a6609037b5b084674d8e64b13199408813459a1b3033ff58c6468b35acc4ded661c8e23348823887046c778e6eba2e5b9586b9a25"),
110157
}
111158

159+
// Sign the payment request.
160+
sighash, err := computeSighash(paymentRequest, 1, value, "tb1q2q0j6gmfxynj40p0kxsr9jkagcvgpuqvqynnup")
161+
errpanic(err)
162+
privKey, _ := btcec.PrivKeyFromBytes([]byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"))
163+
errpanic(err)
164+
signature, err := ecdsa.SignCompact(privKey, sighash, true)
165+
errpanic(err)
166+
paymentRequest.Signature = signature[1:]
167+
112168
_, err = device.BTCSign(
113169
messages.BTCCoin_TBTC,
114170
[]*messages.BTCScriptConfigWithKeypath{

0 commit comments

Comments
 (0)