我如何在 golang 与 typescript 中正确签署 bitclout tx?
how do I properly sign a bitclout tx in golang vs typescript?
我在 typescript 中有一个工作示例:
signTransaction(seedHex: string, transactionHex: string): string {
const privateKey = this.cryptoService.seedHexToPrivateKey(seedHex);
const transactionBytes = new Buffer(transactionHex, 'hex');
const transactionHash = new Buffer(sha256.x2(transactionBytes), 'hex');
const signature = privateKey.sign(transactionHash);
const signatureBytes = new Buffer(signature.toDER());
const signatureLength = uvarint64ToBuf(signatureBytes.length);
const signedTransactionBytes = Buffer.concat([
// This slice is bad. We need to remove the existing signature length field prior to appending the new one.
// Once we have frontend transaction construction we won't need to do this.
transactionBytes.slice(0, -1),
signatureLength,
signatureBytes,
]);
return signedTransactionBytes.toString('hex');
}
并转换为 golang 我写道:
func signTransaction(seedHex, transactionHex string) string {
privateKey := seedHexToPrivateKey(seedHex)
transactionBytes, _ := hex.DecodeString(hexString)
first := sha256.Sum256(transactionBytes)
transactionHash := fmt.Sprintf("%x", sha256.Sum256(first[:]))
signature, _ := privateKey.Sign([]byte(transactionHash))
signatureBytes := signature.Serialize()
signatureLength := make([]byte, 8)
binary.LittleEndian.PutUint64(signatureLength, uint64(len(signatureBytes)))
buff := []byte{}
buff = append(buff, transactionBytes[0:len(transactionBytes)-1]...)
buff = append(buff, signatureLength...)
buff = append(buff, signatureBytes...)
return fmt.Sprintf("%x", buff)
}
我觉得很接近了。在提交和尝试调整内容时,我收到了各种有趣的错误消息。但它不像打字稿那样工作。有人看到任何错误吗?仅供参考,私钥是 *btcec.PrivateKey,即 ecdsa.PrivateKey,签名序列化来自 https://github.com/btcsuite/btcd/blob/master/btcec/signature.go#L40
找到解决方案:
https://github.com/indutny/elliptic/blob/master/lib/elliptic/ec/signature.js#L139
^ toDER 是正确的并且这个:
https://github.com/btcsuite/btcd/blob/master/btcec/signature.go#L40
不是现在我有:
https://github.com/andrewarrow/clout-cli/blob/main/keys/hdkey.go#L48
我从 JavaScript 移植过来,它正在运行!
该签名错误是因为签名是 X9.62,它使用 ASN.1 对值 R 和 S 进行编码。如果随机值 R 或签名 S 以 1 位开头,它将被解释为负数根据 ASN.1 INTEGER 的 BER/DER 编码的值。
由于 R 是随机的并且 S 依赖于它,因此当整数编码不正确时,它们有时会出错。如果第一个/最左边和最高有效位为 1,则应在其前面添加一个 00
字节作为前缀,因此它会产生一个带正符号的大端值。
请注意,编码整数值的大小因此也是动态的,使用太多字节是不正确的。
要从静态大小的大端 R 和 S 值出发,您应该首先从左侧删除所有 00
值字节,然后如果第一个字节值为 0x80
或更高(显然假设无符号字节)。此函数通常称为 O2ISP(八位字节串到整数原语),取自 RSA PKCS#1 规范,其中对其进行了数学描述。 Here on Cryptography is a helpful qustion that is a bit more in depth
我在 typescript 中有一个工作示例:
signTransaction(seedHex: string, transactionHex: string): string {
const privateKey = this.cryptoService.seedHexToPrivateKey(seedHex);
const transactionBytes = new Buffer(transactionHex, 'hex');
const transactionHash = new Buffer(sha256.x2(transactionBytes), 'hex');
const signature = privateKey.sign(transactionHash);
const signatureBytes = new Buffer(signature.toDER());
const signatureLength = uvarint64ToBuf(signatureBytes.length);
const signedTransactionBytes = Buffer.concat([
// This slice is bad. We need to remove the existing signature length field prior to appending the new one.
// Once we have frontend transaction construction we won't need to do this.
transactionBytes.slice(0, -1),
signatureLength,
signatureBytes,
]);
return signedTransactionBytes.toString('hex');
}
并转换为 golang 我写道:
func signTransaction(seedHex, transactionHex string) string {
privateKey := seedHexToPrivateKey(seedHex)
transactionBytes, _ := hex.DecodeString(hexString)
first := sha256.Sum256(transactionBytes)
transactionHash := fmt.Sprintf("%x", sha256.Sum256(first[:]))
signature, _ := privateKey.Sign([]byte(transactionHash))
signatureBytes := signature.Serialize()
signatureLength := make([]byte, 8)
binary.LittleEndian.PutUint64(signatureLength, uint64(len(signatureBytes)))
buff := []byte{}
buff = append(buff, transactionBytes[0:len(transactionBytes)-1]...)
buff = append(buff, signatureLength...)
buff = append(buff, signatureBytes...)
return fmt.Sprintf("%x", buff)
}
我觉得很接近了。在提交和尝试调整内容时,我收到了各种有趣的错误消息。但它不像打字稿那样工作。有人看到任何错误吗?仅供参考,私钥是 *btcec.PrivateKey,即 ecdsa.PrivateKey,签名序列化来自 https://github.com/btcsuite/btcd/blob/master/btcec/signature.go#L40
找到解决方案:
https://github.com/indutny/elliptic/blob/master/lib/elliptic/ec/signature.js#L139
^ toDER 是正确的并且这个:
https://github.com/btcsuite/btcd/blob/master/btcec/signature.go#L40
不是现在我有:
https://github.com/andrewarrow/clout-cli/blob/main/keys/hdkey.go#L48
我从 JavaScript 移植过来,它正在运行!
该签名错误是因为签名是 X9.62,它使用 ASN.1 对值 R 和 S 进行编码。如果随机值 R 或签名 S 以 1 位开头,它将被解释为负数根据 ASN.1 INTEGER 的 BER/DER 编码的值。
由于 R 是随机的并且 S 依赖于它,因此当整数编码不正确时,它们有时会出错。如果第一个/最左边和最高有效位为 1,则应在其前面添加一个 00
字节作为前缀,因此它会产生一个带正符号的大端值。
请注意,编码整数值的大小因此也是动态的,使用太多字节是不正确的。
要从静态大小的大端 R 和 S 值出发,您应该首先从左侧删除所有 00
值字节,然后如果第一个字节值为 0x80
或更高(显然假设无符号字节)。此函数通常称为 O2ISP(八位字节串到整数原语),取自 RSA PKCS#1 规范,其中对其进行了数学描述。 Here on Cryptography is a helpful qustion that is a bit more in depth