Replace base58 implementation, add new key tests
[NovacoinLibrary.git] / Novacoin / CKeyPair.cs
1 \feffusing System.Collections.Generic;
2 using System.Linq;
3 using System;
4
5 using Org.BouncyCastle.Math;
6 using Org.BouncyCastle.Math.EC;
7
8 using Org.BouncyCastle.Crypto;
9 using Org.BouncyCastle.Crypto.Generators;
10 using Org.BouncyCastle.Crypto.Parameters;
11 using Org.BouncyCastle.Security;
12
13
14 namespace Novacoin
15 {
16     public class CKeyPair : CKey
17     {
18         private ECPrivateKeyParameters _Private;
19
20         /// <summary>
21         /// Initialize new CKeyPair instance with random secret.
22         /// </summary>
23         public CKeyPair(bool Compressed=true)
24         {
25             ECKeyGenerationParameters genParams = new ECKeyGenerationParameters(domain, new SecureRandom());
26             ECKeyPairGenerator generator = new ECKeyPairGenerator("ECDSA");
27             generator.Init(genParams);
28             AsymmetricCipherKeyPair ecKeyPair = generator.GenerateKeyPair();
29
30             _Private = (ECPrivateKeyParameters)ecKeyPair.Private;
31             _Public = (ECPublicKeyParameters)ecKeyPair.Public;
32
33             if (Compressed)
34             {
35                 _Public = Compress(_Public);
36             }
37         }
38
39         /// <summary>
40         /// Init key pair using secret sequence of bytes
41         /// </summary>
42         /// <param name="secretBytes">Byte sequence</param>
43         public CKeyPair(IEnumerable<byte> secretBytes, bool Compressed=true)
44         {
45             // Deserialize secret value
46             BigInteger D = new BigInteger(secretBytes.ToArray());
47
48             // Calculate public key
49             ECPoint Q = curve.G.Multiply(D);
50
51             _Private = new ECPrivateKeyParameters(D, domain);
52             _Public = new ECPublicKeyParameters(Q, domain);
53
54             if (Compressed)
55             {
56                 _Public = Compress(_Public);
57             }
58         }
59
60         public CKeyPair(string strBase58)
61         {
62             List<byte> rawBytes = AddressTools.Base58DecodeCheck(strBase58).ToList();
63             rawBytes.RemoveAt(0); // Remove key version byte
64
65             int nSecretLen = rawBytes[0] == 0x00 ? 33 : 32;
66             int nTaggedSecretLen = nSecretLen + 1;
67
68             if (rawBytes.Count > nTaggedSecretLen || rawBytes.Count < nSecretLen)
69             {
70                 throw new FormatException("Invalid private key");
71             }
72
73             // Deserialize secret value
74             BigInteger D = new BigInteger(rawBytes.Take(nSecretLen).ToArray());
75
76             // Calculate public key
77             ECPoint Q = curve.G.Multiply(D);
78
79             _Private = new ECPrivateKeyParameters(D, domain);
80             _Public = new ECPublicKeyParameters(Q, domain);
81
82             if (rawBytes.Count == nTaggedSecretLen && rawBytes.Last() == 0x01) // Check compression tag
83             {
84                 _Public = Compress(_Public);
85             }
86         }
87
88         /// <summary>
89         /// Create signature for supplied data
90         /// </summary>
91         /// <param name="data">Data bytes sequence</param>
92         /// <returns>Signature bytes sequence</returns>
93         public IEnumerable<byte> Sign(IEnumerable<byte> data)
94         {
95             byte[] dataBytes = data.ToArray();
96
97             ISigner signer = SignerUtilities.GetSigner("SHA-256withECDSA");
98             signer.Init(true, _Private);
99             signer.BlockUpdate(dataBytes, 0, dataBytes.Length);
100
101             return signer.GenerateSignature();
102         }
103
104         public CPubKey GetPubKey()
105         {
106             return new CPubKey(Public);
107         }
108
109         /// <summary>
110         /// Secret part of key pair
111         /// </summary>
112         public IEnumerable<byte> Secret
113         {
114             get { return _Private.D.ToByteArray(); }
115         }
116
117         public string ToHex()
118         {
119             List<byte> r = new List<byte>(Secret);
120             
121             if (IsCompressed)
122             {
123                 r.Add(0x01);
124             }
125
126             return Interop.ToHex(r);
127         }
128
129         public override string ToString()
130         {
131             List<byte> r = new List<byte>();
132
133             r.Add((byte)(128 + AddrType.PUBKEY_ADDRESS));
134
135             r.AddRange(Secret);
136
137             if (IsCompressed)
138             {
139                 r.Add(0x01);
140             }
141
142             return AddressTools.Base58EncodeCheck(r);
143         }
144     }
145 }