2 * Novacoin classes library
3 * Copyright (C) 2015 Alex D. (balthazar.ad@gmail.com)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Affero General Public License as
7 * published by the Free Software Foundation, either version 3 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Affero General Public License for more details.
15 * You should have received a copy of the GNU Affero General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 using Org.BouncyCastle.Crypto;
20 using Org.BouncyCastle.Crypto.Generators;
22 using System.Security.Cryptography;
24 using Org.BouncyCastle.Crypto.Parameters;
25 using Org.BouncyCastle.Math;
26 using Org.BouncyCastle.Security;
27 using System.Collections.Generic;
33 public class CKeyPair : CKey
35 private ECPrivateKeyParameters _Private;
36 private RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
39 /// Initialize new CKeyPair instance with random secret.
41 public CKeyPair(bool Compressed = true)
45 var genParams = new ECKeyGenerationParameters(domain, new SecureRandom());
46 var generator = new ECKeyPairGenerator("ECDSA");
47 generator.Init(genParams);
48 var ecKeyPair = generator.GenerateKeyPair();
50 _Private = (ECPrivateKeyParameters)ecKeyPair.Private;
51 _Public = (ECPublicKeyParameters)ecKeyPair.Public;
55 var buffer1 = new byte[32];
56 var buffer2 = new byte[32];
60 rng.GetBytes(buffer1);
61 rng.GetNonZeroBytes(buffer2);
63 D = new BigInteger(Hash256.ComputeRaw256(ref buffer1, ref buffer2));
65 if (D.BitLength < 249)
66 System.Console.WriteLine(D.BitLength);
68 while (D.SignValue == -1);
70 var Q = curve.G.Multiply(D);
72 _Private = new ECPrivateKeyParameters(D, domain);
73 _Public = new ECPublicKeyParameters(Q, domain);
78 _Public = Compress(_Public);
83 /// Init key pair using secret sequence of bytes
85 /// <param name="secretBytes">Byte sequence</param>
86 /// <param name="Compressed">Compression flag</param>
87 public CKeyPair(byte[] secretBytes, bool Compressed=true)
89 if (secretBytes.Length != 32)
91 throw new ArgumentException("Serialized secret key must be 32 bytes long.");
94 // Deserialize secret value
95 var D = new BigInteger(secretBytes);
97 // Append with zero byte if necessary
98 if (D.SignValue == -1)
100 var positiveKeyBytes = new byte[33];
101 Array.Copy(secretBytes, 0, positiveKeyBytes, 1, 32);
102 D = new BigInteger(positiveKeyBytes);
105 // Calculate public key
106 var Q = curve.G.Multiply(D);
108 _Private = new ECPrivateKeyParameters(D, domain);
109 _Public = new ECPublicKeyParameters(Q, domain);
113 _Public = Compress(_Public);
118 /// Init key pair using secret sequence of bytes
120 /// <param name="secretBytes">Byte sequence</param>
121 public CKeyPair(byte[] secretBytes) :
122 this (secretBytes.Take(32).ToArray(), (secretBytes.Count() == 33 && secretBytes.Last() == 0x01))
126 public CKeyPair(string strBase58)
128 var rawSecretBytes = AddressTools.Base58DecodeCheck(strBase58);
130 if (rawSecretBytes.Length > 34 || rawSecretBytes.Length < 33)
132 throw new ArgumentException("Though you have provided a correct Base58 representation of some data, this data doesn't represent a valid private key.");
135 // Deserialize secret value
136 var D = new BigInteger(rawSecretBytes.Skip(1).Take(32).ToArray());
138 if (D.SignValue == -1)
140 var secretBytes = new byte[33];
141 Array.Copy(rawSecretBytes, 1, secretBytes, 1, 32); // Copying the privkey, 32 bytes starting from second byte of array
143 D = new BigInteger(secretBytes); // Try decoding again
146 // Calculate public key
147 var Q = curve.G.Multiply(D);
149 _Private = new ECPrivateKeyParameters(D, domain);
150 _Public = new ECPublicKeyParameters(Q, domain);
152 if (rawSecretBytes.Length == 34 && rawSecretBytes.Last() == 0x01) // Check compression tag
154 _Public = Compress(_Public);
159 /// Initialize a copy of CKeyPair instance
161 /// <param name="pair">CKyPair instance</param>
162 public CKeyPair(CKeyPair pair)
164 _Public = pair._Public;
165 _Private = pair._Private;
169 /// Create signature for supplied data
171 /// <param name="data">Hash to sigh</param>
172 /// <returns>Signature bytes sequence</returns>
173 public byte[] Sign(Hash sigHash)
175 var signer = SignerUtilities.GetSigner("NONEwithECDSA");
176 signer.Init(true, _Private);
177 signer.BlockUpdate(sigHash, 0, sigHash.hashSize);
179 return signer.GenerateSignature();
182 public CPubKey PubKey
184 get { return new CPubKey(_Public.Q.GetEncoded()); }
188 /// SecretBytes part of key pair
190 public static implicit operator byte[] (CKeyPair kp)
192 var secretBytes = new List<byte>(kp._Private.D.ToByteArray());
194 if (secretBytes.Count == 33 && secretBytes[0] == 0x00)
197 secretBytes.RemoveAt(0);
202 // Set compression flag
203 secretBytes.Add(0x01);
206 return secretBytes.ToArray();
209 public string ToHex()
211 return Interop.ToHex((byte[])this);
215 /// Generate Base58 string in wallet import format
217 /// <returns></returns>
218 public override string ToString()
220 var r = new List<byte>();
222 r.Add((byte)(128 + AddrType.PUBKEY_ADDRESS)); // Key version
223 r.AddRange((byte[])this); // Key data
225 return AddressTools.Base58EncodeCheck(r.ToArray());