Skip to content

Commit

Permalink
Various cleanup, friendly names, etc
Browse files Browse the repository at this point in the history
  • Loading branch information
mrz1836 committed Sep 30, 2020
1 parent 970ddec commit fef5af2
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 81 deletions.
2 changes: 1 addition & 1 deletion address.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (a *A25) EmbeddedChecksum() (c [4]byte) {
}

// Tmpl and Set58 are adapted from the C solution.
// Go has big integers but this techinique seems better.
// Go has big integers but this technique seems better.
var tmpl = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")

// Set58 takes a base58 encoded address and decodes it into the receiver.
Expand Down
2 changes: 1 addition & 1 deletion sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
func SignMessage(privKey string, message string) string {
prefixBytes := []byte("Bitcoin Signed Message:\n")
messageBytes := []byte(message)
bytes := []byte{}
var bytes []byte
bytes = append(bytes, byte(len(prefixBytes)))
bytes = append(bytes, prefixBytes...)
bytes = append(bytes, byte(len(messageBytes)))
Expand Down
6 changes: 4 additions & 2 deletions sign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
// Identity Private Key
const privKey = "E83385AF76B2B1997326B567461FB73DD9C27EAB9E1E86D26779F4650C5F2B75"

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

// privKey string, message string, compress bool
Expand All @@ -17,13 +18,14 @@ func TestSignMessage(t *testing.T) {
}
}

