Skip to content

Commit 6eaa007

Browse files
authored
Merge pull request #56 from bitcoin-sv/feat/api-extension
Feat/api extension
2 parents 41fc75e + 34c9c08 commit 6eaa007

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1340
-214
lines changed

CHANGELOG.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file. The format
44

55
## Table of Contents
66

7+
- [1.1.10 - 2024-10-20](#119---2024-10-20)
78
- [1.1.9 - 2024-10-01](#118---2024-10-01)
89
- [1.1.8 - 2024-09-17](#118---2024-09-17)
910
- [1.1.7 - 2024-09-10](#117---2024-09-10)
@@ -16,6 +17,34 @@ All notable changes to this project will be documented in this file. The format
1617
- [1.1.0 - 2024-08-19](#110---2024-08-19)
1718
- [1.0.0 - 2024-06-06](#100---2024-06-06)
1819

20+
## [1.1.10] - 2024-10-20
21+
Big thanks for contributions from @wregulski
22+
23+
### Changed
24+
- `pubKey.ToDER()` now returns bytes
25+
- `pubKey.ToHash()` is now `pubKey.Hash()`
26+
- `pubKey.SerializeCompressed()` is now `pubKey.Compressed()`
27+
- `pubKey.SerializeUncompressed()` is now `pubKey.Uncompressed()`
28+
- `pubKey.SerializeHybrid()` is now `pubKey.Hybrid()`
29+
- updated `merklepath.go` to use new helper functions from `transaction.merkletreeparent.go`
30+
31+
### Added
32+
- files `spv/verify.go`, `spv/verify_test.go` - chain tracker for whatsonchain.com
33+
- `spv.Verify()` ensures transaction scripts, merkle paths and fees are valid
34+
- `spv.VerifyScripts()` ensures transaction scripts are valid
35+
- file `docs/examples/verify_transaction/verify_transaction.go`
36+
- `publickey.ToDERHex()` returns a hex encoded public key
37+
- `script.Chunks()` helper method for `DecodeScript(scriptBytes)`
38+
- `script.PubKey()` returns a `*ec.PublicKey`
39+
- `script.PubKeyHex()` returns a hex string
40+
- `script.Address()` and `script.Addresses()` helpers
41+
- file `transaction.merkletreeparent.go` which contains helper functions
42+
- `transaction.MerkleTreeParentStr()`
43+
- `transaction.MerkleTreeParentBytes()`
44+
- `transaction.MerkleTreeParents()`
45+
- file `transaction/chaintracker/whatsonchain.go`, `whatsonchain_test.go` - chain tracker for whatsonchain.com
46+
- `chaintracker.NewWhatsOnChain` chaintracker
47+
1948
## [1.1.9] - 2024-10-01
2049
### Changed
2150
- Updated readme

compat/bip32/derive.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ func (k *ExtendedKey) DerivePublicKeyFromPath(derivationPath string) ([]byte, er
8888
if err != nil {
8989
return nil, fmt.Errorf("failed to generate public key %w", err)
9090
}
91-
return pubKey.SerializeCompressed(), nil
91+
return pubKey.Compressed(), nil
9292
}
9393

9494
func childInt(child string) (uint32, error) {

compat/bip32/derive_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ func TestDerivePublicKeyFromPath(t *testing.T) {
198198
require.NoError(t, err)
199199
pubKey, err := xpubKey.ECPubKey()
200200
require.NoError(t, err)
201-
return pubKey.SerializeCompressed()
201+
return pubKey.Compressed()
202202
}(),
203203
expectedErr: nil,
204204
},
@@ -215,7 +215,7 @@ func TestDerivePublicKeyFromPath(t *testing.T) {
215215
require.NoError(t, err)
216216
pubKey, err := xpubKey.ECPubKey()
217217
require.NoError(t, err)
218-
return pubKey.SerializeCompressed()
218+
return pubKey.Compressed()
219219
}(),
220220
expectedErr: nil,
221221
},

compat/bip32/extendedkey.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ func (k *ExtendedKey) pubKeyBytes() []byte {
158158
if len(k.pubKey) == 0 {
159159
pkx, pky := ec.S256().ScalarBaseMult(k.key)
160160
pubKey := ec.PublicKey{Curve: ec.S256(), X: pkx, Y: pky}
161-
k.pubKey = pubKey.SerializeCompressed()
161+
k.pubKey = pubKey.Compressed()
162162
}
163163
})
164164

@@ -324,7 +324,7 @@ func (k *ExtendedKey) Child(i uint32) (*ExtendedKey, error) {
324324
// childKey = serP(point(parse256(Il)) + parentKey)
325325
childX, childY := ec.S256().Add(ilx, ily, pubKey.X, pubKey.Y)
326326
pk := ec.PublicKey{Curve: ec.S256(), X: childX, Y: childY}
327-
childKey = pk.SerializeCompressed()
327+
childKey = pk.Compressed()
328328
}
329329

330330
// The fingerprint of the parent for the derived child is the first 4

compat/bip32/hd_key_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -643,8 +643,8 @@ func TestGetPublicKeyFromHDKey(t *testing.T) {
643643
t.Fatalf("%s Failed: [%v] inputted and was nil but not expected", t.Name(), test.input)
644644
} else if publicKey != nil && test.expectedNil {
645645
t.Fatalf("%s Failed: [%v] inputted and was NOT nil but expected to be nil", t.Name(), test.input)
646-
} else if publicKey != nil && hex.EncodeToString(publicKey.SerializeCompressed()) != test.expectedKey {
647-
t.Fatalf("%s Failed: [%v] inputted [%s] expected but got: %s", t.Name(), test.input, test.expectedKey, hex.EncodeToString(publicKey.SerializeCompressed()))
646+
} else if publicKey != nil && hex.EncodeToString(publicKey.Compressed()) != test.expectedKey {
647+
t.Fatalf("%s Failed: [%v] inputted [%s] expected but got: %s", t.Name(), test.input, test.expectedKey, hex.EncodeToString(publicKey.Compressed()))
648648
}
649649
}
650650
}
@@ -674,7 +674,7 @@ func ExampleGetPublicKeyFromHDKey() {
674674
return
675675
}
676676

677-
fmt.Printf("public key: %s", hex.EncodeToString(publicKey.SerializeCompressed()))
677+
fmt.Printf("public key: %s", hex.EncodeToString(publicKey.Compressed()))
678678
// Output:public key: 03a25f6c10eedcd41eebac22c6bbc5278690fa1aab3afc2bbe8f2277c85e5c5def
679679
}
680680

@@ -856,10 +856,10 @@ func TestGetPublicKeysForPath(t *testing.T) {
856856
t.Fatalf("%s Failed: [%v] [%d] inputted and was nil but not expected", t.Name(), test.input, test.inputNum)
857857
} else if pubKeys != nil && test.expectedNil {
858858
t.Fatalf("%s Failed: [%v] [%d] inputted and was NOT nil but expected to be nil", t.Name(), test.input, test.inputNum)
859-
} else if pubKeys != nil && hex.EncodeToString(pubKeys[0].SerializeCompressed()) != test.expectedPubKey1 {
860-
t.Fatalf("%s Failed: [%v] [%d] inputted key 1 [%s] expected but got: %s", t.Name(), test.input, test.inputNum, test.expectedPubKey1, hex.EncodeToString(pubKeys[0].SerializeCompressed()))
861-
} else if pubKeys != nil && hex.EncodeToString(pubKeys[1].SerializeCompressed()) != test.expectedPubKey2 {
862-
t.Fatalf("%s Failed: [%v] [%d] inputted key 2 [%s] expected but got: %s", t.Name(), test.input, test.inputNum, test.expectedPubKey2, hex.EncodeToString(pubKeys[1].SerializeCompressed()))
859+
} else if pubKeys != nil && hex.EncodeToString(pubKeys[0].Compressed()) != test.expectedPubKey1 {
860+
t.Fatalf("%s Failed: [%v] [%d] inputted key 1 [%s] expected but got: %s", t.Name(), test.input, test.inputNum, test.expectedPubKey1, hex.EncodeToString(pubKeys[0].Compressed()))
861+
} else if pubKeys != nil && hex.EncodeToString(pubKeys[1].Compressed()) != test.expectedPubKey2 {
862+
t.Fatalf("%s Failed: [%v] [%d] inputted key 2 [%s] expected but got: %s", t.Name(), test.input, test.inputNum, test.expectedPubKey2, hex.EncodeToString(pubKeys[1].Compressed()))
863863
}
864864
}
865865
}
@@ -890,7 +890,7 @@ func ExampleGetPublicKeysForPath() {
890890
return
891891
}
892892

