/// <summary>
        /// Default constructor.  Creates a new matched pair of escrow invitation codes.
        /// </summary>
        public EscrowCodeSet()
        {
            SecureRandom sr = new SecureRandom();

            byte[] x = new byte[32];
            byte[] y = new byte[32];
            sr.NextBytes(x);
            sr.NextBytes(y);

            KeyPair kx = new KeyPair(x, true);
            KeyPair ky = new KeyPair(y, true);

            BigInteger xi = new BigInteger(1, x);
            BigInteger yi = new BigInteger(1, y);

            ECPoint Gx = kx.GetECPoint();
            byte[] bytesGx = Gx.GetEncoded();
            ECPoint Gy = ky.GetECPoint();
            byte[] bytesGy = Gy.GetEncoded();
            ECPoint Gxy = Gx.Multiply(yi);

            byte[] bytesGxy = Gxy.GetEncoded();
            Sha256Digest sha256 = new Sha256Digest();
            byte[] hashGxy = new byte[32];
            sha256.BlockUpdate(bytesGxy, 0, bytesGxy.Length);
            sha256.DoFinal(hashGxy, 0);
            sha256.BlockUpdate(hashGxy, 0, 32);
            sha256.DoFinal(hashGxy, 0);

            int identifier30 = ((hashGxy[0] & 0x3f) << 24) + (hashGxy[1] << 16) + (hashGxy[2] << 8) + hashGxy[3];

            byte[] invitationA = new byte[74];
            byte[] invitationB = new byte[74];

            long headA = headbaseA + (long)identifier30;
            long headB = headbaseB + (long)identifier30;

            // turn headA and headB into bytes
            for (int i = 7; i >= 0; i--) {
                invitationA[i] = (byte)(headA & 0xFF);
                invitationB[i] = (byte)(headB & 0xFF);
                headA >>= 8;
                headB >>= 8;
            }

            Array.Copy(x, 0, invitationA, 8 + 1, 32);
            Array.Copy(y, 0, invitationB, 8 + 1, 32);
            Array.Copy(bytesGy, 0, invitationA, 8 + 1 + 32, 33);
            Array.Copy(bytesGx, 0, invitationB, 8 + 1 + 32, 33);

            EscrowInvitationCodeA = Bitcoin.ByteArrayToBase58Check(invitationA);
            EscrowInvitationCodeB = Bitcoin.ByteArrayToBase58Check(invitationB);
        }
        /// <summary>
        /// Encryption constructor (non-EC-multiply)
        /// </summary>
        public Bip38KeyPair(KeyPair key, string passphrase)
        {
            if (passphrase == null && passphrase == "") {
                throw new ArgumentException("Passphrase is required");
            }

            if (key == null) throw new ArgumentException("Passphrase is required");

            this.IsCompressedPoint = key.IsCompressedPoint;
            this._addressType = key.AddressType;

            UTF8Encoding utf8 = new UTF8Encoding(false);
            SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider();
            byte[] addrhashfull = sha256.ComputeHash(sha256.ComputeHash(utf8.GetBytes(key.AddressBase58)));
            byte[] addresshash = new byte[] { addrhashfull[0], addrhashfull[1], addrhashfull[2], addrhashfull[3] };

            byte[] derivedBytes = new byte[64];
            SCrypt.ComputeKey(utf8.GetBytes(passphrase), addresshash, 16384, 8, 8, 8, derivedBytes);

            AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
            aes.KeySize = 256;
            aes.Mode = CipherMode.ECB;
            byte[] aeskey = new byte[32];
            Array.Copy(derivedBytes, 32, aeskey, 0, 32);
            aes.Key = aeskey;
            ICryptoTransform encryptor = aes.CreateEncryptor();

            byte[] unencrypted = new byte[32];
            byte[] rv = new byte[39];
            Array.Copy(key.PrivateKeyBytes, unencrypted, 32);
            for (int x = 0; x < 32; x++) unencrypted[x] ^= derivedBytes[x];

            encryptor.TransformBlock(unencrypted, 0, 16, rv, 7);
            encryptor.TransformBlock(unencrypted, 0, 16, rv, 7);
            encryptor.TransformBlock(unencrypted, 16, 16, rv, 23);
            encryptor.TransformBlock(unencrypted, 16, 16, rv, 23);

            // put header
            rv[0] = 0x01;
            rv[1] = 0x42;
            rv[2] = IsCompressedPoint ? (byte)0xe0 : (byte)0xc0;

            byte[] checksum = sha256.ComputeHash(sha256.ComputeHash(utf8.GetBytes(key.AddressBase58)));
            rv[3] = checksum[0];
            rv[4] = checksum[1];
            rv[5] = checksum[2];
            rv[6] = checksum[3];

            _encryptedKey = Bitcoin.ByteArrayToBase58Check(rv);
            _pubKey = key.PublicKeyBytes;
            _hash160 = key.Hash160;
        }
        /// <summary>
        /// Encrypt constructor.
        /// Creates a new encrypted key pair with a passphrase.
        /// The resulting key pair record retains the public key and bitcoin address
        /// but not the passphrase or the unencrypted private key.
        /// </summary>
        public ShaPassphraseKeyPair(KeyPair key, string passphrase)
        {
            if (passphrase == null || passphrase == "") {
                throw new ArgumentException("Passphrase is required");
            }

            if (key == null) throw new ArgumentException("Key is required");
            IsCompressedPoint = key.IsCompressedPoint;
            _addressType = key.AddressType;
            this._hash160 = key.Hash160;
            this._pubKey = key.PublicKeyBytes;

            AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
            aes.KeySize = 256;
            aes.Mode = CipherMode.ECB;

            SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider();
            UTF8Encoding utf8 = new UTF8Encoding(false);
            byte[] encryptionKey = sha256.ComputeHash(utf8.GetBytes(passphrase));
            aes.Key = encryptionKey;
            ICryptoTransform encryptor = aes.CreateEncryptor();

            byte[] rv = new byte[36];

            encryptor.TransformBlock(_privKey, 0, 16, rv, 4);
            encryptor.TransformBlock(_privKey, 0, 16, rv, 4);
            byte[] interblock = new byte[16];
            Array.Copy(rv, 4, interblock, 0, 16);
            for (int x = 0; x < 16; x++) interblock[x] ^= _privKey[16 + x];
            encryptor.TransformBlock(interblock, 0, 16, rv, 20);
            encryptor.TransformBlock(interblock, 0, 16, rv, 20);

            // put header
            rv[0] = 0x02;
            rv[1] = 0x05;

            byte[] checksum = sha256.ComputeHash(utf8.GetBytes(passphrase + "?"));

            rv[2] = (byte)(checksum[0] & 0x7F);
            rv[3] = (byte)(checksum[1] & 0xFE);
            if (key.IsCompressedPoint) rv[3]++;
            this._encryptedKey = Bitcoin.ByteArrayToBase58Check(rv);
        }
        private void setAddressConfirmationCode(int identifier30, byte networkbyte, byte flagbyte, byte[] z, byte[] hash160)
        {
            byte[] accbytes = new byte[74];
            long head = headconfP + (int)identifier30;
            for (int i=7; i>=0; i--) {
                accbytes[i] = (byte)(head & 0x7F);
                head >>= 8;
            }
            accbytes[8]=networkbyte;

            byte[] Gzbytes = new KeyPair(z, true).GetECPoint().GetEncoded();
            Array.Copy(Gzbytes, 0, accbytes, 8+1, 33);
            Array.Copy(hash160, 0, accbytes, 8+1+33, 20);
            accbytes[8+1+33+20] = flagbyte;
            this.AddressConfirmationCode = Bitcoin.ByteArrayToBase58Check(accbytes);
        }
        /// <summary>
        /// Constructor which attempts to redeem a completed set of three codes, and calculate the private key.
        /// </summary>
        public EscrowCodeSet(string code1, string code2, string code3)
        {
            if (code1 == null || code2 == null || code3 == null || code1 == "" || code2 == "" || code3 == "") {
                throw new ArgumentException("Three codes are required to use this function.");
            }

            string codea = null, codeb=null, codep = null;

            if (code1.StartsWith("einva")) codea = code1;
            if (code2.StartsWith("einva")) codea = code2;
            if (code3.StartsWith("einva")) codea = code3;
            if (code1.StartsWith("einvb")) codeb = code1;
            if (code2.StartsWith("einvb")) codeb = code2;
            if (code3.StartsWith("einvb")) codeb = code3;
            if (code1.StartsWith("einvp")) codep = code1;
            if (code2.StartsWith("einvp")) codep = code2;
            if (code3.StartsWith("einvp")) codep = code3;

            if (codea==null || codeb == null || codep == null) {
                throw new ArgumentException("In order to use this function, one code MUST be an Escrow Invitation A (starting " +
                    "with \"einva\"), one must be an Escrow Invitation B (starting with \"einvb\") and the last " +
                    "code MUST be a Payment Invitation (starting with \"einvp\").");
            }

            byte[] pubparta, privparta;
            int identifier30a;
            string failreason = parseEscrowCode(codea, out pubparta, out privparta, out identifier30a);
            if (failreason != null) throw new ArgumentException("Escrow Invitation Code A: " + failreason);

            byte[] pubpartb, privpartb;
            int identifier30b;
            failreason = parseEscrowCode(codeb, out pubpartb, out privpartb, out identifier30b);
            if (failreason != null) throw new ArgumentException("Escrow Invitation Code B: " + failreason);

            if (identifier30a != identifier30b) {
                throw new ArgumentException("The two Escrow Invitations are not mates and cannot unlock the private key.");
            }

            string notvalid = "Not a valid Payment Invitation Code";
            string notvalid2 = "Code is not a valid Payment Invitation Code or may have a typo or other error.";
            string notvalid3 = "The Payment Invitation does not belong to the provided Escrow Invitation.";

            long headp;
            byte[] invbytesp;
            string failReason = parseEitherCode(codep, notvalid, notvalid2, out invbytesp, out headp);

            if (headp < headbaseP) throw new ArgumentException(notvalid);
            long identifier30L = headp - headbaseP;
            if (identifier30L < 0 || identifier30L > 0x3FFFFFFFL) throw new ArgumentException(notvalid);

            if (identifier30L != (long)identifier30a) {
                throw new ArgumentException("The Payment Invitation was not generated from either of the provided Escrow Invitation codes and cannot be unlocked by them.");
            }

            byte[] privpartz = new byte[32];
            Array.Copy(invbytesp, 8 + 1 + 1, privpartz, 0, 32);
            byte networkByte = invbytesp[8];
            bool compressedFlag = (invbytesp[8 + 1 + 1 + 32 + 20] & 0x1) == 1;

            // get private key
            BigInteger xyz = new BigInteger(1, privparta).Multiply(new BigInteger(1, privpartb)).Multiply(new BigInteger(1, privpartz));
            var ps = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");
            xyz = xyz.Mod(ps.N);

            KeyPair kp = new KeyPair(xyz, compressedFlag, networkByte);

            // provide everything
            this.EscrowInvitationCodeA = codea;
            this.EscrowInvitationCodeB = codeb;
            this.PaymentInvitationCode = codep;
            this.BitcoinAddress = kp.AddressBase58;
            this.PrivateKey = kp.PrivateKey;
        }
        /// <summary>
        /// Initialize the intermediate from a passphrase
        /// </summary>
        private void createFromPassphrase(string passphrase, byte[] ownersalt)
        {
            if (passphrase == null || passphrase == "") {
                throw new ArgumentException("Passphrase is required");
            }

            _ownersalt = ownersalt;

            UTF8Encoding utf8 = new UTF8Encoding(false);
            _passfactor = new byte[32];
            SCrypt.ComputeKey(utf8.GetBytes(passphrase), _ownersalt, 16384, 8, 8, 8, _passfactor);

            // make a compressed key out of it just by using the existing bitcoin address classes
            KeyPair kp = new KeyPair(_passfactor, compressed: true);

            _passpoint = kp.PublicKeyBytes;

            byte[] result = new byte[49];

            // 8 bytes are a constant, responsible for making the result start with the characters "passphrase"
            Array.Copy(magic, 0, result, 0, 8);
            Array.Copy(_ownersalt, 0, result, 8, 8);
            Array.Copy(_passpoint, 0, result, 16, 33);
            Code = Bitcoin.ByteArrayToBase58Check(result);
        }
        private void btnCombine_Click(object sender, EventArgs e)
        {
            // What is input #1?

            string input1 = txtInput1.Text;
            string input2 = txtInput2.Text;
            PublicKey pub1 = null, pub2 = null;
            KeyPair kp1 = null, kp2 = null;

            if (KeyPair.IsValidPrivateKey(input1)) {
                pub1 = kp1 = new KeyPair(input1);
            } else if (PublicKey.IsValidPublicKey(input1)) {
                pub1 = new PublicKey(input1);
            } else {
                MessageBox.Show("Input key #1 is not a valid Public Key or Private Key Hex", "Can't combine", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (KeyPair.IsValidPrivateKey(input2)) {
                pub2 = kp2 = new KeyPair(input2);
            } else if (PublicKey.IsValidPublicKey(input2)) {
                pub2 = new PublicKey(input2);
            } else {
                MessageBox.Show("Input key #2 is not a valid Public Key or Private Key Hex", "Can't combine", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (kp1 == null && kp2 == null && rdoAdd.Checked == false) {
                MessageBox.Show("Can't multiply two public keys.  At least one of the keys must be a private key.",
                    "Can't combine", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (pub1.IsCompressedPoint != pub2.IsCompressedPoint) {
                MessageBox.Show("Can't combine a compressed key with an uncompressed key.", "Can't combine", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (pub1.AddressBase58 == pub2.AddressBase58) {
                if (MessageBox.Show("Both of the key inputs have the same public key hash.  You can continue, but " +
                   "the results are probably going to be wrong.  You might have provided the wrong " +
                   "information, such as two parts from the same side of the transaction, instead " +
                    "of one part from each side.  Continue anyway?", "Duplicate Key Warning", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning) != DialogResult.OK) {
                    return;
                }

            }

            var ps = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");

            // Combining two private keys?
            if (kp1 != null && kp2 != null) {

                BigInteger e1 = new BigInteger(1, kp1.PrivateKeyBytes);
                BigInteger e2 = new BigInteger(1, kp2.PrivateKeyBytes);
                BigInteger ecombined = (rdoAdd.Checked ? e1.Add(e2) : e1.Multiply(e2)).Mod(ps.N);

                System.Diagnostics.Debug.WriteLine(kp1.PublicKeyHex);
                System.Diagnostics.Debug.WriteLine(kp2.PublicKeyHex);
                KeyPair kpcombined = new KeyPair(Bitcoin.Force32Bytes(ecombined.ToByteArrayUnsigned()), compressed: kp1.IsCompressedPoint);

                txtOutputAddress.Text = kpcombined.AddressBase58;
                txtOutputPubkey.Text = kpcombined.PublicKeyHex.Replace(" ", "");
                txtOutputPriv.Text = kpcombined.PrivateKeyBase58;

            } else if (kp1 != null || kp2 != null) {
                // Combining one public and one private

                KeyPair priv = (kp1 == null) ? kp2 : kp1;
                PublicKey pub = (kp1 == null) ? pub1 : pub2;

                ECPoint point = pub.GetECPoint();

                ECPoint combined = rdoAdd.Checked ? point.Add(priv.GetECPoint()) : point.Multiply(new BigInteger(1, priv.PrivateKeyBytes));
                ECPoint combinedc = ps.Curve.CreatePoint(combined.X.ToBigInteger(), combined.Y.ToBigInteger(), priv.IsCompressedPoint);
                PublicKey pkcombined = new PublicKey(combinedc.GetEncoded());
                txtOutputAddress.Text = pkcombined.AddressBase58;
                txtOutputPubkey.Text = pkcombined.PublicKeyHex.Replace(" ", "");
                txtOutputPriv.Text = "Only available when combining two private keys";
            } else {
                // Adding two public keys
                ECPoint combined = pub1.GetECPoint().Add(pub2.GetECPoint());
                ECPoint combinedc = ps.Curve.CreatePoint(combined.X.ToBigInteger(), combined.Y.ToBigInteger(), pub1.IsCompressedPoint);
                PublicKey pkcombined = new PublicKey(combinedc.GetEncoded());
                txtOutputAddress.Text = pkcombined.AddressBase58;
                txtOutputPubkey.Text = pkcombined.PublicKeyHex.Replace(" ", "");
                txtOutputPriv.Text = "Only available when combining two private keys";
            }
        }
        public void Decode()
        {
            ChecksumMatched=false;
            Decoded=false;
            KeyPair = null;

            if (PartsAccepted < PartsNeeded) return;

            BigInteger[] pc = new BigInteger[8];
            for (int i = 0; i < decodedKeyParts.Count; i++) {
                byte[] g = decodedKeyParts[i];
                pc[i] = new BigInteger(1, g, 4, 35);
                // If there is an overflow, then add it in.
                if ((g[2] & 0x80) == 0x80) {
                    pc[i] = pc[i].Add(new BigInteger(((int)((g[2] & 0x60) >> 5)).ToString()).ShiftLeft(280));
                    Debug.WriteLine("overflow added");

                }
            }

            List<equation> equations = new List<equation>();

            // create equations for all the parts we need.
            for (int i = 0; i < PartsNeeded; i++) {
                byte[] got = decodedKeyParts[i];
                // extract out part number
                int partnumber0 = (byte)((got[2] & 0x0e) >> 1);
                equations.Add(new equation(i, PartsNeeded, partnumber0));
            }

            List<List<equation>> steps = new List<List<equation>>();
            steps.Add(equations);

            // goal: get our equation set down such that there's only one coefficient on the left side.
            while (equations.Count > 1) {
                equations = solvesome(equations);
                steps.Add(equations);
                Debug.WriteLine("-----");
                foreach (equation eq in equations) {
                    Debug.WriteLine(eq.ToString());
                }
            }

            BigInteger[] v = new BigInteger[8];

            while (steps.Count > 0) {
                // pop off the last step
                List<equation> laststeps = steps[steps.Count - 1];
                steps.RemoveAt(steps.Count - 1);
                equation laststep = laststeps[0];
                Debug.WriteLine("-----");
                Debug.WriteLine(laststep.ToString());

                // solve for v
                long divisor = laststep.leftside[0].multiplier;
                laststep.divisor = laststep.leftside[0].multiplier;
                laststep.leftside[0].multiplier = 1;
                //foreach (coefficient c in laststep.rightside) c.divisor = divisor;
                //laststep.subtractor = laststep.subtractor.Divide(new BigInteger(divisor.ToString()));

                long idx = laststep.leftside[0].vindex;
                v[idx] = laststep.SolveRight(pc);
                Debug.WriteLine(String.Format("v({0})={1}", laststep.leftside[0].vindex, v[idx].ToString()));
                // go through all other steps and see that our solved value is incorporated into the equation.
                foreach (List<equation> eqbl in steps) {
                    foreach (equation eqb in eqbl) eqb.SolveLeft(v);
                }

            }

            // xor the ones we need

            BigInteger xoraccum = BigInteger.Zero;
            for (int i = 0; i < PartsNeeded; i++) {
                xoraccum = xoraccum.Xor(v[i]);
            }

            ChecksumMatched = false;
            Decoded = true;

            byte[] keybytes = xoraccum.ToByteArrayUnsigned();
            if (keybytes.Length > 32) {
                // if more than 32 bytes, decoding probably went wrong! truncate to 32 bytes, but force a checksum failure
                byte[] newkey = new byte[32];
                for (int jj = 0; jj < 32; jj++) newkey[jj] = keybytes[jj];
                keybytes = newkey;
                return;
            } else if (keybytes.Length < 32) {
                byte[] array32 = new byte[32];
                Array.Copy(keybytes, 0, array32, 32 - keybytes.Length, keybytes.Length);
                keybytes = array32;
            }
            KeyPair = new KeyPair(keybytes);

            // Get the bitcoin address

            SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider();
            ASCIIEncoding ae = new ASCIIEncoding();
            byte[] checksum = sha256.ComputeHash(ae.GetBytes(BitcoinAddress));

            int mychecksum = ((checksum[0] & 1) << 8) + checksum[1];
            if (mychecksum == expectedChecksum) ChecksumMatched=true;
        }
        public override bool DecryptWithPassphrase(string passphrase)
        {
            if (passphrase == null) {
                return false;
            }

            byte[] hex = Bitcoin.Base58CheckToByteArray(_encryptedKey);
            KeyPair tempkey = null;

            if (hex.Length == 39 && hex[0] == 1 && hex[1] == 0x42) {
                UTF8Encoding utf8 = new UTF8Encoding(false);
                byte[] addresshash = new byte[] { hex[3], hex[4], hex[5], hex[6] };

                byte[] derivedBytes = new byte[64];
                SCrypt.ComputeKey(utf8.GetBytes(passphrase), addresshash, 16384, 8, 8, 8, derivedBytes);

                AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
                aes.KeySize = 256;
                aes.Mode = CipherMode.ECB;
                byte[] aeskey = new byte[32];
                Array.Copy(derivedBytes, 32, aeskey, 0, 32);
                aes.Key = aeskey;
                ICryptoTransform decryptor = aes.CreateDecryptor();

                byte[] decrypted = new byte[32];
                decryptor.TransformBlock(hex, 7, 16, decrypted, 0);
                decryptor.TransformBlock(hex, 7, 16, decrypted, 0);
                decryptor.TransformBlock(hex, 23, 16, decrypted, 16);
                decryptor.TransformBlock(hex, 23, 16, decrypted, 16);
                for (int x = 0; x < 32; x++) decrypted[x] ^= derivedBytes[x];

                tempkey = new KeyPair(decrypted, compressed: IsCompressedPoint);

                Sha256Digest sha256 = new Sha256Digest();
                byte[] addrhash = new byte[32];
                byte[] addrtext = utf8.GetBytes(tempkey.AddressBase58);
                sha256.BlockUpdate(addrtext, 0, addrtext.Length);
                sha256.DoFinal(addrhash, 0);
                sha256.BlockUpdate(addrhash, 0, 32);
                sha256.DoFinal(addrhash, 0);
                if (addrhash[0] != hex[3] || addrhash[1] != hex[4] || addrhash[2] != hex[5] || addrhash[3] != hex[6]) {
                    return false;
                }
                _privKey = tempkey.PrivateKeyBytes;
                _pubKey = tempkey.PublicKeyBytes;
                _hash160 = tempkey.Hash160;
                return true;
            } else if (hex.Length == 39 && hex[0] == 1 && hex[1] == 0x43) {

                // produce the intermediate from the passphrase

                // get ownersalt and encryptedpart2 since they are in the record
                byte[] ownersalt = new byte[8];
                Array.Copy(hex, 7, ownersalt, 0, 8);
                Bip38Intermediate intermediate = new Bip38Intermediate(passphrase, ownersalt);

                tempkey = decryptUsingIntermediate(intermediate, hex);
                if (verifyAddressHash(tempkey.AddressBase58, hex) == false) return false;
            }
            _privKey = tempkey.PrivateKeyBytes;
            _pubKey = tempkey.PublicKeyBytes;
            _hash160 = tempkey.Hash160;
            return true;
        }
        /// <summary>
        /// Encryption constructor to create a new random key from an intermediate
        /// </summary>
        public Bip38KeyPair(Bip38Intermediate intermediate, bool retainPrivateKeyWhenPossible=false)
        {
            // generate seedb
            byte[] seedb = new byte[24];
            SecureRandom sr = new SecureRandom();
            sr.NextBytes(seedb);

            // get factorb as sha256(sha256(seedb))
            Sha256Digest sha256 = new Sha256Digest();
            sha256.BlockUpdate(seedb, 0, 24);
            factorb = new byte[32];
            sha256.DoFinal(factorb, 0);
            sha256.BlockUpdate(factorb, 0, 32);
            sha256.DoFinal(factorb, 0);

            // get ECPoint from passpoint
            PublicKey pk = new PublicKey(intermediate.passpoint);

            ECPoint generatedpoint = pk.GetECPoint().Multiply(new BigInteger(1, factorb));
            byte[] generatedpointbytes = generatedpoint.GetEncoded();
            PublicKey generatedaddress = new PublicKey(generatedpointbytes);

            // get addresshash
            UTF8Encoding utf8 = new UTF8Encoding(false);
            byte[] generatedaddressbytes = utf8.GetBytes(generatedaddress.AddressBase58);
            sha256.BlockUpdate(generatedaddressbytes, 0, generatedaddressbytes.Length);
            byte[] addresshashfull = new byte[32];
            sha256.DoFinal(addresshashfull, 0);
            sha256.BlockUpdate(addresshashfull, 0, 32);
            sha256.DoFinal(addresshashfull, 0);

            byte[] addresshashplusownersalt = new byte[12];
            Array.Copy(addresshashfull, 0, addresshashplusownersalt, 0, 4);
            Array.Copy(intermediate.ownersalt, 0, addresshashplusownersalt, 4, 8);

            // derive encryption key material
            derived = new byte[64];
            SCrypt.ComputeKey(intermediate.passpoint, addresshashplusownersalt, 1024, 1, 1, 1, derived);

            byte[] derivedhalf2 = new byte[32];
            Array.Copy(derived, 32, derivedhalf2, 0, 32);

            byte[] unencryptedpart1 = new byte[16];
            for (int i = 0; i < 16; i++) {
                unencryptedpart1[i] = (byte)(seedb[i] ^ derived[i]);
            }
            byte[] encryptedpart1 = new byte[16];

            // encrypt it
            AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
            aes.KeySize = 256;
            aes.Mode = CipherMode.ECB;
            aes.Key = derivedhalf2;
            ICryptoTransform encryptor = aes.CreateEncryptor();

            encryptor.TransformBlock(unencryptedpart1, 0, 16, encryptedpart1, 0);
            encryptor.TransformBlock(unencryptedpart1, 0, 16, encryptedpart1, 0);

            byte[] unencryptedpart2 = new byte[16];
            for (int i = 0; i < 8; i++) {
                unencryptedpart2[i] = (byte)(encryptedpart1[i + 8] ^ derived[i + 16]);
            }
            for (int i = 0; i < 8; i++) {
                unencryptedpart2[i + 8] = (byte)(seedb[i + 16] ^ derived[i + 24]);
            }

            byte[] encryptedpart2 = new byte[16];
            encryptor.TransformBlock(unencryptedpart2, 0, 16, encryptedpart2, 0);
            encryptor.TransformBlock(unencryptedpart2, 0, 16, encryptedpart2, 0);

            byte[] result = new byte[39];
            result[0] = 0x01;
            result[1] = 0x43;
            result[2] = generatedaddress.IsCompressedPoint ? (byte)0x20 : (byte)0x00;
            Array.Copy(addresshashfull, 0, result, 3, 4);
            Array.Copy(intermediate.ownersalt, 0, result, 7, 8);
            Array.Copy(encryptedpart1, 0, result, 15, 8);
            Array.Copy(encryptedpart2, 0, result, 23, 16);

            _encryptedKey = Bitcoin.ByteArrayToBase58Check(result);
            _pubKey = generatedaddress.PublicKeyBytes;
            _hash160 = generatedaddress.Hash160;

            var ps = Org.BouncyCastle.Asn1.Sec.SecNamedCurves.GetByName("secp256k1");

            if (retainPrivateKeyWhenPossible && intermediate.passfactor != null) {
                BigInteger privatekey = new BigInteger(1, intermediate.passfactor).Multiply(new BigInteger(1, factorb)).Mod(ps.N);
                _privKey = new KeyPair(privatekey).PrivateKeyBytes;

            }

            // create the confirmation code
            confirmationCodeInfo = new byte[51];
            // constant provides for prefix "cfrm38"
            confirmationCodeInfo[0] = 0x64;
            confirmationCodeInfo[1] = 0x3B;
            confirmationCodeInfo[2] = 0xF6;
            confirmationCodeInfo[3] = 0xA8;
            confirmationCodeInfo[4] = 0x9A;
            // fields for flagbyte, addresshash, and ownersalt all copy verbatim
            Array.Copy(result, 2, confirmationCodeInfo, 5, 1 + 4 + 8);
        }
        private void button1_Click(object sender, EventArgs e)
        {
            if (button1.Enabled)
            {
                int n = 0;

                if (Int32.TryParse(textBox2.Text, out n) == false) n = 0;
                if (n < 1 || n > 9999) {
                    MessageBox.Show("Please enter a number of addresses between 1 and 9999", "Invalid entry");
                    return;
                }

                if (txtPassphrase.Text.Length < 20)
                {

                    if (MessageBox.Show("Your passphrase is too short (< 20 characters). If you generate this wallet it may be easily compromised. Are you sure you'd like to use this passphrase?", "Passphrase too short", MessageBoxButtons.YesNo) == DialogResult.No)
                    {
                        return;
                    }

                }

                if (Bitcoin.PassphraseTooSimple(txtPassphrase.Text))
                {

                    if (MessageBox.Show("Your passphrase is too simple. If you generate this wallet it may be easily compromised. Are you sure you'd like to use this passphrase?", "Passphrase too simple", MessageBoxButtons.YesNo) == DialogResult.No)
                    {
                        return;
                    }

                }

                StringBuilder wallet = new StringBuilder();

                bool CSVmode = cboOutputType.Text.Contains("CSV");
                bool ScriptMode = cboOutputType.Text.Contains("Import script");
                bool ShowHelpText = cboOutputType.Text.Contains("Normal");

                if (ShowHelpText) {
                    wallet.AppendLine("Paper Bitcoin Wallet.  Keep private, do not lose, do not allow anyone to make a copy.  Anyone with the passphrase or private keys can steal your funds.\r\n");

                    wallet.AppendLine("Passphrase was:");
                    wallet.AppendLine(txtPassphrase.Text);
                    wallet.AppendLine("Freely give out the Bitcoin address.  The private key after each address is the key needed to unlock funds sent to the Bitcoin address.\r\n");

                }
                progressBar1.Maximum = n;
                progressBar1.Minimum = 0;
                progressBar1.Visible = true;
                label3.Text = "Progress:";
                button1.Enabled = false;

                for (int i = 1; i <= n; i++)
                {
                    Application.DoEvents();

                    string privatestring;
                    switch (GenerationFormula) {
                        case 1:
                            privatestring = txtPassphrase.Text + i.ToString();
                            break;
                        default:
                            privatestring = i.ToString() + "/" + txtPassphrase.Text + "/" + i.ToString() + "/BITCOIN";
                            break;
                    }
                    SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider();
                    UTF8Encoding encoding = new UTF8Encoding(false);
                    byte[] privatekey = sha256.ComputeHash(encoding.GetBytes(privatestring));

                    KeyPair kp = new KeyPair(privatekey);

                    string bytestring = kp.PrivateKeyHex;
                    string PrivWIF = kp.PrivateKeyBase58;
                    string PubHex = kp.PublicKeyHex;
                    string Address = kp.AddressBase58;

                    if (CSVmode) {
                        wallet.AppendFormat("{0},\"{1}\",\"{2}\"\r\n", i, Address, PrivWIF);
                    } else if (ScriptMode) {
                        wallet.AppendFormat("# {0}: {1}\"\r\n./bitcoind importprivkey {2}\r\n", i, Address, PrivWIF);
                    } else {
                        wallet.AppendFormat("Bitcoin Address #{0}: {1}\r\n", i, Address);
                        wallet.AppendFormat("Private Key: {0}\r\n\r\n", PrivWIF);
                    }

                    progressBar1.Value = i;
                }

                txtWallet.Text = wallet.ToString();

                progressBar1.Value = 0;
                progressBar1.Visible = false;
                label3.Text = "Passphrase:";
                button1.Enabled = true;
            }
        }
 /// <summary>
 /// Returns true if a given string can be turned into a private key.
 /// </summary>
 public static bool IsValidPrivateKey(string key)
 {
     KeyPair kp = new KeyPair();
     string result = kp.constructWithKey(key, false);
     return (result == null);
 }
        /// <summary>
        /// Generate a set of M-of-N parts for a specific private key.
        /// If desiredPrivKey is null, then a random key will be selected.
        /// </summary>
        public void Generate(int PartsNeededToDecode, int PartsToGenerate, byte[] desiredPrivKey)
        {
            if (PartsNeededToDecode > PartsToGenerate) {
                throw new ApplicationException("Number of parts needed exceeds number of parts to generate.");
            }

            if (PartsNeededToDecode > 8 || PartsToGenerate > 8) {
                throw new ApplicationException("Maximum number of parts is 8");
            }

            if (PartsNeededToDecode < 1 || PartsToGenerate < 1) {
                throw new ApplicationException("Minimum number of parts is 1");
            }

            if (desiredPrivKey != null && desiredPrivKey.Length != 32) {
                throw new ApplicationException("Desired private key must be 32 bytes");
            }

            KeyParts.Clear();
            decodedKeyParts.Clear();

            SecureRandom sr = new SecureRandom();

            // Get 8 random big integers into v[i].
            byte[][] vvv = new byte[8][];
            BigInteger[] v = new BigInteger[8];

            for (int i = 0; i < 8; i++) {
                byte[] b = new byte[32];
                sr.NextBytes(b, 0, 32);
                // For larger values of i, chop off some most-significant-bits to prevent overflows as they are
                // multiplied with increasingly larger factors.
                if (i >= 7) {
                    b[0] &= 0x7f;
                }
                v[i] = new BigInteger(1, b);
                Debug.WriteLine(String.Format("v({0})={1}", i, v[i].ToString()));

            }

            // if a certain private key is desired, then specify it.
            if (desiredPrivKey != null) {
                // replace v[0] with xor(v[1...7]) xor desiredPrivKey
                BigInteger newv0 = BigInteger.Zero;
                for (int i=1; i<PartsNeededToDecode; i++) {
                    newv0 = newv0.Xor(v[i]);
                }
                v[0] = newv0.Xor(new BigInteger(1,desiredPrivKey));

            }

            // Generate the expected private key from all the parts
            BigInteger privkey = new BigInteger("0");
            for (int i = 0; i < PartsNeededToDecode; i++) {
                privkey = privkey.Xor(v[i]);
            }

            // Get the bitcoin address
            byte[] keybytes = privkey.ToByteArrayUnsigned();
            // make sure we have 32 bytes, we'll need it
            if (keybytes.Length < 32) {
                byte[] array32 = new byte[32];
                Array.Copy(keybytes, 0, array32, 32 - keybytes.Length, keybytes.Length);
                keybytes = array32;
            }
            KeyPair = new BtcAddress.KeyPair(keybytes);

            SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider();
            ASCIIEncoding ae = new ASCIIEncoding();
            byte[] checksum = sha256.ComputeHash(ae.GetBytes(BitcoinAddress));

            // Generate the parts
            for (int i = 0; i < PartsToGenerate; i++) {
                BigInteger total = new BigInteger("0");
                for (int j = 0; j < PartsNeededToDecode; j++) {

                    int factor = 1;
                    for (int ii = 0; ii <= i; ii++) factor = factor * (j + 1);

                    BigInteger bfactor = new BigInteger(factor.ToString());

                    total = total.Add(v[j].Multiply(bfactor));
                }

                Debug.WriteLine(String.Format(" pc{0}={1}", i, total.ToString()));
                byte[] parts = new byte[39];
                parts[0] = 0x4f;
                parts[1] = (byte)(0x93 + PartsNeededToDecode);
                int parts23 = (((checksum[0] << 8) + checksum[1]) & 0x1ff);
                Debug.WriteLine("checksum " + parts23.ToString());
                parts23 += 0x6000;
                parts23 += (i << 9);
                byte[] btotal = total.ToByteArrayUnsigned();
                for (int jj = 0; jj < btotal.Length; jj++) {
                    parts[jj + 4 + (35 - btotal.Length)] = btotal[jj];
                }

                parts[2] = (byte)((parts23 & 0xFF00) >> 8);
                parts[3] = (byte)(parts23 & 0xFF);

                KeyParts.Add(Bitcoin.ByteArrayToBase58Check(parts));
                decodedKeyParts.Add(parts);
            }
        }
 /// <summary>
 /// Calculates public key and returns true if calculating public key was possible.
 /// This might cause a delay of milliseconds if it must be computed from the public
 /// key, possibly more if it leads to decrypting a private key.
 /// </summary>
 protected virtual bool calculatePubKey()
 {
     if (IsUnencryptedPrivateKeyAvailable()) {
         KeyPair kp = new KeyPair(_privKey, compressed: IsCompressedPoint, addressType: _addressType);
         _pubKey = kp.PublicKeyBytes;
         return true;
     }
     return false;
 }
        /// <summary>
        /// A string that allows someone to independently calculate the
        /// bitcoin address given their key material, without divulging the encrypted private key.
        /// This can be used to prove that the bitcoin address is encumbered by the passphrase.
        /// This is null if unavailable or not applicable.  When available, calculates upon first
        /// read, which involves an EC multiply and takes a little bit of CPU time.
        /// </summary>
        public string GetConfirmationCode()
        {
            if (_confirmationCode != null) return _confirmationCode;
            if (confirmationCodeInfo == null || factorb == null) return null;

            // finish calculating the confirmation code
            // use the KeyPair class to do the EC multiply for us
            KeyPair kp = new KeyPair(new BigInteger(1, factorb), true);

            // the public key is 33 bytes, or rather, 32 bytes plus one bit
            // (the first byte is either 0x02 or 0x03).
            // xor it with one bit of derived so it's not readable from the confirmation code.
            byte[] kppubbytes = kp.PublicKeyBytes;
            confirmationCodeInfo[18] = (byte)(kppubbytes[0] ^ (derived[63] & 0x01));

            // xor the pub bytes with derived[0...31] to get similar benefit like having an IV
            byte[] unencrypted = new byte[32];
            for (int i = 0; i < 32; i++) unencrypted[i] = (byte)(kppubbytes[i + 1] ^ derived[i]);

            // prepare for AES encryption
            byte[] derivedhalf2 = new byte[32];
            Array.Copy(derived, 32, derivedhalf2, 0, 32);
            AesCryptoServiceProvider aes = new AesCryptoServiceProvider();
            aes.KeySize = 256;
            aes.Mode = CipherMode.ECB;
            aes.Key = derivedhalf2;
            ICryptoTransform encryptor = aes.CreateEncryptor();

            // encrypt remaining two blocks of 16 bytes using same derived key

            encryptor.TransformBlock(unencrypted, 0, 16, confirmationCodeInfo, 19);
            encryptor.TransformBlock(unencrypted, 0, 16, confirmationCodeInfo, 19);
            encryptor.TransformBlock(unencrypted, 16, 16, confirmationCodeInfo, 19+16);
            encryptor.TransformBlock(unencrypted, 16, 16, confirmationCodeInfo, 19+16);

            _confirmationCode = Bitcoin.ByteArrayToBase58Check(confirmationCodeInfo);
            return _confirmationCode;
        }
        private void btnGenerateSpecific_Click(object sender, EventArgs e)
        {
            KeyPair k = null;

            try {
                k = new KeyPair(txtPrivKey.Text);
                targetPrivKey = k.PrivateKeyBytes;

            } catch (Exception) {
                MessageBox.Show("Not a valid private key.");
            }

            btnGenerate_Click(sender, e);
            targetPrivKey = null;
        }
        public static MiniKeyPair CreateDeterministic(string seed)
        {
            // flow:
            // 1. take SHA256 of seed to yield 32 bytes
            // 2. base58-encode those 32 bytes as though it were a regular private key. now we have 51 characters.
            // 3. remove all instances of the digit 1. (likely source of typos)
            // 4. take 29 characters starting with position 4
            //    (this is to skip those first characters of a base58check-encoded private key with low entropy)
            // 5. test to see if it matches the typo check.  while it does not, increment and try again.
            SHA256CryptoServiceProvider sha256 = new SHA256CryptoServiceProvider();
            UTF8Encoding utf8 = new UTF8Encoding(false);
            byte[] sha256ofseed = sha256.ComputeHash(utf8.GetBytes(seed));

            string asbase58 = new KeyPair(sha256ofseed).PrivateKeyBase58.Replace("1","");

            string keytotry = "S" + asbase58.Substring(4, 29);
            char[] chars = keytotry.ToCharArray();
            char[] charstest = (keytotry + "?").ToCharArray();

            while (sha256.ComputeHash(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];
                    if (c == '9') {
                        charstest[i] = chars[i] = 'A';
                        break;
                    } else if (c == 'H') {
                        charstest[i] = chars[i] = 'J';
                        break;
                    } else if (c == 'N') {
                        charstest[i] = chars[i] = 'P';
                        break;
                    } else if (c == 'Z') {
                        charstest[i] = chars[i] = 'a';
                        break;
                    } else if (c == 'k') {
                        charstest[i] = chars[i] = 'm';
                        break;
                    } else if (c == 'z') {
                        charstest[i] = chars[i] = '2';
                        // No break - let loop increment prior character.
                    } else {
                        charstest[i] = chars[i] = ++c;
                        break;
                    }
                }
            }
            return new MiniKeyPair(new String(chars));
        }