如何在Golang和TypeScript中正确签名BitClout交易?

huangapple go评论101阅读模式
英文:

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');
  }

我将其转换为Go语言的代码:

func signTransaction(seedHex, transactionHex string) string {
  privateKey := seedHexToPrivateKey(seedHex)
  transactionBytes, _ := hex.DecodeString(transactionHex)
  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)
}

我认为它们非常接近。当我提交并尝试调整一些内容时,我收到了各种有趣的错误消息。但它的工作方式与typescript版本不同。有人看到任何错误吗?请注意,privateKey是*btcec.PrivateKey,它是ecdsa.PrivateKey,而签名序列化是来自https://github.com/btcsuite/btcd/blob/master/btcec/signature.go#L40

英文:

I have a working example in 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');
  }

and converting to golang I wrote:

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)
}

It's very close I think. I get back all sorts of interesting error messages when submitting and trying to adjust stuff. But it's not working like the typescript one is. Anyone see any errors? FYI privateKey is *btcec.PrivateKey which is ecdsa.PrivateKey and the signture Serialized is from https://github.com/btcsuite/btcd/blob/master/btcec/signature.go#L40

答案1

得分: 1

那个签名错误是因为签名是使用ASN.1编码的X9.62格式,用于编码值R和S。如果随机值R或签名S以1位开始,根据ASN.1 INTEGER的BER/DER编码,它将被解释为负值。

由于R是随机的,而S依赖于它,当整数未正确编码时,它们有时会出错。如果最左边和最重要的位是1,则应在其前面加上一个00字节,以使其成为正的有符号大端值。

请注意,编码整数值的大小也是动态的,使用过多的字节是不正确的。


要从静态大小的大端R和S值转换,您应首先从左侧删除所有值为00的字节,然后如果第一个字节的值为0x80或更高(假设是无符号字节),则再添加一个字节。这个函数通常被称为O2ISP(八位字节串到整数原语),它来自RSA PKCS#1规范,在该规范中对其进行了数学描述。在Cryptography上有一个更深入的有用问题

英文:

That signature error is because the signature is X9.62 which uses ASN.1 to encode both value R and S. If the random value R or the signature S starts with a 1 bit it will be interpreted as a negative value according to the BER/DER encoding of an ASN.1 INTEGER.

As R is randomized and S depends on it they will sometimes error when the integer is not encoded correctly. If the first / leftmost and most significant bit is 1 then a 00 byte should be prefixed to it, so it makes a positive signed big endian value.

Note that the size of the encoded integer value is therefore dynamic as well, it is incorrect to use too many bytes for it.


To go from a statically sized, big endian R and S value you should first remove all 00 valued bytes from the left hand side, and then add one back again if the first byte value is 0x80 or higher (assuming unsigned bytes, obviously). This function is commonly referred to as O2ISP (octet-string to integer primitive), taken from the RSA PKCS#1 specifications where it is mathematically described. Here on Cryptography is a helpful qustion that is a bit more in depth

答案2

得分: 0

找到解决方案:

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移植到Go,并且它正常工作!

英文:

Found solution:

https://github.com/indutny/elliptic/blob/master/lib/elliptic/ec/signature.js#L139

That ^ toDER is correct and this:

https://github.com/btcsuite/btcd/blob/master/btcec/signature.go#L40

is not so now I have:

https://github.com/andrewarrow/clout-cli/blob/main/keys/hdkey.go#L48

which I ported from JavaScript to go and it's working!

huangapple
  • 本文由 发表于 2021年5月23日 23:12:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/67661276.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定