首页  >  文章  >  后端开发  >  为什么 ed25519 的 Go 实现在某些情况下生成的公钥与预期不同?

为什么 ed25519 的 Go 实现在某些情况下生成的公钥与预期不同?

Mary-Kate Olsen
Mary-Kate Olsen原创
2024-10-30 17:24:031001浏览

Why does the Go implementation of ed25519 generate a different public key than expected in certain cases?

ed25519 公钥生成差异

ed25519 加密包提供了一种从私钥生成公钥的方法。然而,用户发现 Go 实现生成的公钥与特定用例中的预期值不一致。

根本原因:

这种差异产生于用于表示 ed25519 私钥的不同格式。 Go 包使用一种格式,其中私钥表示为 32 字节种子和 32 字节公钥的串联。相反,定义预期结果的测试向量将私钥表示为散列种子的 64 字节输出。

解决方案:

鉴于这是不可行的逆向哈希过程,不可能将测试向量私钥转换为与 Go 实现兼容的格式。或者,您可以创建支持替代私钥格式的 Go 库的修改版本。

修改的库代码:

以下代码片段提供了自定义版本Go 实现支持备用私钥格式:

生成公钥:

<code class="go">// Generate the public key corresponding to the already hashed private
// key.
//
// This code is mostly copied from GenerateKey in the
// golang.org/x/crypto/ed25519 package, from after the SHA512
// calculation of the seed.
func getPublicKey(privateKey []byte) []byte {
    var A edwards25519.ExtendedGroupElement
    var hBytes [32]byte
    copy(hBytes[:], privateKey)
    edwards25519.GeScalarMultBase(&amp;A, &amp;hBytes)
    var publicKeyBytes [32]byte
    A.ToBytes(&amp;publicKeyBytes)

    return publicKeyBytes[:]
}</code>

签名:

<code class="go">// Calculate the signature from the (pre hashed) private key, public key
// and message.
//
// This code is mostly copied from the Sign function from
// golang.org/x/crypto/ed25519, from after the SHA512 calculation of the
// seed.
func sign(privateKey, publicKey, message []byte) []byte {

    var privateKeyA [32]byte
    copy(privateKeyA[:], privateKey) // we need this in an array later
    var messageDigest, hramDigest [64]byte

    h := sha512.New()
    h.Write(privateKey[32:])
    h.Write(message)
    h.Sum(messageDigest[:0])

    var messageDigestReduced [32]byte
    edwards25519.ScReduce(&amp;messageDigestReduced, &amp;messageDigest)
    var R edwards25519.ExtendedGroupElement
    edwards25519.GeScalarMultBase(&amp;R, &amp;messageDigestReduced)

    var encodedR [32]byte
    R.ToBytes(&amp;encodedR)

    h.Reset()
    h.Write(encodedR[:])
    h.Write(publicKey)
    h.Write(message)
    h.Sum(hramDigest[:0])
    var hramDigestReduced [32]byte
    edwards25519.ScReduce(&amp;hramDigestReduced, &amp;hramDigest)

    var s [32]byte
    edwards25519.ScMulAdd(&amp;s, &amp;hramDigestReduced, &amp;privateKeyA, &amp;messageDigestReduced)

    signature := make([]byte, 64)
    copy(signature[:], encodedR[:])
    copy(signature[32:], s[:])

    return signature
}</code>

演示:

以下代码演示了如何使用自定义函数来生成预期的公钥和签名:

<code class="go">privateKeyHex := "e06d3183d14159228433ed599221b80bd0a5ce8352e4bdf0262f76786ef1c74db7e7a9fea2c0eb269d61e3b38e450a22e754941ac78479d6c54e1faf6037881d"

expectedPublicKey := "77ff84905a91936367c01360803104f92432fcd904a43511876df5cdf3e7e548"
expectedSig := "6834284b6b24c3204eb2fea824d82f88883a3d95e8b4a21b8c0ded553d17d17ddf9a8a7104b1258f30bed3787e6cb896fca78c58f8e03b5f18f14951a87d9a08"

privateKey, _ := hex.DecodeString(privateKeyHex)
publicKey := getPublicKey(privateKey)

fmt.Printf("Calculated key: %x\n", publicKey)
fmt.Printf("Expected key:   %s\n", expectedPublicKey)
keyMatches := expectedPublicKey == hex.EncodeToString(publicKey)
fmt.Printf("Public key matches expected: %v\n", keyMatches)

buffer := []byte("4:salt6:foobar3:seqi1e1:v12:Hello World!")
calculatedSig := sign(privateKey, publicKey, buffer)

fmt.Printf("Calculated sig: %x\n", calculatedSig)
fmt.Printf("Expected sig:   %s\n", expectedSig)
sigMatches := expectedSig == hex.EncodeToString(calculatedSig)
fmt.Printf("Signature matches expected: %v\n", sigMatches)</code>

通过集成这些自定义函数函数到您的代码中,您可以处理以替代私钥格式定义的测试向量并执行公钥生成和签名等操作,而不会遇到不匹配的结果。

以上是为什么 ed25519 的 Go 实现在某些情况下生成的公钥与预期不同?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn