Browse Source

crypto/ed25519: Update the godocs (#2002)

This commit updates the godocs for the package, and adds an optimization
to the privkey.Pubkey() method.

The optimization is that in golang, the private key (due to interface
compatibility reasons) has a copy of the public key stored inside of it.
Therefore if this copy has already been computed, there is no need to
recompute it.
pull/1966/head
Dev Ojha 7 years ago
committed by Anton Kaliaev
parent
commit
67762aec73
2 changed files with 68 additions and 19 deletions
  1. +67
    -19
      crypto/ed25519/ed25519.go
  2. +1
    -0
      crypto/ed25519/ed25519_test.go

+ 67
- 19
crypto/ed25519/ed25519.go View File

@ -44,21 +44,40 @@ func init() {
Ed25519SignatureAminoRoute, nil)
}
// Implements crypto.PrivKey
// PrivKeyEd25519 implements crypto.PrivKey.
type PrivKeyEd25519 [64]byte
// Bytes marshals the privkey using amino encoding.
func (privKey PrivKeyEd25519) Bytes() []byte {
return cdc.MustMarshalBinaryBare(privKey)
}
// Sign produces a signature on the provided message.
func (privKey PrivKeyEd25519) Sign(msg []byte) (crypto.Signature, error) {
privKeyBytes := [64]byte(privKey)
signatureBytes := ed25519.Sign(&privKeyBytes, msg)
return SignatureEd25519(*signatureBytes), nil
}
// PubKey gets the corresponding public key from the private key.
func (privKey PrivKeyEd25519) PubKey() crypto.PubKey {
privKeyBytes := [64]byte(privKey)
initialized := false
// If the latter 32 bytes of the privkey are all zero, compute the pubkey
// otherwise privkey is initialized and we can use the cached value inside
// of the private key.
for _, v := range privKeyBytes[32:] {
if v != 0 {
initialized = true
break
}
}
if initialized {
var pubkeyBytes [PubKeyEd25519Size]byte
copy(pubkeyBytes[:], privKeyBytes[32:])
return PubKeyEd25519(pubkeyBytes)
}
pubBytes := *ed25519.MakePublicKey(&privKeyBytes)
return PubKeyEd25519(pubBytes)
}
@ -73,53 +92,74 @@ func (privKey PrivKeyEd25519) Equals(other crypto.PrivKey) bool {
}
}
func (privKey PrivKeyEd25519) ToCurve25519() *[32]byte {
// ToCurve25519 takes a private key and returns its representation on
// Curve25519. Curve25519 is birationally equivalent to Edwards25519,
// which Ed25519 uses internally. This method is intended for use in
// an X25519 Diffie Hellman key exchange.
func (privKey PrivKeyEd25519) ToCurve25519() *[PubKeyEd25519Size]byte {
keyCurve25519 := new([32]byte)
privKeyBytes := [64]byte(privKey)
extra25519.PrivateKeyToCurve25519(keyCurve25519, &privKeyBytes)
return keyCurve25519
}
// Deterministically generates new priv-key bytes from key.
// Generate deterministically derives a new priv-key bytes from key.
// The privkey is generated as Sha256(amino_encode({privkey, index}))
// Note that we append the public key to the private key, the same way
// that golang/x/crypto/ed25519 does. See
// https://github.com/tendermint/ed25519/blob/master/ed25519.go#L39 for
// further details.
func (privKey PrivKeyEd25519) Generate(index int) PrivKeyEd25519 {
bz, err := cdc.MarshalBinaryBare(struct {
bz := cdc.MustMarshalBinaryBare(struct {
PrivKey [64]byte
Index int
}{privKey, index})
if err != nil {
panic(err)
}
newBytes := crypto.Sha256(bz)
newKey := new([64]byte)
copy(newKey[:32], newBytes)
// ed25519.MakePublicKey(newKey) alters the last 32 bytes of newKey.
// It places the pubkey in the last 32 bytes of newKey, and returns the
// public key.
ed25519.MakePublicKey(newKey)
return PrivKeyEd25519(*newKey)
}
// GenPrivKeyEd25519 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 GenPrivKeyEd25519() PrivKeyEd25519 {
privKeyBytes := new([64]byte)
copy(privKeyBytes[:32], crypto.CRandBytes(32))
ed25519.MakePublicKey(privKeyBytes)
return PrivKeyEd25519(*privKeyBytes)
privKey := new([64]byte)
copy(privKey[:32], crypto.CRandBytes(32))
// ed25519.MakePublicKey(privKey) alters the last 32 bytes of privKey.
// It places the pubkey in the last 32 bytes of privKey, and returns the
// public key.
ed25519.MakePublicKey(privKey)
return PrivKeyEd25519(*privKey)
}
// GenPrivKeyEd25519FromSecret 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 GenPrivKeyEd25519FromSecret(secret []byte) PrivKeyEd25519 {
privKey32 := crypto.Sha256(secret) // Not Ripemd160 because we want 32 bytes.
privKeyBytes := new([64]byte)
copy(privKeyBytes[:32], privKey32)
ed25519.MakePublicKey(privKeyBytes)
return PrivKeyEd25519(*privKeyBytes)
privKey := new([64]byte)
copy(privKey[:32], privKey32)
// ed25519.MakePublicKey(privKey) alters the last 32 bytes of privKey.
// It places the pubkey in the last 32 bytes of privKey, and returns the
// public key.
ed25519.MakePublicKey(privKey)
return PrivKeyEd25519(*privKey)
}
//-------------------------------------
var _ crypto.PubKey = PubKeyEd25519{}
// PubKeyEd25519Size is the number of bytes in an Ed25519 signature.
const PubKeyEd25519Size = 32
// Implements PubKeyInner
// PubKeyEd25519 implements crypto.PubKey for the Ed25519 signature scheme.
type PubKeyEd25519 [PubKeyEd25519Size]byte
// Address is the SHA256-20 of the raw pubkey bytes.
@ -127,6 +167,7 @@ func (pubKey PubKeyEd25519) Address() crypto.Address {
return crypto.Address(tmhash.Sum(pubKey[:]))
}
// Bytes marshals the PubKey using amino encoding.
func (pubKey PubKeyEd25519) Bytes() []byte {
bz, err := cdc.MarshalBinaryBare(pubKey)
if err != nil {
@ -146,8 +187,12 @@ func (pubKey PubKeyEd25519) VerifyBytes(msg []byte, sig_ crypto.Signature) bool
return ed25519.Verify(&pubKeyBytes, msg, &sigBytes)
}
// For use with golang/crypto/nacl/box
// If error, returns nil.
// ToCurve25519 takes a public key and returns its representation on
// Curve25519. Curve25519 is birationally equivalent to Edwards25519,
// which Ed25519 uses internally. This method is intended for use in
// an X25519 Diffie Hellman key exchange.
//
// If there is an error, then this function returns nil.
func (pubKey PubKeyEd25519) ToCurve25519() *[PubKeyEd25519Size]byte {
keyCurve25519, pubKeyBytes := new([PubKeyEd25519Size]byte), [PubKeyEd25519Size]byte(pubKey)
ok := extra25519.PublicKeyToCurve25519(keyCurve25519, &pubKeyBytes)
@ -161,6 +206,7 @@ func (pubKey PubKeyEd25519) String() string {
return fmt.Sprintf("PubKeyEd25519{%X}", pubKey[:])
}
// nolint: golint
func (pubKey PubKeyEd25519) Equals(other crypto.PubKey) bool {
if otherEd, ok := other.(PubKeyEd25519); ok {
return bytes.Equal(pubKey[:], otherEd[:])
@ -173,9 +219,11 @@ func (pubKey PubKeyEd25519) Equals(other crypto.PubKey) bool {
var _ crypto.Signature = SignatureEd25519{}
// Size of an Edwards25519 signature. Namely the size of a compressed
// Edwards25519 point, and a field element. Both of which are 32 bytes.
const SignatureEd25519Size = 64
// Implements crypto.Signature
// SignatureEd25519 implements crypto.Signature
type SignatureEd25519 [SignatureEd25519Size]byte
func (sig SignatureEd25519) Bytes() []byte {


+ 1
- 0
crypto/ed25519/ed25519_test.go View File

@ -32,6 +32,7 @@ func TestSignAndValidateEd25519(t *testing.T) {
assert.True(t, pubKey.VerifyBytes(msg, sig))
// Mutate the signature, just one bit.
// TODO: Replace this with a much better fuzzer, tendermint/ed25519/issues/10
sigEd := sig.(ed25519.SignatureEd25519)
sigEd[7] ^= byte(0x01)
sig = sigEd


Loading…
Cancel
Save