ホームページ >バックエンド開発 >Golang >ed25519 の Go 実装が、特定の場合に予想とは異なる公開鍵を生成するのはなぜですか?

ed25519 の Go 実装が、特定の場合に予想とは異なる公開鍵を生成するのはなぜですか?

Mary-Kate Olsen
Mary-Kate Olsenオリジナル
2024-10-30 17:24:031091ブラウズ

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 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。