-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
333 changed files
with
72,484 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.