@ -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) |
||||
|
} |