internal SignatureVerificationResult VerifySignature(
            string signature,
            string userAgent,
            string signRole,
            string key,
            bool isKeyBase64Encoded,
            int?expiry,
            string[] ipAddresses)
        {
            SignatureVerificationResult validationResult = new SignatureVerificationResult();

            try
            {
                key = isKeyBase64Encoded ? SignatureVerifierUtils.KeyDecode(key) : key;

                Dictionary <string, Object> data;
                try
                {
                    data = Parse4(signature);
                }
                catch (BaseSignatureVerificationException exp)
                {
                    if (exp is SignatureRangeException)
                    {
                        data = Parse3(signature);
                    }
                    else
                    {
                        validationResult.Error = exp.Message;
                        return(validationResult);
                    }
                }

                data.TryGetValue(signRole + "Token", out var signRoleTokenObj);
                string signRoleToken = (string)signRoleTokenObj;

                if (signRoleToken == null || signRoleToken.Length == 0)
                {
                    validationResult.Error = "sign role signature mismatch";
                    return(validationResult);
                }

                int signType = SignatureVerifierUtils.CharacterToInt(data[signRole + "SignType"]);

                foreach (var ipAddress in ipAddresses)
                {
                    string currentIpAddress = ipAddress;
                    string token;
                    if (currentIpAddress == null || currentIpAddress.Length == 0)
                    {
                        continue;
                    }
                    if (IpV6Utils.Validate(currentIpAddress))
                    {
                        if (!data.ContainsKey(signRole + "TokenV6"))
                        {
                            continue;
                        }
                        token            = (string)data[signRole + "TokenV6"];
                        currentIpAddress = IpV6Utils.Abbreviate(currentIpAddress);
                    }
                    else
                    {
                        if (!data.ContainsKey(signRole + "Token"))
                        {
                            continue;
                        }

                        token = (string)data[signRole + "Token"];
                    }

                    int signatureTime = SignatureVerifierUtils.CharacterToInt(data["signatureTime"]);
                    int requestTime   = SignatureVerifierUtils.CharacterToInt(data["requestTime"]);

                    foreach (string result in _results.Keys)
                    {
                        switch (signType)
                        {
                        case 1:
                            string signatureBase =
                                GetBase(result, requestTime, signatureTime, currentIpAddress, userAgent);

                            bool isHashedDataEqualToToken = SignatureVerifierUtils.CompareBytes(SignatureVerifierUtils.Encode(key, signatureBase), token);

                            if (isHashedDataEqualToToken)
                            {
                                if (IsExpired(expiry, signatureTime, requestTime))
                                {
                                    validationResult.Expired = true;
                                    return(validationResult);
                                }

                                validationResult.Score         = int.Parse(result);
                                validationResult.Verdict       = _results[result.ToString()];
                                validationResult.IpAddress     = currentIpAddress;
                                validationResult.RequestTime   = int.Parse(data["requestTime"].ToString());
                                validationResult.SignatureTime = int.Parse(data["signatureTime"].ToString());

                                return(validationResult);
                            }
                            break;

                        case 2:
                            validationResult.Error = "unsupported signature";
                            return(validationResult);

                        default:
                            validationResult.Error = "unrecognized signature";
                            return(validationResult);
                        }
                    }
                }

                validationResult.Error = "no verdict";
                return(validationResult);
            }
            catch (Exception exp)
            {
                string base64Exception = "The input is not a valid Base-64 string";

                if (exp.Message.StartsWith(base64Exception))
                {
                    validationResult.Error = exp.Message.Replace(base64Exception, "Key/Signature is not a valid Base-64 string");
                    return(validationResult);
                }
                else
                {
                    validationResult.Error = exp.Message;
                    return(validationResult);
                }
            }
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="signature"></param>
        /// <returns></returns>
        /// <exception cref="BaseSignatureVerificationException"></exception>
        private Dictionary <string, Object> Parse4(string signature)

        {
            signature = SignatureVerifierUtils.FromBase64(signature);

            if (signature.Length == 0)
            {
                throw new SignatureVerificationException("invalid base64 payload");
            }

            Dictionary <string, Object> data = Unpacker.Unpack("Cversion/CfieldNum", signature).Data;

            int version = SignatureVerifierUtils.CharacterToInt(data["version"]);

            if (version != 4)
            {
                throw new SignatureRangeException("unsupported version");
            }
            signature = SignatureVerifierUtils.Substr(signature, 2);

            int fieldNum = SignatureVerifierUtils.CharacterToInt(data["fieldNum"]);

            for (int i = 0; i < fieldNum; ++i)
            {
                Dictionary <string, Object> header = Unpacker.Unpack("CfieldId", signature).Data;

                if (header.Count == 0 || !header.ContainsKey("fieldId")) // header.entrySet().size() ???
                {
                    throw new SignatureVerificationException("premature end of signature 0x01");
                }

                Field fieldTypeDef            = FieldTypeDef(SignatureVerifierUtils.CharacterToInt(header["fieldId"]), i);
                Dictionary <string, Object> v = new Dictionary <string, Object>();
                Dictionary <string, Object> l;

                switch (fieldTypeDef.Type)
                {
                case "uchar":
                    v = Unpacker.Unpack("Cx/Cv", signature).Data;
                    if (v.ContainsKey("v"))
                    {
                        data.Add(fieldTypeDef.Name, v["v"]);
                    }
                    else
                    {
                        throw new SignatureVerificationException("premature end of signature 0x02");
                    }
                    signature = SignatureVerifierUtils.Substr(signature, 2);
                    break;

                case "ushort":
                    v = Unpacker.Unpack("Cx/nv", signature).Data;
                    if (v.ContainsKey("v"))
                    {
                        data.Add(fieldTypeDef.Name, v["v"]);
                    }
                    else
                    {
                        throw new Exception("premature end of signature 0x03");
                    }
                    signature = SignatureVerifierUtils.Substr(signature, 3);
                    break;

                case "ulong":
                    v = Unpacker.Unpack("Cx/Nv", signature).Data;
                    if (v.ContainsKey("v"))
                    {
                        data.Add(fieldTypeDef.Name, v["v"]);
                    }
                    else
                    {
                        throw new Exception("premature end of signature 0x04");
                    }
                    signature = SignatureVerifierUtils.Substr(signature, 5);
                    break;

                case "string":
                    l = Unpacker.Unpack("Cx/nl", signature).Data;
                    if (!l.ContainsKey("l"))
                    {
                        throw new Exception("premature end of signature 0x05");
                    }
                    if ((SignatureVerifierUtils.CharacterToInt(l["l"]) & 0x8000) > 0)
                    {
                        int newl = SignatureVerifierUtils.CharacterToInt(l["l"]) & 0xFF;
                        l.Add("l", newl);
                    }

                    string newV = SignatureVerifierUtils.Substr(signature, 3, SignatureVerifierUtils.CharacterToInt(l["l"]));
                    v.Add("v", newV);
                    data.Add(fieldTypeDef.Name, newV);

                    if (((string)v["v"]).Length != SignatureVerifierUtils.CharacterToInt(l["l"]))
                    {
                        throw new SignatureVerificationException("premature end of signature 0x06");
                    }

                    signature = SignatureVerifierUtils.Substr(signature, 3 + SignatureVerifierUtils.CharacterToInt(l["l"]));

                    break;

                default:
                    throw new SignatureVerificationException("unsupported variable type");
                }
            }

            data.Remove(fieldNum.ToString());

            return(data);
        }