mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-05-23 07:16:47 +00:00

* Naive bip39 with address reuse * Avoid address reuse in libkaspawallet * Add wallet daemon * Use daemon everywhere * Add forceOverride * Make CreateUnsignedTransaction endpoint receive amount in sompis * Collect close UTXOs * Filter out non-spendable UTXOs from selectUTXOs * Use different paths for multisig and non multisig * Fix tests to use non zero path * Fix multisig cosigner index detection * Add comments * Fix dump_unencrypted_data.go according to bip39 and bip32 * Fix wrong derivation path for multisig on wallet creation * Remove IsSynced endpoint and add validation if wallet is synced for the relevant endpoints * Rename server address to daemon address * Fix capacity for extendedPublicKeys * Use ReadBytes instead of ReadLine * Add validation when importing * Increment before using index value, and use it as is * Save keys file exactly where needed * Use %+v printErrorAndExit * Remove redundant consts * Rnemae collectCloseUTXOs and collectFarUTXOs * Move typedefs around * Add comment to addressesToQuery * Update collectUTXOsFromRecentAddresses comment about locks * Split collectUTXOs to small functions * Add sanity check * Add addEntryToUTXOSet function * Change validateIsSynced to isSynced * Simplify createKeyPairsFromFunction logic * Rename .Sync() to .Save() * Fix typo * Create bip39BitSize const * Add consts to purposes * Add multisig check for 'send' * Rename updatedPSTxBytes to partiallySignedTransaction * Change collectUTXOsFromFarAddresses's comment * Use setters for last used indexes * Don't use the pstx acronym * Fix SetPath * Remove spaces when reading lines * Fix walletserver to daemonaddress * Fix isUTXOSpendable to use DAA score Co-authored-by: Svarog <feanorr@gmail.com>
149 lines
4.6 KiB
Go
149 lines
4.6 KiB
Go
package bip32
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"github.com/kaspanet/go-secp256k1"
|
|
"github.com/kaspanet/kaspad/cmd/kaspawallet/libkaspawallet/bip32/base58"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
const (
|
|
versionSerializationLen = 4
|
|
depthSerializationLen = 1
|
|
fingerprintSerializationLen = 4
|
|
childNumberSerializationLen = 4
|
|
chainCodeSerializationLen = 32
|
|
keySerializationLen = 33
|
|
checkSumLen = 4
|
|
)
|
|
|
|
const extendedKeySerializationLen = versionSerializationLen +
|
|
depthSerializationLen +
|
|
fingerprintSerializationLen +
|
|
childNumberSerializationLen +
|
|
chainCodeSerializationLen +
|
|
keySerializationLen +
|
|
checkSumLen
|
|
|
|
// DeserializeExtendedKey deserialized the given base58 string and returns an extended key
|
|
func DeserializeExtendedKey(extKeyString string) (*ExtendedKey, error) {
|
|
serializedBytes := base58.Decode(extKeyString)
|
|
return deserializeExtendedPrivateKey(serializedBytes)
|
|
}
|
|
|
|
func deserializeExtendedPrivateKey(serialized []byte) (*ExtendedKey, error) {
|
|
if len(serialized) != extendedKeySerializationLen {
|
|
return nil, errors.Errorf("key length must be %d bytes but got %d", extendedKeySerializationLen, len(serialized))
|
|
}
|
|
|
|
err := validateChecksum(serialized)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
extKey := &ExtendedKey{}
|
|
|
|
copy(extKey.Version[:], serialized[:versionSerializationLen])
|
|
extKey.Depth = serialized[versionSerializationLen]
|
|
copy(extKey.ParentFingerprint[:], serialized[versionSerializationLen+depthSerializationLen:])
|
|
extKey.ChildNumber = binary.BigEndian.Uint32(
|
|
serialized[versionSerializationLen+depthSerializationLen+fingerprintSerializationLen:],
|
|
)
|
|
copy(
|
|
extKey.ChainCode[:],
|
|
serialized[versionSerializationLen+depthSerializationLen+fingerprintSerializationLen+childNumberSerializationLen:],
|
|
)
|
|
|
|
isPrivate := isPrivateVersion(extKey.Version)
|
|
if isPrivate {
|
|
privateKeyPadding := serialized[versionSerializationLen+
|
|
depthSerializationLen+
|
|
fingerprintSerializationLen+
|
|
childNumberSerializationLen+
|
|
chainCodeSerializationLen]
|
|
if privateKeyPadding != 0 {
|
|
return nil, errors.Errorf("expected 0 padding for private key but got %d", privateKeyPadding)
|
|
}
|
|
|
|
extKey.privateKey, err = secp256k1.DeserializeECDSAPrivateKeyFromSlice(serialized[versionSerializationLen+
|
|
depthSerializationLen+
|
|
fingerprintSerializationLen+
|
|
childNumberSerializationLen+
|
|
chainCodeSerializationLen+1 : versionSerializationLen+
|
|
depthSerializationLen+
|
|
fingerprintSerializationLen+
|
|
childNumberSerializationLen+
|
|
chainCodeSerializationLen+
|
|
keySerializationLen])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
extKey.publicKey, err = secp256k1.DeserializeECDSAPubKey(serialized[versionSerializationLen+
|
|
depthSerializationLen+
|
|
fingerprintSerializationLen+
|
|
childNumberSerializationLen+
|
|
chainCodeSerializationLen : versionSerializationLen+
|
|
depthSerializationLen+
|
|
fingerprintSerializationLen+
|
|
childNumberSerializationLen+
|
|
chainCodeSerializationLen+
|
|
keySerializationLen])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return extKey, nil
|
|
}
|
|
|
|
func (extKey *ExtendedKey) serialize() ([]byte, error) {
|
|
var serialized [extendedKeySerializationLen]byte
|
|
copy(serialized[:], extKey.Version[:])
|
|
serialized[versionSerializationLen] = extKey.Depth
|
|
copy(serialized[versionSerializationLen+depthSerializationLen:], extKey.ParentFingerprint[:])
|
|
binary.BigEndian.PutUint32(
|
|
serialized[versionSerializationLen+depthSerializationLen+fingerprintSerializationLen:],
|
|
extKey.ChildNumber,
|
|
)
|
|
copy(
|
|
serialized[versionSerializationLen+depthSerializationLen+fingerprintSerializationLen+childNumberSerializationLen:],
|
|
extKey.ChainCode[:],
|
|
)
|
|
|
|
if extKey.IsPrivate() {
|
|
serialized[versionSerializationLen+depthSerializationLen+fingerprintSerializationLen+childNumberSerializationLen+chainCodeSerializationLen] = 0
|
|
copy(
|
|
serialized[versionSerializationLen+
|
|
depthSerializationLen+
|
|
fingerprintSerializationLen+
|
|
childNumberSerializationLen+
|
|
chainCodeSerializationLen+
|
|
1:],
|
|
extKey.privateKey.Serialize()[:],
|
|
)
|
|
} else {
|
|
publicKey, err := extKey.PublicKey()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
serializedPublicKey, err := publicKey.Serialize()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
copy(
|
|
serialized[versionSerializationLen+depthSerializationLen+fingerprintSerializationLen+childNumberSerializationLen+chainCodeSerializationLen:],
|
|
serializedPublicKey[:],
|
|
)
|
|
}
|
|
|
|
checkSum := doubleSha256(serialized[:len(serialized)-checkSumLen])
|
|
copy(
|
|
serialized[versionSerializationLen+depthSerializationLen+fingerprintSerializationLen+childNumberSerializationLen+chainCodeSerializationLen+keySerializationLen:],
|
|
checkSum,
|
|
)
|
|
return serialized[:], nil
|
|
}
|