参考:https://github.com/liuchengxu/blockchain-tutorial/blob/master/content/part-5/address.md
类似于比特币实现一个用户一个地址,并分配10对ecc公私钥。
package main
import (
"bytes"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"golang.org/x/crypto/ripemd160"
"log"
"fmt"
"encoding/hex"
"math/big"
)
const version = byte(0x00)
const addressChecksumLen = 4
var b58Alphabet = []byte("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz")
type userKeys struct {
prk *ecdsa.PrivateKey
puk ecdsa.PublicKey
}
type Address struct {
PrivateKey ecdsa.PrivateKey
PublicKey []byte
usrAddress string
usrKeys [10]userKeys
}
func getKey() (*ecdsa.PrivateKey, error) {
prk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return prk, err
}
return prk, nil
}
func newKeyPair() (ecdsa.PrivateKey, []byte) {
curve := elliptic.P256()
private, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
log.Panic(err)
}
pubKey := append(private.PublicKey.X.Bytes(), private.PublicKey.Y.Bytes()...)
return *private, pubKey
}
func hashPubKey(pubKey []byte) []byte {
publicSHA256 := sha256.Sum256(pubKey)
RIPEMD160Hasher := ripemd160.New()
_, err := RIPEMD160Hasher.Write(publicSHA256[:])
if err != nil {
log.Panic(err)
}
publicRIPEMD160 := RIPEMD160Hasher.Sum(nil)
return publicRIPEMD160
}
func newAddress() Address {
var address Address
private, public := newKeyPair()
address.PublicKey = public
address.PrivateKey = private
for i := 0; i < 10; i++ {
prk, err := getKey()
if err != nil {
panic(err)
}
address.usrKeys[i].prk = prk
address.usrKeys[i].puk = prk.PublicKey
}
address.usrAddress = getAddress(address)
return address
}
func getAddress(a Address) string {
pubKeyHash := hashPubKey(a.PublicKey)
versionedPayload := append([]byte{version}, pubKeyHash...)
checksum := checksum(versionedPayload)
fullPayload := append(versionedPayload, checksum...)
address := Base58Encode(fullPayload)
return string(address)
}
func checksum(payload []byte) []byte {
firstSHA := sha256.Sum256(payload)
secondSHA := sha256.Sum256(firstSHA[:])
return secondSHA[:addressChecksumLen]
}
func Base58Encode(input []byte) []byte {
var result []byte
x := big.NewInt(0).SetBytes(input)
base := big.NewInt(int64(len(b58Alphabet)))
zero := big.NewInt(0)
mod := &big.Int{}
for x.Cmp(zero) != 0 {
x.DivMod(x, base, mod)
result = append(result, b58Alphabet[mod.Int64()])
}
if input[0] == 0x00 {
result = append(result, b58Alphabet[0])
}
return result
}
func Base58Decode(input []byte) []byte {
result := big.NewInt(0)
for _, b := range input {
charIndex := bytes.IndexByte(b58Alphabet, b)
result.Mul(result, big.NewInt(58))
result.Add(result, big.NewInt(int64(charIndex)))
}
decoded := result.Bytes()
if input[0] == b58Alphabet[0] {
decoded = append([]byte{0x00}, decoded...)
}
return decoded
}
func main() {
var ars Address = newAddress();
fmt.Println("user PublicKey is :", hex.EncodeToString(ars.PublicKey))
fmt.Println("user Address is :", ars.usrAddress)
for i := 0; i < 10; i++ {
fmt.Println(ars.usrKeys[i].prk)
fmt.Println(ars.usrKeys[i].puk)
}
}