Skip to content

Commit

Permalink
feat: create key exchange for sr25519 package mailchain#505
Browse files Browse the repository at this point in the history
  • Loading branch information
developerfred committed Jan 6, 2020
1 parent b996e14 commit a0a714f
Show file tree
Hide file tree
Showing 6 changed files with 509 additions and 26 deletions.
38 changes: 38 additions & 0 deletions crypto/cipher/ecdh/ecdh_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import (
"github.com/mailchain/mailchain/crypto/cipher"
"github.com/mailchain/mailchain/crypto/ed25519"
"github.com/mailchain/mailchain/crypto/ed25519/ed25519test"
"github.com/mailchain/mailchain/crypto/sr25519"
"github.com/mailchain/mailchain/crypto/sr25519/sr25519test"
"github.com/mailchain/mailchain/crypto/secp256k1"
"github.com/mailchain/mailchain/crypto/secp256k1/secp256k1test"
"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -95,6 +97,42 @@ func Test_SharedSecretEndToEnd(t *testing.T) {
ed25519test.CharlottePrivateKey,
},
},
{
"sr25519-random",
args{
func() cipher.KeyExchange {
kx, _ := NewSR25519(rand.Reader)
return kx
}(),
func() crypto.PrivateKey {
pk, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
assert.FailNow("sr25519.GenerateKey error = %v", err)
}
return pk
}(),
},
},
{
"sr25519-sofia",
args{
func() cipher.KeyExchange {
kx, _ := NewED25519(rand.Reader)
return kx
}(),
sr25519test.SofiaPrivateKey,
},
},
{
"sr25519-charlotte",
args{
func() cipher.KeyExchange {
kx, _ := NewSR25519(rand.Reader)
return kx
}(),
sr25519test.CharlottePrivateKey,
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
79 changes: 79 additions & 0 deletions crypto/cipher/ecdh/sr25519.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package ecdh

import (
"bytes"
"errors"
"io"

"github.com/agl/ed25519/extra25519"
"github.com/mailchain/mailchain/crypto"
"golang.org/x/crypto/curve25519"
)

type SR25519 struct {
rand io.Reader
}

func NewSR25519(rand io.Reader) (*SR25519, error) {
if rand == nil {
return nil, errors.New("rand must not be nil")
}

return &SR25519{rand: rand}, nil
}

func (kx SR25519) EphemeralKey() (crypto.PrivateKey, error) {
return sr25519.GenerateKey(kx.rand)
}

func (kx SR25519) SharedSecret(ephemeralKey crypto.PrivateKey, recipientKey crypto.PublicKey) ([]byte, error) {
ephemeralPrivateKey, err := kx.privateKey(ephemeralKey)
if err != nil {
return nil, ErrSharedSecretGenerate
}

recipientPublicKey, err := kx.publicKey(recipientKey)
if err != nil {
return nil, ErrSharedSecretGenerate
}

ephemeralPublicKey, _ := kx.publicKey(ephemeralKey.PublicKey())

if bytes.Equal(ephemeralPublicKey[:], recipientPublicKey[:]) {
return nil, ErrSharedSecretGenerate
}

var secret [32]byte

curve25519.ScalarMult(&secret, &ephemeralPrivateKey, &recipientPublicKey)

return secret[:], nil
}

func (kx SR25519) publicKey(pubKey crypto.PublicKey) (key [32]byte, err error) {
switch pk := pubKey.(type) {
case *sr25519.PublicKey:
var sr25519Key, key [32]byte

copy(sr25519Key[:], pk.Bytes())
extra25519.PublicKeyToCurve25519(&key, &sr25519Key)

return key, nil
default:
return [32]byte{}, ErrSharedSecretGenerate
}
}

func (kx SR25519) privateKey(privKey crypto.PrivateKey) (key [32]byte, err error) {
switch pk := privKey.(type) {
case *sr25519.PrivateKey:
var sr25519Key [64]byte

copy(sr25519Key[:], pk.Bytes())
extra25519.PrivateKeyToCurve25519(&key, &sr25519Key)

return key, nil
default:
return [32]byte{}, ErrSharedSecretGenerate
}
}
Loading

0 comments on commit a0a714f

Please sign in to comment.