/// <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)); }
/// <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"); } }
/// <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)); }
/// <summary> /// Computes the non-revocation proof. /// </summary> /// <param name="ip">The Issuer parameters associated with the presented U-Prove token.</param> /// <param name="rap">The Revocation Authority parameters.</param> /// <param name="witness">The user non-revocation witness.</param> /// <param name="commitmentIndex">The 0-based index of the revocation commitment in the attribute commitments.</param> /// <param name="presentationProof">The presentation proof generated with the U-Prove token.</param> /// <param name="cpv">The commitment private values generated when presenting the U-Prove token.</param> /// <param name="revocationIndex">The 1-based index of the revocation attribute in the U-Prove token.</param> /// <param name="attributes">The token attributes.</param> /// <returns>A non-revocation proof.</returns> public static NonRevocationProof GenerateNonRevocationProof(IssuerParameters ip, RAParameters rap, RevocationWitness witness, int commitmentIndex, PresentationProof presentationProof, CommitmentPrivateValues cpv, int revocationIndex, byte[][] attributes) { if (revocationIndex <= 0) { throw new ArgumentException("revocationIndex must be positive: " + revocationIndex); } GroupElement tildeCid = presentationProof.Commitments[commitmentIndex].TildeC; FieldZqElement xid = ProtocolHelper.ComputeXi(ip, revocationIndex - 1, attributes[revocationIndex - 1]); FieldZqElement tildeOid = cpv.TildeO[commitmentIndex]; return(GenerateNonRevocationProof(rap, witness, tildeCid, xid, tildeOid)); }
/// <summary> /// Constructs a RevocationAuthority instance. /// </summary> /// <param name="raParams">The public parameters.</param> /// <param name="privateKey">The private key.</param> /// <param name="accumulator">The optional current accumulator. If not present, then the accumulator is reset and the revocation list is considered empty.</param> public RevocationAuthority(RAParameters raParams, FieldZqElement privateKey, GroupElement accumulator = null) { RAParameters = raParams; PrivateKey = privateKey; Accumulator = accumulator; }