/// <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));
        }
        /// <summary>
        /// Creates a new breach-proof password for specified user's password.
        /// </summary>
        /// <param name="password">The user's password.</param>
        public async Task <BreachProofPassword> CreateBreachProofPasswordAsync(string password)
        {
            if (string.IsNullOrEmpty(password))
            {
                throw new ArgumentNullException(nameof(password));
            }

            var blindingResult  = this.pythiaCrypto.Blind(password);
            var currentVersion  = this.proofKeys.Keys.Max();
            var currentProofKey = this.proofKeys[currentVersion];

            var salt = this.pythiaCrypto.GenerateSalt();

            var transformModel = new TransformModel
            {
                BlindedPassword = blindingResult.BlindedPassword,
                Salt            = salt,
                Version         = currentVersion,
                IncludeProof    = true
            };

            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);

            var proofParams = new PythiaProofParams
            {
                TransformedPassword     = result.TransformedPassword,
                TransformationPublicKey = currentProofKey,
                BlindedPassword         = blindingResult.BlindedPassword,
                Tweak       = 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(new BreachProofPassword
            {
                DeblindedPassword = deblindedPassword,
                Salt = salt,
                Version = currentVersion
            });
        }