Files
tendermint/crypto/sr25519/privkey.go
M. J. Fromberger dbe2146d0a rpc: simplify the encoding of interface-typed arguments in JSON (#7600)
Add package jsontypes that implements a subset of the custom libs/json 
package. Specifically it handles encoding and decoding of interface types
wrapped in "tagged" JSON objects. It omits the deep reflection on arbitrary
types, preserving only the handling of type tags wrapper encoding.

- Register interface types (Evidence, PubKey, PrivKey) for tagged encoding.
- Update the existing implementations to satisfy the type.
- Register those types with the jsontypes registry.
- Add string tags to 64-bit integer fields where needed.
- Add marshalers to structs that export interface-typed fields.
2022-01-14 18:14:09 -08:00

169 lines
3.7 KiB
Go

package sr25519
import (
"encoding/json"
"fmt"
"io"
"github.com/oasisprotocol/curve25519-voi/primitives/sr25519"
"github.com/tendermint/tendermint/crypto"
)
var (
_ crypto.PrivKey = PrivKey{}
signingCtx = sr25519.NewSigningContext([]byte{})
)
const (
// PrivKeySize is the size of a sr25519 signature in bytes.
PrivKeySize = sr25519.MiniSecretKeySize
KeyType = "sr25519"
)
// PrivKey implements crypto.PrivKey.
type PrivKey struct {
msk sr25519.MiniSecretKey
kp *sr25519.KeyPair
}
// TypeTag satisfies the jsontypes.Tagged interface.
func (PrivKey) TypeTag() string { return PrivKeyName }
// Bytes returns the byte-encoded PrivKey.
func (privKey PrivKey) Bytes() []byte {
if privKey.kp == nil {
return nil
}
return privKey.msk[:]
}
// Sign produces a signature on the provided message.
func (privKey PrivKey) Sign(msg []byte) ([]byte, error) {
if privKey.kp == nil {
return nil, fmt.Errorf("sr25519: uninitialized private key")
}
st := signingCtx.NewTranscriptBytes(msg)
sig, err := privKey.kp.Sign(crypto.CReader(), st)
if err != nil {
return nil, fmt.Errorf("sr25519: failed to sign message: %w", err)
}
sigBytes, err := sig.MarshalBinary()
if err != nil {
return nil, fmt.Errorf("sr25519: failed to serialize signature: %w", err)
}
return sigBytes, nil
}
// PubKey gets the corresponding public key from the private key.
//
// Panics if the private key is not initialized.
func (privKey PrivKey) PubKey() crypto.PubKey {
if privKey.kp == nil {
panic("sr25519: uninitialized private key")
}
b, err := privKey.kp.PublicKey().MarshalBinary()
if err != nil {
panic("sr25519: failed to serialize public key: " + err.Error())
}
return PubKey(b)
}
// Equals - you probably don't need to use this.
// Runs in constant time based on length of the keys.
func (privKey PrivKey) Equals(other crypto.PrivKey) bool {
if otherSr, ok := other.(PrivKey); ok {
return privKey.msk.Equal(&otherSr.msk)
}
return false
}
func (privKey PrivKey) Type() string {
return KeyType
}
func (privKey PrivKey) MarshalJSON() ([]byte, error) {
var b []byte
// Handle uninitialized private keys gracefully.
if privKey.kp != nil {
b = privKey.Bytes()
}
return json.Marshal(b)
}
func (privKey *PrivKey) UnmarshalJSON(data []byte) error {
for i := range privKey.msk {
privKey.msk[i] = 0
}
privKey.kp = nil
var b []byte
if err := json.Unmarshal(data, &b); err != nil {
return fmt.Errorf("sr25519: failed to deserialize JSON: %w", err)
}
if len(b) == 0 {
return nil
}
msk, err := sr25519.NewMiniSecretKeyFromBytes(b)
if err != nil {
return err
}
sk := msk.ExpandEd25519()
privKey.msk = *msk
privKey.kp = sk.KeyPair()
return nil
}
// GenPrivKey generates a new sr25519 private key.
// It uses OS randomness in conjunction with the current global random seed
// in tendermint/libs/common to generate the private key.
func GenPrivKey() PrivKey {
return genPrivKey(crypto.CReader())
}
func genPrivKey(rng io.Reader) PrivKey {
msk, err := sr25519.GenerateMiniSecretKey(rng)
if err != nil {
panic("sr25519: failed to generate MiniSecretKey: " + err.Error())
}
sk := msk.ExpandEd25519()
return PrivKey{
msk: *msk,
kp: sk.KeyPair(),
}
}
// GenPrivKeyFromSecret hashes the secret with SHA2, and uses
// that 32 byte output to create the private key.
// NOTE: secret should be the output of a KDF like bcrypt,
// if it's derived from user input.
func GenPrivKeyFromSecret(secret []byte) PrivKey {
seed := crypto.Sha256(secret) // Not Ripemd160 because we want 32 bytes.
var privKey PrivKey
if err := privKey.msk.UnmarshalBinary(seed); err != nil {
panic("sr25519: failed to deserialize MiniSecretKey: " + err.Error())
}
sk := privKey.msk.ExpandEd25519()
privKey.kp = sk.KeyPair()
return privKey
}