// $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://www.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://www.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)"); } } }