Skip to content

Commit

Permalink
Release v0.1.0
Browse files Browse the repository at this point in the history
  • Loading branch information
mdb1 committed Oct 1, 2019
1 parent fe624a6 commit 7f78ab4
Show file tree
Hide file tree
Showing 333 changed files with 72,484 additions and 0 deletions.
73 changes: 73 additions & 0 deletions V1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package libwallet

import (
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
"github.com/pkg/errors"
)

// CreateAddressV1 returns a P2PKH MuunAddress from a publicKey for using in TransactionSchameV1
func CreateAddressV1(publicKey *HDPublicKey) (MuunAddress, error) {
pubkey, err := btcutil.NewAddressPubKey(publicKey.Raw(), publicKey.Network.network)
if err != nil {
return nil, err
}

pubkeyHash := pubkey.AddressPubKeyHash()
address := pubkeyHash.String()

return &muunAddress{address: address, version: addressV1, derivationPath: publicKey.Path}, nil
}

func addUserSignatureInputV1(input Input, index int, tx *wire.MsgTx, privateKey *HDPrivateKey) (*wire.TxIn, error) {

txInput := tx.TxIn[index]

sig, err := signInputV1(input, index, tx, privateKey)
if err != nil {
return nil, errors.Wrapf(err, "failed to sign V1 input")
}

builder := txscript.NewScriptBuilder()
builder.AddData(sig)
builder.AddData(privateKey.PublicKey().Raw())
script, err := builder.Script()
if err != nil {
return nil, errors.Wrapf(err, "failed to generate signing script")
}

txInput.SignatureScript = script

return txInput, nil
}

func createRedeemScriptV1(publicKey *HDPublicKey) ([]byte, error) {

userAddress, err := btcutil.NewAddressPubKey(publicKey.Raw(), publicKey.Network.network)
if err != nil {
return nil, errors.Wrapf(err, "failed to generate address for user")
}

return txscript.PayToAddrScript(userAddress.AddressPubKeyHash())
}

func signInputV1(input Input, index int, tx *wire.MsgTx, privateKey *HDPrivateKey) ([]byte, error) {

redeemScript, err := createRedeemScriptV1(privateKey.PublicKey())
if err != nil {
return nil, errors.Wrapf(err, "failed to build reedem script for signing")
}

privKey, err := privateKey.key.ECPrivKey()
if err != nil {
return nil, errors.Wrapf(err, "failed to produce EC priv key for signing")
}

sig, err := txscript.RawTxInSignature(tx, index, redeemScript, txscript.SigHashAll, privKey)
if err != nil {
return nil, errors.Wrapf(err, "failed to sign V1 input")
}

return sig, nil
}
106 changes: 106 additions & 0 deletions V2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package libwallet

import (
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcutil"
"github.com/pkg/errors"

"github.com/btcsuite/btcd/wire"
)

func CreateAddressV2(userKey, muunKey *HDPublicKey) (MuunAddress, error) {

script, err := createRedeemScriptV2(userKey, muunKey)
if err != nil {
return nil, errors.Wrapf(err, "failed to generate redeem script v2")
}

address, err := btcutil.NewAddressScriptHash(script, userKey.Network.network)
if err != nil {
return nil, errors.Wrapf(err, "failed to generate multisig address")
}

return &muunAddress{
address: address.String(),
version: addressV2,
derivationPath: userKey.Path,
redeemScript: script,
}, nil
}

func createRedeemScriptV2(userKey, muunKey *HDPublicKey) ([]byte, error) {

userAddress, err := btcutil.NewAddressPubKey(userKey.Raw(), userKey.Network.network)
if err != nil {
return nil, errors.Wrapf(err, "failed to generate address for user")
}

muunAddress, err := btcutil.NewAddressPubKey(muunKey.Raw(), muunKey.Network.network)
if err != nil {
return nil, errors.Wrapf(err, "failed to generate address for muun")
}

return txscript.MultiSigScript([]*btcutil.AddressPubKey{
userAddress,
muunAddress,
}, 2)
}

