/// <summary>
        /// Helper method for constructing proof. Computes a[index], c[index], r[index] values for when
        /// the committedValue is not equal to prover.MemberSet[index].
        /// </summary>
        /// <param name="index">Index into prover.MemberSet</param>
        /// <param name="prover">Prover parameters</param>
        /// <param name="randomChallengeValue">Value to set c[index]</param>
        /// <param name="randomResponseValue">Value to set r[index]</param>
        private void generateFakeProof(int index, ProverSetMembershipParameters prover, FieldZqElement randomChallengeValue, FieldZqElement randomResponseValue)
        {
            if (index < this.c.Length)
            {
                this.c[index] = randomChallengeValue;
            }

            this.r[index] = randomResponseValue;

            // compute this.a[index] as a multi-exponentiation
            // a[index] = h^r[index] * g^{memberset[index] + c[index]} * X^{-c[index]
            GroupElement[] bases = new GroupElement[3]
            {
                prover.H,                         // h
                prover.G,                         // g
                prover.ClosedCommitment           // X
            };
            FieldZqElement[] exponents = new FieldZqElement[3]
            {
                randomResponseValue,                            // r[index]
                prover.MemberSet[index] * randomChallengeValue, // memberset[index] * c
                randomChallengeValue.Negate()                   // -c
            };
            this.a[index] = prover.Group.MultiExponentiate(bases, exponents);
        }
        /// <summary>
        /// Verifies that the given (commitment, challenge, response) values are a
        /// valid proof for this object.  See IOpenEquation for how commitment and response are generated.
        /// </summary>
        /// <param name="challenge">The challenge for this proof (second step in Sigma protocol).</param>
        /// <param name="responseValues">The response (third step in Sigma protocol).</param>
        /// <param name="commitment">The commitment (first step in Sigma protocol).</param>
        /// <returns></returns>
        public override bool Verify(GroupElement commitment, FieldZqElement challenge, FieldZqElement[] response)
        {
            if ((response == null) || (response.Length != this.RepresentationLength))
            {
                return(false);
            }

            GroupElement[]   bases     = new GroupElement[this.RepresentationLength + 1];
            FieldZqElement[] exponents = new FieldZqElement[this.RepresentationLength + 1];
            for (int i = 0; i < response.Length; ++i)
            {
                bases[i]     = this.BaseAtIndex(i);
                exponents[i] = response[i];
            }
            exponents[0] = challenge.Negate();
            bases[this.RepresentationLength]     = this.PublicKey;
            exponents[this.RepresentationLength] = response[0];

            GroupElement verifier = this.Group.MultiExponentiate(bases, exponents);

            if (commitment != verifier)
            {
                return(false);
            }
            return(true);
        }
예제 #3
0
        /// <summary>
        /// Generates the U-Prove key and tokens.
        /// </summary>
        /// <param name="message">The third issuance message.</param>
        /// <param name="skipTokenValidation">Set to <code>true</code> to skip token validation;
        /// <code>false</code> otherwise. Token validation SHOULD be performed before use, either
        /// by setting <code>skipTokenValidation</code> to <code>false</code>, or by later using the
        /// <code>ProtocolHelper.VerifyTokenSignature</code> method.
        /// </param>
        /// <exception cref="InvalidUProveArtifactException">If the token signature is invalid.</exception>
        /// <returns>An array of U-Prove keys and tokens</returns>
        public UProveKeyAndToken[] GenerateTokens(ThirdIssuanceMessage message, bool skipTokenValidation = false)
        {
            if (state != State.Second)
            {
                throw new InvalidOperationException("GenerateSecondMessage must be called first");
            }

            bool doBatchValidation  = !skipTokenValidation && batchValidationSecurityLevel > 0;
            bool doNormalValidation = !skipTokenValidation && batchValidationSecurityLevel <= 0;

            Group   Gq = ip.Gq;
            FieldZq Zq = ip.Zq;

            FieldZqElement[] sigmaRPrime = new FieldZqElement[numberOfTokens];

            FieldZqElement phoAR = Zq.Zero, phoR = Zq.Zero, phoAC = Zq.Zero, phoC = Zq.Zero;

            GroupElement[]   batchAccBases = new GroupElement[numberOfTokens];
            FieldZqElement[] s             = null;
            if (!skipTokenValidation)
            {
                s = Zq.GetRandomElements(numberOfTokens, true, batchValidationSecurityLevel);
            }
            for (int i = 0; i < numberOfTokens; i++)
            {
                sigmaRPrime[i] = message.sigmaR[i] + beta2[i];
                if (doBatchValidation)
                {
                    phoAR           += (s[i] * alpha[i] * sigmaRPrime[i]);
                    phoR            += (s[i] * sigmaRPrime[i]);
                    phoAC           += (s[i] * alpha[i] * sigmaCPrime[i]);
                    phoC            += (s[i] * sigmaCPrime[i]);
                    batchAccBases[i] = sigmaAPrime[i] * sigmaBPrime[i];
                }
                else if (doNormalValidation)
                {
                    if (!(sigmaAPrime[i] * sigmaBPrime[i]).Equals(
                            Gq.MultiExponentiate(new GroupElement[] { Gq.G *h[i], ip.G[0] * sigmaZPrime[i] },
                                                 new FieldZqElement[] { sigmaRPrime[i], sigmaCPrime[i].Negate() })))
                    {
                        throw new InvalidUProveArtifactException("Invalid token signature: " + i);
                    }
                }
                ukat[i].Token = new UProveToken(ip.UidP, h[i], TI, PI, sigmaZPrime[i], sigmaCPrime[i], sigmaRPrime[i], isDeviceProtected);
            }
            if (doBatchValidation &&
                (Gq.MultiExponentiate(batchAccBases, s) !=
                 Gq.MultiExponentiate(new GroupElement[] { Gq.G, gamma, ip.G[0], sigmaZ },
                                      new FieldZqElement[] { phoR, phoAR, phoC.Negate(), phoAC.Negate() })))      // TODO: batch validation with blinded gamma needs to multiply beta0inverse to phoAR
            {
                throw new InvalidUProveArtifactException("Invalid token signature");
            }

            state = State.Tokens;
            return(ukat);
        }
예제 #4
0
        /// <summary>
        /// Updates the revocation witness for a user, either adding or removing a revoked value.
        /// </summary>
        /// <param name="rap">The Revocation Authority parameters.</param>
        /// <param name="xid">The revocation attribute value <c>xid</c>.</param>
        /// <param name="revoked">The attribute value to added to the accumulator, or <c>null</c>.</param>
        /// <param name="unrevoked">The attribute value to deleted to the accumulator, or <c>null</c>.</param>
        /// <param name="oldAccumulator">The old accumulator value <c>V</c>. If <c>null</c>, then the accumulator is freshly calculated.</param>
        /// <param name="updatedAccumulator">The old accumulator value <c>V'</c>.</param>
        /// <param name="oldWitness">The old witness values. If <c>null</c>, then the witness is freshly calculated.</param>
        /// <returns></returns>
        public static RevocationWitness UpdateWitness(RAParameters rap, FieldZqElement xid, FieldZqElement revoked, FieldZqElement unrevoked, GroupElement oldAccumulator, GroupElement updatedAccumulator, RevocationWitness oldWitness)
        {
            // TODO: implement batch updates
            if (revoked != null && unrevoked != null)
            {
                throw new ArgumentException("only one of revoked and unrevoked can be non-null");
            }

            FieldZqElement one = rap.group.FieldZq.One;

            if (oldAccumulator == null)
            {
                // set the accumulator value for an empty revocation set
                oldAccumulator = rap.gt;
            }
            if (oldWitness == null)
            {
                oldWitness = new RevocationWitness(rap.group.FieldZq.One, rap.group.Identity, rap.group.Identity);
            }

            if (revoked == null && unrevoked == null)
            {
                // nothing to do
                return(oldWitness);
            }

            FieldZqElement dPrime = null;
            GroupElement   WPrime = null;
            GroupElement   QPrime = null;

            FieldZqElement xDiff = one;

            // add values to witness
            if (revoked != null)
            {
                xDiff  = (revoked - xid);
                dPrime = oldWitness.d * xDiff;
                WPrime = oldAccumulator * oldWitness.W.Exponentiate(xDiff);
            }

            xDiff = one;
            // remove values from witness
            if (unrevoked != null)
            {
                xDiff  = (unrevoked - xid).Invert();
                dPrime = oldWitness.d * xDiff;
                WPrime = updatedAccumulator.Exponentiate(one.Negate()) * oldWitness.W.Exponentiate(xDiff);
            }

            // update QPrime value
            QPrime = updatedAccumulator * WPrime.Exponentiate(xid.Negate()) * rap.gt.Exponentiate(dPrime.Negate());

            return(new RevocationWitness(dPrime, WPrime, QPrime));
        }
        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);
            }
        }
예제 #6
0
        /// <summary>
        /// Genererates proof for when prover.CompareToKnownValue=true.
        /// </summary>
        /// <param name="prover"></param>
        private void CreateProofForKnownValue(ProverInequalityProofParameters prover)
        {
            // Pedersen Commitment to a random value a
            // A = g^a h^r
            FieldZqElement     a     = prover.FieldZq.GetRandomElement(true);
            FieldZqElement     r     = prover.FieldZq.GetRandomElement(true);
            PedersenCommitment openA = new PedersenCommitment(prover.G, prover.H, a, r, prover.Group);

            // B = g^(x-value)a
            DLRepOfGroupElement openB = new DLRepOfGroupElement(
                new GroupElement[1] {
                prover.G
            },
                new FieldZqElement[1] {
                (prover.CommitmentX.CommittedValue - prover.Value) * a
            },
                prover.Group
                );

            // C = (Xg^{-value})^a h^{-ya} = B
            PedersenCommitment openC = new PedersenCommitment(
                prover.CommitmentX.Value * prover.G.Exponentiate(prover.Value.Negate()),
                prover.H,
                a,
                a.Negate() * prover.CommitmentX.Opening,
                prover.Group
                );

            // Create DL equations
            DLRepOfGroupElement[] equations = new DLRepOfGroupElement[]
            {
                prover.CommitmentX,
                openA,
                openB,
                openC
            };

            // generate proof
            EqualityMap map = this.GetEqualityMap();
            ProverEqualityParameters eqProver = new ProverEqualityParameters(equations, map, prover);

            this.Proof = new EqualityProof(eqProver);
            this.A     = openA.Value;
            this.B     = openB.Value;
        }
예제 #7
0
            FieldZqElement IDevicePresentationContext.GetDeviceResponse(byte[] messageForDevice, byte[] partialChallengeDigest, string hashOID)
            {
                if (this.device == null)
                {
                    throw new DeviceException("Invalid context.");
                }
                if (this.wdPrime == null)
                {
                    throw new DeviceException("Initial witness not yet calculated.");
                }

                HashFunction   hashFunction = new HashFunction(GetHashFunctionName(hashOID));
                FieldZqElement c            = ProtocolHelper.GenerateChallengeForDevice(device.Zq, hashFunction, messageForDevice, partialChallengeDigest);
                FieldZqElement rdPrime      = c.Negate() * device.xd + wdPrime;

                this.device = null;
                return(rdPrime);
            }
