Skip to content
Snippets Groups Projects
key.go 2.57 KiB
Newer Older
package mock

import (
	"crypto/rand"
	"encoding/json"
	"fmt"

	acm "github.com/hyperledger/burrow/account"
	"github.com/hyperledger/burrow/keys"
	"github.com/pkg/errors"
	"github.com/tendermint/go-crypto"
	"github.com/wayn3h0/go-uuid"
	"golang.org/x/crypto/ed25519"
	"golang.org/x/crypto/ripemd160"
)

// Mock ed25510 key for mock keys client
// Simple ed25519 key structure for mock purposes with ripemd160 address
type Key struct {
	Name       string
	Address    acm.Address
	PublicKey  []byte
	PrivateKey []byte
}

func newKey(name string) (*Key, error) {
	key := &Key{
		Name:       name,
		PublicKey:  make([]byte, ed25519.PublicKeySize),
		PrivateKey: make([]byte, ed25519.PrivateKeySize),
	}
	// this is a mock key, so the entropy of the source is purely
	// for testing
	publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
	if err != nil {
		return nil, err
	}
	copy(key.PrivateKey[:], privateKey[:])
	copy(key.PublicKey[:], publicKey[:])

	// prepend 0x01 for ed25519 public key
	typedPublicKeyBytes := append([]byte{0x01}, key.PublicKey...)
	hasher := ripemd160.New()
	hasher.Write(typedPublicKeyBytes)
	key.Address, err = acm.AddressFromBytes(hasher.Sum(nil))
	if err != nil {
		return nil, err
	}
	if key.Name == "" {
		key.Name = key.Address.String()
	}
	return key, nil
}

func mockKeyFromPrivateAccount(privateAccount acm.PrivateAccount) *Key {
	_, ok := privateAccount.PrivateKey().Unwrap().(crypto.PrivKeyEd25519)
	if !ok {
		panic(fmt.Errorf("mock key client only supports ed25519 private keys at present"))
	}
	key := &Key{
		Name:       privateAccount.Address().String(),
		Address:    privateAccount.Address(),
		PublicKey:  privateAccount.PublicKey().RawBytes(),
		PrivateKey: privateAccount.PrivateKey().RawBytes(),
	}
	return key
}

func (key *Key) Sign(message []byte) (acm.Signature, error) {
	return acm.SignatureFromBytes(ed25519.Sign(key.PrivateKey, message))
}

// TODO: remove after merging keys taken from there to match serialisation
type plainKeyJSON struct {
	Id         []byte
	Type       string
	Address    string
	PrivateKey []byte
}

// Returns JSON string compatible with that stored by monax-keys
func (key *Key) MonaxKeysJSON() string {
	id, err := uuid.NewRandom()
	if err != nil {
		return errors.Wrap(err, "could not create monax key json").Error()
	}
	jsonKey := plainKeyJSON{
		Id:         []byte(id.String()),
		Address:    key.Address.String(),
		Type:       string(keys.KeyTypeEd25519Ripemd160),
		PrivateKey: key.PrivateKey,
	}
	bs, err := json.Marshal(jsonKey)
	if err != nil {
		return errors.Wrap(err, "could not create monax key json").Error()
	}
	return string(bs)
}