Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/bsm-bytes'
Browse files Browse the repository at this point in the history
  • Loading branch information
rohenaz committed Sep 6, 2024
2 parents 6970583 + 493a330 commit bbbd07f
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 16 deletions.
6 changes: 5 additions & 1 deletion compat/bsm/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ const hBSV = "Bitcoin Signed Message:\n"
// SignMessage signs a string with the provided PrivateKey using Bitcoin Signed Message encoding
// sigRefCompressedKey bool determines whether the signature will reference a compressed or uncompresed key
// Spec: https://github.com/bitcoin/bitcoin/pull/524
func SignMessage(privateKey *ec.PrivateKey, message []byte, sigRefCompressedKey bool) ([]byte, error) {
func SignMessage(privateKey *ec.PrivateKey, message []byte) ([]byte, error) {
return SignMessageWithCompression(privateKey, message, true)
}

func SignMessageWithCompression(privateKey *ec.PrivateKey, message []byte, sigRefCompressedKey bool) ([]byte, error) {
if privateKey == nil {
return nil, errors.New("private key is required")
}
Expand Down
102 changes: 93 additions & 9 deletions compat/bsm/sign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestSigningCompression(t *testing.T) {
if err != nil {
t.Errorf("Get address err %s", err)
}
sig, err := compat.SignMessage(testKey, testData, true)
sig, err := compat.SignMessage(testKey, testData)
if err != nil {
t.Errorf("Failed to sign compressed %s", err)
}
Expand All @@ -33,9 +33,96 @@ func TestSigningCompression(t *testing.T) {

// TestSignMessage will test the method SignMessage()
func TestSignMessage(t *testing.T) {

t.Parallel()
var tests = []struct {
inputKey string
inputMessage string
expectedSignature string
expectedError bool
}{
{
"0499f8239bfe10eb0f5e53d543635a423c96529dd85fa4bad42049a0b435ebdd",
"test message",
"IFxPx8JHsCiivB+DW/RgNpCLT6yG3j436cUNWKekV3ORBrHNChIjeVReyAco7PVmmDtVD3POs9FhDlm/nk5I6O8=",
false,
},
{
"ef0b8bad0be285099534277fde328f8f19b3be9cadcd4c08e6ac0b5f863745ac",
"This is a test message",
"H+zZagsyz7ioC/ZOa5EwsaKice0vs2BvZ0ljgkFHxD3vGsMlGeD4sXHEcfbI4h8lP29VitSBdf4A+nHXih7svf4=",
false,
},
{
"0499f8239bfe10eb0f5e53d543635a423c96529dd85fa4bad42049a0b435ebdd",
"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.",
"HxRcFXQc7LHxFNpK5lzhR+LF5ixIvhB089bxYzTAV02yGHm/3ALxltz/W4lGp77Q5UTxdj+TU+96mdAcJ5b/fGs=",
false,
},
{
"93596babb564cbbdc84f2370c710b9bcc94333495b60af719b5fcf9ba00ba82c",
"This is a test message",
"IIuDw09ffPgEDuxEw5yHVp1+mi4QpuhAwLyQdpMTfsHCOkMqTKXuP7dSNWMEJqZsiQ8eKMDRvf2wZ4e5bxcu4O0=",
false,
},
{
"50381cf8f52936faae4a05a073a03d688a9fa206d005e87a39da436c75476d78",
"This is a test message",
"ILBmbjCY2Z7eSXGXZoBI3x2ZRaYUYOGtEaDjXetaY+zNDtMOvagsOGEHnVT3f5kXlEbuvmPydHqLnyvZP3cDOWk=",
false,
},
{
"c7726663147afd1add392d129086e57c0b05aa66a6ded564433c04bd55741434",
"This is a test message",
"IOI207QUnTLr2Ll+s4kUxNgLgorkc/Z5Pc+XNvUBYLy2TxaU6oHEJ2TTJ1mZVrtUyHm6e315v1tIjeosW3Odfqw=",
false,
},
{
"c7726663147afd1add392d129086e57c0b05aa66a6ded564433c04bd55741434",
"1",
"IMcRFG1VNN9TDGXpCU+9CqKLNOuhwQiXI5hZpkTOuYHKBDOWayNuAABofYLqUHYTMiMf9mYFQ0sPgFJZz3F7ELQ=",
false,
},
{
"",
"This is a test message",
"",
true,
},
{
"0",
"This is a test message",
"",
true,
},
{
"0000000",
"This is a test message",
"",
true,
},
{
"c7726663147afd1add392d129086e57c0b",
"This is a test message",
"H6N+iPf23i2YkLsNzF/yyeBm9eSYBoY/HFV1Md1F0ElWBXW5E5mkdRtgjoRuq0yNb1CCFNWWlkn2gZknFJNUFJ8=",
false,
},
}

for idx, test := range tests {
testPk, errKey := ec.PrivateKeyFromHex(test.inputKey)
if signature, err := compat.SignMessage(testPk, []byte(test.inputMessage)); err != nil && !test.expectedError {
t.Fatalf("%d %s Failed: [%s] [%s] inputted and error not expected but got: %s", idx, t.Name(), test.inputKey, test.inputMessage, err.Error())
} else if err == nil && errKey == nil && test.expectedError {
t.Fatalf("%d %s Failed: [%s] [%s] inputted and error was expected", idx, t.Name(), test.inputKey, test.inputMessage)
} else if base64.StdEncoding.EncodeToString(signature) != test.expectedSignature {
t.Fatalf("%d %s Failed: [%s] [%s] inputted [%s] expected but got: %s", idx, t.Name(), test.inputKey, test.inputMessage, test.expectedSignature, signature)
}

}
}

func TestSignMessageUncompressed(t *testing.T) {
t.Parallel()
var tests = []struct {
inputKey string
inputMessage string
Expand Down Expand Up @@ -111,36 +198,33 @@ func TestSignMessage(t *testing.T) {
}

for idx, test := range tests {

testPk, errKey := ec.PrivateKeyFromHex(test.inputKey)

if signature, err := compat.SignMessage(testPk, []byte(test.inputMessage), false); err != nil && !test.expectedError {
if signature, err := compat.SignMessageWithCompression(testPk, []byte(test.inputMessage), false); err != nil && !test.expectedError {
t.Fatalf("%d %s Failed: [%s] [%s] inputted and error not expected but got: %s", idx, t.Name(), test.inputKey, test.inputMessage, err.Error())
} else if err == nil && errKey == nil && test.expectedError {
t.Fatalf("%d %s Failed: [%s] [%s] inputted and error was expected", idx, t.Name(), test.inputKey, test.inputMessage)
} else if base64.StdEncoding.EncodeToString(signature) != test.expectedSignature {
t.Fatalf("%d %s Failed: [%s] [%s] inputted [%s] expected but got: %s", idx, t.Name(), test.inputKey, test.inputMessage, test.expectedSignature, signature)
}

}
}

// ExampleSignMessage example using SignMessage()
func ExampleSignMessage() {
pk, _ := ec.PrivateKeyFromHex("ef0b8bad0be285099534277fde328f8f19b3be9cadcd4c08e6ac0b5f863745ac")
signature, err := compat.SignMessage(pk, []byte("This is a test message"), false)
signature, err := compat.SignMessage(pk, []byte("This is a test message"))
if err != nil {
fmt.Printf("error occurred: %s", err.Error())
return
}
fmt.Printf("signature created: %s", base64.StdEncoding.EncodeToString(signature))
// Output:signature created: G+zZagsyz7ioC/ZOa5EwsaKice0vs2BvZ0ljgkFHxD3vGsMlGeD4sXHEcfbI4h8lP29VitSBdf4A+nHXih7svf4=
// Output:signature created: H+zZagsyz7ioC/ZOa5EwsaKice0vs2BvZ0ljgkFHxD3vGsMlGeD4sXHEcfbI4h8lP29VitSBdf4A+nHXih7svf4=
}

// BenchmarkSignMessage benchmarks the method SignMessage()
func BenchmarkSignMessage(b *testing.B) {
key, _ := ec.NewPrivateKey()
for i := 0; i < b.N; i++ {
_, _ = compat.SignMessage(key, []byte("This is a test message"), false)
_, _ = compat.SignMessage(key, []byte("This is a test message"))
}
}
6 changes: 1 addition & 5 deletions compat/bsm/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,9 @@ func VerifyMessage(address string, sig, data []byte) error {
return err
}

if !wasCompressed {
return fmt.Errorf("only compressed keys and signatures are supported")
}

// Get the address
var scriptAddress *script.Address
if scriptAddress, err = script.NewAddressFromPublicKey(publicKey, true); err != nil {
if scriptAddress, err = script.NewAddressFromPublicKeyWithCompression(publicKey, true, wasCompressed); err != nil {
return err
}

Expand Down
11 changes: 10 additions & 1 deletion script/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,16 @@ func NewAddressFromPublicKeyHash(hash []byte, mainnet bool) (*Address, error) {
// If mainnet parameter is true it will return a mainnet address (starting with a 1).
// Otherwise, (mainnet is false) it will return a testnet address (starting with an m or n).
func NewAddressFromPublicKey(pubKey *ec.PublicKey, mainnet bool) (*Address, error) {
hash := crypto.Hash160(pubKey.SerializeCompressed())
return NewAddressFromPublicKeyWithCompression(pubKey, mainnet, true)
}

func NewAddressFromPublicKeyWithCompression(pubKey *ec.PublicKey, mainnet bool, isCompressed bool) (*Address, error) {
var hash []byte
if isCompressed {
hash = crypto.Hash160(pubKey.SerializeCompressed())
} else {
hash = crypto.Hash160(pubKey.SerializeUncompressed())
}

// regtest := 111
// mainnet: 0
Expand Down

0 comments on commit bbbd07f

Please sign in to comment.