public static PublicKey fromString(byte[] str, string curve = "secp256k1", bool validatePoint = true)
        {
            CurveFp curveObject = Curves.getCurveByName(curve);

            int baseLen = curveObject.length();

            if (str.Length != 2 * baseLen)
            {
                throw new ArgumentException("string length [" + str.Length + "] should be " + 2 * baseLen);
            }

            string xs = Utils.BinaryAscii.hexFromBinary(Utils.Bytes.sliceByteArray(str, 0, baseLen));
            string ys = Utils.BinaryAscii.hexFromBinary(Utils.Bytes.sliceByteArray(str, baseLen));

            Point p = new Point(
                Utils.BinaryAscii.numberFromHex(xs),
                Utils.BinaryAscii.numberFromHex(ys)
                );

            if (validatePoint & !curveObject.contains(p))
            {
                throw new ArgumentException(
                          "point (" +
                          p.x.ToString() +
                          ", " +
                          p.y.ToString() +
                          ") is not valid for curve " +
                          curveObject.name
                          );
            }

            return(new PublicKey(p, curveObject));
        }
        public static PrivateKey fromDer(byte[] der)
        {
            Tuple <byte[], byte[]> removeSequence = Utils.Der.removeSequence(der);

            if (removeSequence.Item2.Length > 0)
            {
                throw new ArgumentException("trailing junk after DER private key: " + Utils.BinaryAscii.hexFromBinary(removeSequence.Item2));
            }

            Tuple <BigInteger, byte[]> removeInteger = Utils.Der.removeInteger(removeSequence.Item1);

            if (removeInteger.Item1 != 1)
            {
                throw new ArgumentException("expected '1' at start of DER private key, got " + removeInteger.Item1.ToString());
            }

            Tuple <byte[], byte[]> removeOctetString = Utils.Der.removeOctetString(removeInteger.Item2);

            byte[] privateKeyStr = removeOctetString.Item1;

            Tuple <int, byte[], byte[]> removeConstructed = Utils.Der.removeConstructed(removeOctetString.Item2);
            int tag = removeConstructed.Item1;

            byte[] curveOidString = removeConstructed.Item2;
            if (tag != 0)
            {
                throw new ArgumentException("expected tag 0 in DER private key, got " + tag.ToString());
            }

            Tuple <int[], byte[]> removeObject = Utils.Der.removeObject(curveOidString);

            int[] oidCurve = removeObject.Item1;
            if (removeObject.Item2.Length > 0)
            {
                throw new ArgumentException(
                          "trailing junk after DER private key curve_oid: " +
                          Utils.BinaryAscii.hexFromBinary(removeObject.Item2)
                          );
            }

            string stringOid = string.Join(",", oidCurve);

            if (!Curves.curvesByOid.ContainsKey(stringOid))
            {
                int      numCurves       = Curves.supportedCurves.Length;
                string[] supportedCurves = new string[numCurves];
                for (int i = 0; i < numCurves; i++)
                {
                    supportedCurves[i] = Curves.supportedCurves[i].name;
                }
                throw new ArgumentException(
                          "Unknown curve with oid [" +
                          string.Join(", ", oidCurve) +
                          "]. Only the following are available: " +
                          string.Join(", ", supportedCurves)
                          );
            }

            CurveFp curve = Curves.curvesByOid[stringOid];

            if (privateKeyStr.Length < curve.length())
            {
                int    length  = curve.length() - privateKeyStr.Length;
                string padding = "";
                for (int i = 0; i < length; i++)
                {
                    padding += "00";
                }
                privateKeyStr = Utils.Der.combineByteArrays(new List <byte[]> {
                    Utils.BinaryAscii.binaryFromHex(padding), privateKeyStr
                });
            }

            return(fromString(privateKeyStr, curve.name));
        }