예제 #8
0
        /// <summary>
        /// Returns ProverRangeProofParameters that the committed date to the
        /// the verifier target date.  Range proof will require bit decomposition of  approximately  9 + log_2 (maxYear - minYear) bits.
        /// </summary>
        /// <param name="crypto">Crypto parameters</param>
        /// <param name="commitmentToDayOfYear">Commitment value in [0,365]</param>
        /// <param name="commitmentToYear">Commitment to a year in [minYear, maxYear].</param>
        /// <param name="rangeProofType">Range proof type.</param>
        /// <param name="verifierTargetDate">Commitment to a date in [minYear, maxYear +1).</param>
        /// <param name="minYear">Limits range of proof. </param>
        /// <param name="maxYear">Limits range of proof.</param>
        /// <returns></returns>
        public static ProverRangeProofParameters GetDateTimeProverParameters(CryptoParameters crypto, PedersenCommitment commitmentToYear, PedersenCommitment commitmentToDayOfYear, VerifierRangeProofParameters.ProofType rangeProofType, DateTime verifierTargetDate, int minYear, int maxYear)
        {
            //Check crypto parameters and pedersen commitment generators G and H
            if (!commitmentToYear.AreBasesEqual(commitmentToDayOfYear))
            {
                throw new ArgumentException("PedersenCommitments commitmentToYear and commitmentToDayOfYear have different bases.");
            }
            if ((crypto.G != commitmentToYear.BaseAtIndex(0)) ||
                (crypto.H != commitmentToYear.BaseAtIndex(1)))
            {
                throw new ArgumentException("PedersenCommitments commitmentToYear and commitmentToDayOfYear should use bases crypto.G and crypto.H.");
            }

            FieldZqElement minYearElement = crypto.FieldZq.GetElement((uint)minYear);
            FieldZqElement daysInOneYear  = crypto.FieldZq.GetElement(366);
            FieldZqElement committedYear  = commitmentToYear.ExponentAtIndex(0);
            FieldZqElement committedDay   = commitmentToDayOfYear.ExponentAtIndex(0);
            FieldZqElement openingYear    = commitmentToYear.ExponentAtIndex(1);
            FieldZqElement openingDay     = commitmentToDayOfYear.ExponentAtIndex(1);

            PedersenCommitment commitmentToYearAndDay = new PedersenCommitment(
                crypto.G,
                crypto.H,
                (committedYear + minYearElement.Negate()) * daysInOneYear + committedDay,
                openingYear * daysInOneYear + openingDay,
                crypto.Group);



            int maxValue           = (maxYear - minYear) * 366 + 365;
            int verifierYearAndDay = EncodeYearAndDay(verifierTargetDate, minYear);

            return(new ProverRangeProofParameters(
                       crypto,
                       commitmentToYearAndDay,
                       rangeProofType,
                       verifierYearAndDay,
                       0,
                       maxValue));
        }
예제 #9
0
        /// <summary>
        /// Generates a non-revocation proof.
        /// </summary>
        /// <param name="rap">The Revocation Authority parameters.</param>
        /// <param name="rw">The user's revocation witness.</param>
        /// <param name="tildeCid">The revocation attribute commitment.</param>
        /// <param name="xid">The revocation attribute.</param>
        /// <param name="tildeOid">The revocation attribute commitment's opening value.</param>
        /// <param name="preGenRandom">The optional pre-generated random values for the proof, or <c>null</c>.</param>
        /// <returns></returns>
        public static NonRevocationProof GenerateNonRevocationProof(RAParameters rap, RevocationWitness rw, GroupElement tildeCid, FieldZqElement xid, FieldZqElement tildeOid, NonRevocationProofGenerationRandomData preGenRandom = null)
        {
            if (rap == null || rw == null || tildeCid == null || xid == null || tildeOid == null)
            {
                throw new ArgumentNullException("null input to GenerateNonRevocationProof");
            }

            Group   Gq = rap.group;
            FieldZq Zq = Gq.FieldZq;
            NonRevocationProofGenerationRandomData rand = preGenRandom;

            if (rand == null)
            {
                rand = NonRevocationProofGenerationRandomData.Generate(Zq);
            }
            GroupElement   X            = rw.W * rap.g.Exponentiate(rand.t1);
            GroupElement   Y            = rw.Q * rap.K.Exponentiate(rand.t1);
            GroupElement   Cd           = rap.gt.Exponentiate(rw.d) * rap.g1.Exponentiate(rand.t2);
            FieldZqElement w            = rw.d.Invert();
            FieldZqElement z            = rand.t1 * tildeOid - rand.t2;
            FieldZqElement zPrime       = rand.t2.Negate() * w;
            GroupElement   T1           = Gq.MultiExponentiate(new GroupElement[] { X, tildeCid * rap.K, rap.g1 }, new FieldZqElement[] { rand.k1, rand.k2.Negate(), rand.k3 });
            GroupElement   T2           = Gq.MultiExponentiate(new GroupElement[] { rap.g, rap.g1 }, new FieldZqElement[] { rand.k1, rand.k4 });
            GroupElement   T3           = Gq.MultiExponentiate(new GroupElement[] { Cd, rap.g1 }, new FieldZqElement[] { rand.k5, rand.k6 });
            FieldZqElement cPrime       = Zq.GetElementFromDigest(rap.ComputeChallenge(tildeCid, X, Y, Cd, T1, T2, T3));
            FieldZqElement cPrimeNegate = cPrime.Negate();
            FieldZqElement s1           = cPrimeNegate * xid + rand.k1;
            FieldZqElement s2           = cPrimeNegate * rand.t1 + rand.k2;
            FieldZqElement s3           = cPrimeNegate * z + rand.k3;
            FieldZqElement s4           = cPrimeNegate * tildeOid + rand.k4;
            FieldZqElement s5           = cPrimeNegate * w + rand.k5;
            FieldZqElement s6           = cPrimeNegate * zPrime + rand.k6;

            rand.Clear();
            return(new NonRevocationProof(cPrime, new FieldZqElement[] { s1, s2, s3, s4, s5, s6 }, X, Y, Cd));
        }
