public equation CombineAndReduce(equation othereq)
        {
            long topmultiplier = 0, bottommultiplier = 0;

            // This function considers "this" the top, and othereq the bottom.
            // It multiplies both equations by the first coefficient of the opposite equation,
            // and then subtracts the bottom from the top, eliminating the first coefficient from
            // the left side, and adding coefficients to the right.

            equation neweq = new equation();

            othereq.KillFactors();

            for (int i = 0; i < leftside.Count; i++)
            {
                coefficient topco    = leftside[i];
                coefficient bottomco = othereq.leftside[i];

                if (i == 0)
                {
                    topmultiplier    = bottomco.multiplier;
                    bottommultiplier = topco.multiplier;
                    // avoid saving a coefficient because the multiplier and subtraction guarantee they cancel
                }
                else
                {
                    neweq.leftside.Add(new coefficient(topco.multiplier * topmultiplier - bottomco.multiplier * bottommultiplier, topco.vindex));
                }
            }

            for (int i = 0; i < 8; i++)
            {
                long multiplier = 0;
                foreach (coefficient r in rightside)
                {
                    if (r.vindex == i)
                    {
                        multiplier += (r.multiplier * topmultiplier);
                    }
                }

                foreach (coefficient r in othereq.rightside)
                {
                    if (r.vindex == i)
                    {
                        multiplier -= (r.multiplier * bottommultiplier);
                    }
                }

                if (multiplier != 0)
                {
                    neweq.rightside.Add(new coefficient(multiplier, i));
                }
            }

            neweq.KillFactors();
            return(neweq);
        }
        public equation CombineAndReduce(equation othereq)
        {
            long topmultiplier = 0, bottommultiplier = 0;

                // This function considers "this" the top, and othereq the bottom.
                // It multiplies both equations by the first coefficient of the opposite equation,
                // and then subtracts the bottom from the top, eliminating the first coefficient from
                // the left side, and adding coefficients to the right.

                equation neweq = new equation();
                othereq.KillFactors();

                for (int i = 0; i < leftside.Count; i++) {
                    coefficient topco = leftside[i];
                    coefficient bottomco = othereq.leftside[i];

                    if (i == 0) {
                        topmultiplier = bottomco.multiplier;
                        bottommultiplier = topco.multiplier;
                        // avoid saving a coefficient because the multiplier and subtraction guarantee they cancel
                    } else {
                        neweq.leftside.Add(new coefficient(topco.multiplier * topmultiplier - bottomco.multiplier * bottommultiplier, topco.vindex));
                    }
                }

                for (int i = 0; i < 8; i++) {
                    long multiplier = 0;
                    foreach (coefficient r in rightside) {
                        if (r.vindex == i) multiplier += (r.multiplier * topmultiplier);
                    }

                    foreach (coefficient r in othereq.rightside) {
                        if (r.vindex == i) multiplier -= (r.multiplier * bottommultiplier);
                    }

                    if (multiplier != 0) {
                        neweq.rightside.Add(new coefficient(multiplier, i));
                    }
                }

                neweq.KillFactors();
                return neweq;
        }
        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


            byte[] checksum = Util.ComputeSha256(BitcoinAddress);

            int mychecksum = ((checksum[0] & 1) << 8) + checksum[1];

            if (mychecksum == expectedChecksum)
            {
                ChecksumMatched = true;
            }
        }