public bool CheckBase58Bip38(string bip38, out string message) { if (!Base58.IsValid(bip38)) { message = "The given BIP-38 string contains invalid base-58 characters."; return(false); } if (!Base58.IsValidWithChecksum(bip38)) { message = "The given BIP-38 string has an invalid checksum."; return(false); } byte[] data = Base58.DecodeWithChecksum(bip38); if (data.Length != ConstantsFO.Bip38ByteLen) { message = "The given BIP-38 string has an invalid byte length."; return(false); } if (data[0] != 1 || (data[1] != 0x42 && data[1] != 0x43)) { message = "The given BIP-38 string has invalid starting bytes."; return(false); } message = "The given BIP-38 string is valid."; return(true); }
public string CheckPrivateKey(string key) { if (!Base58.IsValid(key)) { return("The given key contains invalid base-58 characters."); } if (!Base58.IsValidWithChecksum(key)) { return("The given key has an invalid checksum."); } byte[] keyBa = Base58.DecodeWithChecksum(key); if (keyBa[0] != ConstantsFO.PrivKeyFirstByte) { return($"Invalid first key byte (actual={keyBa[0]}, expected={ConstantsFO.PrivKeyFirstByte})."); } if (keyBa.Length == 33) { if (!IsPrivateKeyInRange(keyBa.SubArray(1))) { return("Invalid key integer value (outside of the range defined by secp256k1 curve)."); } return("The given key is a valid uncompressed private key."); } else if (keyBa.Length == 34) { if (keyBa[^ 1] != ConstantsFO.PrivKeyCompLastByte)
public string CheckBase58Address(string address) { if (!Base58.IsValid(address)) { return("The given address contains invalid base-58 characters."); } if (!Base58.IsValidWithChecksum(address)) { return("The given address has an invalid checksum."); } byte[] addrBa = Base58.DecodeWithChecksum(address); if (addrBa[0] != ConstantsFO.P2pkhAddrFirstByte && addrBa[0] != ConstantsFO.P2shAddrFirstByte) { return("The given address starts with an invalid byte."); } if (addrBa.Length != 21) { return("The given address byte length is invalid."); } return($"The given address is a valid base-58 encoded address used for " + $"{(addrBa[0] == ConstantsFO.P2pkhAddrFirstByte ? "P2PKH" : "P2SH")} scripts."); }
public void LoadFromJson(string json) { JObject data = JObject.Parse(json); if (data["version"].Value <string>() != Version) { throw new FormatException(String.Format("Invalid wallet version: {0}", data["version"].Value <ulong>())); } KeyHashes = data["key_hashes"].Value <ulong>(); IV = Base58.DecodeWithChecksum(data["encrypted"]["iv"].Value <string>()); Salt = Base58.DecodeWithChecksum(data["encrypted"]["salt"].Value <string>()); if (data["watch_addresses"] != null) { foreach (JToken key in data["watch_addresses"]) { WatchAddresses.Add(key["addr"].Value <string>(), key["label"] != null ? key["label"].Value <string>() : null); } } if (data["public_addresses"] != null) { foreach (JToken key in data["public_addresses"]) { PublicAddresses.Add(key["addr"].Value <string>(), key["label"] != null ? key["label"].Value <string>() : null); } } EncryptedData = Base58.DecodeWithChecksum(data["encrypted"]["data"].Value <string>()); }
/// <summary> /// Initializes a new instance of <see cref="BIP0032"/> using the given base-58 encoded /// extended public or private key string. /// <para/>This will set the <see cref="ExtendedKeyType"/> property that can be used by caller to decide /// what derivation path and address type to use for child keys. /// </summary> /// <exception cref="ArgumentNullException"/> /// <exception cref="ArgumentOutOfRangeException">If given private key is outside of curve range.</exception> /// <exception cref="FormatException"/> /// <param name="extendedKey">Base-58 encoded extended key to use</param> public BIP0032(string extendedKey) { if (string.IsNullOrWhiteSpace(extendedKey)) { throw new ArgumentNullException(nameof(extendedKey), "Extended key can not be null or empty."); } byte[] decoded = Base58.DecodeWithChecksum(extendedKey); if (decoded.Length != ExtendedKeyLength) { throw new FormatException($"Extended key length should be {ExtendedKeyLength} bytes " + $"but it is {decoded.Length} bytes."); } int version = decoded[3] | (decoded[2] << 8) | (decoded[1] << 16) | (decoded[0] << 24); ExtendedKeyDepth = decoded[4]; ParentFingerPrint = decoded.SubArray(5, 4); ChildNumber = decoded.SubArray(9, 4); ChainCode = decoded.SubArray(13, 32); byte[] key = decoded.SubArray(45, 33); bool isPublic; if (Enum.IsDefined(typeof(XType), version)) { ExtendedKeyType = (XType)version; isPublic = IsPublic(ExtendedKeyType); } else { ExtendedKeyType = XType.Unknown; isPublic = key[0] != 0; } if (!isPublic && key[0] != 0) { throw new FormatException($"The key has an invalid first byte, " + $"it should be 0 for private keys but it is 0x{key[0]:x2}."); } if (isPublic) { PrvKey = null; if (!PublicKey.TryRead(key, out PubKey)) { throw new ArgumentOutOfRangeException("public key", "Invalid public key format."); } } else { // The following line will check if the key is valid and throws ArgumentOutOfRangeException if not PrvKey = new PrivateKey(key.SubArray(1)); PubKey = PrvKey.ToPublicKey(); } }
public void DecodeWithChecksum_ExceptionTest(string s, string expErrMsg) { Exception ex = Assert.Throws <FormatException>(() => Base58.DecodeWithChecksum(s)); Assert.Contains(expErrMsg, ex.Message); Assert.False(Base58.TryDecodeWithChecksum(s, out byte[] result)); Assert.Null(result); }
// public static EcKey FromAsn1(byte[] asn1PrivKey) { // return new EcKey(ExtractPrivateKeyFromAsn1(asn1PrivKey)); // } public static ECKey FromWalletImportFormat(string wif) { byte[] decoded = Base58.DecodeWithChecksum(wif); if (decoded[0] != 0x80) { throw new FormatException("Invalid private key"); } return(new ECKey(ArrayHelpers.SubArray(decoded, 1))); }
static string GetHashedAddress(Address address) { byte[] currentHash = Base58.DecodeWithChecksum(address.ID); for (int i = 0; i < 1024; i++) { currentHash = SHA256.Hash(currentHash); } return(Base58.Encode(currentHash)); }
public static bool AddressIsValid(string address) { // byte[] bytes = Base58.DecodeWithChecksum(address); Base58.DecodeWithChecksum(address); if (!SupportedAddressPrefix(address[0])) { throw new FormatException(String.Format("'{0}' is an unsupported address prefix", address[0])); } return(true); }
/// <summary> /// Decrypts the given base-58 encoded encrypted key using the given password bytes and first 4 bytes of hash of /// (un)compressed P2PKH address as <see cref="Scrypt"/> salt. /// </summary> /// <exception cref="ArgumentNullException"/> /// <exception cref="FormatException"/> /// <exception cref="ObjectDisposedException"/> /// <param name="encrypted">Base-58 encrypted key (it will be normalized using Unicode Normalization Form C (NFC))</param> /// <param name="password">Password to use</param> /// <param name="isCompressed">Indicates whether to use compressed or uncompressed public key to build P2PKH address</param> /// <returns>The private key</returns> public PrivateKey Decrypt(string encrypted, byte[] password, out bool isCompressed) { if (isDisposed) { throw new ObjectDisposedException(nameof(BIP0038), "Instance was disposed."); } if (string.IsNullOrWhiteSpace(encrypted)) { throw new ArgumentNullException(nameof(encrypted), "Invalid (null) encrypted key."); } if (password == null) { throw new ArgumentNullException(nameof(password), "Password can not be null."); } byte[] encryptedBytes = Base58.DecodeWithChecksum(encrypted); if (encryptedBytes.Length != EncodedLength) { throw new FormatException("Invalid encrypted bytes length."); } if (!((Span <byte>)encryptedBytes).Slice(0, 2).SequenceEqual(prefix)) { throw new FormatException("Invalid prefix."); } isCompressed = IsCompressed(encryptedBytes[2]); Span <byte> salt = ((Span <byte>)encryptedBytes).Slice(3, 4); byte[] dk = scrypt.GetBytes(password, salt.ToArray(), 64); byte[] decryptedResult = new byte[32]; aes.Key = dk.SubArray(32, 32); // AES key is derivedhalf2 using ICryptoTransform decryptor = aes.CreateDecryptor(); decryptor.TransformBlock(encryptedBytes, 7, 16, decryptedResult, 0); decryptor.TransformBlock(encryptedBytes, 23, 16, decryptedResult, 16); // XOR method will only work on first item's length (32 byte here) so it doesn't matter of dk.Legth is 64 PrivateKey result = new PrivateKey(XOR(decryptedResult, dk)); string address = Address.GetP2pkh(result.ToPublicKey(), isCompressed, NetworkType.MainNet); Span <byte> computedHash = hash.ComputeHashTwice(Encoding.ASCII.GetBytes(address)).SubArray(0, 4); if (!computedHash.SequenceEqual(salt)) { throw new FormatException("Wrong password (derived address hash is not the same)."); } return(result); }
private byte[] Decode(EncodingNames fromEnc, string input) { return(fromEnc switch { EncodingNames.Base16 => Base16.Decode(input), EncodingNames.Base43 => Base43.Decode(input), EncodingNames.Base58 => Base58.Decode(input), EncodingNames.Base58Check => Base58.DecodeWithChecksum(input), EncodingNames.Base64 => Convert.FromBase64String(input), EncodingNames.UTF8 => Encoding.UTF8.GetBytes(input), EncodingNames.Unicode => Encoding.Unicode.GetBytes(input), _ => throw new ArgumentException("undefined encoding.") });
public AddressType GetAddressType(string address) { if (string.IsNullOrWhiteSpace(address)) { return(AddressType.Invalid); } try { byte[] decoded = Base58.DecodeWithChecksum(address); if (decoded.Length == Hash160.HashByteSize + 1) { if (decoded[0] == versionByte_P2pkh_MainNet || decoded[0] == versionByte_P2pkh_TestNet || decoded[0] == versionByte_P2pkh_RegTest) { return(AddressType.P2PKH); } else if (decoded[0] == versionByte_P2sh_MainNet || decoded[0] == versionByte_P2sh_TestNet || decoded[0] == versionByte_P2sh_RegTest) { return(AddressType.P2SH); } } return(AddressType.Invalid); } catch (Exception) { } try { byte[] decoded = Bech32.Decode(address, Bech32.Mode.B32, out byte witVer, out string hrp); if (witVer == 0 && hrp == hrp_MainNet || hrp == hrp_TestNet || hrp == hrp_RegTest) { if (decoded.Length == Hash160.HashByteSize) { return(AddressType.P2WPKH); } else if (decoded.Length == witHashFunc.BlockByteSize) { return(AddressType.P2WSH); } } } catch (Exception) { } return(AddressType.Invalid); }
/// <summary> /// Initializes a new instance of <see cref="PrivateKey"/> using the given WIF (Base-58 encoded private key /// with a checksum) /// </summary> /// <exception cref="ArgumentException"/> /// <exception cref="ArgumentNullException"/> /// <exception cref="ArgumentOutOfRangeException"/> /// <exception cref="FormatException"/> /// <param name="wif">Wallet import format</param> /// <param name="netType"> /// [Default value = <see cref="NetworkType.MainNet"/>] /// Network type to check against (affects WIF's starting characters) /// </param> public PrivateKey(string wif, NetworkType netType = NetworkType.MainNet) { if (string.IsNullOrWhiteSpace(wif)) { throw new ArgumentNullException(nameof(wif), "Input WIF can not be null or empty."); } byte[] ba = Base58.DecodeWithChecksum(wif); if (ba[0] != GetWifFirstByte(netType)) { throw new FormatException("Invalid first byte."); } if (ba.Length == KeyByteSize + 1) // Uncompressed { SetBytes(ba.SubArray(1)); } else if (ba.Length == KeyByteSize + 2) // Compressed { if (ba[^ 1] != CompressedByte)
public void DecodeWithChecksumTest(string s, byte[] expected) { byte[] actual = Base58.DecodeWithChecksum(s); Assert.Equal(expected, actual); }
public void DecodeBitcoinAddress() { var actualBytes = Base58.DecodeWithChecksum(addressText); Assert.AreEqual(BitConverter.ToString(addressBytes), BitConverter.ToString(actualBytes)); }
public void DecodeBrokenBitcoinAddress() { Assert.Throws <FormatException>(() => { Base58.DecodeWithChecksum(brokenAddressText); }); }
public static Transaction Create(List <Output> inpoints, IReadOnlyDictionary <Address, Money> destinations, IReadOnlyDictionary <Address, ECKey> privateKeys, bool allowDust = false) { if (!allowDust && destinations.Select(d => d.Value).Sum() <= DustValue) { throw new DustException(); } var tx = new Transaction { Version = CurrentVersion }; int outputIndex = 0; foreach (KeyValuePair <Address, Money> destination in destinations) { Script pkScript = Script.Create(Op.Dup, Op.Hash160, ArrayHelpers.SubArray(Base58.DecodeWithChecksum(destination.Key.ID), 1), Op.EqualVerify, Op.CheckSig); tx.Outputs.Add(new Output(pkScript, destination.Value, tx, (uint)outputIndex)); outputIndex++; } foreach (Output inpoint in inpoints) { tx.Inputs.Add(new Input(inpoint, (uint)tx.Inputs.Count)); } foreach (Input input in tx.Inputs) { ECKey key = privateKeys[input.Outpoint.Recipient]; byte[] sig = tx.GenerateInputSignature(key, SigHash.All, input.Outpoint.ScriptPubKey, (int)input.Index); input.ScriptSig = Script.Create(sig, key.PubKey); } tx.LockTime = 0U; return(tx); }