public static void TryUpdateLookAhead(string passphrase, X1WalletFile x1WalletFile) { if (string.IsNullOrWhiteSpace(passphrase)) { return; } x1WalletFile.LookAhead.Clear(); var decryptedSeed = VCL.DecryptWithPassphrase(passphrase, x1WalletFile.HdSeed); var changeAddressGaps = GetIndexGaps(C.Change, x1WalletFile); foreach (var index in changeAddressGaps) { var generated = GeneratePubKeyHashAddress(decryptedSeed, passphrase, x1WalletFile.CoinType, C.Change, index); x1WalletFile.LookAhead[generated.Address] = generated; } var receiveAddressGaps = GetIndexGaps(C.External, x1WalletFile); foreach (var index in receiveAddressGaps) { var generated = GeneratePubKeyHashAddress(decryptedSeed, passphrase, x1WalletFile.CoinType, C.External, index); x1WalletFile.LookAhead[generated.Address] = generated; } x1WalletFile.SaveX1WalletFile(x1WalletFile.CurrentPath); }
internal static ExportKeysResponse ExportKeys(ExportKeysRequest exportKeysRequest, IReadOnlyCollection <ISegWitAddress> addresses) { var header = new StringBuilder(); header.AppendLine($"Starting export from wallet {exportKeysRequest.WalletName}, network {C.Network.Name} on {DateTime.UtcNow} UTC."); var errors = new StringBuilder(); errors.AppendLine("Errors"); var success = new StringBuilder(); success.AppendLine("Exported Private Key (Hex); Unix Time UTC; IsChange; Address; Label:"); int errorCount = 0; int successCount = 0; try { header.AppendLine($"{addresses.Count} found in wallet."); var enc = new Bech32Encoder($"{C.Network.CoinTicker.ToLowerInvariant()}key"); foreach (var a in addresses) { try { var decryptedKey = VCL.DecryptWithPassphrase(exportKeysRequest.WalletPassphrase, a.GetEncryptedPrivateKey()); if (decryptedKey == null) { errorCount++; header.AppendLine( $"Address '{a.Address}' could not be decrpted with this passphrase."); } else { var privateKey = enc.Encode(0, decryptedKey); success.AppendLine($"{privateKey};{a.Address}"); successCount++; } } catch (Exception e) { header.AppendLine($"Exception processing Address '{a.Address}': {e.Message}"); } } header.AppendLine($"{errorCount} errors occured."); header.AppendLine($"{successCount} addresses with private keys successfully exported."); } catch (Exception e) { errors.AppendLine(e.Message); return(new ExportKeysResponse { Message = $"Export failed because an exception occured: {e.Message}" }); } return(new ExportKeysResponse { Message = $"{header}{Environment.NewLine}{success}{Environment.NewLine}{errors}{Environment.NewLine}" }); }
internal static void EnsureDefaultMultisigAddress(string passphrase, X1WalletFile x1WalletFile) { //if (x1WalletFile.ColdStakingAddresses.Count > 0) // return; var decryptedSeed = VCL.DecryptWithPassphrase(passphrase, x1WalletFile.HdSeed); KeyMaterial myKeyMaterial = KeyHelper.CreateHdKeyMaterial(decryptedSeed, passphrase, C.Network.Consensus.CoinType, AddressType.MultiSig, C.External, 0); PubKey myPubKey = myKeyMaterial.GetKey(passphrase).PubKey.Compress(); // other Key KeyMaterial otherKeyMaterial = KeyHelper.CreateHdKeyMaterial(decryptedSeed, passphrase, C.Network.Consensus.CoinType, AddressType.MultiSig, C.External, 1); var otherPubKey = otherKeyMaterial.GetKey(passphrase).PubKey.Compress(); // The redeem script looks like: // 1 03fad6426522dbda5c5a9f8cab24a54ccc374517ad8790bf7e5a14308afc1bf77b 0340ecf2e20978075a49369e35269ecf0651d2f48061ebbf918f3eb1964051f65c 2 OP_CHECKMULTISIG Script redeemScript = PayToMultiSigTemplate.Instance.GenerateScriptPubKey(1, myPubKey, otherPubKey); // The address looks like: // odx1qvar8r29r8llzj53q5utmcewpju59263h38250ws33lp2q45lmalqg5lmdd string bech32ScriptAddress = redeemScript.WitHash.GetAddress(C.Network).ToString(); // In P2SH payments, we refer to the hash of the Redeem Script as the scriptPubKey. It looks like: // 0 674671a8a33ffe295220a717bc65c19728556a3789d547ba118fc2a0569fdf7e Script scriptPubKey = redeemScript.WitHash.ScriptPubKey; var scp = scriptPubKey.ToString(); var multiSigAddress = new MultiSigAddress { OwnKey = myKeyMaterial, Address = bech32ScriptAddress, AddressType = AddressType.MultiSig, Label = "Default 1-of-2 MultiSig", MaxSignatures = 2, LastSeenHeight = null, SignaturesRequired = 1, RedeemScriptHex = redeemScript.ToBytes().ToHexString(), ScriptPubKeyHex = scriptPubKey.ToBytes().ToHexString(), OtherPublicKeys = new System.Collections.Generic.Dictionary <string, string>(), }; multiSigAddress.OtherPublicKeys.Add(otherPubKey.ToBytes().ToHexString(), "Bob"); x1WalletFile.MultiSigAddresses[multiSigAddress.Address] = multiSigAddress; }
internal static void EnsureDefaultColdStakingAddress(string passphrase, X1WalletFile x1WalletFile) { //if (x1WalletFile.ColdStakingAddresses.Count > 0) // return; var decryptedSeed = VCL.DecryptWithPassphrase(passphrase, x1WalletFile.HdSeed); var coldKey = KeyHelper.CreateHdKeyMaterial(decryptedSeed, passphrase, C.Network.Consensus.CoinType, AddressType.ColdStakingCold, C.External, 0); var hotKey = KeyHelper.CreateHdKeyMaterial(decryptedSeed, passphrase, C.Network.Consensus.CoinType, AddressType.ColdStakingHot, C.External, 0); PubKey coldPubKey = coldKey.GetKey(passphrase).PubKey.Compress(); Key hotPrivateKey = hotKey.GetKey(passphrase); PubKey hotPubKey = hotPrivateKey.PubKey.Compress(); Script csRedeemScript = ColdStakingScriptTemplate.Instance.GenerateScriptPubKey(hotPubKey.WitHash.AsKeyId(), coldPubKey.WitHash.AsKeyId()); string csScriptAddress = csRedeemScript.WitHash.GetAddress(C.Network).ToString(); Script csScriptAddressScriptPubKey = csRedeemScript.WitHash.ScriptPubKey; var csAddress = new ColdStakingAddress { ColdKey = coldKey, HotKey = hotKey, StakingKey = hotPrivateKey.ToBytes(), Label = "Default CS", AddressType = AddressType.ColdStakingHot, // TODO: which address type? Address = csScriptAddress, LastSeenHeight = null, ScriptPubKeyHex = csScriptAddressScriptPubKey.ToBytes().ToHexString(), RedeemScriptHex = csRedeemScript.ToBytes().ToHexString() }; if (csAddress.AddressType == AddressType.ColdStakingHot) { csAddress.StakingKey = hotPrivateKey.ToBytes(); } x1WalletFile.ColdStakingAddresses[csAddress.Address] = csAddress; }
/// <summary> /// Wallet must be in perfect state, must be called locked. /// </summary> public static PubKeyHashAddress CreateAndInsertNewReceiveAddress(string label, string passphrase, X1WalletFile x1WalletFile) { if (!IsLabelUnique(label, x1WalletFile)) { throw new X1WalletException($"The label '{label}' is already in use"); } var nextIndex = GetNextIndex(C.External, x1WalletFile, out var _); var decryptedSeed = VCL.DecryptWithPassphrase(passphrase, x1WalletFile.HdSeed); var address = GeneratePubKeyHashAddress(decryptedSeed, passphrase, x1WalletFile.CoinType, C.External, nextIndex); if (!x1WalletFile.PubKeyHashAddresses.TryAdd(address.Address, address)) { throw new X1WalletException(HttpStatusCode.InternalServerError, $"Receive address {address.Address} already exists."); } x1WalletFile.SaveX1WalletFile(x1WalletFile.CurrentPath); return(address); }
public void StartStaking(string passphrase) { if (this.isDisposing) { return; } Guard.NotNull(passphrase, nameof(passphrase)); if (VCL.DecryptWithPassphrase(passphrase, base.GetPassphraseChallenge()) == null) { throw new X1WalletException(HttpStatusCode.Unauthorized, "The passphrase is not correct."); } base.SetStakingPassphrase(passphrase); if (this.stakingService == null) { this.stakingService = new StakingService(this, passphrase, this.nodeServices); this.stakingService.Start(); } }
/// <summary> /// We assume that all PubKeyHashAddress addresses in this file are already used. Therefore this method /// should only be called when the wallet is fully up-to-date so that all used addresses are already discovered. /// </summary> public static List <PubKeyHashAddress> CreateAndInsertNewChangeAddresses(string passphrase, int addressesToCreate, X1WalletFile x1WalletFile) { var decryptedSeed = VCL.DecryptWithPassphrase(passphrase, x1WalletFile.HdSeed); var nextIndex = GetNextIndex(C.Change, x1WalletFile, out var _); var created = 0; var newAddresses = new List <PubKeyHashAddress>(addressesToCreate); while (created < addressesToCreate) { var address = GeneratePubKeyHashAddress(decryptedSeed, passphrase, x1WalletFile.CoinType, C.Change, nextIndex); newAddresses.Add(address); if (!x1WalletFile.PubKeyHashAddresses.TryAdd(address.Address, address)) { Log.Logger.LogWarning($"Change address {address.Address} already existed - nothing was added."); } created++; nextIndex++; } x1WalletFile.SaveX1WalletFile(x1WalletFile.CurrentPath); return(newAddresses); }
public static Key GetPrivateKey(this SegWitCoin segWitCoin, string passphrase) { return(new Key(VCL.DecryptWithPassphrase(passphrase, segWitCoin.SegWitAddress.GetEncryptedPrivateKey()))); }
public static ImportKeysResponse ImportKeys(ImportKeysRequest importKeysRequest, byte[] passphraseChallenge) { if (importKeysRequest == null) { throw new ArgumentNullException(nameof(importKeysRequest)); } if (importKeysRequest.WalletPassphrase == null) { throw new ArgumentNullException(nameof(importKeysRequest.WalletPassphrase)); } if (importKeysRequest.Keys == null) { throw new ArgumentNullException(nameof(importKeysRequest.Keys)); } var delimiters = new HashSet <char>(); foreach (var c in importKeysRequest.Keys.Trim().ToCharArray()) { if (char.IsWhiteSpace(c)) { delimiters.Add(c); } } var items = importKeysRequest.Keys.Split(delimiters.ToArray()); var possibleKeys = items.Where(i => i.Length == 52).Distinct().ToList(); if (possibleKeys.Count == 0) { throw new X1WalletException(HttpStatusCode.BadRequest, "Input material cointained no keys."); } var test = VCL.DecryptWithPassphrase(importKeysRequest.WalletPassphrase, passphraseChallenge); if (test == null) { throw new X1WalletException(HttpStatusCode.Unauthorized, "Your passphrase is incorrect."); } var importedAddresses = new List <string>(); var obsidianNetwork = new ObsidianNetwork(); foreach (var candidate in possibleKeys) { try { var secret = new BitcoinSecret(candidate, obsidianNetwork); var privateKey = secret.PrivateKey.ToBytes(); throw new NotImplementedException(); //var address = AddressHelper.CreateWithPrivateKey(privateKey, importKeysRequest.WalletPassphrase, AddressType.SingleKey); //this.X1WalletFile.Addresses.Add(address.Address, address); //importedAddresses.Add($"{secret.GetAddress()} -> {address.Address}"); } catch (Exception e) { Log.Logger.LogWarning($"Could not import '{candidate}' as key or address. {e.Message}"); } } // this.X1WalletFile.SaveX1WalletFile(this.CurrentX1WalletFilePath); var response = new ImportKeysResponse { ImportedAddresses = importedAddresses, Message = $"Imported {importedAddresses.Count} addresses." }; return(response); }
public static Key GetKey(this KeyMaterial keyMaterial, string passphrase) { return(new Key(VCL.DecryptWithPassphrase(passphrase, keyMaterial.EncryptedPrivateKey))); }