X-Git-Url: https://git.novaco.in/?a=blobdiff_plain;f=Novacoin%2FCKeyPair.cs;h=5dcedbb52455787e293a3dcd0f2bb3f5deb1783a;hb=1dcac5faa2b1477034f82466ffb16170fa2e9bb6;hp=9c5903ceea070acb74ac86b10e8b77278a19e74e;hpb=5e24f8fe130223d3a270b7353a93499d334839dc;p=NovacoinLibrary.git diff --git a/Novacoin/CKeyPair.cs b/Novacoin/CKeyPair.cs index 9c5903c..5dcedbb 100644 --- a/Novacoin/CKeyPair.cs +++ b/Novacoin/CKeyPair.cs @@ -1,95 +1,200 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +/** + * Novacoin classes library + * Copyright (C) 2015 Alex D. (balthazar.ad@gmail.com) -using Org.BouncyCastle.Math; -using Org.BouncyCastle.Math.EC; + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ -using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Asn1.X9; +using System.Security.Cryptography; + +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Math; using Org.BouncyCastle.Security; -using Org.BouncyCastle.Asn1.Sec; +using System.Collections.Generic; +using System.Linq; +using System; +using System.Diagnostics.Contracts; namespace Novacoin { - public class CKeyPair - { - private BigInteger D; - private ECPoint Q; - private static X9ECParameters curve = SecNamedCurves.GetByName("secp256k1"); - private static ECDomainParameters domain = new ECDomainParameters(curve.Curve, curve.G, curve.N, curve.H, curve.GetSeed()); + public class CKeyPair : CKey + { + private ECPrivateKeyParameters _Private; /// /// Initialize new CKeyPair instance with random secret. /// - public CKeyPair() + public CKeyPair(bool Compressed = true) { - ECKeyGenerationParameters genParams = new ECKeyGenerationParameters(domain, new SecureRandom()); - - ECKeyPairGenerator generator = new ECKeyPairGenerator("ECDSA"); + var genParams = new ECKeyGenerationParameters(domain, new SecureRandom()); + var generator = new ECKeyPairGenerator("ECDSA"); generator.Init(genParams); - AsymmetricCipherKeyPair ecKeyPair = generator.GenerateKeyPair(); + var ecKeyPair = generator.GenerateKeyPair(); - Q = ((ECPublicKeyParameters)ecKeyPair.Public).Q; - D = ((ECPrivateKeyParameters)ecKeyPair.Private).D; + _Private = (ECPrivateKeyParameters)ecKeyPair.Private; + _Public = (ECPublicKeyParameters)ecKeyPair.Public; + + if (Compressed) + { + _Public = Compress(_Public); + } } /// /// Init key pair using secret sequence of bytes /// /// Byte sequence - public CKeyPair(IEnumerable secretBytes) + /// Compression flag + public CKeyPair(byte[] secretBytes, bool Compressed=true) { - D = new BigInteger(secretBytes.ToArray()); - Q = curve.G.Multiply(D); + Contract.Requires(secretBytes.Length == 32, "Serialized secret key must be 32 bytes long."); + + // Deserialize secret value + var D = new BigInteger(secretBytes); + + // Append with zero byte if necessary + if (D.SignValue == -1) + { + var positiveKeyBytes = new byte[33]; + Array.Copy(secretBytes, 0, positiveKeyBytes, 1, 32); + D = new BigInteger(positiveKeyBytes); + } + + // Calculate public key + var Q = curve.G.Multiply(D); + + _Private = new ECPrivateKeyParameters(D, domain); + _Public = new ECPublicKeyParameters(Q, domain); + + if (Compressed) + { + _Public = Compress(_Public); + } } /// - /// Create signature for supplied data + /// Init key pair using secret sequence of bytes /// - /// Data bytes sequence - /// Signature bytes sequence - public IEnumerable Sign(IEnumerable data) + /// Byte sequence + public CKeyPair(byte[] secretBytes) : + this (secretBytes.Take(32).ToArray(), (secretBytes.Count() == 33 && secretBytes.Last() == 0x01)) { - byte[] dataBytes = data.ToArray(); + } - ISigner signer = SignerUtilities.GetSigner("SHA-256withECDSA"); - ECPrivateKeyParameters keyParameters = new ECPrivateKeyParameters(D, domain); - signer.Init(true, keyParameters); - signer.BlockUpdate(dataBytes, 0, dataBytes.Length); + public CKeyPair(string strBase58) + { + var rawSecretBytes = AddressTools.Base58DecodeCheck(strBase58); - return signer.GenerateSignature(); + if (rawSecretBytes.Length != 33 && rawSecretBytes.Length != 34) + { + throw new ArgumentException("Though you have provided a correct Base58 representation of some data, this data doesn't represent a valid private key."); + } + + // Deserialize secret value + var D = new BigInteger(rawSecretBytes.Skip(1).Take(32).ToArray()); + + if (D.SignValue == -1) + { + var secretBytes = new byte[33]; + Array.Copy(rawSecretBytes, 1, secretBytes, 1, 32); // Copying the privkey, 32 bytes starting from second byte of array + + D = new BigInteger(secretBytes); // Try decoding again + } + + // Calculate public key + var Q = curve.G.Multiply(D); + + _Private = new ECPrivateKeyParameters(D, domain); + _Public = new ECPublicKeyParameters(Q, domain); + + if (rawSecretBytes.Length == 34 && rawSecretBytes.Last() == 0x01) // Check compression tag + { + _Public = Compress(_Public); + } } /// - /// Secret part of key pair + /// Initialize a copy of CKeyPair instance /// - public IEnumerable Secret + /// CKyPair instance + public CKeyPair(CKeyPair pair) + { + _Public = pair._Public; + _Private = pair._Private; + } + + /// + /// Create signature for supplied data + /// + /// Hash to sigh + /// Signature bytes sequence + public byte[] Sign(uint256 sigHash) { - get { return D.ToByteArray(); } + var signer = SignerUtilities.GetSigner("NONEwithECDSA"); + signer.Init(true, _Private); + signer.BlockUpdate(sigHash, 0, sigHash.Size); + + return signer.GenerateSignature(); + } + + public CPubKey PubKey + { + get { return new CPubKey(_Public.Q.GetEncoded()); } } /// - /// Public part of key pair + /// SecretBytes part of key pair /// - public IEnumerable Public + public static implicit operator byte[] (CKeyPair kp) { - get { return Q.GetEncoded(); } + var secretBytes = new List(kp._Private.D.ToByteArray()); + + if (secretBytes.Count == 33 && secretBytes[0] == 0x00) + { + // Remove sign + secretBytes.RemoveAt(0); + } + + if (kp.IsCompressed) + { + // Set compression flag + secretBytes.Add(0x01); + } + + return secretBytes.ToArray(); + } + + public string ToHex() + { + return Interop.ToHex((byte[])this); } + /// + /// Generate Base58 string in wallet import format + /// + /// public override string ToString() { - StringBuilder sb = new StringBuilder(); + var r = new List(); - sb.AppendFormat("CKeyPair(Secret={0}, Public={1})", Interop.ToHex(Secret), Interop.ToHex(Public)); + r.Add((byte)(128 + AddrType.PUBKEY_ADDRESS)); // Key version + r.AddRange((byte[])this); // Key data - return sb.ToString(); + return AddressTools.Base58EncodeCheck(r.ToArray()); } } }