893-
fmt.Printf("found [%d] keys! Key 1: %s Key 2: %s", len(publicKeys), hex.EncodeToString(publicKeys[0].SerializeCompressed()), hex.EncodeToString(publicKeys[1].SerializeCompressed()))
893+
fmt.Printf("found [%d] keys! Key 1: %s Key 2: %s", len(publicKeys), hex.EncodeToString(publicKeys[0].Compressed()), hex.EncodeToString(publicKeys[1].Compressed()))
894894
// Output:found [2] keys! Key 1: 03f87ac38fb0cfca12988b51a2f1cd3e85bb4aeb1b05f549682190ac8205a67d30 Key 2: 02e78303aeef1acce1347c6493fadc1914e6d85ef3189a8856afb3accd53fbd9c5
895895
}
896896

compat/bsm/sign.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package compat
22

33
import (
44
"bytes"
5+
"encoding/base64"
56
"errors"
67

78
ec "github.com/bitcoin-sv/go-sdk/primitives/ec"
@@ -43,3 +44,13 @@ func SignMessageWithCompression(privateKey *ec.PrivateKey, message []byte, sigRe
4344
// Sign
4445
return ec.SignCompact(ec.S256(), privateKey, messageHash, sigRefCompressedKey)
4546
}
47+
48+
// SignMessageString signs the message and returns the signature as a base64-encoded string
49+
func SignMessageString(privateKey *ec.PrivateKey, message []byte) (string, error) {
50+
sigBytes, err := SignMessageWithCompression(privateKey, message, true)
51+
if err != nil {
52+
return "", err
53+
}
54+
55+
return base64.StdEncoding.EncodeToString(sigBytes), nil
56+
}

compat/bsm/sign_test.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func TestSigningCompression(t *testing.T) {
3131
}
3232
}
3333

