Skip to content

Commit

Permalink
primitives/sr25519: Enable generating secret keys from ed25519 keys
Browse files Browse the repository at this point in the history
  • Loading branch information
jberci committed Aug 18, 2023
1 parent db37f07 commit 3abeae8
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 0 deletions.
28 changes: 28 additions & 0 deletions primitives/sr25519/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,34 @@ func NewSecretKeyFromBytes(b []byte) (*SecretKey, error) {
return &sk, nil
}

// NewSecretKeyFromEd25519Bytes constructs a SecretKey from the byte representation
// of an expanded Ed25519 key.
func NewSecretKeyFromEd25519Bytes(b []byte) (*SecretKey, error) {
if len(b) != SecretKeySize {
return nil, fmt.Errorf("sr25519: invalid expanded ed25519 key length")
}

// Check the scalar is valid, s == clamp(s)
s := b[:SecretKeyScalarSize]
if s[0] != (s[0]&0b1111_1000) || (s[31] != ((s[31] & 0b0011_1111) | 0b0100_0000)) {
return nil, fmt.Errorf("sr25519: ed25519 scalar invalid")
}

scalar, err := scalarDivideByCofactor(b[:SecretKeyScalarSize])
if err != nil {
return nil, err
}

var nonce [SecretKeyNonceSize]byte
copy(nonce[:], b[SecretKeyScalarSize:])

sk := &SecretKey{
key: scalar,
nonce: nonce,
}
return sk, nil
}

// GenerateSecretKey generates a SecretKey using entropy from rng.
// If rng is nil, crypto/rand.Reader will be used.
func GenerateSecretKey(rng io.Reader) (*SecretKey, error) {
Expand Down
31 changes: 31 additions & 0 deletions primitives/sr25519/keys_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ package sr25519
import (
"bytes"
"crypto/rand"
"encoding/hex"
"testing"

"github.com/oasisprotocol/curve25519-voi/curve/scalar"
Expand Down Expand Up @@ -197,6 +198,36 @@ func TestSecretKey(t *testing.T) {
t.Fatalf("sk == sk2")
}
})
t.Run("Ed25519Bytes", func(t *testing.T) {
ed25519Bytes, _ := hex.DecodeString("28b0ae221c6bb06856b287f60d7ea0d98552ea5a16db16956849aa371db3eb51fd190cce74df356432b410bd64682309d6dedb27c76845daf388557cbac3ca34")
sk, err := NewSecretKeyFromEd25519Bytes(ed25519Bytes)
if err != nil {
t.Fatalf("NewSecretKeyFromEd25519Bytes: %v", err)
}

pkBytes, err := sk.PublicKey().MarshalBinary()
if err != nil {
t.Fatalf("sk.MarshalBinary: %v", err)
}
expectedPkBytes, _ := hex.DecodeString("46ebddef8cd9bb167dc30878d7113b7e168e6f0646beffd77d69d39bad76b47a")
if !bytes.Equal(pkBytes, expectedPkBytes) {
t.Fatalf("public key bytes differ: %v != %v", hex.EncodeToString(pkBytes), hex.EncodeToString(expectedPkBytes))
}

skBytes := make([]byte, scalar.ScalarSize)
if sk.key.ToBytes(skBytes) != nil {
t.Fatalf("sk.ToBytes: %v", err)
}
expectedSkBytes, _ := hex.DecodeString("05d65584630d16cd4af6d0bec10f34bb504a5dcb62dba2122d49f5a663763d0a")
if !bytes.Equal(skBytes, expectedSkBytes) {
t.Fatalf("secret key bytes differ (%v != %v)", hex.EncodeToString(skBytes), hex.EncodeToString(expectedSkBytes))
}

expectedNonce, _ := hex.DecodeString("fd190cce74df356432b410bd64682309d6dedb27c76845daf388557cbac3ca34")
if !bytes.Equal(sk.nonce[:], expectedNonce) {
t.Fatalf("nonce bytes differ: %v != %v", hex.EncodeToString(sk.nonce[:]), hex.EncodeToString(expectedNonce))
}
})
}

func TestPublicKey(t *testing.T) {
Expand Down

0 comments on commit 3abeae8

Please sign in to comment.