/// <summary>
        /// Updates the user's breach-proof password by specified update token.
        /// </summary>
        /// <returns>The breach-proof password.</returns>
        /// <param name="breachProofPassword">Breach proof password.</param>
        /// <param name="updateToken">Update token.</param>
        public BreachProofPassword UpdateBreachProofPassword(
            string updateToken, BreachProofPassword breachProofPassword)
        {
            if (string.IsNullOrEmpty(updateToken))
            {
                throw new ArgumentNullException(nameof(updateToken));
            }

            if (breachProofPassword == null)
            {
                throw new ArgumentNullException(nameof(breachProofPassword));
            }

            var parsedUpdateToken = this.TryParseUpdateToken(updateToken);

            if (breachProofPassword.Version == parsedUpdateToken.Item2)
            {
                throw new PythiaUpdatingException("This breach-proof password has already been updated");
            }

            if (breachProofPassword.Version != parsedUpdateToken.Item1)
            {
                throw new PythiaUpdatingException("This breach-proof password version does not match this update token");
            }

            var newDeblindedPassword = this.pythiaCrypto.UpdateDeblindedPassword(
                breachProofPassword.DeblindedPassword, parsedUpdateToken.Item3);

            return(new BreachProofPassword
            {
                DeblindedPassword = newDeblindedPassword,
                Version = parsedUpdateToken.Item2,
                Salt = breachProofPassword.Salt
            });
        }
        /// <summary>
        /// Verifies the user's original password by specified breach-proof password.
        /// </summary>///
        /// <param name="originalPassword">The original user's password</param>
        /// <param name="breachProofPassword"></param>
        /// <returns>Returns true if password is valid, otherwise false.</returns>
        public async Task <bool> VerifyBreachProofPasswordAsync(string originalPassword,
                                                                BreachProofPassword breachProofPassword, bool prove = false)
        {
            if (string.IsNullOrEmpty(originalPassword))
            {
                throw new ArgumentNullException(nameof(originalPassword));
            }

            if (breachProofPassword == null)
            {
                throw new ArgumentNullException(nameof(breachProofPassword));
            }

            var blindingResult = this.pythiaCrypto.Blind(originalPassword);

            var transformModel = new TransformModel
            {
                BlindedPassword = blindingResult.BlindedPassword,
                Salt            = breachProofPassword.Salt,
                Version         = breachProofPassword.Version,
                IncludeProof    = prove
            };

            var tokenContext = new TokenContext("pythia", "transform");
            var token        = await this.tokenProvider.GetTokenAsync(tokenContext).ConfigureAwait(false);

            var result = await this.client.TransformPasswordAsync(
                transformModel, token.ToString()).ConfigureAwait(false);

            if (prove)
            {
                var proofKey    = this.proofKeys[breachProofPassword.Version];
                var proofParams = new PythiaProofParams
                {
                    TransformedPassword     = result.TransformedPassword,
                    TransformationPublicKey = proofKey,
                    BlindedPassword         = blindingResult.BlindedPassword,
                    Tweak       = breachProofPassword.Salt,
                    ProofValueC = result.Proof.ValueC,
                    ProofValueU = result.Proof.ValueU
                };

                if (!this.pythiaCrypto.Verify(proofParams))
                {
                    throw new PythiaProofIsNotValidException();
                }
            }

            var deblindedPassword = this.pythiaCrypto.Deblind(
                result.TransformedPassword, blindingResult.BlindingSecret);

            return(deblindedPassword.SequenceEqual(breachProofPassword.DeblindedPassword));
        }