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.Generators;
21 using System.Security.Cryptography;
23 using Org.BouncyCastle.Crypto.Parameters;
24 using Org.BouncyCastle.Math;
25 using Org.BouncyCastle.Security;
26 using System.Collections.Generic;
29 using System.Diagnostics.Contracts;
34 public class CKeyPair : CKey
36 private ECPrivateKeyParameters _Private;
39 /// Initialize new CKeyPair instance with random secret.
41 public CKeyPair(bool Compressed = true)
43 var genParams = new ECKeyGenerationParameters(domain, new SecureRandom());
44 var generator = new ECKeyPairGenerator("ECDSA");
45 generator.Init(genParams);
46 var ecKeyPair = generator.GenerateKeyPair();
48 _Private = (ECPrivateKeyParameters)ecKeyPair.Private;
49 _Public = (ECPublicKeyParameters)ecKeyPair.Public;
53 _Public = Compress(_Public);
58 /// Init key pair using secret sequence of bytes
60 /// <param name="secretBytes">Byte sequence</param>
61 /// <param name="Compressed">Compression flag</param>
62 public CKeyPair(byte[] secretBytes, bool Compressed=true)
64 Contract.Requires<ArgumentException>(secretBytes.Length == 32, "Serialized secret key must be 32 bytes long.");
66 // Deserialize secret value
67 var D = new BigInteger(secretBytes);
69 // Append with zero byte if necessary
70 if (D.SignValue == -1)
72 var positiveKeyBytes = new byte[33];
73 Array.Copy(secretBytes, 0, positiveKeyBytes, 1, 32);
74 D = new BigInteger(positiveKeyBytes);
77 // Calculate public key
78 var Q = curve.G.Multiply(D);
80 _Private = new ECPrivateKeyParameters(D, domain);
81 _Public = new ECPublicKeyParameters(Q, domain);
85 _Public = Compress(_Public);
90 /// Init key pair using secret sequence of bytes
92 /// <param name="secretBytes">Byte sequence</param>
93 public CKeyPair(byte[] secretBytes) :
94 this (secretBytes.Take(32).ToArray(), (secretBytes.Count() == 33 && secretBytes.Last() == 0x01))
98 public CKeyPair(string strBase58)
100 var rawSecretBytes = AddressTools.Base58DecodeCheck(strBase58);
102 if (rawSecretBytes.Length != 33 && rawSecretBytes.Length != 34)
104 throw new ArgumentException("Though you have provided a correct Base58 representation of some data, this data doesn't represent a valid private key.");
107 // Deserialize secret value
108 var D = new BigInteger(rawSecretBytes.Skip(1).Take(32).ToArray());
110 if (D.SignValue == -1)
112 var secretBytes = new byte[33];
113 Array.Copy(rawSecretBytes, 1, secretBytes, 1, 32); // Copying the privkey, 32 bytes starting from second byte of array
115 D = new BigInteger(secretBytes); // Try decoding again
118 // Calculate public key
119 var Q = curve.G.Multiply(D);
121 _Private = new ECPrivateKeyParameters(D, domain);
122 _Public = new ECPublicKeyParameters(Q, domain);
124 if (rawSecretBytes.Length == 34 && rawSecretBytes.Last() == 0x01) // Check compression tag
126 _Public = Compress(_Public);
131 /// Initialize a copy of CKeyPair instance
133 /// <param name="pair">CKyPair instance</param>
134 public CKeyPair(CKeyPair pair)
136 _Public = pair._Public;
137 _Private = pair._Private;
141 /// Create signature for supplied data
143 /// <param name="data">Hash to sigh</param>
144 /// <returns>Signature bytes sequence</returns>
145 public byte[] Sign(Hash sigHash)
147 var signer = SignerUtilities.GetSigner("NONEwithECDSA");
148 signer.Init(true, _Private);
149 signer.BlockUpdate(sigHash, 0, sigHash.hashSize);
151 return signer.GenerateSignature();
154 public CPubKey PubKey
156 get { return new CPubKey(_Public.Q.GetEncoded()); }
160 /// SecretBytes part of key pair
162 public static implicit operator byte[] (CKeyPair kp)
164 var secretBytes = new List<byte>(kp._Private.D.ToByteArray());
166 if (secretBytes.Count == 33 && secretBytes[0] == 0x00)
169 secretBytes.RemoveAt(0);
174 // Set compression flag
175 secretBytes.Add(0x01);
178 return secretBytes.ToArray();
181 public string ToHex()
183 return Interop.ToHex((byte[])this);
187 /// Generate Base58 string in wallet import format
189 /// <returns></returns>
190 public override string ToString()
192 var r = new List<byte>();
194 r.Add((byte)(128 + AddrType.PUBKEY_ADDRESS)); // Key version
195 r.AddRange((byte[])this); // Key data
197 return AddressTools.Base58EncodeCheck(r.ToArray());