func addUserSignatureInputV2(input Input, index int, tx *wire.MsgTx, privateKey *HDPrivateKey,
muunKey *HDPublicKey) (*wire.TxIn, error) {

if len(input.MuunSignature()) == 0 {
return nil, errors.Errorf("muun signature must be present")
}

txInput := tx.TxIn[index]

redeemScript, err := createRedeemScriptV2(privateKey.PublicKey(), muunKey)
if err != nil {
return nil, errors.Wrapf(err, "failed to build reedem script for signing")
}

sig, err := signInputV2(input, index, tx, privateKey.PublicKey(), muunKey, privateKey)
if err != nil {
return nil, err
}

// This is a standard 2 of 2 multisig script
// 0 because of a bug in bitcoind
// Then the 2 sigs: first the users and then muuns
// Last, the script that contains the two pub keys and OP_CHECKMULTISIG
builder := txscript.NewScriptBuilder()
builder.AddInt64(0)
builder.AddData(sig)
builder.AddData(input.MuunSignature())
builder.AddData(redeemScript)
script, err := builder.Script()
if err != nil {
return nil, errors.Wrapf(err, "failed to generate signing script")
}

txInput.SignatureScript = script

return txInput, nil
}

func signInputV2(input Input, index int, tx *wire.MsgTx, userKey, muunKey *HDPublicKey,
signingKey *HDPrivateKey) ([]byte, error) {

redeemScript, err := createRedeemScriptV2(userKey, muunKey)
if err != nil {
return nil, errors.Wrapf(err, "failed to build reedem script for signing")
}

privKey, err := signingKey.key.ECPrivKey()
if err != nil {
return nil, errors.Wrapf(err, "failed to produce EC priv key for signing")
}

sig, err := txscript.RawTxInSignature(tx, index, redeemScript, txscript.SigHashAll, privKey)
if err != nil {
return nil, errors.Wrapf(err, "failed to sign V2 output")
}

return sig, nil
}
56 changes: 56 additions & 0 deletions V2_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package libwallet

import (
"encoding/hex"
"reflect"
"testing"
)

func Test_CreateAddressV2(t *testing.T) {

const (
addressPath = "m/schema:1'/recovery:1'/external:1/0"
originAddress = "2NDeWrsJEwvxwVnvtWzPjhDC5B2LYkFuX2s"

encodedMuunKey = "tpubDBYMnFoxYLdMBZThTk4uARTe4kGPeEYWdKcaEzaUxt1cesetnxtTqmAxVkzDRou51emWytommyLWcF91SdF5KecA6Ja8oHK1FF7d5U2hMxX"
encodedUserKey = "tprv8dfM4H5fYJirMai5Er3LguicgUAyxmcSQbFub5ens16amX1e1HAFiW4SXnFVw9nu9FedFQqTPGTTjPEmgfvvXMKww3UcRpFbbC4DFjbCcTb"
basePath = "m/schema:1'/recovery:1'"
v2EncodedScript = "5221029fa5af7a34c142c1ce348b360abeb7de01df25b1d50129e58a67a6b846c9303b21025714f6b3670d4a38f5e2d6e8f239c9fc072543ce33dca54fcb4f4886a5cb87a652ae"
)

v2Script := make([]byte, 71)
hex.Decode(v2Script[:], []byte(v2EncodedScript))

baseMuunKey, _ := NewHDPublicKeyFromString(encodedMuunKey, basePath)
muunKey, _ := baseMuunKey.DeriveTo(addressPath)

baseUserKey, _ := NewHDPrivateKeyFromString(encodedUserKey, basePath)
userKey, _ := baseUserKey.DeriveTo(addressPath)

type args struct {
userKey *HDPublicKey
muunKey *HDPublicKey
}
tests := []struct {
name string
args args
want MuunAddress
wantErr bool
}{
{name: "gen address",
args: args{userKey: userKey.PublicKey(), muunKey: muunKey},
want: &muunAddress{address: originAddress, derivationPath: addressPath, version: addressV2, redeemScript: v2Script}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := CreateAddressV2(tt.args.userKey, tt.args.muunKey)
if (err != nil) != tt.wantErr {
t.Errorf("CreateAddressV2() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("CreateAddressV2() = %v, want %v", got, tt.want)
}
})
}
}
84 changes: 84 additions & 0 deletions V3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package libwallet

import (
"github.com/btcsuite/btcutil"

"github.com/pkg/errors"

"github.com/btcsuite/btcd/wire"
)

func CreateAddressV3(userKey, muunKey *HDPublicKey) (MuunAddress, error) {

redeemScript, err := createRedeemScriptV3(userKey, muunKey)
if err != nil {
return nil, err
}

address, err := btcutil.NewAddressScriptHash(redeemScript, userKey.Network.network)
if err != nil {
return nil, err
}

return &muunAddress{
address: address.EncodeAddress(),
version: addressV3,
derivationPath: userKey.Path,
redeemScript: redeemScript,
}, nil
}

