Home >Backend Development >Golang >How to reconcile the discrepancy between Golang and Bittorrent private key formats for Ed25519?

How to reconcile the discrepancy between Golang and Bittorrent private key formats for Ed25519?

DDD
DDDOriginal
2024-10-31 07:06:30596browse

How to reconcile the discrepancy between Golang and Bittorrent private key formats for Ed25519?

ed25519.Public Result Discrepancy

The issue arises from different formats for ed25519 private keys. The key starts as a 32-byte seed that is hashed using SHA512 to create 64 bytes (certain bits are flipped during this process).

Golang Private Key Format

The Golang private key format comprises the 32-byte seed concatenated with the 32-byte public key.

Bittorrent Private Key Format

The Bittorrent private keys are the 64-byte output of the hash or potentially just 64 random bytes used in the same way as the hash result.

Converting Bittorrent Keys to Golang Format

Unfortunately, it's not feasible to convert Bittorrent keys into a format that the Golang API accepts because the hash process is not reversible.

Custom Golang Implementation for Test Vectors

To address this issue, a modified version of the Golang library based on the internal package golang.org/x/crypto/ed25519/internal/edwards25519 can be created:

Function for Generating Public Key from Private Key

<code class="go">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>

Function for Signature Generation

<code class="go">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(&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>

Example Usage

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

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

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

keyMatches := expectedPublicKey == hex.EncodeToString(publicKey)
sigMatches := expectedSig == hex.EncodeToString(sign(privateKey, publicKey, []byte("4:salt6:foobar3:seqi1e1:v12:Hello World!")))</code>

The above is the detailed content of How to reconcile the discrepancy between Golang and Bittorrent private key formats for Ed25519?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn