/// <summary> /// Generates the second issuance message. /// </summary> /// <param name="message">The first issuance message.</param> /// <returns>The second issuance message.</returns> public SecondIssuanceMessage GenerateSecondMessage(FirstIssuanceMessage message) { if (state != State.Initialized) { throw new InvalidOperationException("Prover not initialized properly"); } Group Gq = ip.Gq; this.sigmaZ = message.sigmaZ; sigmaZPrime = new GroupElement[numberOfTokens]; sigmaAPrime = new GroupElement[numberOfTokens]; sigmaBPrime = new GroupElement[numberOfTokens]; sigmaCPrime = new FieldZqElement[numberOfTokens]; FieldZqElement[] sigmaC = new FieldZqElement[numberOfTokens]; for (int i = 0; i < numberOfTokens; i++) { FieldZqElement blindingExponent = alpha[i]; sigmaZPrime[i] = message.sigmaZ.Exponentiate(blindingExponent); sigmaAPrime[i] = t1[i] * message.sigmaA[i]; sigmaBPrime[i] = sigmaZPrime[i].Exponentiate(beta1[i]) * t2[i] * message.sigmaB[i].Exponentiate(blindingExponent); HashFunction hash = ip.HashFunction; hash.Hash(h[i]); hash.Hash(PI); hash.Hash(sigmaZPrime[i]); hash.Hash(sigmaAPrime[i]); hash.Hash(sigmaBPrime[i]); sigmaCPrime[i] = ip.Zq.GetElementFromDigest(hash.Digest); sigmaC[i] = sigmaCPrime[i] + beta1[i]; } state = State.Second; return(new SecondIssuanceMessage(sigmaC)); }
/// <summary> /// Generates the second issuance message. /// </summary> /// <param name="message">The first issuance message.</param> /// <returns>The second issuance message.</returns> public SecondIssuanceMessage GenerateSecondMessage(FirstIssuanceMessage message) { if (state != State.Initialized) { throw new InvalidOperationException("Prover not initialized properly"); } Group Gq = ip.Gq; this.sigmaZ = message.sigmaZ.Exponentiate(beta0Inverse); // remove the blind that was included in gamma (if no blind beta0Inverse = 1) sigmaZPrime = new GroupElement[numberOfTokens]; sigmaAPrime = new GroupElement[numberOfTokens]; sigmaBPrime = new GroupElement[numberOfTokens]; sigmaCPrime = new FieldZqElement[numberOfTokens]; FieldZqElement[] sigmaC = new FieldZqElement[numberOfTokens]; for (int i = 0; i < numberOfTokens; i++) { FieldZqElement sigmaBExponent = alpha[i].Multiply(beta0Inverse); // will remove the collab-issuance blind, if present sigmaZPrime[i] = this.sigmaZ.Exponentiate(alpha[i]); sigmaAPrime[i] = t1[i] * message.sigmaA[i]; sigmaBPrime[i] = Gq.MultiExponentiate(new GroupElement[] { sigmaZPrime[i], h[i], message.sigmaB[i] }, new FieldZqElement[] { beta1[i], beta2[i], sigmaBExponent }); HashFunction hash = ip.HashFunction; hash.Hash(h[i]); hash.Hash(PI); hash.Hash(sigmaZPrime[i]); hash.Hash(sigmaAPrime[i]); hash.Hash(sigmaBPrime[i]); sigmaCPrime[i] = ip.Zq.GetElementFromDigest(hash.Digest); sigmaC[i] = sigmaCPrime[i] + beta1[i]; } state = State.Second; return(new SecondIssuanceMessage(sigmaC)); }
// Private helper function private static byte[] ComputeChallenge(IssuerParameters ip, GroupElement h0, GroupElement CGamma, GroupElement Ch0, GroupElement[] C, GroupElement tildeD, GroupElement tildeCgamma, GroupElement tildeT, GroupElement[] tildeC, byte[] message) { HashFunction H = ip.HashFunction; H.Hash(ip.Digest(false)); H.Hash(h0); H.Hash(CGamma); H.Hash(Ch0); H.Hash(C); H.Hash(tildeD); H.Hash(tildeCgamma); H.Hash(tildeT); H.Hash(tildeC); H.Hash(message); byte[] digest = H.Digest; #if DEBUG Debug.WriteLine("h0 = " + BitConverter.ToString(h0.GetEncoded())); Debug.WriteLine("CGamma = " + BitConverter.ToString(CGamma.GetEncoded())); Debug.WriteLine("Ch0 = " + BitConverter.ToString(Ch0.GetEncoded())); if (tildeC != null) { Debug.WriteLine("tildeC[0] = " + BitConverter.ToString(tildeC[0].GetEncoded())); } Debug.WriteLine("tildeD = " + BitConverter.ToString(tildeD.GetEncoded())); Debug.WriteLine("tildeT = " + BitConverter.ToString(tildeT.GetEncoded())); Debug.WriteLine("tildeCgamma = " + BitConverter.ToString(tildeCgamma.GetEncoded())); Debug.WriteLine("digest = " + BitConverter.ToString(digest)); #endif return(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)"); } 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"); } }
internal static FieldZqElement ComputeXt(IssuerParameters ip, byte[] TI, bool supportDevice) { HashFunction hash = ip.HashFunction; hash.Hash((byte)1); hash.Hash(ip.Digest(supportDevice)); hash.Hash(TI); return(ip.Zq.GetElementFromDigest(hash.Digest)); }
/// <summary> /// Computes the U-Prove token identifier. /// </summary> /// <param name="ip">The issuer parameters associated with <code>upt</code>.</param> /// <param name="upt">The U-Prove token from which to compute the identifier.</param> /// <returns></returns> public static byte[] ComputeTokenID(IssuerParameters ip, UProveToken upt) { HashFunction hash = ip.HashFunction; hash.Hash(upt.H); hash.Hash(upt.SigmaZPrime); hash.Hash(upt.SigmaCPrime); hash.Hash(upt.SigmaRPrime); return(hash.Digest); }
/// <summary> /// Computes the value x_i. /// A field element is computed from an attribute value /// </summary> /// <param name="ip"> The issuer paramters</param> /// <param name="i"> The index of the attribute</param> /// <param name="A"> An array contianing the attributes</param> /// <returns></returns> public static FieldZqElement ComputeXi(IssuerParameters ip, int i, byte[] A) { FieldZqElement xi; if (ip.E[i] == 0x01) // hash { if (A == null) { xi = ip.Zq.Zero; } else { HashFunction hash = ip.HashFunction; hash.Hash(A); xi = ip.Zq.GetElementFromDigest(hash.Digest); } } else if (ip.E[i] == 0x00) // do not hash { if (A == null) { throw new ArgumentNullException("A", "A can't be null when ip.E[i] == 0x00"); } else { xi = ip.Zq.GetElement(A); } } else { throw new ArgumentException("invalid E[" + i + "] value"); } return(xi); }
/// <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"); } }
public void HashFormattingTest() { HashFunction hash; // byte hash = new HashFunction(TestVectorData.HashVectors.UIDh); byte b = 0x01; hash.Hash(b); Assert.IsTrue(HexToBytes(TestVectorData.HashVectors.hash_byte).SequenceEqual(hash.Digest), "hash_byte"); // octet string hash = new HashFunction(TestVectorData.HashVectors.UIDh); byte[] octetString = new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05 }; hash.Hash(octetString); Assert.IsTrue(HexToBytes(TestVectorData.HashVectors.hash_octetstring).SequenceEqual(hash.Digest), "hash_octetstring"); // null hash = new HashFunction(TestVectorData.HashVectors.UIDh); hash.HashNull(); Assert.IsTrue(HexToBytes(TestVectorData.HashVectors.hash_null).SequenceEqual(hash.Digest), "hash_null"); // list hash = new HashFunction(TestVectorData.HashVectors.UIDh); hash.Hash(3); // list length hash.Hash(b); hash.Hash(octetString); hash.HashNull(); Assert.IsTrue(HexToBytes(TestVectorData.HashVectors.hash_list).SequenceEqual(hash.Digest), "hash_list"); // subgroup 1.3.6.1.4.1.311.75.1.1.1 hash = new HashFunction(TestVectorData.HashVectors.UIDh); hash.Hash(SubgroupParameterSets.ParamSetL2048N256V1.Group); Assert.IsTrue(HexToBytes(TestVectorData.HashVectors.hash_subgroup).SequenceEqual(hash.Digest), "hash_subgroup"); // ec group 1.3.6.1.4.1.311.75.1.2.1 hash = new HashFunction(TestVectorData.HashVectors.UIDh); hash.Hash(ECParameterSets.ParamSet_EC_P256_V1.Group); Assert.IsTrue(HexToBytes(TestVectorData.HashVectors.hash_ecgroup).SequenceEqual(hash.Digest), "hash_ecgroup"); }
private byte[] ComputeDigest(bool deviceProtected) { HashFunction H = this.HashFunction; H.Hash(UidP); H.Hash(group); if (deviceProtected) { // Gd must be part of the Gi array GroupElement[] GWithGd = new GroupElement[G.Length + 1]; Array.Copy(G, GWithGd, G.Length); GWithGd[G.Length] = gd; H.Hash(GWithGd); } else { H.Hash(G); } H.Hash(E); H.Hash(S); return(H.Digest); }
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[] mdPrime) { hash.Hash(md); hash.Hash(mdPrime); return zq.GetElementFromDigest(hash.Digest); }
internal static FieldZqElement GenerateChallenge(IssuerParameters ip, UProveToken upt, byte[] a, int pseudonymIndex, byte[] ap, GroupElement Ps, byte[] m, byte[] md, int[] disclosed, FieldZqElement[] disclosedX, int[] committed, CommitmentValues[] commitments, out byte[] mdPrime) { bool hasCommitments = (committed != null && committed.Length > 0); if (hasCommitments) { if (committed.Length != commitments.Length) { throw new ArgumentException("Inconsistent committed indices and commitment values"); } } HashFunction hash = ip.HashFunction; hash.Hash(ComputeTokenID(ip, upt)); hash.Hash(a); hash.Hash(disclosed); hash.Hash(disclosedX); if (!hasCommitments) { hash.HashNull(); // C hash.HashNull(); // < {tildeC} > hash.HashNull(); // < {tildeA} > } else { hash.Hash(committed); hash.Hash(commitments.Length); // length of < {tildeC} > for (int i = 0; i < commitments.Length; i++) { hash.Hash(commitments[i].TildeC); } hash.Hash(commitments.Length); // length of < {tildeA} > for (int i = 0; i < commitments.Length; i++) { hash.Hash(commitments[i].TildeA); } } hash.Hash(pseudonymIndex == PresentationProof.DeviceAttributeIndex ? 0 : pseudonymIndex); hash.Hash(ap); hash.Hash(Ps); hash.Hash(m); mdPrime = hash.Digest; if (upt.IsDeviceProtected) { hash = ip.HashFunction; hash.Hash(md); hash.Hash(mdPrime); return(ip.Zq.GetElementFromDigest(hash.Digest)); } else { return(ip.Zq.GetElementFromDigest(mdPrime)); } }
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"); } }
/// <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); }
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"); } }
internal static FieldZqElement GenerateChallengeForDevice(FieldZq zq, HashFunction hash, byte[] md, byte[] cp) { hash.Hash(new byte[][] { cp, md }); return(zq.GetElementFromDigest(hash.Digest)); }