Skip to content

Instantly share code, notes, and snippets.

@mvanhalen
Last active April 30, 2023 10:41
Show Gist options
  • Select an option

  • Save mvanhalen/e37e384e2d4a2199f0ff23b458a81833 to your computer and use it in GitHub Desktop.

Select an option

Save mvanhalen/e37e384e2d4a2199f0ff23b458a81833 to your computer and use it in GitHub Desktop.
Sign DeSo transaction correct version. Working after April Fork.
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.Sec;
using Org.BouncyCastle.Crypto.Digests;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Signers;
using Org.BouncyCastle.Math;
public partial class TransactionHelpers
{
public static async Task<long> GetSignatureFieldLenght(string transactionHex)
{
long result = 0;
HttpClient hc = new HttpClient();
Txn data = new Txn()
{
TransactionHex = transactionHex,
};
string path = "api/v0/signature-index";
StringContent content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");
hc.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage response = await hc.PostAsync(apiUrl + path, content);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
string json = await response.Content.ReadAsStringAsync();
if (!string.IsNullOrEmpty(json))
{
IndexTxnResponse signatureIndex = JsonConvert.DeserializeObject<IndexTxnResponse>(json);
result = signatureIndex.SignatureIndex;
}
}
return result;
}
public static async Task<string> SignTransaction(string privateKey, string txnHex)
{
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 txnBytes = Convert(txnHex);
var hash = GetHash(GetHash(txnBytes));
var signature = signer.GenerateSignature(hash);
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();
long signatureIndex = await GetSignatureFieldLenght(txnHex);
byte[] v0FieldsWithoutSignature = txnBytes.Take((int)signatureIndex).ToArray();
byte[] v1FieldsBuffer = txnBytes.Skip((int)signatureIndex + 1).ToArray();
var sigBytes =new List<byte>();
foreach(var item in v0FieldsWithoutSignature)
{
sigBytes.Add(item);
}
sigBytes.Add((byte)(derSignature.Length));
foreach(var item in derSignature)
{
sigBytes.Add(item);
}
foreach(var item in v1FieldsBuffer)
{
sigBytes.Add(item);
}
string signedTxn = Convert(sigBytes.ToArray());
return signedTxn;
}
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;
}
public static string Convert(byte[] input)
{
return string.Concat(input.Select(x => x.ToString("x2")));
}
public static 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();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment