/// <summary>
        /// Validates the payload received from the other participant during round 3.
        ///
        /// See JPakeParticipant for more details on round 3.
        ///
        /// After execution, the State state will be STATE_ROUND_3_VALIDATED.
        ///
        /// Throws CryptoException if validation fails. Throws InvalidOperationException if called prior to
        /// CalculateKeyingMaterial or multiple times
        /// </summary>
        /// <param name="round3PayloadReceived">The round 3 payload received from the other participant.</param>
        /// <param name="keyingMaterial">The keying material as returned from CalculateKeyingMaterial().</param>
        public virtual void ValidateRound3PayloadReceived(JPakeRound3Payload round3PayloadReceived, BigInteger keyingMaterial)
        {
            if (this.state >= STATE_ROUND_3_VALIDATED)
            {
                throw new InvalidOperationException("Validation already attempted for round 3 payload for " + this.participantId);
            }
            if (this.state < STATE_KEY_CALCULATED)
            {
                throw new InvalidOperationException("Keying material must be calculated prior to validating round 3 payload for " + this.participantId);
            }

            JPakeUtilities.ValidateParticipantIdsDiffer(participantId, round3PayloadReceived.ParticipantId);
            JPakeUtilities.ValidateParticipantIdsEqual(this.partnerParticipantId, round3PayloadReceived.ParticipantId);

            JPakeUtilities.ValidateMacTag(
                this.participantId,
                this.partnerParticipantId,
                this.gx1,
                this.gx2,
                this.gx3,
                this.gx4,
                keyingMaterial,
                this.digest,
                round3PayloadReceived.MacTag);

            // Clear the rest of the fields.
            this.gx1 = null;
            this.gx2 = null;
            this.gx3 = null;
            this.gx4 = null;

            this.state = STATE_ROUND_3_VALIDATED;
        }
        /// <summary>
        /// Validates the payload received from the other participant during round 2.
        /// Note that this DOES NOT detect a non-common password.
        /// The only indication of a non-common password is through derivation
        /// of different keys (which can be detected explicitly by executing round 3 and round 4)
        ///
        /// Must be called prior to CalculateKeyingMaterial().
        ///
        /// After execution, the State state will be STATE_ROUND_2_VALIDATED.
        ///
        /// Throws CryptoException if validation fails. Throws
        /// InvalidOperationException if called prior to ValidateRound1PayloadReceived(JPakeRound1Payload), or multiple times
        /// </summary>
        public virtual void ValidateRound2PayloadReceived(JPakeRound2Payload round2PayloadReceived)
        {
            if (this.state >= STATE_ROUND_2_VALIDATED)
            {
                throw new InvalidOperationException("Validation already attempted for round 2 payload for " + this.participantId);
            }
            if (this.state < STATE_ROUND_1_VALIDATED)
            {
                throw new InvalidOperationException("Round 1 payload must be validated prior to validation round 2 payload for " + this.participantId);
            }

            BigInteger gB = JPakeUtilities.CalculateGA(p, gx3, gx1, gx2);

            this.b = round2PayloadReceived.A;
            BigInteger[] knowledgeProofForX4s = round2PayloadReceived.KnowledgeProofForX2s;

            JPakeUtilities.ValidateParticipantIdsDiffer(participantId, round2PayloadReceived.ParticipantId);
            JPakeUtilities.ValidateParticipantIdsEqual(this.partnerParticipantId, round2PayloadReceived.ParticipantId);
            JPakeUtilities.ValidateGa(gB);
            JPakeUtilities.ValidateZeroKnowledgeProof(p, q, gB, b, knowledgeProofForX4s, round2PayloadReceived.ParticipantId, digest);

            this.state = STATE_ROUND_2_VALIDATED;
        }