@ -0,0 +1,94 @@ |
|||
package core |
|||
|
|||
import ( |
|||
"crypto/ecdsa" |
|||
"crypto/elliptic" |
|||
"crypto/rand" |
|||
"encoding/hex" |
|||
"errors" |
|||
"math/big" |
|||
) |
|||
|
|||
// Address is the type data for addresses
|
|||
type Address [32]byte |
|||
|
|||
func (addr Address) String() string { |
|||
return hex.EncodeToString(addr[:]) |
|||
} |
|||
|
|||
func NewKey() (*ecdsa.PrivateKey, error) { |
|||
curve := elliptic.P256() |
|||
|
|||
privatekey := new(ecdsa.PrivateKey) |
|||
privatekey, err := ecdsa.GenerateKey(curve, rand.Reader) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
return privatekey, err |
|||
} |
|||
|
|||
func PackPubK(pubK *ecdsa.PublicKey) []byte { |
|||
return elliptic.Marshal(pubK.Curve, pubK.X, pubK.Y) |
|||
} |
|||
func UnpackPubK(b []byte) *ecdsa.PublicKey { |
|||
x, y := elliptic.Unmarshal(elliptic.P256(), b) |
|||
return &ecdsa.PublicKey{ |
|||
Curve: elliptic.P256(), |
|||
X: x, |
|||
Y: y, |
|||
} |
|||
} |
|||
|
|||
func AddressFromPrivK(privK *ecdsa.PrivateKey) Address { |
|||
h := HashBytes(PackPubK(&privK.PublicKey)) |
|||
return Address(h) |
|||
} |
|||
|
|||
func PackSignature(r, s *big.Int) []byte { |
|||
sig := r.Bytes() |
|||
sig = append(sig, s.Bytes()...) |
|||
return sig |
|||
} |
|||
|
|||
func UnpackSignature(sig []byte) (*big.Int, *big.Int, error) { |
|||
if len(sig) != 64 { |
|||
return nil, nil, errors.New("Invalid signature") |
|||
} |
|||
rBytes := sig[:32] |
|||
sBytes := sig[32:] |
|||
|
|||
r := new(big.Int).SetBytes(rBytes) |
|||
s := new(big.Int).SetBytes(sBytes) |
|||
|
|||
return r, s, nil |
|||
} |
|||
|
|||
func Sign(privK *ecdsa.PrivateKey, m []byte) ([]byte, error) { |
|||
r := big.NewInt(0) |
|||
s := big.NewInt(0) |
|||
|
|||
hashMsg := HashBytes(m) |
|||
|
|||
r, s, err := ecdsa.Sign(rand.Reader, privK, hashMsg[:]) |
|||
if err != nil { |
|||
return []byte{}, err |
|||
} |
|||
|
|||
sig := PackSignature(r, s) |
|||
|
|||
return sig, nil |
|||
|
|||
} |
|||
|
|||
func VerifySignature(pubK *ecdsa.PublicKey, m []byte, sig []byte) bool { |
|||
hashMsg := HashBytes(m) |
|||
|
|||
r, s, err := UnpackSignature(sig) |
|||
if err != nil { |
|||
return false |
|||
} |
|||
|
|||
verified := ecdsa.Verify(pubK, hashMsg[:], r, s) |
|||
return verified |
|||
} |
@ -0,0 +1,34 @@ |
|||
package core |
|||
|
|||
import ( |
|||
"fmt" |
|||
"testing" |
|||
|
|||
"github.com/stretchr/testify/assert" |
|||
) |
|||
|
|||
func TestNewKey(t *testing.T) { |
|||
_, err := NewKey() |
|||
assert.Nil(t, err) |
|||
} |
|||
func TestAddress(t *testing.T) { |
|||
privK, err := NewKey() |
|||
assert.Nil(t, err) |
|||
|
|||
addr := AddressFromPrivK(privK) |
|||
fmt.Println(addr.String()) |
|||
} |
|||
|
|||
func TestSignAndVerify(t *testing.T) { |
|||
privK, err := NewKey() |
|||
assert.Nil(t, err) |
|||
|
|||
// Sign
|
|||
m := []byte("test") |
|||
sig, err := Sign(privK, m) |
|||
assert.Nil(t, err) |
|||
|
|||
// Verify
|
|||
verified := VerifySignature(&privK.PublicKey, m, sig) |
|||
assert.True(t, verified) |
|||
} |