Home > Article > Backend Development > How can I derive the correct public key and signature from a prehashed private key using the Go package golang.org/x/crypto/ed25519?
Problem Description:
Using the Go package golang.org/x/crypto/ed25519, attempts to derive the public key from a given private key produce a different result compared to the expected public key as defined in a given test case.
Root Cause:
The discrepancy arises from the use of different ed25519 private key formats.
Private Key Format Difference:
Solution:
Since reversing the hash used to generate the test case private keys is not feasible, conversion to a format compatible with the Go package is not possible.
Proposed Solution:
To obtain the correct public key for the test case, a modified version of the Go package can be created that utilizes the following custom functions:
getPublicKey:
<code class="go">// GetPublicKey generates the public key from the prehashed private key. func getPublicKey(privateKey []byte) []byte { var A edwards25519.ExtendedGroupElement var hBytes [32]byte copy(hBytes[:], privateKey) edwards25519.GeScalarMultBase(&A, &hBytes) var publicKeyBytes [32]byte A.ToBytes(&publicKeyBytes) return publicKeyBytes[:] }</code>
sign:
<code class="go">// Sign generates a signature from the prehashed private key, public key, and message. func sign(privateKey, publicKey, message []byte) []byte { var privateKeyA [32]byte copy(privateKeyA[:], privateKey) 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(&messageDigestReduced, &messageDigest) var R edwards25519.ExtendedGroupElement edwards25519.GeScalarMultBase(&R, &messageDigestReduced) var encodedR [32]byte R.ToBytes(&encodedR) h.Reset() h.Write(encodedR[:]) h.Write(publicKey) h.Write(message) h.Sum(hramDigest[:0]) var hramDigestReduced [32]byte edwards25519.ScReduce(&hramDigestReduced, &hramDigest) var s [32]byte edwards25519.ScMulAdd(&s, &hramDigestReduced, &privateKeyA, &messageDigestReduced) signature := make([]byte, 64) copy(signature[:], encodedR[:]) copy(signature[32:], s[:]) return signature }</code>
Usage Example:
<code class="go">privateKeyHex := "e06d3183d14159228433ed599221b80bd0a5ce8352e4bdf0262f76786ef1c74db7e7a9fea2c0eb269d61e3b38e450a22e754941ac78479d6c54e1faf6037881d" privateKey, _ := hex.DecodeString(privateKeyHex) expectedPublicKey := "77ff84905a91936367c01360803104f92432fcd904a43511876df5cdf3e7e548" expectedSig := "6834284b6b24c3204eb2fea824d82f88883a3d95e8b4a21b8c0ded553d17d17ddf9a8a7104b1258f30bed3787e6cb896fca78c58f8e03b5f18f14951a87d9a08" publicKey := getPublicKey(privateKey) fmt.Printf("Calculated Public Key: %x\n", publicKey) fmt.Printf("Expected Public Key: %s\n", expectedPublicKey) calculatedSig := sign(privateKey, publicKey, []byte("Hello, World!")) fmt.Printf("Calculated Signature: %x\n", calculatedSig) fmt.Printf("Expected Signature: %s\n", expectedSig)</code>
This approach allows for the calculation of the correct public key and signature using the modified Go package, as specified in the test case.
The above is the detailed content of How can I derive the correct public key and signature from a prehashed private key using the Go package golang.org/x/crypto/ed25519?. For more information, please follow other related articles on the PHP Chinese website!