34-
// TestSignMessage will test the method SignMessage()
34+
// TestSignMessage will test the method SignMessage() and SignMessageString()
3535
func TestSignMessage(t *testing.T) {
3636
t.Parallel()
3737
var tests = []struct {
@@ -108,14 +108,26 @@ func TestSignMessage(t *testing.T) {
108108
},
109109
}
110110

111+
const failedUnexpectedError = "%d %s Failed: [%s] [%s] inputted and error not expected but got: %s"
112+
const failedExpectedError = "%d %s Failed: [%s] [%s] inputted and error was expected"
113+
const failedExpectedSignature = "%d %s Failed: [%s] [%s] inputted [%s] expected but got: %s"
114+
111115
for idx, test := range tests {
112116
testPk, errKey := ec.PrivateKeyFromHex(test.inputKey)
113117
if signature, err := compat.SignMessage(testPk, []byte(test.inputMessage)); err != nil && !test.expectedError {
114-
t.Fatalf("%d %s Failed: [%s] [%s] inputted and error not expected but got: %s", idx, t.Name(), test.inputKey, test.inputMessage, err.Error())
118+
t.Fatalf(failedUnexpectedError, idx, t.Name(), test.inputKey, test.inputMessage, err.Error())
115119
} else if err == nil && errKey == nil && test.expectedError {
116-
t.Fatalf("%d %s Failed: [%s] [%s] inputted and error was expected", idx, t.Name(), test.inputKey, test.inputMessage)
120+
t.Fatalf(failedExpectedError, idx, t.Name(), test.inputKey, test.inputMessage)
117121
} else if base64.StdEncoding.EncodeToString(signature) != test.expectedSignature {
118-
t.Fatalf("%d %s Failed: [%s] [%s] inputted [%s] expected but got: %s", idx, t.Name(), test.inputKey, test.inputMessage, test.expectedSignature, signature)
122+
t.Fatalf(failedExpectedSignature, idx, t.Name(), test.inputKey, test.inputMessage, test.expectedSignature, signature)
123+
}
124+
125+
if sigStr, err := compat.SignMessageString(testPk, []byte(test.inputMessage)); err != nil && !test.expectedError {
126+
t.Fatalf(failedUnexpectedError, idx, t.Name(), test.inputKey, test.inputMessage, err.Error())
127+
} else if err == nil && errKey == nil && test.expectedError {
128+
t.Fatalf(failedExpectedError, idx, t.Name(), test.inputKey, test.inputMessage)
129+
} else if sigStr != test.expectedSignature {
130+
t.Fatalf(failedExpectedSignature, idx, t.Name(), test.inputKey, test.inputMessage, test.expectedSignature, sigStr)
119131
}
120132

121133
}

compat/ecies/ecies.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func ElectrumEncrypt(message []byte,
7575

7676
// Derive ECDH key
7777
x, y := toPublicKey.Curve.ScalarMult(toPublicKey.X, toPublicKey.Y, ephemeralPrivateKey.D.Bytes())
78-
ecdhKey := (&ec.PublicKey{X: x, Y: y}).SerializeCompressed()
78+
ecdhKey := (&ec.PublicKey{X: x, Y: y}).Compressed()
7979

8080
// SHA512(ECDH_KEY)
8181
key := c.Sha512(ecdhKey)
@@ -94,7 +94,7 @@ func ElectrumEncrypt(message []byte,
9494
encrypted = append([]byte("BIE1"), cipherText...)
9595
} else {
9696
// encrypted = magic_bytes(4 bytes) + ephemeral_public_key(33 bytes) + cipher
97-
encrypted = append(append([]byte("BIE1"), ephemeralPublicKey.SerializeCompressed()...), cipherText...)
97+
encrypted = append(append([]byte("BIE1"), ephemeralPublicKey.Compressed()...), cipherText...)
9898
}
9999

100100
mac := c.Sha256HMAC(encrypted, keyM)
@@ -119,7 +119,7 @@ func ElectrumDecrypt(encryptedData []byte, toPrivateKey *ec.PrivateKey, fromPubl
119119
if fromPublicKey != nil {
120120
// Use counterparty public key to derive shared secret
121121
x, y := toPrivateKey.Curve.ScalarMult(fromPublicKey.X, fromPublicKey.Y, toPrivateKey.D.Bytes())
122-
sharedSecret = (&ec.PublicKey{X: x, Y: y}).SerializeCompressed()
122+
sharedSecret = (&ec.PublicKey{X: x, Y: y}).Compressed()
123123
if len(encryptedData) > 69 { // 4 (magic) + 33 (pubkey) + 32 (mac)
124124
cipherText = encryptedData[37 : len(encryptedData)-32]
125125
} else {
@@ -132,7 +132,7 @@ func ElectrumDecrypt(encryptedData []byte, toPrivateKey *ec.PrivateKey, fromPubl
132132
return nil, err
133133
}
134134
x, y := ephemeralPublicKey.Curve.ScalarMult(ephemeralPublicKey.X, ephemeralPublicKey.Y, toPrivateKey.D.Bytes())
135-
sharedSecret = (&ec.PublicKey{X: x, Y: y}).SerializeCompressed()
135+
sharedSecret = (&ec.PublicKey{X: x, Y: y}).Compressed()
136136
cipherText = encryptedData[37 : len(encryptedData)-32]
137137
}
138138

@@ -172,7 +172,7 @@ func BitcoreEncrypt(message []byte,
172172
fromPrivateKey, _ = ec.NewPrivateKey()
173173
}
174174

175-
RBuf := fromPrivateKey.PubKey().ToDERBytes()
175+
RBuf := fromPrivateKey.PubKey().ToDER()
176176
P := toPublicKey.Mul(fromPrivateKey.D)
177177

178178
Sbuf := P.X.Bytes()

docs/examples/keyshares_pk_to_backup/to_backup.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
func main() {
1111
pk, _ := ec.PrivateKeyFromWif("KxPEP4DCP2a4g3YU5amfXjFH4kWmz8EHWrTugXocGWgWBbhGsX7a")
12-
log.Println("Private key:", hex.EncodeToString(pk.PubKey().ToHash())[:8])
12+
log.Println("Private key:", hex.EncodeToString(pk.PubKey().Hash())[:8])
1313
totalShares := 5
1414
threshold := 3
1515
shares, _ := pk.ToBackupShares(threshold, totalShares)
Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
11
package main
22

33
import (
4-
"github.com/bitcoin-sv/go-sdk/chainhash"
4+
"github.com/bitcoin-sv/go-sdk/spv"
55
"github.com/bitcoin-sv/go-sdk/transaction"
66
)
77

8-
type GullibleHeadersClient struct{}
9-
10-
func (g *GullibleHeadersClient) IsValidRootForHeight(merkleRoot *chainhash.Hash, height uint32) bool {
11-
// DO NOT USE IN A REAL PROJECT due to security risks of accepting any merkle root as valid without verification
12-
return true
13-
}
14-
158
// Replace with the BEEF structure you'd like to check
169
const BEEFHex = "0100beef01fe636d0c0007021400fe507c0c7aa754cef1f7889d5fd395cf1f785dd7de98eed895dbedfe4e5bc70d1502ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e010b00bc4ff395efd11719b277694cface5aa50d085a0bb81f613f70313acd28cf4557010400574b2d9142b8d28b61d88e3b2c3f44d858411356b49a28a4643b6d1a6a092a5201030051a05fc84d531b5d250c23f4f886f6812f9fe3f402d61607f977b4ecd2701c19010000fd781529d58fc2523cf396a7f25440b409857e7e221766c57214b1d38c7b481f01010062f542f45ea3660f86c013ced80534cb5fd4c19d66c56e7e8c5d4bf2d40acc5e010100b121e91836fd7cd5102b654e9f72f3cf6fdbfd0b161c53a9c54b12c841126331020100000001cd4e4cac3c7b56920d1e7655e7e260d31f29d9a388d04910f1bbd72304a79029010000006b483045022100e75279a205a547c445719420aa3138bf14743e3f42618e5f86a19bde14bb95f7022064777d34776b05d816daf1699493fcdf2ef5a5ab1ad710d9c97bfb5b8f7cef3641210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013e660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac0000000001000100000001ac4e164f5bc16746bb0868404292ac8318bbac3800e4aad13a014da427adce3e000000006a47304402203a61a2e931612b4bda08d541cfb980885173b8dcf64a3471238ae7abcd368d6402204cbf24f04b9aa2256d8901f0ed97866603d2be8324c2bfb7a37bf8fc90edd5b441210263e2dee22b1ddc5e11f6fab8bcd2378bdd19580d640501ea956ec0e786f93e76ffffffff013c660000000000001976a9146bfd5c7fbe21529d45803dbcf0c87dd3c71efbc288ac0000000000"
1710

@@ -22,6 +15,6 @@ func main() {
2215
panic(err)
2316
}
2417
// This ensures the BEEF structure is legitimate
25-
verified, _ := tx.MerklePath.Verify(tx.TxID(), &GullibleHeadersClient{})
18+
verified, _ := tx.MerklePath.Verify(tx.TxID(), &spv.GullibleHeadersClient{})
2619
println(verified)
2720
}

0 commit comments

Comments
 (0)