private void ConstructorHelper(ProverSetMembershipParameters prover, SetMembershipProofGenerationRandomData smRandom = null)
        {
            try
            {
                // check that parameters can be used to construct valid proof.
                if (!prover.Verify())
                {
                    throw new ArgumentException("Invalid proof parameters.  Cannot create proof");
                }

                // set Group context
                this.Group = prover.Group;
                this.IsGroupSerializable = true;

                // allocate space for proof
                this.c = new FieldZqElement[prover.MemberSet.Length - 1];
                this.a = new GroupElement[prover.MemberSet.Length];
                this.r = new FieldZqElement[prover.MemberSet.Length];

                // generate random values needed for proof
                if (smRandom == null)
                {
                    // generate a pair of random values for each fake proofs, plus the random exponent for the real one
                    smRandom = SetMembershipProofGenerationRandomData.Generate(prover.FieldZq, prover.MemberSet.Length - 1);
                }

                // Find index of prover.OpenCommitment.CommittedValue in prover.MemberSet
                int indexOfCommittedValue = prover.IndexOfCommittedValueInSet;

                // generate a fake proof for each prover.MemberSet element that is not
                // equal to CommitedValue.
                FieldZqElement sumOfSubChallenges = prover.FieldZq.Zero;

                int randomIndex = 0;
                for (int index = 0; index < prover.MemberSet.Length; ++index)
                {
                    if (index != indexOfCommittedValue)
                    {
                        this.generateFakeProof(index, prover, smRandom.c[randomIndex], smRandom.r[randomIndex]);
                        sumOfSubChallenges += smRandom.c[randomIndex];
                        randomIndex++;
                    }
                }

                // generate challenge, and a real proof for committment.CommittedValue
                this.generateRealA(indexOfCommittedValue, prover, smRandom.w);
                FieldZqElement challenge = this.ComputeChallenge(prover);
                this.generateRealProof(indexOfCommittedValue, prover, smRandom.w, sumOfSubChallenges.Negate() + challenge);
            }
            catch (Exception e)
            {
                throw new Exception("Could not create SetMembershipProof.", e);
            }
        }
        /// <summary>
        /// Generates a set membership proof from U-Prove parameters.
        /// </summary>
        /// <param name="pppp">The prover presentation protocol parameters.</param>
        /// <param name="pp">The presentation proof.</param>
        /// <param name="cpv">The commitment private values returned when generating the presentation proof.</param>
        /// <param name="committedIndex">Index of the committed attribute used to generate the set membership proof.</param>
        /// <param name="setValues">Set values to prove against.</param>
        /// <param name="smRandom">Optional pregenerated random values, or <c>null</c>.</param>
        /// <returns>A set membership proof.</returns>
        public static SetMembershipProof Generate(ProverPresentationProtocolParameters pppp, PresentationProof pp, CommitmentPrivateValues cpv, int committedIndex, byte[][] setValues, SetMembershipProofGenerationRandomData smRandom = null)
        {
            // get the index of the commitment to use, given the underlying attribute's index
            int commitmentIndex = ClosedPedersenCommitment.GetCommitmentIndex(pppp.Committed, committedIndex);
            // generate the membership proof
            ProverSetMembershipParameters setProver =
                new ProverSetMembershipParameters(
                    new PedersenCommitment(pppp, pp, cpv, commitmentIndex),
                    VerifierSetMembershipParameters.GenerateMemberSet(pppp.IP, committedIndex, setValues),
                    new CryptoParameters(pppp.IP));

            return(new SetMembershipProof(setProver, smRandom));
        }
        /// <summary>
        /// Constructor. Creates a proof that a token attribute is in a given set.
        /// </summary>
        /// <param name="prover">Token description.</param>
        /// <param name="attributeIndexForProver">1-based attribute index in token.</param>
        /// <param name="setValues">Set of attributes to compare to token attribute.</param>
        /// <param name="smRandom">Random data for set membership proof.</param>
        /// <returns>Inequality proof.</returns>
        public SetMembershipProof(ProverPresentationProtocolParameters prover, int attributeIndexForProver, byte[][] setValues, SetMembershipProofGenerationRandomData smRandom = null)
        {
            // generate Pedersen Commitments to token attribute
            ProverPresentationProtocolParameters[] provers = new ProverPresentationProtocolParameters[] { prover };
            int[] attributeIndices = new int[] { attributeIndexForProver };
            PedersenCommitment[] attributeCommitments = PedersenCommitment.PedersenCommmitmentsToAttributes(provers, attributeIndices);

            // create set membership proof using Pedersen Commitment
            FieldZqElement[] memberSet = VerifierSetMembershipParameters.GenerateMemberSet(prover.IP, attributeIndexForProver, setValues);
            ProverSetMembershipParameters setProver = new ProverSetMembershipParameters(attributeCommitments[0], memberSet, new CryptoParameters(prover.IP));

            ConstructorHelper(setProver, smRandom);

            // add UProve Integration proof
            this.UPIProof = new UProveIntegrationProof(provers, attributeIndices, attributeCommitments);
            this.UPIProof.IsGroupSerializable = false;
        }
        }                                                // responses

        /// <summary>
        /// Constructs a SetMembershipProof.  Throws exception if prover
        /// parameters do not allow creating valid proof.
        /// </summary>
        /// <param name="prover">Prover parameters</param>
        /// <param name="smRandom">The optional pre-generated random values to generate the proof, or <c>null</c>.</param>
        public SetMembershipProof(ProverSetMembershipParameters prover, SetMembershipProofGenerationRandomData smRandom = null)
        {
            ConstructorHelper(prover, smRandom);
        }