// TestVerifyMessage will test the method VerifyMessage()
func TestVerifyMessage(t *testing.T) {

var sig = "IBDscOd/Ov4yrd/YXantqajSAnW4fudpfr2KQy5GNo9pZybF12uNaal4KI822UpQLS/UJD+UK2SnNMn6Z3E4na8="
var address = "1FiyJnrgwBc3Ff83V1yRWAkmXBdGrDQnXQ"
var data = "Testing!"

if !VerifyMessage(address, sig, data) {
t.Error("Failed to verify message")
if err := VerifyMessage(address, sig, data); err != nil {
t.Fatalf("failed to verify message: %s", err.Error())
}
}
1 change: 1 addition & 0 deletions util.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package bitcoin
import "encoding/hex"

// HexDecode returns a decoded hex string without handling errors
// todo: why ignore the error? (@mrz)
func HexDecode(str string) []byte {
b, _ := hex.DecodeString(str)
return b
Expand Down
162 changes: 85 additions & 77 deletions verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import (
)

func sha256d(body []byte) []byte {
msghash1 := sha256.Sum256([]byte(body))
msghash2 := sha256.Sum256(msghash1[:])
return msghash2[:]
msgHash1 := sha256.Sum256(body)
msgHash2 := sha256.Sum256(msgHash1[:])
return msgHash2[:]
}

const (
Expand All @@ -23,60 +23,56 @@ const (
)

// VerifyMessage verifies a string and address against the provided signature and assumes Bitcoin Signed Message encoding
func VerifyMessage(address, signature, data string) (ok bool) {
addrs, err := sigmestoaddr(signature, data)
func VerifyMessage(address, signature, data string) error {
addresses, err := sigMessageToAddress(signature, data)
if err != nil {
return
return err
}
for _, addr2 := range addrs {
for _, addr2 := range addresses {
if address == addr2 {
ok = true
return
return nil
}
}
return
return fmt.Errorf("address: %s not found", address)
}

func messagehash(message, header string) (msghash2 []byte, err error) {
hlen := len(header)
if hlen >= 0xfd {
err = fmt.Errorf("long header is not supported")
return
}
mlen := len(message)
if mlen >= 0xfd {
err = fmt.Errorf("long message is not supported")
return
}
bitcoinmsg := string([]byte{byte(hlen)})
bitcoinmsg += header
bitcoinmsg += string([]byte{byte(mlen)})
bitcoinmsg += message
msghash2 = sha256d([]byte(bitcoinmsg))
return
// messageHash will compute a hash for the given message & header
func messageHash(message, header string) ([]byte, error) {
headerLength := len(header)
if headerLength >= 0xfd {
return nil, fmt.Errorf("long header is not supported")
}
messageLength := len(message)
if messageLength >= 0xfd {
return nil, fmt.Errorf("long message is not supported")
}
bitcoinMsg := string([]byte{byte(headerLength)})
bitcoinMsg += header
bitcoinMsg += string([]byte{byte(messageLength)})
bitcoinMsg += message
return sha256d([]byte(bitcoinMsg)), nil
}

func parseSignature(signature string) (sig secp256k1.Signature, recid int,
err error) {
sigraw, err2 := base64.StdEncoding.DecodeString(signature)
if err2 != nil {
err = err2
// parseSignature will parse the given signature
func parseSignature(signature string) (sig secp256k1.Signature, recID int, err error) {
var sigRaw []byte
if sigRaw, err = base64.StdEncoding.DecodeString(signature); err != nil {
return
}
r0 := sigraw[0] - 27
recid = int(r0 & 3)
r0 := sigRaw[0] - 27
recID = int(r0 & 3)
compressed := (r0 & 4) == 1
if compressed {
err = fmt.Errorf("compressed type is not supported")
return
}
sig.R.SetBytes(sigraw[1 : 1+32])
sig.S.SetBytes(sigraw[1+32 : 1+32+32])
sig.R.SetBytes(sigRaw[1 : 1+32])
sig.S.SetBytes(sigRaw[1+32 : 1+32+32])
return
}

func pubtoaddr(pubkeyXy2 secp256k1.XY, compressed bool,
magic []byte) (bcpy []byte) {
// pubKeyToAddress will convert a pubkey to an address
func pubKeyToAddress(pubkeyXy2 secp256k1.XY, compressed bool, magic []byte) (bcpy []byte) {
size := 65
if compressed {
size = 33
Expand All @@ -97,16 +93,16 @@ func pubtoaddr(pubkeyXy2 secp256k1.XY, compressed bool,
return
}

func addrToStr(bcpy []byte) (s string, err error) {
// addressToString will convert a raw address to a string version
func addressToString(bcpy []byte) (s string, err error) {
z := new(big.Int)
z.SetBytes(bcpy)
enc := base58.BitcoinEncoding
var encdd []byte
encdd, err = enc.Encode([]byte(z.String()))
if err != nil {
var encodeResults []byte
if encodeResults, err = enc.Encode([]byte(z.String())); err != nil {
return
}
s = string(encdd)
s = string(encodeResults)
for _, v := range bcpy {
if v != 0 {
break
Expand All @@ -120,23 +116,22 @@ func addrToStr(bcpy []byte) (s string, err error) {
// And modified for local package.
// License is:
// https://github.com/piotrnar/gocoin/blob/master/lib/secp256k1/COPYING
func getBin(num *secp256k1.Number, le int) []byte {
func getBin(num *secp256k1.Number, le int) ([]byte, error) {
bts := num.Bytes()
if len(bts) > le {
panic("buffer too small")
return nil, fmt.Errorf("buffer too small")
}
if len(bts) == le {
return bts
return bts, nil
}
return append(make([]byte, le-len(bts)), bts...)
return append(make([]byte, le-len(bts)), bts...), nil
}

// This function is copied from "piotrnar/gocoin/lib/secp256k1".
// And modified for local package.
// License is:
// https://github.com/piotrnar/gocoin/blob/master/lib/secp256k1/COPYING
func recover(sig *secp256k1.Signature, pubkey *secp256k1.XY,
m *secp256k1.Number, recid int) (ret bool) {
func recoverSig(sig *secp256k1.Signature, pubkey *secp256k1.XY, m *secp256k1.Number, recID int) (bool, error) {
var theCurveP secp256k1.Number
theCurveP.SetBytes([]byte{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
Expand All @@ -147,18 +142,23 @@ func recover(sig *secp256k1.Signature, pubkey *secp256k1.XY,
var xj, qj secp256k1.XYZ

rx.Set(&sig.R.Int)
if (recid & 2) != 0 {
if (recID & 2) != 0 {
rx.Add(&rx.Int, &secp256k1.TheCurve.Order.Int)
if rx.Cmp(&theCurveP.Int) >= 0 {
return false
return false, nil // todo: is this actually an error?
}
}

fx.SetB32(getBin(&rx, 32))
bin, err := getBin(&rx, 32)
if err != nil {
return false, err
}

fx.SetB32(bin)

X.SetXO(&fx, (recid&1) != 0)
X.SetXO(&fx, (recID&1) != 0)
if !X.IsValid() {
return false
return false, nil // todo: is this actually an error?
}

xj.SetXY(&X)
Expand All @@ -175,39 +175,47 @@ func recover(sig *secp256k1.Signature, pubkey *secp256k1.XY,
xj.ECmult(&qj, &u2, &u1)
pubkey.SetXYZ(&qj)

return true
return true, nil
}

func sigmestoaddr(signature, message string) (addrs []string, err error) {
msghash2, err2 := messagehash(message, hBSV)
if err2 != nil {
err = err2
return
// sigMessageToAddress will convert a signature & message to a list of addresses
func sigMessageToAddress(signature, message string) ([]string, error) {

// Get message hash
msgHash, err := messageHash(message, hBSV)
if err != nil {
return nil, err
}
sig, recid, err2 := parseSignature(signature)
if err2 != nil {
err = err2
return

// Parse the signature
var sig secp256k1.Signature
var recID int
sig, recID, err = parseSignature(signature)
if err != nil {
return nil, err
}
var msg secp256k1.Number
msg.SetBytes(msghash2)
msg.SetBytes(msgHash)

var pubkeyXy2 secp256k1.XY
ret2 := recover(&sig, &pubkeyXy2, &msg, recid)
if !ret2 {
err = fmt.Errorf("recover pubkey failed")
return
var ret bool
ret, err = recoverSig(&sig, &pubkeyXy2, &msg, recID)
if err != nil {
return nil, err
} else if !ret {
return nil, fmt.Errorf("recover pubkey failed")
}

addrs = make([]string, 2)
addresses := make([]string, 2)
for i, compressed := range []bool{true, false} {
bcpy := pubtoaddr(pubkeyXy2, compressed, []byte{byte(0)})
s, err2 := addrToStr(bcpy)
if err2 != nil {
err = err2
return
bcpy := pubKeyToAddress(pubkeyXy2, compressed, []byte{byte(0)})

var addressString string
addressString, err = addressToString(bcpy)
if err != nil {
return nil, err
}
addrs[i] = s
addresses[i] = addressString
}
return
return addresses, nil
}

0 comments on commit fef5af2

Please sign in to comment.