/// <summary> /// Compare two <c>IDEscrowProof</c> objects. /// </summary> /// <param name="proof2">The object to compare against.</param> /// <returns>True if equal, false otherwise.</returns> public bool Equals(IDEscrowProof proof2) { if (proof2 == null) { return(false); } if (!proof2.c.Equals(c)) { return(false); } if (!proof2.rXb.Equals(rXb)) { return(false); } if (!proof2.rR.Equals(rR)) { return(false); } if (!proof2.rOb.Equals(rOb)) { return(false); } return(true); }
/// <summary> /// Verifies that an <c>IECiphertext</c> was computed correctly. /// </summary> /// <param name="param">Paramters of the ID escrow scheme.</param> /// <param name="ctext"> A ciphertext created with <c>param</c> and <c>pk</c>.</param> /// <param name="tokenID">The ID of the U-Prove token this ciphertext is assocaited with.</param> /// <param name="pk">Public key of the Auditor (the authority who can decrypt <c>ctext</c>).</param> /// <param name="Cxb"> The commitment value (commitment to x_b, with bases g, g1).</param> /// <returns><c>true</c> if the ciphertext is valid, and <c>false</c> otherwise.</returns> /// <remarks> /// The input <c>pk</c> is assumed to be valid, coming from a /// trusted source (e.g., a certificate or a trusted store of parameters), and that they /// are consistent with the group specified by <c>param</c>. /// </remarks> public static bool Verify(IDEscrowParams param, IDEscrowCiphertext ctext, byte[] tokenID, IDEscrowPublicKey pk, GroupElement Cxb) { GroupElement g = param.ip.Gq.G; // first base for commitment GroupElement g1 = param.ip.G[1]; // second base for commitment if (param == null || ctext == null || tokenID == null || pk == null || Cxb == null || g == null || g1 == null) { throw new ArgumentNullException("null input to Verify"); } if (tokenID.Length == 0) { throw new ArgumentOutOfRangeException("tokenID has length 0"); } Group G = param.ip.Gq; FieldZq F = param.Zq; IDEscrowProof proof = ctext.proof; // [1.]Checks on inputs. These should be done during deserialization -- but we do // them explicitly anyway, in case they were missed if (!IsGroupElement(G, ctext.E1) || !IsGroupElement(G, ctext.E2) || !IsGroupElement(G, Cxb)) { return(false); } if (!F.IsElement(proof.c) || !F.IsElement(proof.rOb) || !F.IsElement(proof.rR) || !F.IsElement(proof.rXb)) { return(false); } // [2.] Recompute inputs to hash (using tilde{x} instead of x'' for this section.) GroupElement tildeCxb = G.MultiExponentiate( new GroupElement[] { g, g1, Cxb }, new FieldZqElement[] { proof.rXb, proof.rOb, proof.c }); // tildeCxb = (g^rXb)*(g1^rOb)*(Cxb^c) GroupElement tildeE1 = G.MultiExponentiate( new GroupElement[] { param.Ge, ctext.E1 }, new FieldZqElement[] { proof.rR, proof.c }); // tildeE1 = (E1^c)*(ge^rR) GroupElement tildeE2 = G.MultiExponentiate( new GroupElement[] { param.Ge, pk.H, ctext.E2 }, new FieldZqElement[] { proof.rXb, proof.rR, proof.c }); // tildeE2 = (ge^rXb)*(H^rR)*(E2^c) // [3.] FieldZqElement cPrime = ComputeChallenge(param.ip, tokenID, pk, Cxb, ctext.E1, ctext.E2, tildeCxb, tildeE1, tildeE2, ctext.additionalInfo); // [4.] if (cPrime.Equals(proof.c)) { return(true); } return(false); }
/// <summary> /// Create a verifiable encryption of a pseudonym. The output IECiphertext /// object will contain the ciphertext and proof that it was formed correctly. /// The pseudonym that is encrypted is (param.Ge)^(x_b), where x_b is an attribute /// from the token. /// </summary> /// <param name="param"> Paramters of the ID escrow scheme.</param> /// <param name="pk"> Public key of the Auditor (the authority who can decrypt the output ciphertex).</param> /// <param name="tokenID"> The ID of the U-Prove token this ciphertext is assocaited with.</param> /// <param name="Cxb"> The commitment value (commitment to x_b, with bases g, g1).</param> /// <param name="x_b"> The attributed commited to by <c>Cxb</c></param> /// <param name="o_b"> The randomizer value used to create <c>Cxb</c></param> /// <param name="additionalInfo"> Arbitrary data that will be cryptographically bound to the ciphertext, /// but <b>NOT</b> encrypted, and will be included with the output ciphertext. /// The integrity of the <c>additionalInfo</c> is protected, i.e., modifying /// the <c>additionalInfo</c> included in the ciphertext will cause verification/decryption to fail. /// The <c>additionalInfo</c> field is sometimes referred to in the cryptographic literature /// as a <i>label</i>. </param> /// <param name="preGenRandom">Optional pre-generated random values to be used in the protocol. /// Set to <c>null</c> if unused. The primary use of this field is for testing with test vectors.</param> /// <returns>An <c>IECiphertext</c> object with the ciphertext and proof.</returns> /// <remarks> /// The additionalInfo field may be null to signify that there is no input, all other input /// paramters must be non-null. /// /// Input validation is limited to checking for non-null. We assume that all group & field elements are consistent /// with the parameters specified by the IdEscrowParams. /// </remarks> public static IDEscrowCiphertext VerifiableEncrypt(IDEscrowParams param, IDEscrowPublicKey pk, byte[] tokenID, GroupElement Cxb, FieldZqElement x_b, FieldZqElement o_b, byte[] additionalInfo, IDEscrowProofGenerationRandomData preGenRandom = null) { // Notation & numbering follows draft spec -- subject to change. GroupElement g = param.ip.Gq.G; // first base for commitment Cxb GroupElement g1 = param.ip.G[1]; // second base for Cxb if (param == null || pk == null || tokenID == null || Cxb == null || g == null || g1 == null || x_b == null || o_b == null) { throw new ArgumentNullException("Null input to VerifiableEncrypt"); } if (tokenID.Length == 0) { throw new ArgumentOutOfRangeException("tokenID has length 0"); } Group G = param.G; FieldZq F = param.Zq; if (preGenRandom == null || preGenRandom.HasNullValue()) { preGenRandom = IDEscrowProofGenerationRandomData.Generate(F); } // [1.] Encrypt // Compute E1 FieldZqElement r = preGenRandom.R; GroupElement E1 = param.Ge.Exponentiate(r); // E1 = (g_e)^r // Compute E2 = (g_e)^x_b * H^r GroupElement E2 = G.MultiExponentiate(new GroupElement[] { pk.H, param.Ge }, new FieldZqElement[] { r, x_b }); // [2.] Generate proof of correctness // [2.a] FieldZqElement xbPrime = preGenRandom.XbPrime; FieldZqElement rPrime = preGenRandom.RPrime; FieldZqElement obPrime = preGenRandom.ObPrime; // [2.b] GroupElement CxbPrime = G.MultiExponentiate(new GroupElement[] { g, g1 }, new FieldZqElement[] { xbPrime, obPrime }); // Cxb' = (g^xb')*(g1^ob') GroupElement E1Prime = param.Ge.Exponentiate(rPrime); // E1' = (ge)^r' GroupElement E2Prime = G.MultiExponentiate(new GroupElement[] { param.Ge, pk.H }, new FieldZqElement[] { xbPrime, rPrime }); // E2' = ((g_e)^xb')*(H^r') // [2.c] FieldZqElement c = ComputeChallenge(param.ip, tokenID, pk, Cxb, E1, E2, CxbPrime, E1Prime, E2Prime, additionalInfo); // [2.d] FieldZqElement rXb = ComputeResponse(xbPrime, c, x_b); FieldZqElement rR = ComputeResponse(rPrime, c, r); FieldZqElement rOb = ComputeResponse(obPrime, c, o_b); IDEscrowProof proof = new IDEscrowProof(c, rXb, rR, rOb); IDEscrowCiphertext ctext = new IDEscrowCiphertext(E1, E2, proof, additionalInfo); return(ctext); }
/// <summary> /// Create a new combined ciphertext and proof object from computed values. /// Users of this library will not use this function, because ciphertexts will be created /// with the <c>VerifiableEncrypt</c> function, which creates the ciphertext. /// </summary> /// <seealso cref="IDEscrow.IDEscrowFunctions.VerifiableEncrypt"/> public IDEscrowCiphertext(GroupElement E1, GroupElement E2, IDEscrowProof proof, byte[] additionalInfo) { if (E1 == null || E2 == null || proof == null) { throw new ArgumentNullException("Null inputs IDEscrowCiphertext()"); } this.E1 = E1; this.E2 = E2; this.proof = proof; this.additionalInfo = additionalInfo; }