Skip to content

Commit 493a330

Browse files
author
David Case
committed
add uncompressed support for addresses and bsm
1 parent dd00e14 commit 493a330

File tree

4 files changed

+109
-16
lines changed

4 files changed

+109
-16
lines changed

compat/bsm/sign.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ const hBSV = "Bitcoin Signed Message:\n"
1414
// SignMessage signs a string with the provided PrivateKey using Bitcoin Signed Message encoding
1515
// sigRefCompressedKey bool determines whether the signature will reference a compressed or uncompresed key
1616
// Spec: https://github.com/bitcoin/bitcoin/pull/524
17-
func SignMessage(privateKey *ec.PrivateKey, message []byte, sigRefCompressedKey bool) ([]byte, error) {
17+
func SignMessage(privateKey *ec.PrivateKey, message []byte) ([]byte, error) {
18+
return SignMessageWithCompression(privateKey, message, true)
19+
}
20+
21+
func SignMessageWithCompression(privateKey *ec.PrivateKey, message []byte, sigRefCompressedKey bool) ([]byte, error) {
1822
if privateKey == nil {
1923
return nil, errors.New("private key is required")
2024
}

compat/bsm/sign_test.go

Lines changed: 93 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func TestSigningCompression(t *testing.T) {
1919
if err != nil {
2020
t.Errorf("Get address err %s", err)
2121
}
22-
sig, err := compat.SignMessage(testKey, testData, true)
22+
sig, err := compat.SignMessage(testKey, testData)
2323
if err != nil {
2424
t.Errorf("Failed to sign compressed %s", err)
2525
}
@@ -33,9 +33,96 @@ func TestSigningCompression(t *testing.T) {
3333

3434
// TestSignMessage will test the method SignMessage()
3535
func TestSignMessage(t *testing.T) {
36-
3736
t.Parallel()
37+
var tests = []struct {
38+
inputKey string
39+
inputMessage string
40+
expectedSignature string
41+
expectedError bool
42+
}{
43+
{
44+
"0499f8239bfe10eb0f5e53d543635a423c96529dd85fa4bad42049a0b435ebdd",
45+
"test message",
46+
"IFxPx8JHsCiivB+DW/RgNpCLT6yG3j436cUNWKekV3ORBrHNChIjeVReyAco7PVmmDtVD3POs9FhDlm/nk5I6O8=",
47+
false,
48+
},
49+
{
50+
"ef0b8bad0be285099534277fde328f8f19b3be9cadcd4c08e6ac0b5f863745ac",
51+
"This is a test message",
52+
"H+zZagsyz7ioC/ZOa5EwsaKice0vs2BvZ0ljgkFHxD3vGsMlGeD4sXHEcfbI4h8lP29VitSBdf4A+nHXih7svf4=",
53+
false,
54+
},
55+
{
56+
"0499f8239bfe10eb0f5e53d543635a423c96529dd85fa4bad42049a0b435ebdd",
57+
"This time I'm writing a new message that is obnixiously long af. This time I'm writing a new message that is obnixiously long af. This time I'm writing a new message that is obnixiously long af. This time I'm writing a new message that is obnixiously long af. This time I'm writing a new message that is obnixiously long af. This time I'm writing a new message that is obnixiously long af. This time I'm writing a new message that is obnixiously long af. This time I'm writing a new message that is obnixiously long af. This time I'm writing a new message that is obnixiously long af. This time I'm writing a new message that is obnixiously long af. This time I'm writing a new message that is obnixiously long af. This time I'm writing a new message that is obnixiously long af. This time I'm writing a new message that is obnixiously long af. This time I'm writing a new message that is obnixiously long af.",
58+
"HxRcFXQc7LHxFNpK5lzhR+LF5ixIvhB089bxYzTAV02yGHm/3ALxltz/W4lGp77Q5UTxdj+TU+96mdAcJ5b/fGs=",
59+
false,
60+
},
61+
{
62+
"93596babb564cbbdc84f2370c710b9bcc94333495b60af719b5fcf9ba00ba82c",
63+
"This is a test message",
64+
"IIuDw09ffPgEDuxEw5yHVp1+mi4QpuhAwLyQdpMTfsHCOkMqTKXuP7dSNWMEJqZsiQ8eKMDRvf2wZ4e5bxcu4O0=",
65+
false,
66+
},
67+
{
68+
"50381cf8f52936faae4a05a073a03d688a9fa206d005e87a39da436c75476d78",
69+
"This is a test message",
70+
"ILBmbjCY2Z7eSXGXZoBI3x2ZRaYUYOGtEaDjXetaY+zNDtMOvagsOGEHnVT3f5kXlEbuvmPydHqLnyvZP3cDOWk=",
71+
false,
72+
},
73+
{
74+
"c7726663147afd1add392d129086e57c0b05aa66a6ded564433c04bd55741434",
75+
"This is a test message",
76+
"IOI207QUnTLr2Ll+s4kUxNgLgorkc/Z5Pc+XNvUBYLy2TxaU6oHEJ2TTJ1mZVrtUyHm6e315v1tIjeosW3Odfqw=",
77+
false,
78+
},
79+
{
80+
"c7726663147afd1add392d129086e57c0b05aa66a6ded564433c04bd55741434",
81+
"1",
82+
"IMcRFG1VNN9TDGXpCU+9CqKLNOuhwQiXI5hZpkTOuYHKBDOWayNuAABofYLqUHYTMiMf9mYFQ0sPgFJZz3F7ELQ=",
83+
false,
84+
},
85+
{
86+
"",
87+
"This is a test message",
88+
"",
89+
true,
90+
},
91+
{
92+
"0",
93+
"This is a test message",
94+
"",
95+
true,
96+
},
97+
{
98+
"0000000",
99+
"This is a test message",
100+
"",
101+
true,
102+
},
103+
{
104+
"c7726663147afd1add392d129086e57c0b",
105+
"This is a test message",
106+
"H6N+iPf23i2YkLsNzF/yyeBm9eSYBoY/HFV1Md1F0ElWBXW5E5mkdRtgjoRuq0yNb1CCFNWWlkn2gZknFJNUFJ8=",
107+
false,
108+
},
109+
}
110+
111+
for idx, test := range tests {
112+
testPk, errKey := ec.PrivateKeyFromHex(test.inputKey)
113+
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())
115+
} 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)
117+
} 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)
119+
}
120+
121+
}
122+
}
38123

