// $Id: bitcoin-raw.cs $
// $Date: 2016-04-01 09:47Z $
// $Revision: 1.0.0 $
// $Author: dai $
// *************************** COPYRIGHT NOTICE ******************************
// This code is copyright (C) 2016 David Ireland, DI Management Services Pty
// Ltd, Australia <http://di-mgt.com.au>.
// Provided "as is" with no warranties. Use at your own risk.
// It is not to be altered or distributed, except as part of an application.
// You are free to use it in any application, provided this copyright notice
// is left unchanged.
// ************************ END OF COPYRIGHT NOTICE **************************
// This module uses functions from CryptoSys (tm) PKI Pro available from
// <http://cryptosys.net/pki/>.
// Add a reference to `diCrSysPKINet.dll` and use "using CryptoSysPKI;".
using System;
using System.Text;
using CryptoSysPKI;
namespace bitcoin_raw
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("PKI Version=" + General.Version());
// READ IN PRIVATE KEY IN (HEX,CURVENAME) FORMAT
string hexKey = "0ecd20654c2e2be708495853e8da35c664247040c00bd10b9b13e5e86e6a808d";
Ecc.CurveName curveName = Ecc.CurveName.Secp256k1;
Console.WriteLine("KEYHEX: " + hexKey);
Console.WriteLine("CURVE: " + curveName.ToString());
string internalKey = Ecc.ReadKeyByCurve(hexKey, curveName);
// Derive public key in hex form from given private key and check against known value
string s = Ecc.QueryKey(internalKey, "publicKey");
Console.WriteLine("Ecc.QueryKey('publicKey')=\n" + s);
// READ IN THE PUBLIC KEY
string pubkeyhex =
"042daa93315eebbe2cb9b5c3505df4c6fb6caca8b756786098567550d4820c09d" +
"b988fe9997d049d687292f815ccd6e7fb5c1b1a91137999818d17c73d0f80aef9";
string internalPubKey = Ecc.ReadKeyByCurve(pubkeyhex, curveName);
Console.WriteLine("keyBits=" + Ecc.QueryKey(internalPubKey, "keyBits"));
Console.WriteLine("isPrivate=" + Ecc.QueryKey(internalPubKey, "isPrivate"));
// COMPUTE THE HASH160 DIGEST OF THE PUBLIC KEY
s = Hash.HexFromHex(pubkeyhex, HashAlgorithm.Bitcoin160);
Console.WriteLine("Bitcoin160('publicKey')=" + s);
// THE RAW INPUT DATA
string datahex =
"0100000001be66e10da854e7aea9338c1f91cd489768d1d6d7189f586d7a3613f2a24d539600" +
"0000001976a914dd6cce9f255a8cc17bda8ba0373df8e861cb866e88acffffffff0123ce0100" +
"000000001976a9142bc89c2702e0e618db7d59eb5ce2f0f147b4075488ac0000000001000000";
byte[] data = Cnv.FromHex(datahex);
Console.WriteLine("RAW_TX:\n" + Cnv.ToHex(data));
// COMPUTE THE DOUBLE SHA-256 DIGEST OF THE RAW DATA
byte[] digest = Hash.Double(data, HashAlgorithm.Sha256);
Console.WriteLine("SHA256(SHA256(RAW_TX)):\n" + Cnv.ToHex(digest));
Console.WriteLine("Same hash value but reversed:\n" + Cnv.ToHex(Cnv.ReverseBytes(digest)));
string sigweb =
"3045022100da43201760bda697222002f56266bf65023fef2094519e13077f777baed55" +
"3b102205ce35d05eabda58cd50a67977a65706347cc25ef43153e309ff210a134722e9e";
// VERIFY THE SIGNATURE PUBLISHED ON THE WEB
int r1 = Sig.VerifyDigest(sigweb, digest, internalPubKey, SigAlgorithm.Ecdsa_Sha256);
Console.WriteLine("Sig.VerifyDigest returns " + r1 + " (expected 0)");
// Sign using ECDSA deterministic method of RFC6979
// -- NOTE this will not be the same as the published signature (which used a random k we cannot reproduce)
// but the deterministic method should always produce the same signature value:
// 30450220587ce0cf0252e2db3a7c3c91b355aa8f3385e128227cd8727c5f7777877ad772022100edc508b7c14891ed15ab38c687019d7ebaf5c12908cf21a83e8ae57e8c47e95c
string sigdet = Sig.SignDigest(digest, internalKey, "", SigAlgorithm.Ecdsa_Sha256,
Sig.SigOptions.UseDeterministic | Sig.SigOptions.Asn1DERStructure, Sig.Encoding.Base16);
Console.WriteLine("SIG (DET): " + sigdet);
// VERIFY THE NEW SIGNATURE
int r2 = Sig.VerifyDigest(sigdet, digest, internalPubKey, SigAlgorithm.Ecdsa_Sha256);
Console.WriteLine("Sig.VerifyDigest(sigdet) returns " + r2 + " (expected 0)");
}
}
}