Skip to content

Commit 9ec3ed8

Browse files
committed
Merge branch 'split-verif'
2 parents 6b2e124 + 58e37ff commit 9ec3ed8

19 files changed

+225
-578
lines changed

backend/coins/btc/account.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,10 @@ func (account *Account) VerifyAddress(addressID string) (bool, error) {
781781
return false, err
782782
}
783783
if canVerifyAddress {
784-
return true, keystore.VerifyAddress(address.Configuration, account.Coin())
784+
return true, keystore.VerifyAddressBTC(
785+
address.AccountConfiguration,
786+
address.Derivation,
787+
account.Coin())
785788
}
786789
return false, nil
787790
}

backend/coins/btc/addresses/address.go

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222
ourbtcutil "github.com/BitBoxSwiss/bitbox-wallet-app/backend/coins/btc/util"
2323
"github.com/BitBoxSwiss/bitbox-wallet-app/backend/signing"
2424
"github.com/BitBoxSwiss/bitbox-wallet-app/util/errp"
25+
"github.com/btcsuite/btcd/btcec/v2"
2526
"github.com/btcsuite/btcd/btcec/v2/schnorr"
2627
"github.com/btcsuite/btcd/btcutil"
2728
"github.com/btcsuite/btcd/chaincfg"
@@ -37,8 +38,9 @@ type AccountAddress struct {
3738

3839
// AccountConfiguration is the account level configuration from which this address was derived.
3940
AccountConfiguration *signing.Configuration
40-
// Configuration contains the absolute keypath and the extended public keys of the address.
41-
Configuration *signing.Configuration
41+
// publicKey is the public key of a single-sig address.
42+
publicKey *btcec.PublicKey
43+
Derivation types.Derivation
4244

4345
// redeemScript stores the redeem script of a BIP16 P2SH output or nil if address type is P2PKH.
4446
redeemScript []byte
@@ -54,25 +56,29 @@ func NewAccountAddress(
5456
log *logrus.Entry,
5557
) *AccountAddress {
5658

57-
var address btcutil.Address
58-
var redeemScript []byte
59-
configuration, err := accountConfiguration.Derive(
60-
signing.NewEmptyRelativeKeypath().
61-
Child(derivation.SimpleChainIndex(), signing.NonHardened).
62-
Child(derivation.AddressIndex, signing.NonHardened),
63-
)
64-
if err != nil {
65-
log.WithError(err).Panic("Failed to derive the configuration.")
66-
}
6759
log = log.WithFields(logrus.Fields{
6860
"accountConfiguration": accountConfiguration.String(),
6961
"change": derivation.Change,
7062
"addressIndex": derivation.AddressIndex,
7163
})
7264
log.Debug("Creating new account address")
7365

74-
publicKeyHash := btcutil.Hash160(configuration.PublicKey().SerializeCompressed())
75-
switch configuration.ScriptType() {
66+
var address btcutil.Address
67+
var redeemScript []byte
68+
relativeKeypath := signing.NewEmptyRelativeKeypath().
69+
Child(derivation.SimpleChainIndex(), signing.NonHardened).
70+
Child(derivation.AddressIndex, signing.NonHardened)
71+
derivedXpub, err := relativeKeypath.Derive(accountConfiguration.ExtendedPublicKey())
72+
if err != nil {
73+
log.WithError(err).Panic("Failed to derive xpub.")
74+
}
75+
publicKey, err := derivedXpub.ECPubKey()
76+
if err != nil {
77+
log.WithError(err).Panic("Failed to convert an extended public key to a normal public key.")
78+
}
79+
80+
publicKeyHash := btcutil.Hash160(publicKey.SerializeCompressed())
81+
switch accountConfiguration.ScriptType() {
7682
case signing.ScriptTypeP2PKH:
7783
address, err = btcutil.NewAddressPubKeyHash(publicKeyHash, net)
7884
if err != nil {
@@ -98,19 +104,20 @@ func NewAccountAddress(
98104
log.WithError(err).Panic("Failed to get p2wpkh addr. from publ. key hash.")
99105
}
100106
case signing.ScriptTypeP2TR:
101-
outputKey := txscript.ComputeTaprootKeyNoScript(configuration.PublicKey())
107+
outputKey := txscript.ComputeTaprootKeyNoScript(publicKey)
102108
address, err = btcutil.NewAddressTaproot(schnorr.SerializePubKey(outputKey), net)
103109
if err != nil {
104110
log.WithError(err).Panic("Failed to get p2tr addr")
105111
}
106112
default:
107-
log.Panic(fmt.Sprintf("Unrecognized script type: %s", configuration.ScriptType()))
113+
log.Panic(fmt.Sprintf("Unrecognized script type: %s", accountConfiguration.ScriptType()))
108114
}
109115

110116
return &AccountAddress{
111117
Address: address,
112118
AccountConfiguration: accountConfiguration,
113-
Configuration: configuration,
119+
publicKey: publicKey,
120+
Derivation: derivation,
114121
redeemScript: redeemScript,
115122
log: log,
116123
}
@@ -126,8 +133,8 @@ func (address *AccountAddress) ID() string {
126133
// - 32 byte x-only public key for p2tr
127134
// See https://github.com/bitcoin/bips/blob/master/bip-0352.mediawiki#user-content-Inputs_For_Shared_Secret_Derivation.
128135
func (address *AccountAddress) BIP352Pubkey() ([]byte, error) {
129-
publicKey := address.Configuration.PublicKey()
130-
switch address.Configuration.ScriptType() {
136+
publicKey := address.publicKey
137+
switch address.AccountConfiguration.ScriptType() {
131138
case signing.ScriptTypeP2PKH, signing.ScriptTypeP2WPKHP2SH, signing.ScriptTypeP2WPKH:
132139
return publicKey.SerializeCompressed(), nil
133140
case signing.ScriptTypeP2TR:
@@ -143,9 +150,11 @@ func (address *AccountAddress) EncodeForHumans() string {
143150
return address.EncodeAddress()
144151
}
145152

146-
// AbsoluteKeypath implements coin.AbsoluteKeypath.
153+
// AbsoluteKeypath implements accounts.Address.
147154
func (address *AccountAddress) AbsoluteKeypath() signing.AbsoluteKeypath {
148-
return address.Configuration.AbsoluteKeypath()
155+
return address.AccountConfiguration.AbsoluteKeypath().
156+
Child(address.Derivation.SimpleChainIndex(), false).
157+
Child(address.Derivation.AddressIndex, false)
149158
}
150159

151160
// PubkeyScript returns the pubkey script of this address. Use this in a tx output to receive funds.
@@ -167,7 +176,7 @@ func (address *AccountAddress) PubkeyScriptHashHex() blockchain.ScriptHashHex {
167176
// calculating the hash to be signed in a transaction. This info is needed when trying to spend
168177
// from this address.
169178
func (address *AccountAddress) ScriptForHashToSign() (bool, []byte) {
170-
switch address.Configuration.ScriptType() {
179+
switch address.AccountConfiguration.ScriptType() {
171180
case signing.ScriptTypeP2PKH:
172181
return false, address.PubkeyScript()
173182
case signing.ScriptTypeP2WPKHP2SH:
@@ -185,8 +194,8 @@ func (address *AccountAddress) ScriptForHashToSign() (bool, []byte) {
185194
func (address *AccountAddress) SignatureScript(
186195
signature types.Signature,
187196
) ([]byte, wire.TxWitness) {
188-
publicKey := address.Configuration.PublicKey()
189-
switch address.Configuration.ScriptType() {
197+
publicKey := address.publicKey
198+
switch address.AccountConfiguration.ScriptType() {
190199
case signing.ScriptTypeP2PKH:
191200
signatureScript, err := txscript.NewScriptBuilder().
192201
AddData(append(signature.SerializeDER(), byte(txscript.SigHashAll))).
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// Copyright 2025 Shift Crypto AG
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package addresses
16+
17+
import "github.com/btcsuite/btcd/btcec/v2"
18+
19+
// TstPublicKey exports the publickey for use in unit tests.
20+
func (address *AccountAddress) TstPublicKey() *btcec.PublicKey {
21+
return address.publicKey
22+
}

backend/coins/btc/addresses/address_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func (s *addressTestSuite) TestNewAddress() {
5757
Child(10, false).
5858
Child(0, false).
5959
Child(0, false)
60-
s.Require().Equal(expectedKeypath, s.address.Configuration.AbsoluteKeypath())
60+
s.Require().Equal(expectedKeypath, s.address.AbsoluteKeypath())
6161
s.Require().Equal("moTM88EgqzATgCjSrcNfahXaT9uCy3FHh3", s.address.EncodeAddress())
6262
s.Require().True(s.address.IsForNet(net))
6363
}

backend/coins/btc/addresses/addresschain_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,8 @@ func (s *addressChainTestSuite) TestEnsureAddresses() {
142142
}
143143
s.Require().Len(newAddresses, s.gapLimit)
144144
for index, address := range newAddresses {
145-
s.Require().Equal(uint32(index), address.Configuration.AbsoluteKeypath().ToUInt32()[1])
146-
s.Require().Equal(getPubKey(index), address.Configuration.PublicKey())
145+
s.Require().Equal(uint32(index), address.AbsoluteKeypath().ToUInt32()[1])
146+
s.Require().Equal(getPubKey(index), address.TstPublicKey())
147147
}
148148
// Address statuses are still the same, so calling it again won't produce more addresses.
149149
addrs, err := s.addresses.EnsureAddresses()
@@ -157,7 +157,7 @@ func (s *addressChainTestSuite) TestEnsureAddresses() {
157157
moreAddresses, err := s.addresses.EnsureAddresses()
158158
s.Require().NoError(err)
159159
s.Require().Len(moreAddresses, s.gapLimit)
160-
s.Require().Equal(uint32(s.gapLimit), moreAddresses[0].Configuration.AbsoluteKeypath().ToUInt32()[1])
160+
s.Require().Equal(uint32(s.gapLimit), moreAddresses[0].Derivation.AddressIndex)
161161

162162
// Repeating it does not add more the unused addresses are the same.
163163
addrs, err = s.addresses.EnsureAddresses()

backend/coins/btc/handlers/handlers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ func (handlers *Handlers) getUTXOs(*http.Request) (interface{}, error) {
380380
"txOutput": output.OutPoint.Index,
381381
"amount": handlers.formatBTCAmountAsJSON(btcutil.Amount(output.TxOut.Value), false),
382382
"address": address,
383-
"scriptType": output.Address.Configuration.ScriptType(),
383+
"scriptType": output.Address.AccountConfiguration.ScriptType(),
384384
"note": handlers.account.TxNote(output.OutPoint.Hash.String()),
385385
"addressReused": addressReused,
386386
"isChange": output.IsChange,

backend/coins/btc/maketx/maketx.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ func toInputConfigurations(
127127
) []*signing.Configuration {
128128
inputConfigurations := make([]*signing.Configuration, len(selectedOutPoints))
129129
for i, outPoint := range selectedOutPoints {
130-
inputConfigurations[i] = spendableOutputs[outPoint].Address.Configuration
130+
inputConfigurations[i] = spendableOutputs[outPoint].Address.AccountConfiguration
131131
}
132132
return inputConfigurations
133133
}
@@ -277,7 +277,7 @@ func NewTx(
277277
}
278278
changeAmount := selectedOutputsSum - targetAmount - maxRequiredFee
279279
changeIsDust := isDustAmount(
280-
changeAmount, len(changePKScript), changeAddress.Configuration, feePerKb)
280+
changeAmount, len(changePKScript), changeAddress.AccountConfiguration, feePerKb)
281281
finalFee := maxRequiredFee
282282
if changeIsDust {
283283
log.Info("change is dust")

backend/coins/btc/maketx/txsize_internal_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func testEstimateTxSize(
9292
Witness: witness,
9393
Sequence: 0,
9494
})
95-
inputConfigurations = append(inputConfigurations, inputAddress.Configuration)
95+
inputConfigurations = append(inputConfigurations, inputAddress.AccountConfiguration)
9696
}
9797
}
9898
changePkScriptSize := 0
@@ -119,8 +119,8 @@ func TestSigScriptWitnessSize(t *testing.T) {
119119
// Test all singlesig configurations.
120120
for _, scriptType := range scriptTypes {
121121
address := addressesTest.GetAddress(scriptType)
122-
t.Run(address.Configuration.String(), func(t *testing.T) {
123-
sigScriptSize, witnessSize := sigScriptWitnessSize(address.Configuration)
122+
t.Run(address.AccountConfiguration.String(), func(t *testing.T) {
123+
sigScriptSize, witnessSize := sigScriptWitnessSize(address.AccountConfiguration)
124124
sigScript, witness := address.SignatureScript(sig)
125125
require.Equal(t, len(sigScript), sigScriptSize)
126126
if witness != nil {

backend/coins/btc/transaction.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func (account *Account) pickChangeAddress(utxos map[wire.OutPoint]maketx.UTXO) (
104104
if p2trIndex >= 0 {
105105
// Check if there is at least one taproot UTXO.
106106
for _, utxo := range utxos {
107-
if utxo.Address.Configuration.ScriptType() == signing.ScriptTypeP2TR {
107+
if utxo.Address.AccountConfiguration.ScriptType() == signing.ScriptTypeP2TR {
108108
// Found a taproot UTXO.
109109
unusedAddresses, err := account.subaccounts[p2trIndex].changeAddresses.GetUnused()
110110
if err != nil {
@@ -211,7 +211,7 @@ func (account *Account) newTx(args *accounts.TxProposalArgs) (
211211
if err != nil {
212212
return nil, nil, err
213213
}
214-
account.log.Infof("Change address script type: %s", changeAddress.Configuration.ScriptType())
214+
account.log.Infof("Change address script type: %s", changeAddress.AccountConfiguration.ScriptType())
215215
txProposal, err = maketx.NewTx(
216216
account.coin,
217217
wireUTXO,

backend/coins/btc/transaction_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ func TestGetFeePerKb(t *testing.T) {
167167
func utxo(scriptType signing.ScriptType) maketx.UTXO {
168168
return maketx.UTXO{
169169
Address: &addresses.AccountAddress{
170-
Configuration: &signing.Configuration{
170+
AccountConfiguration: &signing.Configuration{
171171
BitcoinSimple: &signing.BitcoinSimple{
172172
ScriptType: scriptType,
173173
},

backend/coins/eth/account.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,7 @@ func (account *Account) VerifyAddress(addressID string) (bool, error) {
822822
return false, err
823823
}
824824
if canVerifyAddress {
825-
return true, keystore.VerifyAddress(account.signingConfiguration, account.Coin())
825+
return true, keystore.VerifyAddressETH(account.signingConfiguration, account.Coin())
826826
}
827827
return false, nil
828828
}

0 commit comments

Comments
 (0)