Skip to content

Commit

Permalink
Generated (mini) private keys are now valid, including LTC keys.
Browse files Browse the repository at this point in the history
  • Loading branch information
BitKoot committed Jun 30, 2013
1 parent fb0fe2d commit a464de1
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 40 deletions.
8 changes: 4 additions & 4 deletions Forms/Form1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public partial class Form1 : Form {
}

private void UpdateMinikeyDescription(byte addressType) {
int isminikey = MiniKeyPair.IsValidMiniKey(txtMinikey.Text, addressType);
int isminikey = MiniKeyPair.IsValidMiniKey(txtMinikey.Text);
if (isminikey == 1) {
lblWhyNot.Visible = false;
lblNotSafe.Visible = true;
Expand Down Expand Up @@ -178,7 +178,7 @@ public partial class Form1 : Form {
byte[] str = Util.Force32Bytes(utf8.GetBytes(txtPrivHex.Text.Substring(1, txtPrivHex.Text.Length - 2)));
txtPrivHex.Text = RemoveSpacesIf(Util.ByteArrayToString(str));
}
KeyPair ba = new KeyPair(txtPrivHex.Text, compressed: compressToolStripMenuItem.Checked);
KeyPair ba = new KeyPair(txtPrivHex.Text, compressToolStripMenuItem.Checked, AddressType.ToAddressType(cboCoinType.Text));

if (txtPassphrase.Text != "") {
SetText(txtPrivWIF, new Bip38KeyPair(ba, txtPassphrase.Text).EncryptedPrivateKey);
Expand Down Expand Up @@ -547,7 +547,7 @@ public partial class Form1 : Form {


string pubhex = Util.PrivHexToPubHex(Util.ByteArrayToString(Util.ComputeSha256(shacode)));
string pubhash = Util.PubHexToPubHash(pubhex);
string pubhash = Util.PubHexToPubHash(4, pubhex);
string address = Util.PubHashToAddress(pubhash, "Bitcoin");


Expand Down Expand Up @@ -596,7 +596,7 @@ public partial class Form1 : Form {
byte[] privkey = Util.ComputeSha256(fields[1]);

string pubhex = Util.PrivHexToPubHex(Util.ByteArrayToString(privkey)).Replace(" ", "");
string pubhash = Util.PubHexToPubHash(pubhex);
string pubhash = Util.PubHexToPubHash(4, pubhex);
string address = Util.PubHashToAddress(pubhash, "Bitcoin");

if (address != fields[0] || pubhex != fields[2]) {
Expand Down
10 changes: 6 additions & 4 deletions Model/AddressType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,8 @@ public static class AddressType {
}
}

public static string FromAddressType(byte addressType)
{
switch (addressType)
{
public static string FromAddressType(byte addressType) {
switch (addressType) {
case AddressType.Namecoin:
return "Namecoin";
case AddressType.Testnet:
Expand All @@ -58,5 +56,9 @@ public static string FromAddressType(byte addressType)
return "Bitcoin";
}
}

public static byte ToPrivateKeyPrefix(byte addressType) {
return (byte)(addressType + 0x80);
}
}
}
28 changes: 14 additions & 14 deletions Model/Bitcoin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,27 +51,27 @@ public class Util {
}


public static byte[] ValidateAndGetHexPublicKey(string PubHex) {
public static byte[] ValidateAndGetHexPublicKey(byte leadingbyte, string PubHex) {
byte[] hex = GetHexBytes(PubHex, 64);

if (hex == null || hex.Length < 64 || hex.Length > 65) {
throw new ApplicationException("Hex is not 64 or 65 bytes.");
}

// if leading 00, change it to 0x80
// if leading 00, change it to leadingbyte
if (hex.Length == 65) {
if (hex[0] == 0 || hex[0] == 4) {
hex[0] = 4;
if (hex[0] == 0 || hex[0] == leadingbyte) {
hex[0] = leadingbyte;
} else {
throw new ApplicationException("Not a valid public key");
}
}

// add 0x80 byte if not present
// add leadingbyte byte if not present
if (hex.Length == 64) {
byte[] hex2 = new byte[65];
Array.Copy(hex, 0, hex2, 1, 64);
hex2[0] = 4;
hex2[0] = leadingbyte;
hex = hex2;
}
return hex;
Expand All @@ -96,20 +96,20 @@ public class Util {
throw new ApplicationException("Hex is not 32 or 33 bytes.");
}

// if leading 00, change it to 0x80
// if leading 00, change it to leadingbyte
if (hex.Length == 33) {
if (hex[0] == 0 || hex[0] == 0x80) {
hex[0] = 0x80;
if (hex[0] == 0 || hex[0] == leadingbyte) {
hex[0] = leadingbyte;
} else {
throw new ApplicationException("Not a valid private key");
}
}

// add 0x80 byte if not present
// add leadingbyte if not present
if (hex.Length == 32 && desiredByteCount==33) {
byte[] hex2 = new byte[33];
Array.Copy(hex, 0, hex2, 1, 32);
hex2[0] = 0x80;
hex2[0] = leadingbyte;
hex = hex2;
}

Expand Down Expand Up @@ -303,8 +303,8 @@ public class Util {
return pubaddr;
}

public static string PubHexToPubHash(string PubHex) {
byte[] hex = ValidateAndGetHexPublicKey(PubHex);
public static string PubHexToPubHash(byte leadingbyte, string pubHex) {
byte[] hex = ValidateAndGetHexPublicKey(leadingbyte, pubHex);
if (hex == null) throw new ApplicationException("Invalid public hex key");
return PubHexToPubHash(hex);
}
Expand Down Expand Up @@ -354,7 +354,7 @@ public class Util {
}

// let mini private keys through - they won't contain words, they are nonsense characters, so their entropy is a bit better per character
if (MiniKeyPair.IsValidMiniKey(passphrase, 0) != 1) return false;
if (MiniKeyPair.IsValidMiniKey(passphrase) != 1) return false;

if (passphrase.Length < 30 && (Lowercase < 10 || Uppercase < 3 || Numbers < 2 || Symbols < 2)) {
return true;
Expand Down
22 changes: 11 additions & 11 deletions Model/KeyPair.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public class KeyPair : PublicKey {
/// </summary>
public KeyPair(BigInteger bi, bool compressed = false, byte addressType = 0) {
this.IsCompressedPoint = compressed;
this._addressType = addressType;
this.AddressType = addressType;

var ps = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
if (bi.CompareTo(ps.N) >= 0 || bi.SignValue <= 0) {
Expand All @@ -99,9 +99,9 @@ public class KeyPair : PublicKey {
/// </summary>
public KeyPair(byte[] bytes, bool compressed=false, byte addressType=0) {
if (bytes.Length == 32) {
AddressType = addressType;
PrivateKeyBytes = bytes;
this.IsCompressedPoint = compressed;
this._addressType = addressType;
} else {
throw new ArgumentException("Byte array provided to KeyPair constructor must be 32 bytes long");
}
Expand All @@ -111,7 +111,7 @@ public class KeyPair : PublicKey {
/// Create a Bitcoin address from a key represented in a string.
/// </summary>
public KeyPair(string key, bool compressed=false, byte addressType=0) {
_addressType = addressType;
AddressType = addressType;
string result = constructWithKey(key, compressed);
if (result != null) throw new ArgumentException(result);

Expand All @@ -126,8 +126,8 @@ public class KeyPair : PublicKey {
hex = Util.HexStringToBytes(key, true);
if (hex == null) {
// tolerate a minikey
if (MiniKeyPair.IsValidMiniKey(key, _addressType) > 0) {
PrivateKeyBytes = new MiniKeyPair(key, _addressType).PrivateKeyBytes;
if (MiniKeyPair.IsValidMiniKey(key) > 0) {
PrivateKeyBytes = new MiniKeyPair(key, AddressType).PrivateKeyBytes;
return null;
} else {
return "Invalid private key";
Expand All @@ -138,12 +138,12 @@ public class KeyPair : PublicKey {
_privKey = new byte[32];
Array.Copy(hex, 0, _privKey, 0, 32);
IsCompressedPoint = compressed;
} else if (hex.Length == 33 && hex[0] == 0x80) {
} else if (hex.Length == 33 && hex[0] == Bitcoin.AddressType.ToPrivateKeyPrefix(AddressType)) {
// normal private key
_privKey = new byte[32];
Array.Copy(hex, 1, _privKey, 0, 32);
IsCompressedPoint = false;
} else if (hex.Length == 34 && hex[0] == 0x80 && hex[33] == 0x01) {
} else if (hex.Length == 34 && hex[0] == Bitcoin.AddressType.ToPrivateKeyPrefix(AddressType) && hex[33] == 0x01) {
// compressed private key
_privKey = new byte[32];
Array.Copy(hex, 1, _privKey, 0, 32);
Expand Down Expand Up @@ -232,7 +232,7 @@ public class KeyPair : PublicKey {
return Util.ByteArrayToString(PrivateKeyBytes);
}
protected set {
byte[] hex = Util.ValidateAndGetHexPrivateKey(0x80, value, 32);
byte[] hex = Util.ValidateAndGetHexPrivateKey(Bitcoin.AddressType.ToPrivateKeyPrefix(AddressType), value, 32);
if (hex == null) throw new ApplicationException("Invalid private hex key");
_privKey = hex;
}
Expand Down Expand Up @@ -261,13 +261,13 @@ public class KeyPair : PublicKey {
if (IsCompressedPoint) {
byte[] rv = new byte[34];
Array.Copy(_privKey, 0, rv, 1, 32);
rv[0] = 0x80;
rv[0] = Bitcoin.AddressType.ToPrivateKeyPrefix(AddressType);
rv[33] = 1;
return Util.ByteArrayToBase58Check(rv);
} else {
byte[] rv = new byte[33];
Array.Copy(_privKey, 0, rv, 1, 32);
rv[0] = 0x80;
rv[0] = Bitcoin.AddressType.ToPrivateKeyPrefix(AddressType);
return Util.ByteArrayToBase58Check(rv);
}
}
Expand Down Expand Up @@ -296,7 +296,7 @@ public class KeyPair : PublicKey {

if (hex[0] == 0x82) {
this.IsCompressedPoint = true;
} else if (hex[0] != 0x80) {
} else if (hex[0] != Bitcoin.AddressType.ToPrivateKeyPrefix(AddressType)) {
throw new ApplicationException("This is a valid base58 string but it has no Wallet Import Format identifier.");
}

Expand Down
10 changes: 5 additions & 5 deletions Model/MiniKeyPair.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public class MiniKeyPair : KeyPair {
char[] chars = keytotry.ToCharArray();
char[] charstest = (keytotry + "?").ToCharArray();

while (Util.ComputeSha256(utf8.GetBytes(charstest))[0] != addressType) {
while (Util.ComputeSha256(utf8.GetBytes(charstest))[0] != 0) {
// As long as key doesn't pass typo check, increment it.
for (int i = chars.Length - 1; i >= 0; i--) {
char c = chars[i];
Expand Down Expand Up @@ -102,7 +102,7 @@ public class MiniKeyPair : KeyPair {


public MiniKeyPair(string key, byte addressType = 0) {
_addressType = addressType;
AddressType = addressType;
MiniKey = key;
}

Expand All @@ -124,7 +124,7 @@ public class MiniKeyPair : KeyPair {
if (value == null) {
PrivateKeyBytes = null;
} else {
if (IsValidMiniKey(value, _addressType) <= 0) {
if (IsValidMiniKey(value) <= 0) {
throw new ApplicationException("Not a valid minikey");
}
_minikey = value;
Expand All @@ -143,13 +143,13 @@ public class MiniKeyPair : KeyPair {
/// Zero or negative indicates not a valid Mini Private Key.
/// -1 means well formed but fails typo check.
/// </summary>
public static int IsValidMiniKey(string candidate, byte addressType) {
public static int IsValidMiniKey(string candidate) {
if (candidate.Length != 22 && candidate.Length != 26 && candidate.Length != 30) return 0;
if (candidate.StartsWith("S") == false) return 0;
System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex("^S[1-9A-HJ-NP-Za-km-z]{21,29}$");
if (reg.IsMatch(candidate) == false) return 0;
byte[] ahash = Util.ComputeSha256(candidate + "?"); // first round
if ((int)ahash[0] == addressType) return 1;
if ((int)ahash[0] == 0) return 1;
// for (int ct = 0; ct < 716; ct++) ahash = sha256.ComputeHash(ahash); // second thru 717th
// if (ahash[0] == 0) return 1;
return -1;
Expand Down
4 changes: 2 additions & 2 deletions Model/StringInterpreter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public class StringInterpreter {
case 33:
case 34:
// Unencrypted private key
return new KeyPair(what);
return new KeyPair(what, compressed, addressType);
case 36:
// these pairs aren't decided by length alone,
// but the constructors will throw an exception if they
Expand Down Expand Up @@ -141,7 +141,7 @@ public class StringInterpreter {
} catch { }
}

if (MiniKeyPair.IsValidMiniKey(what, addressType) == 1) return new MiniKeyPair(what, addressType);
if (MiniKeyPair.IsValidMiniKey(what) == 1) return new MiniKeyPair(what, addressType);

return null;

Expand Down

0 comments on commit a464de1

Please sign in to comment.