예제 #10
0
        public void Verify(IssuerParameters ip, int[] disclosed, int[] committed, int pseudonymAttribIndex, GroupElement gs, byte[] message, byte[] messageD, UProveToken upt)
        {
            try
            {
                // make sure disclosed list is sorted
                if (disclosed == null)
                {
                    // can't be null later, so make it an empty array
                    disclosed = new int[] { };
                }
                Array.Sort(disclosed);
                Group Gq = ip.Gq;
                int   n  = ip.E.Length;

                bool presentPseudonym = false;
                if (gs != null && pseudonymAttribIndex != 0)
                {
                    if (pseudonymAttribIndex < 1 || (pseudonymAttribIndex > n && pseudonymAttribIndex != DeviceAttributeIndex))
                    {
                        throw new ArgumentException("pseudonymAttribIndex must be between 1 and " + n + " (inclusive)");
                    }
                    if (disclosed.Contains(pseudonymAttribIndex))
                    {
                        throw new ArgumentException("pseudonymAttribIndex cannot be in the disclosed attribute array");
                    }
                    presentPseudonym = true;
                }
                else // no nym
                {
                    pseudonymAttribIndex = 0;
                }
                bool verifyCommitments = (committed != null && committed.Length > 0);
                if (verifyCommitments)
                {
                    Array.Sort(committed);
                }

                ProtocolHelper.VerifyTokenSignature(ip, upt);

                int              dArraySize = disclosed.Length + 2;
                GroupElement[]   dBases     = new GroupElement[dArraySize];
                FieldZqElement[] dExponents = new FieldZqElement[dArraySize];
                dBases[0] = ip.G[0]; dExponents[0] = ip.Zq.One;                                                       // g0^1
                dBases[1] = ip.G[n + 1]; dExponents[1] = ProtocolHelper.ComputeXt(ip, upt.TI, upt.IsDeviceProtected); // gt^xt
                FieldZqElement[] disclosedX         = new FieldZqElement[disclosedAttributes.Length];
                int              aPreImageArraySize = 2 + (n - disclosed.Length) + (upt.IsDeviceProtected ? 1 : 0);
                GroupElement[]   aPreImageBases     = new GroupElement[aPreImageArraySize];
                FieldZqElement[] aPreImageExponents = new FieldZqElement[aPreImageArraySize];
                // aPreImage arrays' index 0 values depend on the dArray values; they will be filled out later
                aPreImageBases[1] = upt.H; aPreImageExponents[1] = this.r[0]; // h^r0
                int   dIndex = 0;
                int   uIndex = 1;
                int   cIndex = 0;
                int   pseudonymResponseIndex    = 0;
                int[] commitmentResponseIndices = verifyCommitments ? new int[committed.Length] : null;
                for (int i = 1; i <= n; i++)
                {
                    if (disclosed.Contains(i))
                    {
                        disclosedX[dIndex]     = ProtocolHelper.ComputeXi(ip, i - 1, disclosedAttributes[dIndex]);
                        dBases[dIndex + 2]     = ip.G[i];
                        dExponents[dIndex + 2] = disclosedX[dIndex];
                        dIndex++;
                    }
                    else
                    {
                        aPreImageBases[uIndex + 1] = ip.G[i]; aPreImageExponents[uIndex + 1] = this.r[uIndex]; // gi^ri
                        if (presentPseudonym)
                        {
                            if (pseudonymAttribIndex == i)
                            {
                                pseudonymResponseIndex = uIndex;
                            }
                        }
                        if (verifyCommitments)
                        {
                            if (committed.Contains(i))
                            {
                                // remember which response correspond to which commitment
                                commitmentResponseIndices[cIndex] = uIndex;
                                cIndex++;
                            }
                        }
                        uIndex++;
                    }
                }
                if (pseudonymAttribIndex == DeviceAttributeIndex)
                {
                    pseudonymResponseIndex = this.r.Length - 1; // r_d is the last response in the array
                }

                byte[]         unused; // verifier doesn't use the returned message for device
                FieldZqElement c = ProtocolHelper.GenerateChallenge(ip, upt, this.a, pseudonymAttribIndex, this.ap, this.ps, message, messageD, disclosed, disclosedX, committed, this.Commitments, out unused);

                aPreImageBases[0] = Gq.MultiExponentiate(dBases, dExponents); aPreImageExponents[0] = c.Negate(); // g0.gt^xt.Product[gi^xi]_(for disclosed i)
                if (upt.IsDeviceProtected)
                {
                    aPreImageBases[aPreImageArraySize - 1] = ip.Gd; aPreImageExponents[aPreImageArraySize - 1] = this.r[this.r.Length - 1]; // gd^rd
                }
                HashFunction hash = ip.HashFunction;
                hash.Hash(Gq.MultiExponentiate(aPreImageBases, aPreImageExponents));
                if (!this.a.SequenceEqual(hash.Digest))
                {
                    throw new InvalidUProveArtifactException("Invalid presentation proof");
                }

                if (presentPseudonym)
                {
                    hash.Hash(Gq.MultiExponentiate(new GroupElement[] { ps, gs }, new FieldZqElement[] { c, r[pseudonymResponseIndex] }));
                    if (!this.ap.SequenceEqual(hash.Digest))
                    {
                        throw new InvalidUProveArtifactException("Invalid pseudonym");
                    }
                }

                if (verifyCommitments)
                {
                    GroupElement[]   cBases     = new GroupElement[3];
                    FieldZqElement[] cExponents = new FieldZqElement[3];
                    cBases[1]     = Gq.G;
                    cBases[2]     = ip.G[1];
                    cExponents[0] = c;
                    for (int i = 0; i < commitmentResponseIndices.Length; i++)
                    {
                        CommitmentValues commitment = this.Commitments[i];
                        cBases[0]     = commitment.TildeC;
                        cExponents[1] = this.r[commitmentResponseIndices[i]];
                        cExponents[2] = commitment.TildeR;
                        hash.Hash(Gq.MultiExponentiate(cBases, cExponents));
                        if (!commitment.TildeA.SequenceEqual(hash.Digest))
                        {
                            throw new InvalidUProveArtifactException("Invalid commitment " + committed[i]);
                        }
                    }
                }
            }
            catch (ArgumentException)
            {
                throw new InvalidUProveArtifactException("Invalid presentation proof");
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidUProveArtifactException("Invalid presentation proof");
            }
        }
예제 #11
0
        /// <summary>
        /// Generates a presentation proof including optionally presenting a pseudonym, creating attribute commitments, and passing pre-generated random values.
        /// </summary>
        /// <param name="ip">The issuer parameters corresponding to <code>upkt</code>.</param>
        /// <param name="disclosed">An ordered array of disclosed attribute indices.</param>
        /// <param name="committed">An ordered array of committed attribute indices.</param>
        /// <param name="pseudonymAttribIndex">Index of the attribute used to create a scope-exclusive pseudonym, or 0 if no pseudonym is to be presented. The index must not be part of the disclosed attributes.</param>
        /// <param name="gs">The pseudonym scope element, or null if no pseudonym is to be presented.</param>
        /// <param name="message">The presentation message.</param>
        /// <param name="messageD">The message for the Device, or null.</param>
        /// <param name="deviceContext">The active device context, if token is device-protected, or null.</param>
        /// <param name="upkt">The U-Proke key and token.</param>
        /// <param name="attributes">The token attributes.</param>
        /// <param name="preGenW">Optional pregenerated random data for the proof generation.</param>
        /// <param name="cpv">Returned commitment private values if commitments are computed.</param>
        /// <returns>A presentation proof.</returns>
        internal static PresentationProof Generate(IssuerParameters ip, int[] disclosed, int[] committed, int pseudonymAttribIndex, GroupElement gs, byte[] message, byte[] messageD, IDevicePresentationContext deviceContext, UProveKeyAndToken upkt, byte[][] attributes, ProofGenerationRandomData preGenW, out CommitmentPrivateValues cpv)
        {
            if (upkt.Token.IsDeviceProtected && deviceContext == null)
            {
                throw new ArgumentNullException("Device context is not initialized");
            }
            bool generateCommitments = (committed != null && committed.Length > 0);

            FieldZqElement[] tildeO = null;

            // make sure disclosed and committed lists are sorted
            if (disclosed == null)
            {
                // can't be null later, so make it an empty array
                disclosed = new int[] { };
            }
            Array.Sort(disclosed);
            if (generateCommitments)
            {
                Array.Sort(committed);
            }

            int n = 0;

            if (ip.E != null)
            {
                n = ip.E.Length;
                if (n != attributes.Length)
                {
                    throw new ArgumentException("number of attributes is inconsistent with issuer parameters");
                }
            }

            bool presentPseudonym = false;

            if (gs != null)
            {
                if (pseudonymAttribIndex < 1 || (pseudonymAttribIndex > n && pseudonymAttribIndex != DeviceAttributeIndex))
                {
                    throw new ArgumentException("pseudonymAttribIndex must be between 1 and " + n + " (inclusive)");
                }
                if (disclosed.Contains(pseudonymAttribIndex))
                {
                    throw new ArgumentException("pseudonymAttribIndex cannot be in the disclosed attribute array");
                }
                presentPseudonym = true;
            }
            else if (pseudonymAttribIndex > 0)
            {
                throw new ArgumentNullException("gs is null");
            }
            else
            {
                pseudonymAttribIndex = 0;
            }

            Group   Gq = ip.Gq;
            FieldZq Zq = ip.Zq;

            FieldZqElement            xt = ProtocolHelper.ComputeXt(ip, upkt.Token.TI, upkt.Token.IsDeviceProtected);
            ProofGenerationRandomData random;

            if (preGenW == null)
            {
                random = ProofGenerationRandomData.Generate(n - disclosed.Length, generateCommitments ? committed.Length : 0, Zq, upkt.Token.IsDeviceProtected);
            }
            else
            {
                random = preGenW;
            }

            // set up the multi-exponentiation arrays, with h^w0 as the first term
            int multiExpArraySize = 1 + (n - disclosed.Length) + (upkt.Token.IsDeviceProtected ? 1 : 0);

            GroupElement[]   bases     = new GroupElement[multiExpArraySize];
            FieldZqElement[] exponents = new FieldZqElement[multiExpArraySize];
            int multiExpIndex          = 0;

            bases[multiExpIndex]       = upkt.Token.H;
            exponents[multiExpIndex++] = random.W0;

            FieldZqElement[] x      = new FieldZqElement[n];
            int uIndex              = 0;
            int dIndex              = 0;
            int cIndex              = 0;
            PresentationProof proof = new PresentationProof();

            proof.DisclosedAttributes = new byte[disclosed.Length][];
            int pseudonymRandomizerIndex = 0;

            if (generateCommitments)
            {
                proof.Commitments = new CommitmentValues[committed.Length];
                tildeO            = new FieldZqElement[committed.Length];
            }
            HashFunction hash = ip.HashFunction;

            GroupElement[] cBases = new GroupElement[2] {
                Gq.G, ip.G[1]
            };
            for (int i = 0; i < n; i++)
            {
                x[i] = ProtocolHelper.ComputeXi(ip, i, attributes[i]);
                if (!disclosed.Contains(i + 1))
                {
                    bases[multiExpIndex]       = ip.G[i + 1];
                    exponents[multiExpIndex++] = random.W[uIndex];
                    if (presentPseudonym)
                    {
                        if (pseudonymAttribIndex == (i + 1))
                        {
                            pseudonymRandomizerIndex = uIndex;
                        }
                    }

                    if (generateCommitments && committed.Contains(i + 1))
                    {
                        GroupElement tildeC = ip.Gq.MultiExponentiate(cBases, new FieldZqElement[2] {
                            x[i], random.TildeO[cIndex]
                        });
                        tildeO[cIndex] = random.TildeO[cIndex];
                        GroupElement temp2 = ip.Gq.MultiExponentiate(cBases, new FieldZqElement[2] {
                            random.W[uIndex], random.TildeW[cIndex]
                        });
                        hash.Hash(temp2);
                        byte[] tildeA = hash.Digest;
                        proof.Commitments[cIndex] = new CommitmentValues(tildeC, tildeA, null);
                        cIndex++;
                    }

                    uIndex++;
                }
                else if (generateCommitments && committed.Contains(i + 1))
                {
                    throw new ArgumentException("attribute " + (i + 1) + " cannot be both disclosed and committed");
                }
                else
                {
                    proof.DisclosedAttributes[dIndex] = attributes[i];
                    dIndex++;
                }
            }
            GroupElement aPreImage;

            if (upkt.Token.IsDeviceProtected)
            {
                GroupElement ad;
                // pseudonym computed by device
                if (presentPseudonym && pseudonymAttribIndex == DeviceAttributeIndex)
                {
                    GroupElement apPrime;
                    GroupElement Ps;
                    ad = deviceContext.GetInitialWitnessesAndPseudonym(gs, out apPrime, out Ps);
                    hash.Hash(apPrime * gs.Exponentiate(random.Wd));
                    proof.Ap = hash.Digest;
                    proof.Ps = Ps;
                }
                else
                {
                    ad = deviceContext.GetInitialWitness();
                }
                bases[multiExpIndex]       = ip.Gd;
                exponents[multiExpIndex++] = random.Wd;
                aPreImage = Gq.MultiExponentiate(bases, exponents) * ad;
            }
            else
            {
                aPreImage = Gq.MultiExponentiate(bases, exponents);
            }
            hash.Hash(aPreImage);
            proof.a = hash.Digest;

            // pseudonym derived from one token attribute
            if (presentPseudonym && pseudonymAttribIndex != DeviceAttributeIndex)
            {
                hash.Hash(gs.Exponentiate(random.W[pseudonymRandomizerIndex]));
                proof.Ap = hash.Digest;
                proof.Ps = gs.Exponentiate(x[pseudonymAttribIndex - 1]);
            }

            byte[]         mdPrime;
            FieldZqElement c = ProtocolHelper.GenerateChallenge(ip, upkt.Token, proof.a, pseudonymAttribIndex, proof.ap, proof.Ps, message, messageD, disclosed, GetDisclosedX(disclosed, x), committed, proof.Commitments, out mdPrime);

            proof.r    = new FieldZqElement[1 + n - disclosed.Length + (upkt.Token.IsDeviceProtected ? 1 : 0)]; // r_0, {r_i} for undisclosed i, r_d
            proof.r[0] = c * upkt.PrivateKey + random.W0;
            uIndex     = 1;
            for (int i = 1; i <= n; i++)
            {
                if (!disclosed.Contains(i))
                {
                    proof.r[uIndex] = c.Negate() * x[i - 1] + random.W[uIndex - 1];
                    uIndex++;
                }
            }
            if (upkt.Token.IsDeviceProtected)
            {
                proof.r[proof.r.Length - 1] = deviceContext.GetDeviceResponse(messageD, mdPrime, ip.HashFunctionOID) + random.Wd;
            }
            if (generateCommitments)
            {
                for (int i = 0; i < committed.Length; i++)
                {
                    proof.Commitments[i].TildeR = c.Negate() * random.TildeO[i] + random.TildeW[i];
                }
            }

            random.Clear();
            cpv = new CommitmentPrivateValues(tildeO);
            return(proof);
        }
예제 #12
0
        /// <summary>
        /// Generates the U-Prove key and tokens.
        /// </summary>
        /// <param name="message">The third issuance message.</param>
        /// <param name="skipTokenValidation">Set to <code>true</code> to skip token validation;
        /// <code>false</code> otherwise. Token validation SHOULD be performed before use, either
        /// by setting <code>skipTokenValidation</code> to <code>false</code>, or by later using the
        /// <code>ProtocolHelper.VerifyTokenSignature</code> method.
        /// </param>
        /// <exception cref="InvalidUProveArtifactException">If the token signature is invalid.</exception>
        /// <returns>An array of U-Prove keys and tokens</returns>
        public UProveKeyAndToken[] GenerateTokens(ThirdIssuanceMessage message, bool skipTokenValidation = false)
        {
            if (state != State.Second)
            {
                throw new InvalidOperationException("GenerateSecondMessage must be called first");
            }

            bool doBatchValidation  = !skipTokenValidation && batchValidationSecurityLevel > 0;
            bool doNormalValidation = !skipTokenValidation && batchValidationSecurityLevel <= 0;

            Group   Gq = ip.Gq;
            FieldZq Zq = ip.Zq;

            FieldZqElement[] sigmaRPrime = new FieldZqElement[numberOfTokens];

            FieldZqElement phoAR = Zq.Zero, phoR = Zq.Zero, phoAC = Zq.Zero, phoC = Zq.Zero;
            GroupElement   batchAcc = Gq.Identity;

            for (int i = 0; i < numberOfTokens; i++)
            {
                sigmaRPrime[i] = message.sigmaR[i] + beta2[i];
                if (doBatchValidation)
                {
                    FieldZqElement s = Zq.GetRandomElement(true, batchValidationSecurityLevel);
                    phoAR    += (s * alpha[i] * sigmaRPrime[i]);
                    phoR     += (s * sigmaRPrime[i]);
                    phoAC    += (s * alpha[i] * sigmaCPrime[i]);
                    phoC     += (s * sigmaCPrime[i]);
                    batchAcc *= (sigmaAPrime[i] * sigmaBPrime[i]).Exponentiate(s);
                }
                else if (doNormalValidation)
                {
                    if (!(sigmaAPrime[i] * sigmaBPrime[i]).Equals(
                            ((Gq.G * h[i]).Exponentiate(sigmaRPrime[i]) * (ip.G[0] * sigmaZPrime[i]).Exponentiate(sigmaCPrime[i].Negate()))))
                    {
                        throw new InvalidUProveArtifactException("Invalid token signature: " + i);
                    }
                }
                ukat[i].Token = new UProveToken(ip.UidP, h[i], TI, PI, sigmaZPrime[i], sigmaCPrime[i], sigmaRPrime[i], isDeviceProtected);
            }
            if (doBatchValidation &&
                (batchAcc != Gq.G.Exponentiate(phoR) * gamma.Exponentiate(phoAR) * ip.G[0].Exponentiate(phoC.Negate()) * sigmaZ.Exponentiate(phoAC.Negate())))
            {
                throw new InvalidUProveArtifactException("Invalid token signature");
            }

            state = State.Tokens;
            return(ukat);
        }
예제 #13
0
        // Verifies the pre-issuance proof, and returns the element gamma needed for the token issuance.
        /// <summary>
        /// Verifies a pre-issuance proof and returns the element gamma needed for collaborative issuance.
        /// </summary>
        /// <param name="ipip">The pre-issuance proof parameters for the Issuer</param>
        /// <param name="proof">The proof to be verified</param>
        /// <param name="message">An optional message to be verified (must match the one signed by the prover)</param>
        /// <returns>The group element <c>gamma^beta0</c>, a blinded version of the element gamma used during token issuance.</returns>
        /// <exception cref="InvalidUProveArtifactException">Thrown if the proof is invalid.</exception>
        public static GroupElement VerifyProof(IssuerPreIssuanceParameters ipip, PreIssuanceProof proof, byte[] message)
        {
            // Validate paramters first
            ipip.Validate();

            // extension by Fablei -> need to know the number of attributes involved in this proof -> ip.G.length
            int ipGLength = proof.na + 2;

            IssuerParameters ip = ipip.IP;
            FieldZq          Zq = ip.Zq;
            Group            Gq = ip.Gq;

            List <GroupElement>   bases     = new List <GroupElement>();
            List <FieldZqElement> exponents = new List <FieldZqElement>();

            GroupElement[] C      = null;
            GroupElement[] CPrime = null;

            FieldZqElement c = Zq.GetElementFromDigest(proof.c);

            if (ipip.HasCarryOverAttributes)
            {
                // validate presentation proof
                int[] disclosed = new int[] {};
                VerifierPresentationProtocolParameters vppp = new VerifierPresentationProtocolParameters(ipip.SourceIP, disclosed, message, ipip.Tokens);
                vppp.Committed = ipip.Corig;

                try
                {
                    proof.presentation.Verify(vppp);
                }
                catch (InvalidUProveArtifactException e)
                {
                    throw new InvalidUProveArtifactException("Failed to verify pre-Issuance proof, presentation proof " + 0 + " failed to verify (" + e.ToString() + ")");
                }

                // extract the commitments
                C      = new GroupElement[ipip.C.Length];
                CPrime = new GroupElement[ipip.C.Length];
                for (int i = 0; i < C.Length; i++)
                {
                    C[i] = proof.presentation.Commitments[i].TildeC;

                    // Compute the CPrime[i] values.
                    bases     = new List <GroupElement>();
                    exponents = new List <FieldZqElement>();
                    bases.Add(C[i]);
                    exponents.Add(c);
                    bases.Add(Gq.G);
                    exponents.Add(proof.GetResponse("sx" + ipip.C[i]));
                    bases.Add(ip.G[1]);
                    exponents.Add(proof.GetResponse("sR" + i));
                    CPrime[i] = Gq.MultiExponentiate(bases.ToArray(), exponents.ToArray());
                    //Debug.WriteLine("CPrime[i] = " + BitConverter.ToString(CPrime[i].GetEncoded()));
                }
            }

            // Compute D'
            FieldZqElement sd     = proof.GetResponse("sD");
            GroupElement   DPrime = Gq.MultiExponentiate(proof.Ch0, proof.h0, c, c.Negate()); // TODO: add Inverse() to group element to simplify this

            DPrime = DPrime.Multiply(Gq.G.Exponentiate(sd));
            //Debug.WriteLine("DPrime = " + BitConverter.ToString(DPrime.GetEncoded()));

            // Compute T'
            FieldZqElement sBeta0 = proof.GetResponse("sBeta0");
            GroupElement   TPrime = Gq.MultiExponentiate(proof.Ch0, proof.CGamma, c, sBeta0);

            //Debug.WriteLine("TPrime = " + BitConverter.ToString(TPrime.GetEncoded()));

            // Compute gammaK (product of known attributes)
            bases     = new List <GroupElement>();
            exponents = new List <FieldZqElement>();
            //int t = ip.G.Length-1;
            // extension by Fablei
            int            t  = ipGLength - 1;
            FieldZqElement xt = ProtocolHelper.ComputeXt(ip, ipip.TI, ipip.DeviceProtected);

            bases.Add(ip.G[0]);
            exponents.Add(ip.Zq.One);
            bases.Add(ip.G[t]);
            exponents.Add(xt);  // gammaK = g0*(gt^xt)
            for (int i = 1; i < ipGLength - 1; i++)
            {
                if (ipip.K.Contains(i))
                {
                    FieldZqElement xi = ProtocolHelper.ComputeXi(ip, i - 1, ipip.Attributes[i - 1]);
                    bases.Add(ip.G[i]);
                    exponents.Add(xi);
                }
            }
            GroupElement gammaK = Gq.MultiExponentiate(bases.ToArray(), exponents.ToArray());

            // Compute Cgamma'
            bases     = new List <GroupElement>();
            exponents = new List <FieldZqElement>();
            bases.Add(proof.CGamma);
            exponents.Add(c);
            bases.Add(gammaK);
            exponents.Add(c.Negate());  // TODO: do with one exp; i.e., (CGamma/gammaK)^c
            for (int i = 1; i < ipGLength - 1; i++)
            {
                if (!ipip.K.Contains(i))
                {
                    FieldZqElement sxi = proof.GetResponse("sx" + i);
                    bases.Add(ip.G[i]);
                    exponents.Add(sxi);
                }
            }
            bases.Add(Gq.G);
            exponents.Add(proof.GetResponse("sRho"));
            GroupElement CgammaPrime = Gq.MultiExponentiate(bases.ToArray(), exponents.ToArray());

            // TODO: if deviceprotected multiply device base/response.
            //Debug.WriteLine("CgammaPrime = " + BitConverter.ToString(CgammaPrime.GetEncoded()));

            // Recompute challenge
            byte[] cPrime = ComputeChallenge(ip, proof.h0, proof.CGamma, proof.Ch0, C, DPrime, CgammaPrime, TPrime, CPrime, message);
            //Debug.WriteLine("c' = " + BitConverter.ToString(cPrime));

            if (!cPrime.SequenceEqual <byte>(proof.c))
            {
                throw new InvalidUProveArtifactException("invalid proof");
            }

            return(proof.h0);
        }
예제 #14
0
        public void Verify(IssuerParameters ip, int[] disclosed, int[] committed, int pseudonymAttribIndex, GroupElement gs, byte[] message, byte[] messageD, UProveToken upt)
        {
            try
            {
                // make sure disclosed list is sorted
                if (disclosed == null)
                {
                    // can't be null later, so make it an empty array
                    disclosed = new int[] { };
                }
                Array.Sort(disclosed);
                Group Gq = ip.Gq;
                int   n  = ip.E.Length;

                bool presentPseudonym = false;
                if (gs != null && pseudonymAttribIndex != 0)
                {
                    if (pseudonymAttribIndex < 1 || (pseudonymAttribIndex > n && pseudonymAttribIndex != DeviceAttributeIndex))
                    {
                        throw new ArgumentException("pseudonymAttribIndex must be between 1 and " + n + " (inclusive)");
                    }
                    if (disclosed.Contains(pseudonymAttribIndex))
                    {
                        throw new ArgumentException("pseudonymAttribIndex cannot be in the disclosed attribute array");
                    }
                    presentPseudonym = true;
                }
                else // no nym
                {
                    pseudonymAttribIndex = 0;
                }
                bool verifyCommitments = (committed != null && committed.Length > 0);
                if (verifyCommitments)
                {
                    Array.Sort(committed);
                }

                ProtocolHelper.VerifyTokenSignature(ip, upt);
                FieldZqElement[] disclosedX   = new FieldZqElement[disclosedAttributes.Length];
                GroupElement     dAccumulator = ip.G[0] * ip.G[n + 1].Exponentiate(ProtocolHelper.ComputeXt(ip, upt.TI, upt.IsDeviceProtected)); // g0 * gt^xt
                GroupElement     uAccumulator = upt.H.Exponentiate(this.r[0]);
                int   dIndex = 0;
                int   uIndex = 1;
                int   cIndex = 0;
                int   pseudonymResponseIndex    = 0;
                int[] commitmentResponseIndices = verifyCommitments ? new int[committed.Length] : null;
                for (int i = 1; i <= n; i++)
                {
                    if (disclosed.Contains(i))
                    {
                        disclosedX[dIndex] = ProtocolHelper.ComputeXi(ip, i - 1, disclosedAttributes[dIndex]);
                        dAccumulator       = dAccumulator * ip.G[i].Exponentiate(disclosedX[dIndex]);
                        dIndex++;
                    }
                    else
                    {
                        uAccumulator = uAccumulator * ip.G[i].Exponentiate(this.r[uIndex]);
                        if (presentPseudonym)
                        {
                            if (pseudonymAttribIndex == i)
                            {
                                pseudonymResponseIndex = uIndex;
                            }
                        }
                        if (verifyCommitments)
                        {
                            if (committed.Contains(i))
                            {
                                // remember which response correspond to which commitment
                                commitmentResponseIndices[cIndex] = uIndex;
                                cIndex++;
                            }
                        }
                        uIndex++;
                    }
                }
                if (pseudonymAttribIndex == DeviceAttributeIndex)
                {
                    pseudonymResponseIndex = this.r.Length - 1; // r_d is the last response in the array
                }

                byte[]         unused; // verifier doesn't use the returned message for device
                FieldZqElement c = ProtocolHelper.GenerateChallenge(ip, upt, this.a, pseudonymAttribIndex, this.ap, this.ps, message, messageD, disclosed, disclosedX, committed, this.Commitments, out unused);

                HashFunction hash = ip.HashFunction;
                hash.Hash((dAccumulator.Exponentiate(c.Negate()) * uAccumulator * (upt.IsDeviceProtected ? ip.Gd.Exponentiate(this.r[this.r.Length - 1]) : Gq.Identity)));
                if (!this.a.SequenceEqual(hash.Digest))
                {
                    throw new InvalidUProveArtifactException("Invalid presentation proof");
                }

                if (presentPseudonym)
                {
                    hash.Hash(this.ps.Exponentiate(c).Multiply(gs.Exponentiate(this.r[pseudonymResponseIndex])));
                    if (!this.ap.SequenceEqual(hash.Digest))
                    {
                        throw new InvalidUProveArtifactException("Invalid pseudonym");
                    }
                }

                if (verifyCommitments)
                {
                    for (int i = 0; i < commitmentResponseIndices.Length; i++)
                    {
                        CommitmentValues commitment = this.Commitments[i];
                        hash.Hash(commitment.TildeC.Exponentiate(c).Multiply(ip.Gq.G.Exponentiate(this.r[commitmentResponseIndices[i]])).Multiply(ip.G[1].Exponentiate(commitment.TildeR)));
                        if (!commitment.TildeA.SequenceEqual(hash.Digest))
                        {
                            throw new InvalidUProveArtifactException("Invalid commitment " + committed[i]);
                        }
                    }
                }
            }
            catch (ArgumentException)
            {
                throw new InvalidUProveArtifactException("Invalid presentation proof");
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidUProveArtifactException("Invalid presentation proof");
            }
        }
예제 #15
0
        /// <summary>
        /// Computes the revocation witness for a specific user attribute.
        /// </summary>
        /// <param name="revoked">Set of revoked values.</param>
        /// <param name="xid">The user attribute.</param>
        /// <returns>A revocation witness.</returns>
        public RevocationWitness ComputeRevocationWitness(HashSet <FieldZqElement> revoked, FieldZqElement xid)
        {
            if (revoked.Contains(xid))
            {
                throw new ArgumentException("xid cannot be in revoked set");
            }
            Group          Gq             = RAParameters.group;
            FieldZq        Zq             = Gq.FieldZq;
            FieldZqElement d              = Zq.One;
            FieldZqElement deltaPlusXProd = Zq.One;

            foreach (var x in revoked)
            {
                if (x + this.PrivateKey == Zq.Zero)
                {
                    throw new ArgumentException("revocationList cannot contain the negation of the private key");
                }
                d *= (x - xid);
                deltaPlusXProd *= (this.PrivateKey + x);
            }

            GroupElement W = RAParameters.gt.Exponentiate((deltaPlusXProd - d) * (PrivateKey + xid).Invert());
            GroupElement Q = Gq.MultiExponentiate(new GroupElement[] { Accumulator, W, RAParameters.gt }, new FieldZqElement[] { Zq.One, xid.Negate(), d.Negate() });

            return(new RevocationWitness(d, W, Q));
        }