func createRedeemScriptV3(userKey, muunKey *HDPublicKey) ([]byte, error) {
witnessScript, err := createWitnessScriptV3(userKey, muunKey)
if err != nil {
return nil, errors.Wrapf(err, "failed to generate redeem script v3")
}

return createNonNativeSegwitRedeemScript(witnessScript)
}

func createWitnessScriptV3(userKey, muunKey *HDPublicKey) ([]byte, error) {
// createRedeemScriptV2 creates a valid script for both V2 and V3 schemes
return createRedeemScriptV2(userKey, muunKey)
}

func addUserSignatureInputV3(input Input, index int, tx *wire.MsgTx, privateKey *HDPrivateKey, muunKey *HDPublicKey) (*wire.TxIn, error) {

if len(input.MuunSignature()) == 0 {
return nil, errors.Errorf("muun signature must be present")
}


witnessScript, err := createWitnessScriptV3(privateKey.PublicKey(), muunKey)
if err != nil {
return nil, err
}

sig, err := signInputV3(input, index, tx, privateKey.PublicKey(), muunKey, privateKey)
if err != nil {
return nil, err
}

zeroByteArray := []byte{}

txInput := tx.TxIn[index]
txInput.Witness = wire.TxWitness{zeroByteArray, sig, input.MuunSignature(), witnessScript}

return txInput, nil
}

func signInputV3(input Input, index int, tx *wire.MsgTx, userKey *HDPublicKey, muunKey *HDPublicKey,
signingKey *HDPrivateKey) ([]byte, error) {

witnessScript, err := createWitnessScriptV3(userKey, muunKey)
if err != nil {
return nil, err
}

redeemScript, err := createRedeemScriptV3(userKey, muunKey)
if err != nil {
return nil, errors.Wrapf(err, "failed to build reedem script for signing")
}

return signNonNativeSegwitInput(input, index, tx, signingKey, redeemScript, witnessScript)
}
56 changes: 56 additions & 0 deletions V3_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package libwallet

import (
"encoding/hex"
"reflect"
"testing"
)

func Test_CreateAddressV3(t *testing.T) {

const (
addressPath = "m/schema:1'/recovery:1'/external:1/0"

v3Address = "2MswEXmCLaHQq6pUTtnUVF8wVArfYSqUec5"
basePK = "tpubDAN21T1DFREQQS4FvpUktKRBzXXsj5ddenAa5u198hLXvErFFR4Lj8bt8xMG3xnZr6u8mx1vrFW9RwCDXQwQuYRCLq1j9Nr2VJUrENzteQH"
baseCosigningPK = "tpubDAsVhzq6otpasovieofhiaY38bSFGyJaBGvrJjBv9whhSnftUXfMTMVrq4BbTXT5A9b78CqqbPuM2j1ZGWdiggd7JHUTZAHh8GXDTt4Pkj9"
basePath = "m/schema:1'/recovery:1'"
v3EncodedScript = "0020e1fbfbd395aff8b4087fee3e4488815ef659b559b3cd0d6800b5a591efd99f38"
)

v3Script := make([]byte, 34)
hex.Decode(v3Script[:], []byte(v3EncodedScript))

baseMuunKey, _ := NewHDPublicKeyFromString(baseCosigningPK, basePath)
muunKey, _ := baseMuunKey.DeriveTo(addressPath)

baseUserKey, _ := NewHDPublicKeyFromString(basePK, basePath)
userKey, _ := baseUserKey.DeriveTo(addressPath)

type args struct {
userKey *HDPublicKey
muunKey *HDPublicKey
}
tests := []struct {
name string
args args
want MuunAddress
wantErr bool
}{
{name: "gen address",
args: args{userKey: userKey, muunKey: muunKey},
want: &muunAddress{address: v3Address, derivationPath: addressPath, version: addressV3, redeemScript: v3Script}},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := CreateAddressV3(tt.args.userKey, tt.args.muunKey)
if (err != nil) != tt.wantErr {
t.Errorf("CreateAddressV3() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("CreateAddressV3() = %v, want %v", got, tt.want)
}
})
}
}
Loading

0 comments on commit 7f78ab4

Please sign in to comment.