124+
func TestSignMessageUncompressed(t *testing.T) {
125+
t.Parallel()
39126
var tests = []struct {
40127
inputKey string
41128
inputMessage string
@@ -111,36 +198,33 @@ func TestSignMessage(t *testing.T) {
111198
}
112199

113200
for idx, test := range tests {
114-
115201
testPk, errKey := ec.PrivateKeyFromHex(test.inputKey)
116-
117-
if signature, err := compat.SignMessage(testPk, []byte(test.inputMessage), false); err != nil && !test.expectedError {
202+
if signature, err := compat.SignMessageWithCompression(testPk, []byte(test.inputMessage), false); err != nil && !test.expectedError {
118203
t.Fatalf("%d %s Failed: [%s] [%s] inputted and error not expected but got: %s", idx, t.Name(), test.inputKey, test.inputMessage, err.Error())
119204
} else if err == nil && errKey == nil && test.expectedError {
120205
t.Fatalf("%d %s Failed: [%s] [%s] inputted and error was expected", idx, t.Name(), test.inputKey, test.inputMessage)
121206
} else if base64.StdEncoding.EncodeToString(signature) != test.expectedSignature {
122207
t.Fatalf("%d %s Failed: [%s] [%s] inputted [%s] expected but got: %s", idx, t.Name(), test.inputKey, test.inputMessage, test.expectedSignature, signature)
123208
}
124-
125209
}
126210
}
127211

128212
// ExampleSignMessage example using SignMessage()
129213
func ExampleSignMessage() {
130214
pk, _ := ec.PrivateKeyFromHex("ef0b8bad0be285099534277fde328f8f19b3be9cadcd4c08e6ac0b5f863745ac")
131-
signature, err := compat.SignMessage(pk, []byte("This is a test message"), false)
215+
signature, err := compat.SignMessage(pk, []byte("This is a test message"))
132216
if err != nil {
133217
fmt.Printf("error occurred: %s", err.Error())
134218
return
135219
}
136220
fmt.Printf("signature created: %s", base64.StdEncoding.EncodeToString(signature))
137-
// Output:signature created: G+zZagsyz7ioC/ZOa5EwsaKice0vs2BvZ0ljgkFHxD3vGsMlGeD4sXHEcfbI4h8lP29VitSBdf4A+nHXih7svf4=
221+
// Output:signature created: H+zZagsyz7ioC/ZOa5EwsaKice0vs2BvZ0ljgkFHxD3vGsMlGeD4sXHEcfbI4h8lP29VitSBdf4A+nHXih7svf4=
138222
}
139223

140224
// BenchmarkSignMessage benchmarks the method SignMessage()
141225
func BenchmarkSignMessage(b *testing.B) {
142226
key, _ := ec.NewPrivateKey()
143227
for i := 0; i < b.N; i++ {
144-
_, _ = compat.SignMessage(key, []byte("This is a test message"), false)
228+
_, _ = compat.SignMessage(key, []byte("This is a test message"))
145229
}
146230
}

compat/bsm/verify.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,9 @@ func VerifyMessage(address string, sig, data []byte) error {
4848
return err
4949
}
5050

51-
if !wasCompressed {
52-
return fmt.Errorf("only compressed keys and signatures are supported")
53-
}
54-
5551
// Get the address
5652
var scriptAddress *script.Address
57-
if scriptAddress, err = script.NewAddressFromPublicKey(publicKey, true); err != nil {
53+
if scriptAddress, err = script.NewAddressFromPublicKeyWithCompression(publicKey, true, wasCompressed); err != nil {
5854
return err
5955
}
6056

script/address.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,16 @@ func NewAddressFromPublicKeyHash(hash []byte, mainnet bool) (*Address, error) {
101101
// If mainnet parameter is true it will return a mainnet address (starting with a 1).
102102
// Otherwise, (mainnet is false) it will return a testnet address (starting with an m or n).
103103
func NewAddressFromPublicKey(pubKey *ec.PublicKey, mainnet bool) (*Address, error) {
104-
hash := crypto.Hash160(pubKey.SerializeCompressed())
104+
return NewAddressFromPublicKeyWithCompression(pubKey, mainnet, true)
105+
}
106+
107+
func NewAddressFromPublicKeyWithCompression(pubKey *ec.PublicKey, mainnet bool, isCompressed bool) (*Address, error) {
108+
var hash []byte
109+
if isCompressed {
110+
hash = crypto.Hash160(pubKey.SerializeCompressed())
111+
} else {
112+
hash = crypto.Hash160(pubKey.SerializeUncompressed())
113+
}
105114

106115
// regtest := 111
107116
// mainnet: 0

0 commit comments

Comments
 (0)