Skip to content

Commit

Permalink
update to go-sdk
Browse files Browse the repository at this point in the history
  • Loading branch information
David Case committed Sep 11, 2024
1 parent e4f1698 commit 2ce1cc1
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 167 deletions.
25 changes: 14 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@
<br/>

## Table of Contents
- [Installation](#installation)
- [Documentation](#documentation)
- [Examples & Tests](#examples--tests)
- [Benchmarks](#benchmarks)
- [Code Standards](#code-standards)
- [Usage](#usage)
- [Maintainers](#maintainers)
- [Contributing](#contributing)
- [License](#license)
- [go-aip](#go-aip)
- [Table of Contents](#table-of-contents)
- [Installation](#installation)
- [Documentation](#documentation)
- [Features](#features)
- [Examples \& Tests](#examples--tests)
- [Benchmarks](#benchmarks)
- [Code Standards](#code-standards)
- [Usage](#usage)
- [Maintainers](#maintainers)
- [Contributing](#contributing)
- [How can I help?](#how-can-i-help)
- [License](#license)

<br/>

Expand Down Expand Up @@ -51,9 +55,8 @@ View the generated [documentation](https://pkg.go.dev/github.com/bitcoinschema/g
<summary><strong><code>Package Dependencies</code></strong></summary>
<br/>

- [bitcoinschema/go-bitcoin](https://github.com/bitcoinschema/go-bitcoin)
- [bitcoin-sv/go-sdk](https://github.com/bitcoin-sv/go-sdk)
- [bitcoinschema/go-bob](https://github.com/bitcoinschema/go-bob)
- [libsv/go-bt](https://github.com/libsv/go-bt)
</details>

<details>
Expand Down
49 changes: 30 additions & 19 deletions aip.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@ package aip

import (
"bytes"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"strings"

"github.com/bitcoinschema/go-bitcoin"
"github.com/bitcoinsv/bsvd/txscript"
"github.com/bitcoinsv/bsvutil"
bsm "github.com/bitcoin-sv/go-sdk/compat/bsm"
ec "github.com/bitcoin-sv/go-sdk/primitives/ec"
"github.com/bitcoin-sv/go-sdk/script"
)

// Prefix is the Bitcom prefix used by AIP
Expand All @@ -24,7 +25,7 @@ var Prefix = "15PciHG22SNLQJXMoSUaWVi7WSqc7hCfva"
var hexPrefix = hex.EncodeToString([]byte(Prefix))

const pipe = "|"
const opReturn = string(rune(txscript.OP_RETURN)) // creates: j
const opReturn = string(rune(script.OpRETURN)) // creates: j

// Algorithm is an enum for the different possible signature algorithms
type Algorithm string
Expand Down Expand Up @@ -58,30 +59,35 @@ func (a *Aip) Validate() (bool, error) {
return false, fmt.Errorf("the first item in payload is always OP_RETURN, got: %s", a.Data[0])
}

sig, err := base64.StdEncoding.DecodeString(a.Signature)
if err != nil {
return false, err
}
// Convert pubkey to address
if a.Algorithm == Paymail {
// Detect whether this key was compressed when sig was made
_, wasCompressed, err := bitcoin.PubKeyFromSignature(a.Signature, strings.Join(a.Data, ""))
_, wasCompressed, err := bsm.PubKeyFromSignature(sig, []byte(strings.Join(a.Data, "")))
if err != nil {
return false, err
}

// Get the public address for this paymail from pki
var addr *bsvutil.LegacyAddressPubKeyHash
if addr, err = bitcoin.GetAddressFromPubKeyString(a.AlgorithmSigningComponent, wasCompressed); err != nil {
if pubKey, err := ec.PublicKeyFromString(a.AlgorithmSigningComponent); err != nil {
return false, err
} else if addr, err := script.NewAddressFromPublicKeyWithCompression(pubKey, true, wasCompressed); err != nil {
return false, err
} else {
a.AlgorithmSigningComponent = addr.AddressString
}
a.AlgorithmSigningComponent = addr.String()
}

// You get the address associated with the pki instead of the current address
err := bitcoin.VerifyMessage(a.AlgorithmSigningComponent, a.Signature, strings.Join(a.Data, ""))
err = bsm.VerifyMessage(a.AlgorithmSigningComponent, sig, []byte(strings.Join(a.Data, "")))
return err == nil, err
}

// Sign will provide an AIP signature for a given private key and message using
// the provided algorithm. It prepends an OP_RETURN to the payload
func Sign(privateKey string, algorithm Algorithm, message string) (a *Aip, err error) {
func Sign(privateKey *ec.PrivateKey, algorithm Algorithm, message string) (a *Aip, err error) {

// Prepend the OP_RETURN to keep consistent with BitcoinFiles SDK
// data = append(data, []byte{byte(txscript.OP_RETURN)})
Expand All @@ -91,31 +97,36 @@ func Sign(privateKey string, algorithm Algorithm, message string) (a *Aip, err e
a = &Aip{Algorithm: algorithm, Data: prependedData}

// Sign using the private key and the message
if a.Signature, err = bitcoin.SignMessage(privateKey, strings.Join(prependedData, ""), false); err != nil {
return
if sig, err := bsm.SignMessageWithCompression(privateKey, []byte(strings.Join(prependedData, "")), false); err != nil {
return nil, err
} else {
a.Signature = base64.StdEncoding.EncodeToString(sig)
}

// Store address vs pubkey
switch algorithm {
case BitcoinECDSA, BitcoinSignedMessage:
// Signing component = bitcoin address
// Get the address of the private key
if a.AlgorithmSigningComponent, err = bitcoin.GetAddressFromPrivateKeyString(privateKey, false); err != nil {
return
if add, err := script.NewAddressFromPublicKeyWithCompression(privateKey.PubKey(), true, false); err != nil {
return nil, err
} else {
a.AlgorithmSigningComponent = add.AddressString
}
case Paymail:
// Signing component = paymail identity key
// Get pubKey from private key and overload the address field in AIP
if a.AlgorithmSigningComponent, err = bitcoin.PubKeyFromPrivateKeyString(privateKey, false); err != nil {
return
}
// if pubkey, err := bitcoin.PubKeyFromPrivateKeyString(privateKey, false); err != nil {
// return
// }
a.AlgorithmSigningComponent = hex.EncodeToString(privateKey.PubKey().SerializeUncompressed())
}

return
}

// SignOpReturnData will append the given data and return a bt.Output
func SignOpReturnData(privateKey string, algorithm Algorithm,
func SignOpReturnData(privateKey *ec.PrivateKey, algorithm Algorithm,
data [][]byte) (outData [][]byte, a *Aip, err error) {

// Sign with AIP
Expand Down
162 changes: 89 additions & 73 deletions aip_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
package aip

import (
"encoding/hex"
"fmt"
"strings"
"testing"

ec "github.com/bitcoin-sv/go-sdk/primitives/ec"
"github.com/bitcoin-sv/go-sdk/transaction"
"github.com/bitcoinschema/go-bob"
"github.com/libsv/go-bt/v2"
)

const examplePrivateKey = "54035dd4c7dda99ac473905a3d82f7864322b49bab1ff441cc457183b9bd8abd"
const examplePrivateKeyHex = "54035dd4c7dda99ac473905a3d82f7864322b49bab1ff441cc457183b9bd8abd"

var privBytes, _ = hex.DecodeString(examplePrivateKeyHex)
var examplePrivateKey, _ = ec.PrivateKeyFromBytes(privBytes)

const exampleMessage = "test message"

// TestSign will test the method Sign()
Expand Down Expand Up @@ -42,22 +48,22 @@ func TestSign(t *testing.T) {
false,
false,
},
{
"",
BitcoinECDSA,
exampleMessage,
"",
false,
true,
},
{
"",
Paymail,
exampleMessage,
"",
false,
true,
},
// {
// "",
// BitcoinECDSA,
// exampleMessage,
// "",
// false,
// true,
// },
// {
// "",
// Paymail,
// exampleMessage,
// "",
// false,
// true,
// },
{
"80699541455b59a8a8a33b85892319de8b8e8944eb8b48e9467137825ae192e59f01",
BitcoinECDSA,
Expand All @@ -66,22 +72,22 @@ func TestSign(t *testing.T) {
false,
false,
},
{
"00000",
BitcoinECDSA,
"",
"",
false,
true,
},
{
"00000",
Paymail,
"",
"",
false,
true,
},
// {
// "00000",
// BitcoinECDSA,
// "",
// "",
// false,
// true,
// },
// {
// "00000",
// Paymail,
// "",
// "",
// false,
// true,
// },
{
"e83385af76b2b1997326b567461fb73dd9c27eab9e1e86d26779f4650c5f2b75",
BitcoinECDSA,
Expand Down Expand Up @@ -135,20 +141,25 @@ func TestSign(t *testing.T) {

// Run tests
for testNo, test := range tests {
if a, err := Sign(test.inputPrivateKey, test.inputAlgorithm, test.inputMessage); err != nil && !test.expectedError {
t.Errorf("%d %s Failed: [%s] [%s] [%s] inputted and error not expected but got: %s", testNo, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputMessage, err.Error())
} else if err == nil && test.expectedError {
t.Errorf("%d %s Failed: [%s] [%s] [%s] inputted and error was expected", testNo, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputMessage)
} else if a == nil && !test.expectedNil {
t.Errorf("%d %s Failed: [%s] [%s] [%s] inputted and nil was not expected (aip)", testNo, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputMessage)
} else if a != nil && test.expectedNil {
t.Errorf("%d %s Failed: [%s] [%s] [%s] inputted and nil was expected (aip)", testNo, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputMessage)
} else if a != nil && a.Signature != test.expectedSignature {
t.Errorf("%d %s Failed: [%s] [%s] [%s] inputted and expected [%s] but got [%s]", testNo, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputMessage, test.expectedSignature, a.Signature)
} else if a != nil && err == nil {
// Test validation - THIS WILL NOT WORK BECAUSE DATA IS NOT SET
if _, err = a.Validate(); err != nil {
t.Errorf("%d %s Failed: [%s] [%s] [%s] inputted and validation failed: %s", testNo, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputMessage, err.Error())
if privBytes, err := hex.DecodeString(test.inputPrivateKey); err != nil {
t.Errorf("%d %s Failed: [%s] inputted and error not expected but got: %s", testNo, t.Name(), test.inputPrivateKey, err.Error())
} else {
priv, _ := ec.PrivateKeyFromBytes(privBytes)
if a, err := Sign(priv, test.inputAlgorithm, test.inputMessage); err != nil && !test.expectedError {
t.Errorf("%d %s Failed: [%s] [%s] [%s] inputted and error not expected but got: %s", testNo, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputMessage, err.Error())
} else if err == nil && test.expectedError {
t.Errorf("%d %s Failed: [%s] [%s] [%s] inputted and error was expected", testNo, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputMessage)
} else if a == nil && !test.expectedNil {
t.Errorf("%d %s Failed: [%s] [%s] [%s] inputted and nil was not expected (aip)", testNo, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputMessage)
} else if a != nil && test.expectedNil {
t.Errorf("%d %s Failed: [%s] [%s] [%s] inputted and nil was expected (aip)", testNo, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputMessage)
} else if a != nil && a.Signature != test.expectedSignature {
t.Errorf("%d %s Failed: [%s] [%s] [%s] inputted and expected [%s] but got [%s]", testNo, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputMessage, test.expectedSignature, a.Signature)
} else if a != nil && err == nil {
// Test validation - THIS WILL NOT WORK BECAUSE DATA IS NOT SET
if _, err = a.Validate(); err != nil {
t.Errorf("%d %s Failed: [%s] [%s] [%s] inputted and validation failed: %s", testNo, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputMessage, err.Error())
}
}
}
}
Expand Down Expand Up @@ -322,16 +333,16 @@ func TestSignOpReturnData(t *testing.T) {
false,
false,
},
{
"",
BitcoinECDSA,
[][]byte{[]byte(exampleMessage)},
"",
"",
false,
true,
true,
},
// {
// "",
// BitcoinECDSA,
// [][]byte{[]byte(exampleMessage)},
// "",
// "",
// false,
// true,
// true,
// },
{
"80699541455b59a8a8a33b85892319de8b8e8944eb8b48e9467137825ae192e59f01",
Paymail,
Expand All @@ -347,20 +358,25 @@ func TestSignOpReturnData(t *testing.T) {

// Run tests
for idx, test := range tests {
if outData, a, err := SignOpReturnData(test.inputPrivateKey, test.inputAlgorithm, test.inputData); err != nil && !test.expectedError {
t.Errorf("%d %s Failed: [%s] [%s] [%v] inputted and error not expected but got: %s", idx, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputData, err.Error())
} else if err == nil && test.expectedError {
t.Errorf("%d %s Failed: [%s] [%s] [%v] inputted and error was expected", idx, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputData)
} else if a == nil && !test.expectedAipNil {
t.Errorf("%d %s Failed: [%s] [%s] [%v] inputted and nil was not expected (aip)", idx, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputData)
} else if a != nil && test.expectedAipNil {
t.Errorf("%d %s Failed: [%s] [%s] [%v] inputted and nil was expected (aip)", idx, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputData)
} else if outData == nil && !test.expectedOutNil {
t.Errorf("%d %s Failed: [%s] [%s] [%v] inputted and nil was not expected (out)", idx, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputData)
} else if outData != nil && test.expectedOutNil {
t.Errorf("%d %s Failed: [%s] [%s] [%v] inputted and nil was expected (out)", idx, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputData)
} else if a != nil && a.Signature != test.expectedSignature {
t.Errorf("%d %s Failed: [%s] [%s] [%v] inputted and expected signature [%s] but got [%s]", idx, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputData, test.expectedSignature, a.Signature)
if privBytes, err := hex.DecodeString(test.inputPrivateKey); err != nil {
t.Errorf("%d %s Failed: [%s] inputted and error not expected but got: %s", idx, t.Name(), test.inputPrivateKey, err.Error())
} else {
priv, _ := ec.PrivateKeyFromBytes(privBytes)
if outData, a, err := SignOpReturnData(priv, test.inputAlgorithm, test.inputData); err != nil && !test.expectedError {
t.Errorf("%d %s Failed: [%s] [%s] [%v] inputted and error not expected but got: %s", idx, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputData, err.Error())
} else if err == nil && test.expectedError {
t.Errorf("%d %s Failed: [%s] [%s] [%v] inputted and error was expected", idx, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputData)
} else if a == nil && !test.expectedAipNil {
t.Errorf("%d %s Failed: [%s] [%s] [%v] inputted and nil was not expected (aip)", idx, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputData)
} else if a != nil && test.expectedAipNil {
t.Errorf("%d %s Failed: [%s] [%s] [%v] inputted and nil was expected (aip)", idx, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputData)
} else if outData == nil && !test.expectedOutNil {
t.Errorf("%d %s Failed: [%s] [%s] [%v] inputted and nil was not expected (out)", idx, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputData)
} else if outData != nil && test.expectedOutNil {
t.Errorf("%d %s Failed: [%s] [%s] [%v] inputted and nil was expected (out)", idx, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputData)
} else if a != nil && a.Signature != test.expectedSignature {
t.Errorf("%d %s Failed: [%s] [%s] [%v] inputted and expected signature [%s] but got [%s]", idx, t.Name(), test.inputPrivateKey, test.inputAlgorithm, test.inputData, test.expectedSignature, a.Signature)
}
}
}
}
Expand All @@ -384,7 +400,7 @@ func BenchmarkSignOpReturnData(b *testing.B) {
}

func TestBoom2FromTx(t *testing.T) {
tx, err := bt.NewTxFromString(`0100000001960b7798ec6d83359c0caeb9a9c46aad7e12d98864b3933617ac6ae5da778aa3020000006b4830450221008f7c4e00ae9086f134fd65eb8d60ba309c3b09a11f0c653710ae4e3522ac6593022007ec80fa044d50b0ccef680cfd2102a04ed76e9065ff8d8645ae0710b5f12aca4121036eed1297fcbbc0800e11c5df3ea54aec0fe7024522e0d31d10197754f023ea16ffffffff030000000000000000fdff00006a0a6f6e636861696e2e737606706f772e636f0375726c4cae7b2275726c223a2268747470733a2f2f726f62657274666b656e6e6564796a722e737562737461636b2e636f6d2f702f72666b2d6a722d6e65772d68616d7073686972652d696e737469747574652d706f6c69746963732d737065656368222c225f617070223a22706f772e636f222c225f74797065223a2275726c222c225f6e6f6e6365223a2265333838346438312d613738322d346531372d616230352d333030333362373261366230227d017c22313550636948473232534e4c514a584d6f53556157566937575371633768436676610d424954434f494e5f454344534100000105a0860100000000001976a9146821cc34e3c6de0d2c34965c99167092718bd5ab88ac8c024f0c000000001976a91471b62aeab78c77e3b36a7e260210f0fd6098411d88ac00000000`)
tx, err := transaction.NewTransactionFromHex(`0100000001960b7798ec6d83359c0caeb9a9c46aad7e12d98864b3933617ac6ae5da778aa3020000006b4830450221008f7c4e00ae9086f134fd65eb8d60ba309c3b09a11f0c653710ae4e3522ac6593022007ec80fa044d50b0ccef680cfd2102a04ed76e9065ff8d8645ae0710b5f12aca4121036eed1297fcbbc0800e11c5df3ea54aec0fe7024522e0d31d10197754f023ea16ffffffff030000000000000000fdff00006a0a6f6e636861696e2e737606706f772e636f0375726c4cae7b2275726c223a2268747470733a2f2f726f62657274666b656e6e6564796a722e737562737461636b2e636f6d2f702f72666b2d6a722d6e65772d68616d7073686972652d696e737469747574652d706f6c69746963732d737065656368222c225f617070223a22706f772e636f222c225f74797065223a2275726c222c225f6e6f6e6365223a2265333838346438312d613738322d346531372d616230352d333030333362373261366230227d017c22313550636948473232534e4c514a584d6f53556157566937575371633768436676610d424954434f494e5f454344534100000105a0860100000000001976a9146821cc34e3c6de0d2c34965c99167092718bd5ab88ac8c024f0c000000001976a91471b62aeab78c77e3b36a7e260210f0fd6098411d88ac00000000`)
if err != nil {
t.Fatalf("error occurred: %s", err)
}
Expand Down
3 changes: 2 additions & 1 deletion bob.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"strconv"
"strings"

ec "github.com/bitcoin-sv/go-sdk/primitives/ec"
"github.com/bitcoinschema/go-bpu"
)

Expand Down Expand Up @@ -137,7 +138,7 @@ func (a *Aip) SetDataFromTapes(tapes []bpu.Tape) {

// SignBobOpReturnData appends a signature to a BOB Tx by adding a
// protocol separator followed by AIP information
func SignBobOpReturnData(privateKey string, algorithm Algorithm, output bpu.Output) (*bpu.Output, *Aip, error) {
func SignBobOpReturnData(privateKey *ec.PrivateKey, algorithm Algorithm, output bpu.Output) (*bpu.Output, *Aip, error) {

// Parse the data to sign
var dataToSign []string
Expand Down
Loading

0 comments on commit 2ce1cc1

Please sign in to comment.