Skip to content

Instantly share code, notes, and snippets.

@crossle
Last active July 15, 2020 09:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crossle/ea063aa77f879216cc664792d7022700 to your computer and use it in GitHub Desktop.
Save crossle/ea063aa77f879216cc664792d7022700 to your computer and use it in GitHub Desktop.
package main
import (
"crypto/ed25519"
"crypto/rand"
"crypto/sha512"
"encoding/hex"
"fmt"
"math/big"
"golang.org/x/crypto/curve25519"
)
// https://github.com/FiloSottile/age/blob/189041b668629795593766bcb8d3f70ee248b842/agessh/agessh.go#L294
func main() {
pub, priv, err := ed25519.GenerateKey(rand.Reader)
a := hex.EncodeToString(pub)
fmt.Println(a)
b := hex.EncodeToString(priv)
fmt.Println(b)
fmt.Println(err)
c := hex.EncodeToString(ed25519PublicKeyToCurve25519(pub))
fmt.Println(c)
d := hex.EncodeToString(ed25519PrivateKeyToCurve25519(priv))
fmt.Println(d)
}
var curve25519P, _ = new(big.Int).SetString("57896044618658097711785492504343953926634992332820282019728792003956564819949", 10)
func ed25519PrivateKeyToCurve25519(pk ed25519.PrivateKey) []byte {
h := sha512.New()
h.Write(pk.Seed())
out := h.Sum(nil)
return out[:curve25519.ScalarSize]
}
func ed25519PublicKeyToCurve25519(pk ed25519.PublicKey) []byte {
// ed25519.PublicKey is a little endian representation of the y-coordinate,
// with the most significant bit set based on the sign of the x-coordinate.
bigEndianY := make([]byte, ed25519.PublicKeySize)
for i, b := range pk {
bigEndianY[ed25519.PublicKeySize-i-1] = b
}
bigEndianY[0] &= 0b0111_1111
// The Montgomery u-coordinate is derived through the bilinear map
//
// u = (1 + y) / (1 - y)
//
// See https://blog.filippo.io/using-ed25519-keys-for-encryption.
y := new(big.Int).SetBytes(bigEndianY)
denom := big.NewInt(1)
denom.ModInverse(denom.Sub(denom, y), curve25519P) // 1 / (1 - y)
u := y.Mul(y.Add(y, big.NewInt(1)), denom)
u.Mod(u, curve25519P)
out := make([]byte, curve25519.PointSize)
uBytes := u.Bytes()
for i, b := range uBytes {
out[len(uBytes)-i-1] = b
}
return out
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment