/// <summary> /// Verifies a U-Prove token signature. /// </summary> /// <param name="ip">The Issuer parameters corresponding to the U-Prove token.</param> /// <param name="upt">The U-Prove token to verify.</param> /// <exception cref="InvalidUProveArtifactException">If the U-Prove token is invalid.</exception> public static void VerifyTokenSignature(IssuerParameters ip, UProveToken upt) { Group Gq = ip.Gq; FieldZq Zq = ip.Zq; if (upt.H == Gq.Identity) { throw new InvalidUProveArtifactException("Invalid U-Prove token (public key H = 1)"); } GroupElement[] bases = new GroupElement[2]; FieldZqElement[] exponents = new FieldZqElement[2]; HashFunction hash = ip.HashFunction; hash.Hash(upt.H); hash.Hash(upt.PI); hash.Hash(upt.SigmaZPrime); bases[0] = Gq.G; exponents[0] = upt.SigmaRPrime; bases[1] = ip.G[0]; exponents[1] = upt.SigmaCPrime.Negate(); hash.Hash(Gq.MultiExponentiate(bases, exponents)); bases[0] = upt.H; exponents[0] = upt.SigmaRPrime; bases[1] = upt.SigmaZPrime; exponents[1] = upt.SigmaCPrime.Negate(); hash.Hash(Gq.MultiExponentiate(bases, exponents)); if (upt.SigmaCPrime != Zq.GetElementFromDigest(hash.Digest)) { throw new InvalidUProveArtifactException("Invalid U-Prove token signature"); } }
/// <summary> /// Verifies a non-revocation proof. /// </summary> /// <param name="ip">The issuer parameters associated with the proof.</param> /// <param name="revocationCommitmentIndex">The 0-based index corresponding to the revocation commitment in the proof.</param> /// <param name="proof">The presentation proof.</param> /// <param name="nrProof">The non-revocation proof.</param> /// <exception cref="InvalidUProveArtifactException">Thrown if the proof is invalid.</exception> public void VerifyNonRevocationProof(IssuerParameters ip, int revocationCommitmentIndex, PresentationProof proof, NonRevocationProof nrProof) { Group Gq = ip.Gq; FieldZq Zq = Gq.FieldZq; GroupElement tildeCid = proof.Commitments[revocationCommitmentIndex].TildeC; // T1 = (V Y^-1 Cd^-1)^c' * X^s1 * (tildeCid K)^-s2 * g1^s3 GroupElement T1 = Gq.MultiExponentiate( new GroupElement[] { Accumulator *nrProof.Y.Exponentiate(Zq.NegativeOne) * nrProof.Cd.Exponentiate(Zq.NegativeOne), // TODO: is there a better way to calculate this nrProof.X, tildeCid * RAParameters.K, RAParameters.g1 }, new FieldZqElement[] { nrProof.cPrime, nrProof.s[0], // s1 nrProof.s[1].Negate(), // s2 nrProof.s[2] // s3 }); // T2 = tildeCid^c' g^s1 g1^s4 GroupElement T2 = Gq.MultiExponentiate( new GroupElement[] { tildeCid, RAParameters.g, RAParameters.g1 }, new FieldZqElement[] { nrProof.cPrime, nrProof.s[0], // s1 nrProof.s[3], // s4 }); // T3 = gt^c' Cd^s5 g1^s6 GroupElement T3 = Gq.MultiExponentiate( new GroupElement[] { RAParameters.gt, nrProof.Cd, RAParameters.g1 }, new FieldZqElement[] { nrProof.cPrime, nrProof.s[4], // s5 nrProof.s[5], // s6 }); if (!nrProof.cPrime.Equals(Zq.GetElementFromDigest(RAParameters.ComputeChallenge(tildeCid, nrProof.X, nrProof.Y, nrProof.Cd, T1, T2, T3))) || !nrProof.Y.Equals(nrProof.X.Exponentiate(PrivateKey))) { throw new InvalidUProveArtifactException("Invalid non-revocation proof"); } }
// Compute c = H(IP, T, H, Cxb, E1, E2, Cxb', E1', E2', additionalInfo) private static FieldZqElement ComputeChallenge(IssuerParameters ip, byte[] tokenID, IDEscrowPublicKey pk, GroupElement Cxb, GroupElement E1, GroupElement E2, GroupElement CxbPrime, GroupElement E1Prime, GroupElement E2Prime, byte[] additionalInfo) { HashFunction hasher = ip.HashFunction; FieldZq F = ip.Zq; hasher.Hash(ip.UidP); hasher.Hash(tokenID); hasher.Hash(pk.H); hasher.Hash(Cxb); hasher.Hash(E1); hasher.Hash(E2); hasher.Hash(CxbPrime); hasher.Hash(E1Prime); hasher.Hash(E2Prime); hasher.Hash(additionalInfo); // additionalInfo may be null, and Hash() will handle this correctly. return(F.GetElementFromDigest(hasher.Digest)); }
/// <summary> /// Verifies a U-Prove token signature. /// </summary> /// <param name="ip">The Issuer parameters corresponding to the U-Prove token.</param> /// <param name="upt">The U-Prove token to verify.</param> /// <exception cref="InvalidUProveArtifactException">If the U-Prove token is invalid.</exception> public static void VerifyTokenSignature(IssuerParameters ip, UProveToken upt) { Group Gq = ip.Gq; FieldZq Zq = ip.Zq; if (upt.H == Gq.Identity) { throw new InvalidUProveArtifactException("Invalid U-Prove token (public key H = 1)"); } HashFunction hash = ip.HashFunction; hash.Hash(upt.H); hash.Hash(upt.PI); hash.Hash(upt.SigmaZPrime); hash.Hash(Gq.G.Exponentiate(upt.SigmaRPrime) * ip.G[0].Exponentiate(upt.SigmaCPrime.Negate())); hash.Hash(upt.H.Exponentiate(upt.SigmaRPrime) * upt.SigmaZPrime.Exponentiate(upt.SigmaCPrime.Negate())); if (upt.SigmaCPrime != Zq.GetElementFromDigest(hash.Digest)) { throw new InvalidUProveArtifactException("Invalid U-Prove token signature"); } }
/// <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)); }
internal static FieldZqElement GenerateChallengeForDevice(FieldZq zq, HashFunction hash, byte[] md, byte[] mdPrime) { hash.Hash(md); hash.Hash(mdPrime); return(zq.GetElementFromDigest(hash.Digest)); }
internal static FieldZqElement GenerateChallengeForDevice(FieldZq zq, HashFunction hash, byte[] md, byte[] cp) { hash.Hash(new byte[][] { cp, md }); return(zq.GetElementFromDigest(hash.Digest)); }
// 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); }
/// <summary> /// Create a new pre-issuance proof. /// </summary> /// <param name="pipp">The prover parameters.</param> /// <param name="beta0">The random blinding value used to create the proof, output so that the prover can use it during the issuance protocol</param> /// <param name="message">An optional message to sign while creating the proof.</param> /// <returns></returns> public static PreIssuanceProof CreateProof(ProverPreIssuanceParameters pipp, out FieldZqElement beta0, byte[] message) { // validate paramters first pipp.Validate(); bool supportDevice = (pipp.DevicePublicKey == null) ? false : true; IssuerParameters ip = pipp.IP; FieldZq Zq = ip.Zq; Group Gq = ip.Gq; Dictionary <string, FieldZqElement> responses = new Dictionary <string, FieldZqElement>(); // these will be used if there is a carry-over attribute CommitmentPrivateValues cpv = null; PresentationProof presProof = null; GroupElement[] C = null; GroupElement[] tildeC = null; FieldZqElement[] tildeR = null; // extension by Fablei -> needs to calculate the ip.G.Length -> pipp.Attributes.Length + 2 int ipGLength = pipp.Attributes.Length + 2; // Generate random values beta0 = Zq.GetRandomElement(true); FieldZqElement tildeBeta0 = Zq.GetRandomElement(true); FieldZqElement rho = Zq.GetRandomElement(true); FieldZqElement tildeRho = Zq.GetRandomElement(true); FieldZqElement tilde_d = Zq.GetRandomElement(true); FieldZqElement[] tildeX = new FieldZqElement[ipGLength - 1]; for (int i = 1; i < ipGLength - 1; i++) { if (!pipp.K.Contains(i)) { tildeX[i] = Zq.GetRandomElement(true); } } // Compute the U-Prove presentation proof, if there are carry-over attributes if (pipp.HasCarryOverAttributes) { // generate the presentation proof int[] disclosed = new int[] { }; ProverPresentationProtocolParameters pppp = new ProverPresentationProtocolParameters(pipp.SourceIP, disclosed, message, pipp.KeyAndToken, pipp.SourceAttributes); pppp.Committed = pipp.Corig; // TODO: What if the source token is device protected? need to handle this as well. (a pointer to the device should be included in pipp //if (device != null) //{ // pppp.SetDeviceData(deviceMessage, device.GetPresentationContext()); //}- // For now just fail: if (pipp.KeyAndToken.Token.IsDeviceProtected) { throw new NotImplementedException("Device protected tokens may not be used for carry-over attributes"); } presProof = PresentationProof.Generate(pppp, out cpv); //set C C = new GroupElement[pipp.C.Length]; // Generate random values for the commitment randomizers tildeR = Zq.GetRandomElements(pipp.C.Length, true); tildeC = new GroupElement[C.Length]; for (int i = 0; i < C.Length; i++) { C[i] = presProof.Commitments[i].TildeC; tildeC[i] = Gq.MultiExponentiate(Gq.G, ip.G[1], tildeX[pipp.C[i]], tildeR[i]); } } // end if cary-over attributes // Compute gamma GroupElement gamma = ProtocolHelper.ComputeIssuanceInput(ip, pipp.Attributes, pipp.TI, pipp.DevicePublicKey); // Compute h0, Cgamma, Ch0, tildeD, tildeT: GroupElement h0 = gamma.Exponentiate(beta0); GroupElement Cgamma = gamma.Multiply(Gq.G.Exponentiate(rho)); // Cgamma = gamma*(g^rho) GroupElement Ch0 = Cgamma.Exponentiate(beta0); GroupElement tildeD = Gq.G.Exponentiate(tilde_d); GroupElement tildeT = Cgamma.Exponentiate(tildeBeta0); // Compute tildeCgamma: List <GroupElement> bases = new List <GroupElement>(); List <FieldZqElement> exponents = new List <FieldZqElement>(); bases.Add(Gq.G); exponents.Add(tildeRho); for (int i = 1; i < ipGLength - 1; i++) { if (!pipp.K.Contains(i)) // i \not\in K { bases.Add(ip.G[i]); exponents.Add(tildeX[i]); } } GroupElement tildeCgamma = Gq.MultiExponentiate(bases.ToArray(), exponents.ToArray()); // TODO: if device protected, then multiply tildeCgamma by the public key // Note: We leave TI out, (i.e., (g_t)^(x_t) because t \in K implicitly. // Compute the challenge byte[] c = ComputeChallenge(ip, h0, Cgamma, Ch0, C, tildeD, tildeCgamma, tildeT, tildeC, message); FieldZqElement negc = Zq.GetElementFromDigest(c).Negate(); // Compute the responses responses.Add("sBeta0", tildeBeta0.Add(beta0.Multiply(negc))); // sBeta0 = tildeBeta0 - beta0*c responses.Add("sD", tilde_d.Add(beta0.Multiply(rho).Multiply(negc))); // sD = tilde_d - beta0*rho*c responses.Add("sRho", tildeRho.Add(rho.Multiply(negc))); // sRho = tildeRho - rho*c for (int i = 1; i < ipGLength - 1; i++) { if (!pipp.K.Contains(i)) // in \not\in K { FieldZqElement xi = ProtocolHelper.ComputeXi(ip, i - 1, pipp.Attributes[i - 1]); responses.Add("sx" + i, tildeX[i].Add(xi.Multiply(negc))); // sxi = tildeX[i] - xi*c } } if (pipp.HasCarryOverAttributes) { for (int i = 0; i < C.Length; i++) { responses.Add("sR" + i, tildeR[i].Add(cpv.TildeO[i].Multiply(negc))); // sRi = tildeR[i] - tildeO[i]*c } } return(new PreIssuanceProof(h0, Cgamma, Ch0, c, responses, pipp.HasCarryOverAttributes ? presProof : null, pipp.Attributes.Length)); }