Skip to content

Commit

Permalink
core: add Account type, finish address algorithm.
Browse files Browse the repository at this point in the history
crypto: add ecdsa related functions.
  • Loading branch information
qywang2012 authored and Robin Zhong committed Sep 16, 2017
1 parent ee59283 commit 7e69d24
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 1 deletion.
14 changes: 13 additions & 1 deletion Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 52 additions & 0 deletions core/account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (C) 2017 go-nebulas authors
//
// This file is part of the go-nebulas library.
//
// the go-nebulas library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// the go-nebulas library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the go-nebulas library. If not, see <http://www.gnu.org/licenses/>.
//

package core

import (
"crypto/ecdsa"
"fmt"

"github.com/satori/go.uuid"
)

type Account struct {
// uuid is random for unique id
id string

// nick for user account
nick string

address Address

// ecdsa private key ,public & address can be derived from it
privateKey ecdsa.PrivateKey
}

// create new account with nick and private key
func newAccountFromECDSA(nick string, privateKeyECDSA *ecdsa.PrivateKey) *Account {
id := fmt.Sprintf("%s", uuid.NewV4())
addr := NewAddressWithPrivateKey(privateKeyECDSA)
account := &Account{
id: id,
nick: nick,
address: *addr,
privateKey: *privateKeyECDSA,
}
return account
}
47 changes: 47 additions & 0 deletions core/address.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,19 @@

package core

import (
"crypto/ecdsa"

"github.com/nebulasio/go-nebulas/crypto"
"github.com/nebulasio/go-nebulas/crypto/hash"
"github.com/nebulasio/go-nebulas/utils/bytes"
)

const (
CheckSumLength = 4
AddressLength = 20
)

/*
Address Similar to Bitcoin and Ethereum, Nebulas also adopts elliptic curve algorithm as its basic encryption algorithm for Nebulas accounts. A user’s private key is a randomly generated 256-bit binary number, based on which a 64-byte public key can be generated via elliptic curve multiplication. Bitcoin and Ethereum addresses are computed by public key via the deterministic Hash algorithm, and the difference between them lies in: Bitcoin address has the checksum design aiming to prevent a user from sending Bitcoins to a wrong user account accidentally due to entry of several incorrect characters; while Ethereum doesn’t have such checksum design.
Expand Down Expand Up @@ -58,3 +71,37 @@ func NewAddress(address string) *Address {
addr := &Address{address: address}
return addr
}

// NewAddressWithPrivateKey generate Address from private key
func NewAddressWithPrivateKey(privateKey *ecdsa.PrivateKey) *Address {
publicKeyBytes := crypto.FromECDSAPub(&privateKey.PublicKey)
return NewAddressWithPublicKey(publicKeyBytes)
}

// NewAddressWithPublicKey generate Address from public key
func NewAddressWithPublicKey(publicKeyBytes []byte) *Address {
data := hash.Sha3256(publicKeyBytes)[len(publicKeyBytes)-AddressLength:]
checkSum := hash.Sha3256(data)[:CheckSumLength]
address := bytes.Hex(append(data, checkSum...))
addr := &Address{address: address}
return addr
}

type ExtAddress struct {
nick string // nick or some comment for address
address Address
extAddress string
}

// NewExtAddress return new @ExtAddress instance.
func NewExtAddress(nick string, publicKeyBytes []byte) *ExtAddress {
data := hash.Sha3256(publicKeyBytes)[len(publicKeyBytes)-AddressLength:]
addr := NewAddressWithPublicKey(publicKeyBytes)
extHash := hash.Sha3256(append(data, []byte(nick)...))[:2]
extAddress := addr.address + bytes.Hex(extHash)
extAddr := &ExtAddress{
nick: nick,
address: *addr,
extAddress: extAddress}
return extAddr
}
74 changes: 74 additions & 0 deletions crypto/ecdsa.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (C) 2017 go-nebulas authors
//
// This file is part of the go-nebulas library.
//
// the go-nebulas library is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// the go-nebulas library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with the go-nebulas library. If not, see <http://www.gnu.org/licenses/>.
//

package crypto

import (
"crypto/ecdsa"
"crypto/elliptic"
"io"

"encoding/hex"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
"math/big"
)

// S256 returns an instance of the secp256k1 curve.
func S256() elliptic.Curve {
return secp256k1.S256()
}

// generate a ecdsa private key
func GenerateECDSAPrivateKey(rand io.Reader) (*ecdsa.PrivateKey, error) {
privateKeyECDSA, err := ecdsa.GenerateKey(S256(), rand)
if err != nil {
return nil, err
}
return privateKeyECDSA, nil
}

// convert ecdsa public key to bytes
func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
if pub == nil || pub.X == nil || pub.Y == nil {
return nil
}
return elliptic.Marshal(S256(), pub.X, pub.Y)
}

// HexToECDSAPrivate parses a secp256k1 private key.
func HexToECDSAPrivate(hexkey string) (*ecdsa.PrivateKey, error) {
b, err := hex.DecodeString(hexkey)
if err != nil {
return nil, errors.New("invalid hex string")
}
return ToECDSAPrivate(b)
}

// ToECDSAPrivate creates a private key with the given data value.
func ToECDSAPrivate(d []byte) (*ecdsa.PrivateKey, error) {
priv := new(ecdsa.PrivateKey)
priv.PublicKey.Curve = S256()
if 8*len(d) != priv.Params().BitSize {
return nil, fmt.Errorf("invalid length, need %d bits", priv.Params().BitSize)
}
priv.D = new(big.Int).SetBytes(d)
priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(d)
return priv, nil
}
10 changes: 10 additions & 0 deletions utils/bytes/bytes.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,13 @@ func FromInt16(v int16) []byte {
binary.BigEndian.PutUint16(b, uint16(v))
return b
}

// string encode []byte
func String(data []byte) string {
return string(data)
}

// FromString decode s.
func FromString(s string) []byte {
return []byte(s)
}
78 changes: 78 additions & 0 deletions utils/bytes/bytes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -598,3 +598,81 @@ func TestFromInt16(t *testing.T) {
})
}
}

func TestString(t *testing.T) {
type args struct {
data []byte
}
tests := []struct {
name string
args args
want string
}{
{
"empty",
args{[]byte{}},
"",
},
{
"number",
args{[]byte{49, 50}},
"12",
},
{
"letter",
args{[]byte{97, 115}},
"as",
},
{
"special",
args{[]byte{42, 63, 49, 97}},
"*?1a",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := String(tt.args.data); got != tt.want {
t.Errorf("String() = %v, want %v", got, tt.want)
}
})
}
}

func TestFromString(t *testing.T) {
type args struct {
v string
}
tests := []struct {
name string
args args
wantB []byte
}{
{
"empty",
args{""},
[]byte{},
},
{
"number",
args{"12"},
[]byte{49, 50},
},
{
"letter",
args{"as"},
[]byte{97, 115},
},
{
"special",
args{"*?1a"},
[]byte{42, 63, 49, 97},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if gotB := FromString(tt.args.v); !reflect.DeepEqual(gotB, tt.wantB) {
t.Errorf("FromInt16() = %v, want %v", gotB, tt.wantB)
}
})
}
}

0 comments on commit 7e69d24

Please sign in to comment.