diff --git a/did-key/key_test.go b/did-key/key_test.go index 4c1146a..afb9e0e 100644 --- a/did-key/key_test.go +++ b/did-key/key_test.go @@ -1,8 +1,10 @@ package didkey_test import ( + "fmt" "testing" + mbase "github.com/multiformats/go-multibase" "github.com/stretchr/testify/require" "github.com/INFURA/go-did" @@ -39,3 +41,13 @@ func TestEquivalence(t *testing.T) { require.True(t, did0A.Equal(did0B)) require.False(t, did0A.Equal(did1)) } + +func TestFoo(t *testing.T) { + _, bytes, err := mbase.Decode("z6LSj72tK8brWgZja8NLRwPigth2T9QRiG1uH9oKZuKjdh9p") + require.NoError(t, err) + fmt.Println(bytes) + + _, bytes, err = mbase.Decode("z6LSinnAscp9HxuNE9QCpqiwmSMP7oHiTzLepseUb4y6LHFB") + require.NoError(t, err) + fmt.Println(bytes) +} diff --git a/verifications/x25519/key.go b/verifications/x25519/key.go index cb34c3d..b70b8fc 100644 --- a/verifications/x25519/key.go +++ b/verifications/x25519/key.go @@ -1,11 +1,72 @@ package x25519 +// type PublicKey ecdh.PublicKey +// +// func (p PublicKey) Equal(x crypto.PublicKey) bool { +// // TODO implement me +// panic("implement me") +// } +// +// type PrivateKey ecdh.PrivateKey +// +// func (p *PrivateKey) Public() crypto.PublicKey { +// key := p.(ecdh.PrivateKey) +// return key.Public() +// } +// +// func (p *PrivateKey) Equal(x crypto.PrivateKey) bool { +// // TODO implement me +// panic("implement me") +// } +// +// func GenerateKeyPair() (PublicKey, PrivateKey, error) { +// priv, err := ecdh.X25519().GenerateKey(rand.Reader) +// if err != nil { +// return nil, nil, err +// } +// return priv.Public().(PublicKey), priv, nil +// } +// +// // PublicKeyToMultibase encodes the public key in a suitable way for publicKeyMultibase +// func PublicKeyToMultibase(pub PublicKey) string { +// // can only fail with an invalid encoding, but it's hardcoded +// bytes, _ := mbase.Encode(mbase.Base58BTC, append(varint.ToUvarint(MultibaseCode), pub.Bytes()...)) +// return bytes +// } +// +// // MultibaseToPublicKey decodes the public key from its publicKeyMultibase form +// func MultibaseToPublicKey(multibase string) (PublicKey, error) { +// baseCodec, bytes, err := mbase.Decode(multibase) +// if err != nil { +// return nil, err +// } +// // the specification enforces that encoding +// if baseCodec != mbase.Base58BTC { +// return nil, fmt.Errorf("not Base58BTC encoded") +// } +// code, read, err := varint.FromUvarint(bytes) +// if err != nil { +// return nil, err +// } +// if code != MultibaseCode { +// return nil, fmt.Errorf("invalid code") +// } +// if read != 2 { +// return nil, fmt.Errorf("unexpected multibase") +// } +// if len(bytes)-read != ed25519.PublicKeySize { +// return nil, fmt.Errorf("invalid ed25519 public key size") +// } +// return bytes[read:], nil +// } + import ( "bytes" "crypto" "crypto/rand" "fmt" "io" + "math/big" "golang.org/x/crypto/curve25519" @@ -106,11 +167,39 @@ func (priv PrivateKey) Equal(x crypto.PrivateKey) bool { } func PublicKeyFromEd25519(pub ed25519.PublicKey) (PublicKey, error) { - // x, _ := curve25519.X25519(pub, curve25519.Basepoint) - publicKey := make([]byte, PublicKeySize) - copy(publicKey, pub) - publicKey[31] &= 0x7F - publicKey[31] |= 0x40 - publicKey[0] &= 0xF8 - return publicKey, nil + y := new(big.Int).SetBytes(pub) + one := big.NewInt(1) + negOne := big.NewInt(-1) + + if y.Cmp(one) == 0 || y.Cmp(negOne) == 0 { + return nil, fmt.Errorf("x25519 undefined for this public key") + } + + // p = 2^255-19 + // + // Equivalent to: + // two := big.NewInt(2) + // exp := big.NewInt(255) + // p := new(big.Int).Exp(two, exp, nil) + // p.Sub(p, big.NewInt(19)) + // + p := new(big.Int).SetBytes([]byte{ + 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xed, + }) + + // u := new(big.Int).Mul( + // new(big.Int).Add(one, y), + // new(big.Int).ModInverse(new(big.Int).Sub(one, y), p), + // ) + + onePlusY := new(big.Int).Add(one, y) + oneMinusY := new(big.Int).Sub(one, y) + oneMinusYInv := new(big.Int).ModInverse(oneMinusY, p) + u := new(big.Int).Mul(onePlusY, oneMinusYInv) + u.Mod(u, p) + + return u.Bytes(), nil } diff --git a/verifications/x25519/key_test.go b/verifications/x25519/key_test.go index 16bdc88..81b1623 100644 --- a/verifications/x25519/key_test.go +++ b/verifications/x25519/key_test.go @@ -1,51 +1,52 @@ package x25519_test -import ( - "encoding/hex" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/INFURA/go-did/verifications/x25519" -) - -func TestGenerateKey(t *testing.T) { - t.Run("x25519.GenerateKey()", func(t *testing.T) { - _, _, err := x25519.GenerateKey() - require.NoError(t, err, `x25519.GenerateKey should work`) - }) - t.Run("x25519.NewKeyFromSeed(wrongSeedLength)", func(t *testing.T) { - dummy := make([]byte, x25519.SeedSize-1) - _, err := x25519.NewKeyFromSeed(dummy) - require.Error(t, err, `wrong seed size should result in error`) - }) -} - -func TestNewKeyFromSeed(t *testing.T) { - // These test vectors are from RFC7748 Section 6.1 - const alicePrivHex = `77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a` - const alicePubHex = `8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a` - const bobPrivHex = `5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb` - const bobPubHex = `de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f` - - alicePrivSeed, err := hex.DecodeString(alicePrivHex) - require.NoError(t, err, `alice seed decoded`) - alicePriv, err := x25519.NewKeyFromSeed(alicePrivSeed) - require.NoError(t, err, `alice private key`) - - alicePub := alicePriv.Public().(x25519.PublicKey) - require.Equal(t, hex.EncodeToString(alicePub), alicePubHex, `alice public key`) - - bobPrivSeed, err := hex.DecodeString(bobPrivHex) - require.NoError(t, err, `bob seed decoded`) - bobPriv, err := x25519.NewKeyFromSeed(bobPrivSeed) - require.NoError(t, err, `bob private key`) - - bobPub := bobPriv.Public().(x25519.PublicKey) - require.Equal(t, hex.EncodeToString(bobPub), bobPubHex, `bob public key`) - - require.True(t, bobPriv.Equal(bobPriv), `bobPriv should equal bobPriv`) - require.True(t, bobPub.Equal(bobPub), `bobPub should equal bobPub`) - require.False(t, bobPriv.Equal(bobPub), `bobPriv should NOT equal bobPub`) - require.False(t, bobPub.Equal(bobPriv), `bobPub should NOT equal bobPriv`) -} +// +// import ( +// "encoding/hex" +// "testing" +// +// "github.com/stretchr/testify/require" +// +// "github.com/INFURA/go-did/verifications/x25519" +// ) +// +// func TestGenerateKey(t *testing.T) { +// t.Run("x25519.GenerateKey()", func(t *testing.T) { +// _, _, err := x25519.GenerateKey() +// require.NoError(t, err, `x25519.GenerateKey should work`) +// }) +// t.Run("x25519.NewKeyFromSeed(wrongSeedLength)", func(t *testing.T) { +// dummy := make([]byte, x25519.SeedSize-1) +// _, err := x25519.NewKeyFromSeed(dummy) +// require.Error(t, err, `wrong seed size should result in error`) +// }) +// } +// +// func TestNewKeyFromSeed(t *testing.T) { +// // These test vectors are from RFC7748 Section 6.1 +// const alicePrivHex = `77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a` +// const alicePubHex = `8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a` +// const bobPrivHex = `5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb` +// const bobPubHex = `de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f` +// +// alicePrivSeed, err := hex.DecodeString(alicePrivHex) +// require.NoError(t, err, `alice seed decoded`) +// alicePriv, err := x25519.NewKeyFromSeed(alicePrivSeed) +// require.NoError(t, err, `alice private key`) +// +// alicePub := alicePriv.Public().(x25519.PublicKey) +// require.Equal(t, hex.EncodeToString(alicePub), alicePubHex, `alice public key`) +// +// bobPrivSeed, err := hex.DecodeString(bobPrivHex) +// require.NoError(t, err, `bob seed decoded`) +// bobPriv, err := x25519.NewKeyFromSeed(bobPrivSeed) +// require.NoError(t, err, `bob private key`) +// +// bobPub := bobPriv.Public().(x25519.PublicKey) +// require.Equal(t, hex.EncodeToString(bobPub), bobPubHex, `bob public key`) +// +// require.True(t, bobPriv.Equal(bobPriv), `bobPriv should equal bobPriv`) +// require.True(t, bobPub.Equal(bobPub), `bobPub should equal bobPub`) +// require.False(t, bobPriv.Equal(bobPub), `bobPriv should NOT equal bobPub`) +// require.False(t, bobPub.Equal(bobPriv), `bobPub should NOT equal bobPriv`) +// }