我有這個 nodejs 片段,我想在 C# 中實作。SignTransaction 函式接收一個seedHex 字串(長度:64)和一個TransactionHex 字串,使用secp256k1 演算法創建簽名并附加到TransactionHex 的末尾。
const sha256 = require('sha256');
const EC = require('elliptic').ec;
const ec = new EC("secp256k1");
// Serialize a number into an 8-byte array. This is a copy/paste primitive, not worth
// getting into the details.
function uvarint64ToBuf (uint) {
const result = [];
while (uint >= 0x80) {
result.push((uint & 0xFF) | 0x80);
uint >>>= 7;
}
result.push(uint | 0);
return new Buffer(result);
}
// Sign transaction with seed
function signTransaction (seed, txnHex) {
const privateKey = ec.keyFromPrivate(seed);
const transactionBytes = new Buffer(txnHex, '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([
transactionBytes.slice(0, -1),
signatureLength,
signatureBytes
])
return signedTransactionBytes.toString('hex');
}
示例事務十六進制
01efa5060f5fdae5ed9d90e5f076b2c328a64e347d0c87e8e3317daec5a44fe7c8000102bd53e48625f49e60ff6b7a934e3871b54cc2a93a8737352e8320549e42e2322bab0405270000167b22426f6479223a2248656c6c6f20576f726c64227de807d461f4df9efad8a0f3f716002102bd53e48625f49e60ff6b7a934e3871b54cc2a93a8737352e8320549e42e2322b0000
從 javascript 函式回傳的示例簽名交易十六進制
01efa5060f5fdae5ed9d90e5f076b2c328a64e347d0c87e8e3317daec5a44fe7c8000102bd53e48625f49e60ff6b7a934e3871b54cc2a93a8737352e8320549e42e2322bab0405270000167b22426f6479223a2248656c6c6f20576f726c64227de807d461f4df9efad8a0f3f716002102bd53e48625f49e60ff6b7a934e3871b54cc2a93a8737352e8320549e42e2322b00473045022100c36e2b80f2160304cf640b1296244e7a3873aacf2831098bca3727ad06f4c270022007d3697ceef266a05ad70219d92fbd570f6ec7a5731aaf02718213067d42d1cf
如果您注意到簽名的十六進制是TransactionHex 47 (length of signature) 473045022100c36e2b80f2160304cf640b1296244e7a3873aacf2831098bca3727ad06f4c270022007d3697ceef266a05ad70219d92fbd570f6ec7a5731aaf02718213067d42d1cf (actual signature)
我正在嘗試使用 Unity3d 中的 C# Bouncy Castle 庫來生成簽名部分,但沒有成功。
這是 C# 代碼(源代碼)
public string GetSignature(string privateKey, string message)
{
var curve = SecNamedCurves.GetByName("secp256k1");
var domain = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H);
var keyParameters = new ECPrivateKeyParameters(new BigInteger(privateKey, 16), domain);
var signer = new ECDsaSigner(new HMacDsaKCalculator(new Sha256Digest()));
signer.Init(true, keyParameters);
var signature = signer.GenerateSignature(Encoding.UTF8.GetBytes(message));
var r = signature[0];
var s = signature[1];
var otherS = curve.Curve.Order.Subtract(s);
if (s.CompareTo(otherS) == 1)
{
s = otherS;
}
var derSignature = new DerSequence
(
new DerInteger(new BigInteger(1, r.ToByteArray())),
new DerInteger(new BigInteger(1, s.ToByteArray()))
)
.GetDerEncoded();
return Convert(derSignature);
}
public string Convert(byte[] input)
{
return string.Concat(input.Select(x => x.ToString("x2")));
}
public byte[] Convert(string input)
{
if (input.StartsWith("0x")) input = input.Remove(0, 2);
return Enumerable.Range(0, input.Length / 2).Select(x => System.Convert.ToByte(input.Substring(x * 2, 2), 16)).ToArray();
}
這確實會生成一個簽名,但它與我上面提到的那個不同。
從生成的簽名GetSignature
3044022018a06b1f2b8a1e2f5ea2a78b0d6d98ec483b9fa4345821cfef892be6c825ff4702207958160e533c801dff5e50600206e1cd938d6df74ebfa4b0347a95de67dda986
PS這里是簽署交易的 python 等價物供參考。
uj5u.com熱心網友回復:
sha256.x2()在 NodeJS 代碼中散列兩次,而ECDsaSigner在 C# 代碼中根本不散列。因此,在 C# 代碼中,GetSignature()必須顯式哈希兩次:
using Org.BouncyCastle.Crypto.Digests;
...
var messageBytes = Convert(message);
var hash = GetHash(GetHash(messageBytes));
var signature = signer.GenerateSignature(hash);
...
和
private static byte[] GetHash(byte[] data)
{
var digest = new Sha256Digest();
var hash = new byte[digest.GetDigestSize()];
digest.BlockUpdate(data, 0, data.Length);
digest.DoFinal(hash, 0);
return hash;
}
由于兩種代碼都使用 RFC6979 的確定性 ECDSA 演算法,因此相同輸入資料的哈希值是相同的,可以進行比較。
總體結果是txnHex沒有最后一個位元組、簽名的十六進制編碼長度和 ASN.1/DER 格式的簽名的串聯;一個可能的實作是:
var txnHex = "...";
var seed = "...";
string signature = GetSignature(seed, txnHex);
string signedTransactionBytes = txnHex.Substring(0, txnHex.Length - 2) (signature.Length / 2).ToString("x") signature;
請注意,uvarint64ToBuf()實作實際上更復雜,但可以針對此處使用的簽名長度進行簡化。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/476520.html
上一篇:如何設定屬性物件的初始化順序?
