”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 如何协调 Ed25519 的 Golang 和 Bittorrent 私钥格式之间的差异?

如何协调 Ed25519 的 Golang 和 Bittorrent 私钥格式之间的差异?

发布于2024-11-08
浏览:279

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

ed25519.Public Result Discrepancy

问题是由 ed25519 私钥的不同格式引起的。密钥以 32 字节种子开始,使用 SHA512 进行哈希处理以创建 64 字节(在此过程中某些位会翻转)。

Golang 私钥格式

Golang 私钥格式由 32 字节种子与 32 字节公钥连接而成。

Bittorrent 私钥格式

Bittorrent 私钥是 64-哈希的字节输出或可能仅以与哈希结果相同的方式使用 64 个随机字节。

将 Bittorrent 密钥转换为 Golang 格式

不幸的是,将 Bittorrent 密钥转换为Golang API 接受的格式,因为哈希过程不可逆。

测试向量的自定义 Golang 实现

为了解决此问题,Golang 库的修改版本基于内部包 golang.org/x/crypto/ed25519/internal/edwards25519 可以创建:

从私钥生成公钥的函数

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[:]
}

签名生成函数

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
}

用法示例

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!")))
最新教程 更多>

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3