-
Notifications
You must be signed in to change notification settings - Fork 3.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'am-own-ed25519' into marie/6928-baseacc-pk
- Loading branch information
Showing
58 changed files
with
1,079 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,232 @@ | ||
package ed25519 | ||
|
||
import ( | ||
"crypto/subtle" | ||
"fmt" | ||
"io" | ||
|
||
"github.com/tendermint/tendermint/crypto" | ||
tmed25519 "github.com/tendermint/tendermint/crypto/ed25519" | ||
"github.com/tendermint/tendermint/crypto/tmhash" | ||
"golang.org/x/crypto/ed25519" | ||
|
||
"github.com/cosmos/cosmos-sdk/codec" | ||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" | ||
) | ||
|
||
//------------------------------------- | ||
|
||
const ( | ||
PrivKeyName = "cosmos/PrivKeyEd25519" | ||
PubKeyName = "cosmos/PubKeyEd25519" | ||
// PubKeySize is is the size, in bytes, of public keys as used in this package. | ||
PubKeySize = 32 | ||
// PrivateKeySize is the size, in bytes, of private keys as used in this package. | ||
PrivateKeySize = 64 | ||
// Size of an Edwards25519 signature. Namely the size of a compressed | ||
// Edwards25519 point, and a field element. Both of which are 32 bytes. | ||
SignatureSize = 64 | ||
// SeedSize is the size, in bytes, of private key seeds. These are the | ||
// private key representations used by RFC 8032. | ||
SeedSize = 32 | ||
|
||
keyType = "ed25519" | ||
) | ||
|
||
var _ cryptotypes.PrivKey = &PrivKey{} | ||
var _ codec.AminoMarshaler = &PrivKey{} | ||
|
||
// Bytes returns the privkey byte format. | ||
func (privKey *PrivKey) Bytes() []byte { | ||
return privKey.Key | ||
} | ||
|
||
// Sign produces a signature on the provided message. | ||
// This assumes the privkey is wellformed in the golang format. | ||
// The first 32 bytes should be random, | ||
// corresponding to the normal ed25519 private key. | ||
// The latter 32 bytes should be the compressed public key. | ||
// If these conditions aren't met, Sign will panic or produce an | ||
// incorrect signature. | ||
func (privKey *PrivKey) Sign(msg []byte) ([]byte, error) { | ||
signatureBytes := ed25519.Sign(ed25519.PrivateKey(privKey.Key), msg) | ||
return signatureBytes, 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 the latter 32 bytes of the privkey are all zero, privkey is not | ||
// initialized. | ||
initialized := false | ||
for _, v := range privKey.Key[32:] { | ||
if v != 0 { | ||
initialized = true | ||
break | ||
} | ||
} | ||
|
||
if !initialized { | ||
panic("Expected ed25519 PrivKey to include concatenated pubkey bytes") | ||
} | ||
|
||
pubkeyBytes := make([]byte, PubKeySize) | ||
copy(pubkeyBytes, privKey.Key[32:]) | ||
return &PubKey{Key: pubkeyBytes} | ||
} | ||
|
||
// 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 privKey.Type() != other.Type() { | ||
return false | ||
} | ||
|
||
return subtle.ConstantTimeCompare(privKey.Bytes(), other.Bytes()) == 1 | ||
} | ||
|
||
func (privKey *PrivKey) Type() string { | ||
return keyType | ||
} | ||
|
||
// MarshalAmino overrides Amino binary marshalling. | ||
func (privKey PrivKey) MarshalAmino() ([]byte, error) { | ||
return privKey.Key, nil | ||
} | ||
|
||
// UnmarshalAmino overrides Amino binary marshalling. | ||
func (privKey *PrivKey) UnmarshalAmino(bz []byte) error { | ||
*privKey = PrivKey{ | ||
Key: bz, | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// MarshalAminoJSON overrides Amino JSON marshalling. | ||
func (privKey PrivKey) MarshalAminoJSON() ([]byte, error) { | ||
// When we marshal to Amino JSON, we don't marshal the "key" field itself, | ||
// just its contents (i.e. the key bytes). | ||
return privKey.MarshalAmino() | ||
} | ||
|
||
// UnmarshalAminoJSON overrides Amino JSON marshalling. | ||
func (privKey *PrivKey) UnmarshalAminoJSON(bz []byte) error { | ||
return privKey.UnmarshalAmino(bz) | ||
} | ||
|
||
// GenPrivKey generates a new ed25519 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()) | ||
} | ||
|
||
// genPrivKey generates a new ed25519 private key using the provided reader. | ||
func genPrivKey(rand io.Reader) *PrivKey { | ||
seed := make([]byte, SeedSize) | ||
|
||
_, err := io.ReadFull(rand, seed) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
return &PrivKey{Key: ed25519.NewKeyFromSeed(seed)} | ||
} | ||
|
||
// 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. | ||
|
||
return &PrivKey{Key: ed25519.NewKeyFromSeed(seed)} | ||
} | ||
|
||
//------------------------------------- | ||
|
||
var _ cryptotypes.PubKey = &PubKey{} | ||
var _ codec.AminoMarshaler = &PubKey{} | ||
var _ cryptotypes.IntoTmPubKey = &PubKey{} | ||
|
||
// Address is the SHA256-20 of the raw pubkey bytes. | ||
func (pubKey *PubKey) Address() crypto.Address { | ||
if len(pubKey.Key) != PubKeySize { | ||
panic("pubkey is incorrect size") | ||
} | ||
return crypto.Address(tmhash.SumTruncated(pubKey.Key)) | ||
} | ||
|
||
// Bytes returns the PubKey byte format. | ||
func (pubKey *PubKey) Bytes() []byte { | ||
return pubKey.Key | ||
} | ||
|
||
func (pubKey *PubKey) VerifySignature(msg []byte, sig []byte) bool { | ||
// make sure we use the same algorithm to sign | ||
if len(sig) != SignatureSize { | ||
return false | ||
} | ||
|
||
return ed25519.Verify(ed25519.PublicKey(pubKey.Key), msg, sig) | ||
} | ||
|
||
func (pubKey *PubKey) String() string { | ||
return fmt.Sprintf("PubKeyEd25519{%X}", pubKey.Key) | ||
} | ||
|
||
func (pubKey *PubKey) Type() string { | ||
return keyType | ||
} | ||
|
||
func (pubKey *PubKey) Equals(other crypto.PubKey) bool { | ||
if pubKey.Type() != other.Type() { | ||
return false | ||
} | ||
|
||
return subtle.ConstantTimeCompare(pubKey.Bytes(), other.Bytes()) == 1 | ||
} | ||
|
||
// MarshalAmino overrides Amino binary marshalling. | ||
func (pubKey PubKey) MarshalAmino() ([]byte, error) { | ||
return pubKey.Key, nil | ||
} | ||
|
||
// UnmarshalAmino overrides Amino binary marshalling. | ||
func (pubKey *PubKey) UnmarshalAmino(bz []byte) error { | ||
*pubKey = PubKey{ | ||
Key: bz, | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// MarshalAminoJSON overrides Amino JSON marshalling. | ||
func (pubKey PubKey) MarshalAminoJSON() ([]byte, error) { | ||
// When we marshal to Amino JSON, we don't marshal the "key" field itself, | ||
// just its contents (i.e. the key bytes). | ||
return pubKey.MarshalAmino() | ||
} | ||
|
||
// UnmarshalAminoJSON overrides Amino JSON marshalling. | ||
func (pubKey *PubKey) UnmarshalAminoJSON(bz []byte) error { | ||
return pubKey.UnmarshalAmino(bz) | ||
} | ||
|
||
// AsTmPubKey converts our own PubKey into a Tendermint ED25519 pubkey. | ||
func (pubKey *PubKey) AsTmPubKey() crypto.PubKey { | ||
return tmed25519.PubKey(pubKey.Key) | ||
} | ||
|
||
// FromTmEd25519 converts a Tendermint ED25519 pubkey into our own ED25519 | ||
// PubKey. | ||
func FromTmEd25519(pubKey crypto.PubKey) (*PubKey, error) { | ||
tmPk, ok := pubKey.(tmed25519.PubKey) | ||
if !ok { | ||
return nil, fmt.Errorf("expected %T, got %T", tmed25519.PubKey{}, pubKey) | ||
} | ||
|
||
return &PubKey{Key: []byte(tmPk)}, nil | ||
} |
Oops, something went wrong.