Remove Hash, Hash256, Hash160 and ScryptHash256 classes.
[NovacoinLibrary.git] / Novacoin / CKeyPair.cs
1 \feff/**
2  *  Novacoin classes library
3  *  Copyright (C) 2015 Alex D. (balthazar.ad@gmail.com)
4
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.
9
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.
14
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/>.
17  */
18
19 using Org.BouncyCastle.Crypto.Generators;
20
21 using System.Security.Cryptography;
22
23 using Org.BouncyCastle.Crypto.Parameters;
24 using Org.BouncyCastle.Math;
25 using Org.BouncyCastle.Security;
26 using System.Collections.Generic;
27 using System.Linq;
28 using System;
29 using System.Diagnostics.Contracts;
30
31 namespace Novacoin
32 {
33
34     public class CKeyPair : CKey
35     {
36         private ECPrivateKeyParameters _Private;
37
38         /// <summary>
39         /// Initialize new CKeyPair instance with random secret.
40         /// </summary>
41         public CKeyPair(bool Compressed = true)
42         {
43             var genParams = new ECKeyGenerationParameters(domain, new SecureRandom());
44             var generator = new ECKeyPairGenerator("ECDSA");
45             generator.Init(genParams);
46             var ecKeyPair = generator.GenerateKeyPair();
47
48             _Private = (ECPrivateKeyParameters)ecKeyPair.Private;
49             _Public = (ECPublicKeyParameters)ecKeyPair.Public;
50
51             if (Compressed)
52             {
53                 _Public = Compress(_Public);
54             }
55         }
56
57         /// <summary>
58         /// Init key pair using secret sequence of bytes
59         /// </summary>
60         /// <param name="secretBytes">Byte sequence</param>
61         /// <param name="Compressed">Compression flag</param>
62         public CKeyPair(byte[] secretBytes, bool Compressed=true)
63         {
64             Contract.Requires<ArgumentException>(secretBytes.Length == 32, "Serialized secret key must be 32 bytes long.");
65
66             // Deserialize secret value
67             var D = new BigInteger(secretBytes);
68
69             // Append with zero byte if necessary
70             if (D.SignValue == -1)
71             {
72                 var positiveKeyBytes = new byte[33];
73                 Array.Copy(secretBytes, 0, positiveKeyBytes, 1, 32);
74                 D = new BigInteger(positiveKeyBytes);
75             }
76
77             // Calculate public key
78             var Q = curve.G.Multiply(D);
79
80             _Private = new ECPrivateKeyParameters(D, domain);
81             _Public = new ECPublicKeyParameters(Q, domain);
82
83             if (Compressed)
84             {
85                 _Public = Compress(_Public);
86             }
87         }
88
89         /// <summary>
90         /// Init key pair using secret sequence of bytes
91         /// </summary>
92         /// <param name="secretBytes">Byte sequence</param>
93         public CKeyPair(byte[] secretBytes) : 
94             this (secretBytes.Take(32).ToArray(), (secretBytes.Count() == 33 && secretBytes.Last() == 0x01))
95         {
96         }
97
98         public CKeyPair(string strBase58)
99         {
100             var rawSecretBytes = AddressTools.Base58DecodeCheck(strBase58);
101
102             if (rawSecretBytes.Length != 33 && rawSecretBytes.Length != 34)
103             {
104                 throw new ArgumentException("Though you have provided a correct Base58 representation of some data, this data doesn't represent a valid private key.");
105             }
106
107             // Deserialize secret value
108             var D = new BigInteger(rawSecretBytes.Skip(1).Take(32).ToArray());
109
110             if (D.SignValue == -1)
111             {
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
114
115                 D = new BigInteger(secretBytes); // Try decoding again
116             }
117
118             // Calculate public key
119             var Q = curve.G.Multiply(D);
120
121             _Private = new ECPrivateKeyParameters(D, domain);
122             _Public = new ECPublicKeyParameters(Q, domain);
123
124             if (rawSecretBytes.Length == 34 && rawSecretBytes.Last() == 0x01) // Check compression tag
125             {
126                 _Public = Compress(_Public);
127             }
128         }
129
130         /// <summary>
131         /// Initialize a copy of CKeyPair instance
132         /// </summary>
133         /// <param name="pair">CKyPair instance</param>
134         public CKeyPair(CKeyPair pair)
135         {
136             _Public = pair._Public;
137             _Private = pair._Private;
138         }
139
140         /// <summary>
141         /// Create signature for supplied data
142         /// </summary>
143         /// <param name="data">Hash to sigh</param>
144         /// <returns>Signature bytes sequence</returns>
145         public byte[] Sign(uint256 sigHash)
146         {
147             var signer = SignerUtilities.GetSigner("NONEwithECDSA");
148             signer.Init(true, _Private);
149             signer.BlockUpdate(sigHash, 0, sigHash.Size);
150
151             return signer.GenerateSignature();
152         }
153
154         public CPubKey PubKey
155         {
156             get { return new CPubKey(_Public.Q.GetEncoded()); }
157         }
158
159         /// <summary>
160         /// SecretBytes part of key pair
161         /// </summary>
162         public static implicit operator byte[] (CKeyPair kp)
163         {
164             var secretBytes = new List<byte>(kp._Private.D.ToByteArray());
165
166             if (secretBytes.Count == 33 && secretBytes[0] == 0x00)
167             {
168                 // Remove sign
169                 secretBytes.RemoveAt(0);
170             }
171
172             if (kp.IsCompressed)
173             {
174                 // Set compression flag
175                 secretBytes.Add(0x01);
176             }
177
178             return secretBytes.ToArray();
179         }
180
181         public string ToHex()
182         {
183             return Interop.ToHex((byte[])this);
184         }
185
186         /// <summary>
187         /// Generate Base58 string in wallet import format
188         /// </summary>
189         /// <returns></returns>
190         public override string ToString()
191         {
192             var r = new List<byte>();
193
194             r.Add((byte)(128 + AddrType.PUBKEY_ADDRESS)); // Key version
195             r.AddRange((byte[])this); // Key data
196
197             return AddressTools.Base58EncodeCheck(r.ToArray());
198         }
199     }
200 }