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