private void Precompute(GroupElement gamma, ProverRandomData pregeneratedRandomData) { Group Gq = ip.Gq; FieldZq Zq = ip.Zq; if (pregeneratedRandomData == null) { alpha = Zq.GetRandomElements(numberOfTokens, true); beta1 = Zq.GetRandomElements(numberOfTokens, false); beta2 = Zq.GetRandomElements(numberOfTokens, false); } else { alpha = pregeneratedRandomData.Alpha; beta1 = pregeneratedRandomData.Beta1; beta2 = pregeneratedRandomData.Beta2; } h = new GroupElement[numberOfTokens]; t1 = new GroupElement[numberOfTokens]; // we don't compute t2 in the precomputation since we prefer to // compute h^beta2 as part of the sigmaBPrime multi-exponentiation ukat = new UProveKeyAndToken[numberOfTokens]; for (int i = 0; i < numberOfTokens; i++) { ukat[i] = new UProveKeyAndToken(); h[i] = gamma.Exponentiate(alpha[i].Multiply(beta0Inverse)); // remove collab issuance blind, if present t1[i] = Gq.MultiExponentiate(new GroupElement[] { ip.G[0], Gq.G }, new FieldZqElement[] { beta1[i], beta2[i] }); ukat[i].PrivateKey = alpha[i].Invert(); } state = State.Initialized; }
public void TestIEWithSerialized() { // Does a complete encrypt/decrypt sequence from serialized values. // Kind of redundant because each of the testmethods above test serialization // of individual data types //Serialize and deserialize all objects IDEscrowParams ieParam2 = ip.Deserialize <IDEscrowParams>(ip.Serialize(ieParam)); IDEscrowPublicKey pk2 = ip.Deserialize <IDEscrowPublicKey>(ip.Serialize(pk)); IDEscrowPrivateKey sk2 = ip.Deserialize <IDEscrowPrivateKey>(ip.Serialize(sk)); // Encrypt FieldZq F = ip.Zq; FieldZqElement xb2 = F.GetRandomElement(true); FieldZqElement ob2 = F.GetRandomElement(true); GroupElement Cxb2 = ip.Gq.G.Exponentiate(xb2); // Cxb = g^xb Cxb2 = Cxb2.Multiply(ip.G[1].Exponentiate(ob2)); // Cxb = (g^xb)*(g1^ob) GroupElement PE2 = ieParam2.Ge.Exponentiate(xb2); IDEscrowCiphertext ctext2 = IDEscrowFunctions.VerifiableEncrypt(ieParam2, pk2, tokenID, Cxb2, xb2, ob2, additionalInfo); ctext2 = ip.Deserialize <IDEscrowCiphertext>(ip.Serialize(ctext2)); // Verify bool isValid = IDEscrowFunctions.Verify(ieParam2, ctext2, tokenID, pk2, Cxb2); Assert.IsTrue(isValid); // Decrypt GroupElement PEPrime = IDEscrowFunctions.Decrypt(ieParam2, ctext2, sk2); Assert.IsTrue(PE2.Equals(PEPrime)); }
public void TestIEEncrypt() { // Create a commitment and attribute value. // Need g, g1, Cxb, xb, ob FieldZq F = ip.Zq; FieldZqElement xb = F.GetRandomElement(true); FieldZqElement ob = F.GetRandomElement(true); Cxb = ip.Gq.G.Exponentiate(xb); // Cxb = g^xb Cxb = Cxb.Multiply(ip.G[1].Exponentiate(ob)); // Cxb = (g^xb)*(g1^ob) // Create the pseudonym (which will be used later to check that decryption is correct) PE = ieParam.Ge.Exponentiate(xb); // Encrypt ctext = IDEscrowFunctions.VerifiableEncrypt(ieParam, pk, tokenID, Cxb, xb, ob, additionalInfo); // Serialize string ctextStr = ip.Serialize(ctext); Assert.IsFalse(ctextStr.Contains(":null")); // deserialize and compare IDEscrowCiphertext ctext2 = ip.Deserialize <IDEscrowCiphertext>(ctextStr); Assert.IsTrue(ctext.Equals(ctext2)); }
/// <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)); }
public void MultiExponentiateTest() { // make sure test works with both subgroup and ECC string[] groupOIDs = { SubgroupParameterSets.ParamSet_SG_2048256_V1Name, ECParameterSets.ParamSet_EC_P256_V1Name }; foreach (string groupOID in groupOIDs) { ParameterSet set; ParameterSet.TryGetNamedParameterSet(groupOID, out set); Group Gq = set.Group; FieldZq Zq = FieldZq.CreateFieldZq(Gq.Q); int length = 10; GroupElement[] bases = new GroupElement[length]; System.Array.Copy(set.G, bases, length); FieldZqElement[] exponents = Zq.GetRandomElements(length, false); GroupElement value = Gq.Identity; for (int i = 0; i < length; i++) { value = value * bases[i].Exponentiate(exponents[i]); } Assert.AreEqual(value, Gq.MultiExponentiate(bases, exponents)); } }
/// <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> /// Generates the third issuance message. /// </summary> /// <param name="message">The second issuance message.</param> /// <returnn>The third issuance message.</returnn> public ThirdIssuanceMessage GenerateThirdMessage(SecondIssuanceMessage message) { if (state != State.First) { throw new InvalidOperationException("GenerateFirstMessage must be called first"); } if (message.sigmaC.Length != numberOfTokens) { throw new ArgumentException("invalid sigmaC array length"); } FieldZqElement[] sigmaR = new FieldZqElement[message.sigmaC.Length]; Group Gq = ikap.IssuerParameters.Gq; FieldZq Zq = ikap.IssuerParameters.Zq; for (int i = 0; i < message.sigmaC.Length; i++) { sigmaR[i] = message.sigmaC[i] * ikap.PrivateKey + w[i]; w[i] = Zq.Zero; } w = null; state = State.Third; return(new ThirdIssuanceMessage(sigmaR)); }
private void Precompute(GroupElement gamma, ProverRandomData pregeneratedRandomData) { Group Gq = ip.Gq; FieldZq Zq = ip.Zq; if (pregeneratedRandomData == null) { alpha = Zq.GetRandomElements(numberOfTokens, true); beta1 = Zq.GetRandomElements(numberOfTokens, false); beta2 = Zq.GetRandomElements(numberOfTokens, false); } else { alpha = pregeneratedRandomData.Alpha; beta1 = pregeneratedRandomData.Beta1; beta2 = pregeneratedRandomData.Beta2; } h = new GroupElement[numberOfTokens]; t1 = new GroupElement[numberOfTokens]; t2 = new GroupElement[numberOfTokens]; ukat = new UProveKeyAndToken[numberOfTokens]; for (int i = 0; i < numberOfTokens; i++) { ukat[i] = new UProveKeyAndToken(); h[i] = gamma.Exponentiate(alpha[i]); t1[i] = ip.G[0].Exponentiate(beta1[i]) * Gq.G.Exponentiate(beta2[i]); t2[i] = h[i].Exponentiate(beta2[i]); ukat[i].PrivateKey = alpha[i].Invert(); } state = State.Initialized; }
private void Precompute(GroupElement gamma, FieldZqElement[] preGenW) { IssuerParameters ip = ikap.IssuerParameters; Group Gq = ip.Gq; FieldZq Zq = ip.Zq; sigmaZ = gamma.Exponentiate(ikap.PrivateKey); if (preGenW == null) { w = Zq.GetRandomElements(numberOfTokens, false); } else { w = preGenW; } sigmaA = new GroupElement[numberOfTokens]; sigmaB = new GroupElement[numberOfTokens]; for (int i = 0; i < numberOfTokens; i++) { sigmaA[i] = Gq.G.Exponentiate(w[i]); sigmaB[i] = gamma.Exponentiate(w[i]); } state = State.Initialized; }
/// <summary> /// Takes as input a series of commitments to 0 and 1, and composes them into a single Pedersen commitment: /// output.CommittedValue = product (2^i * committedBits[i].CommittedValue) /// </summary> /// <param name="committedBits">Array of commitments to Zero and One. Each commitment must use the same bases G and H.</param> /// <param name="fieldZq">Field corresponding to all PedersenCommitments</param> /// <param name="composition">Output paramter.</param> /// <returns>True on success, false on failure.</returns> private static bool ComposeCommitments(PedersenCommitment[] committedBits, FieldZq fieldZq, out PedersenCommitment composition) { try { FieldZqElement two = fieldZq.GetElement(2); FieldZqElement powerOfTwo = fieldZq.One; DLRepOfGroupElement[] bitsExpPowerOfTwo = new DLRepOfGroupElement[committedBits.Length]; for (int i = 0; i < committedBits.Length; ++i) { bitsExpPowerOfTwo[i] = committedBits[i].Exponentiate(powerOfTwo); powerOfTwo = powerOfTwo * two; } DLRepOfGroupElement actualComposition; bool success = DLRepOfGroupElement.TryStrictMultiply(bitsExpPowerOfTwo, out actualComposition); if (success) { composition = new PedersenCommitment(actualComposition); return(true); } } catch (Exception) { // do nothing } composition = null; return(false); }
public void FieldZqTest() { Group group = SubgroupParameterSets.ParamSetL2048N256V1.Group; FieldZq field1 = group.FieldZq; FieldZq field2 = group.FieldZq; Assert.ReferenceEquals(field1, field2); }
/// <summary> /// Generates a <code>IDEscrowProofGenerationRandomData</code> instance using the internal RNG. /// </summary> /// <param name="Zq">Field Zq</param> /// <returns>A pregenerated set of random values.</returns> internal static IDEscrowProofGenerationRandomData Generate(FieldZq Zq) { return(new IDEscrowProofGenerationRandomData( Zq.GetRandomElement(false), Zq.GetRandomElement(false), Zq.GetRandomElement(false), Zq.GetRandomElement(false) )); }
/// <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); }
/// <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> /// 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); }
internal void OnDeserialized(StreamingContext context) { // begin by deserializing the algebra context if (_group == null) { throw new SerializationException("_group cannot be null."); } this.Group = _group.ToGroup(); this.FieldZq = FieldZq.CreateFieldZq(this.Group.Q); }
public void NegateTest() { FieldZq Zq = FieldZq.CreateFieldZq(new byte[] { 0x05 }); Assert.AreEqual <FieldZqElement>(Zq.Zero.Negate(), Zq.Zero); Assert.AreEqual <FieldZqElement>(Zq.GetElement(1).Negate(), Zq.GetElement(4)); Assert.AreEqual <FieldZqElement>(Zq.GetElement(2).Negate(), Zq.GetElement(3)); Assert.AreEqual <FieldZqElement>(Zq.GetElement(3).Negate(), Zq.GetElement(2)); Assert.AreEqual <FieldZqElement>(Zq.GetElement(4).Negate(), Zq.GetElement(1)); }
public void NegativeOneTest() { FieldZq Zq = FieldZq.CreateFieldZq(new byte[] { 0x05 }); FieldZqElement negone = Zq.NegativeOne; Assert.AreEqual <FieldZqElement>(Zq.One.Negate(), negone, "test first time."); FieldZqElement negoneAgain = Zq.NegativeOne; Assert.ReferenceEquals(negone, negoneAgain); Assert.AreEqual(Zq.One.Negate(), negoneAgain, "negone again"); }
/// <summary> /// Convert a base64 string to a FieldElement. /// </summary> /// <param name="encodedString">The encoded string to convert.</param> /// <param name="Zq">The FieldZq object to which the encoded element belongs.</param> /// <returns>The converted object.</returns> public static FieldZqElement ToFieldZqElement(this String encodedString, FieldZq Zq) { if (encodedString == null) { return(null); } if (Zq == null) { throw new ArgumentNullException("Zq"); } return(Zq.GetElement(Convert.FromBase64String(encodedString))); }
/// <summary> /// Private constructor - takes and sets all fields. /// </summary> /// <param name="Gq">The group</param> /// <param name="gd">The device generator</param> /// <param name="Zq">The Field associated to the group <c>Gq</c></param> /// <param name="xd">The xd.</param> /// <param name="preGenWdPrime">The pre gen wd prime.</param> VirtualDevice(Group Gq, GroupElement gd, FieldZq Zq, FieldZqElement xd, FieldZqElement preGenWdPrime) { if (xd != null && !Zq.IsElement(xd)) { throw new ArgumentException("xd is not a valid Zq element"); } this.Gd = gd; this.Gq = Gq; this.Zq = Zq; this.xd = xd ?? this.Zq.GetRandomElement(true); // assign xd a random value if null this.wdPrime = preGenWdPrime; this.hd = this.Gd.Exponentiate(this.xd); }
/// <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 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); }
public void GetElementIntTest() { FieldZq Zq = FieldZq.CreateFieldZq(new byte[] { 0x05 }); Assert.AreEqual <FieldZqElement>(Zq.GetElement(0), Zq.GetElement(-0), "-0"); Assert.AreEqual <FieldZqElement>(Zq.GetElement(1).Negate(), Zq.GetElement(-1), "-1"); Assert.AreEqual <FieldZqElement>(Zq.GetElement(2).Negate(), Zq.GetElement(-2), "-2"); Assert.AreEqual <FieldZqElement>(Zq.GetElement(3).Negate(), Zq.GetElement(-3), "-3"); Assert.AreEqual <FieldZqElement>(Zq.GetElement(4).Negate(), Zq.GetElement(-4), "-4"); ParameterSet parameters = ECParameterSets.ParamSet_EC_P256_V1; Assert.AreEqual <FieldZqElement>(parameters.Group.FieldZq.GetElement(456).Negate(), parameters.Group.FieldZq.GetElement(-456), "-456"); Assert.AreEqual <FieldZqElement>(parameters.Group.FieldZq.GetElement(1).Negate(), parameters.Group.FieldZq.GetElement(-1), "-1"); Assert.AreEqual <FieldZqElement>(parameters.Group.FieldZq.GetElement(10000034).Negate(), parameters.Group.FieldZq.GetElement(-10000034), "-10000034"); }
/// <summary> /// Constructor. Takes the input group and creates the /// associated FieldZq object. /// </summary> /// <param name="group"></param> public Algebra(Group group) { if (group == null) { throw new ArgumentNullException("Could not create Algebra because group is null."); } this.Group = group; try { this.FieldZq = FieldZq.CreateFieldZq(group.Q); } catch (Exception e) { throw new ArgumentException("Could not create Algebra from input group because could not create associated field.", e); } }
public ProverSetMembershipParameters GeneratePSMParameters(int indexOfCommittedValue, int memberSetLength) { if (indexOfCommittedValue >= memberSetLength) { throw new ArgumentException("indexOfCommittedValue should be less than memberSetLength"); } FieldZq fieldZq = FieldZq.CreateFieldZq(_cryptoParameters.Group.Q); FieldZqElement committedValue = fieldZq.GetRandomElement(true); PedersenCommitment ped = new PedersenCommitment(committedValue, _cryptoParameters); FieldZqElement[] memberSet = fieldZq.GetRandomElements(memberSetLength, true); memberSet[indexOfCommittedValue] = committedValue; return(new ProverSetMembershipParameters(ped, memberSet, _cryptoParameters)); }
/// <summary> /// Takes as input a bit decomposition of some FieldZqElement and computes it. /// </summary> /// <param name="bitDecomposition">Array of zero and one in the field, in little endian order.</param> /// <param name="fieldZq">Field Zq</param> /// <returns>sum bitDecomposition[i] * 2^i</returns> public static FieldZqElement GetBitComposition(BitArray bitDecomposition, FieldZq fieldZq) { FieldZqElement powerOfTwo = fieldZq.One; FieldZqElement two = fieldZq.One + fieldZq.One; FieldZqElement composition = fieldZq.Zero; for (int exponent = 0; exponent < bitDecomposition.Length; ++exponent) { if (bitDecomposition.Get(exponent)) { composition += powerOfTwo; } powerOfTwo *= two; } return(composition); }
public void EncodingTest() { // a large value byte[] modulus = new byte[] { 0xef, 0x09, 0x90, 0x06, 0x1d, 0xb6, 0x7a, 0x9e, 0xae, 0xba, 0x26, 0x5f, 0x1b, 0x8f, 0xa1, 0x2b, 0x55, 0x33, 0x90, 0xa8, 0x17, 0x5b, 0xcb, 0x3d, 0x0c, 0x2e, 0x5e, 0xe5, 0xdf, 0xb8, 0x26, 0xe2, 0x29, 0xad, 0x37, 0x43, 0x11, 0x48, 0xce, 0x31, 0xf8, 0xb0, 0xe5, 0x31, 0x77, 0x7f, 0x19, 0xc1, 0xe3, 0x81, 0xc6, 0x23, 0xe6, 0x00, 0xbf, 0xf7, 0xc5, 0x5a, 0x23, 0xa8, 0xe6, 0x49, 0xcc, 0xbc, 0xf8, 0x33, 0xf2, 0xdb, 0xa9, 0x9e, 0x6a, 0xd6, 0x6e, 0x52, 0x37, 0x8e, 0x92, 0xf7, 0x49, 0x2b, 0x24, 0xff, 0x8c, 0x1e, 0x6f, 0xb1, 0x89, 0xfa, 0x84, 0x34, 0xf5, 0x40, 0x2f, 0xe4, 0x15, 0x24, 0x9a, 0xe0, 0x2b, 0xf9, 0x2b, 0x3e, 0xd8, 0xea, 0xaa, 0xa2, 0x20, 0x2e, 0xc3, 0x41, 0x7b, 0x20, 0x79, 0xda, 0x4f, 0x35, 0xe9, 0x85, 0xbb, 0x42, 0xa4, 0x21, 0xcf, 0xab, 0xa8, 0x16, 0x0b, 0x66, 0x94, 0x99, 0x83, 0x38, 0x4e, 0x56, 0x36, 0x5a, 0x44, 0x86, 0xc0, 0x46, 0x22, 0x9f, 0xc8, 0xc8, 0x18, 0xf9, 0x30, 0xb8, 0x0a, 0x60, 0xd6, 0xc2, 0xc2, 0xe2, 0x0c, 0x5d, 0xf8, 0x80, 0x53, 0x4d, 0x42, 0x40, 0xd0, 0xd8, 0x1e, 0x9a, 0x37, 0x0e, 0xef, 0x67, 0x6a, 0x1c, 0x3b, 0x0e, 0xd1, 0xd8, 0xff, 0x30, 0x34, 0x0a, 0x96, 0xb2, 0x1b, 0x89, 0xf6, 0x9c, 0x54, 0xce, 0xb8, 0xf3, 0xdf, 0x17, 0xe3, 0x1b, 0xc2, 0x0c, 0x5b, 0x60, 0x1e, 0x99, 0x44, 0x45, 0xa1, 0xd3, 0x47, 0xa4, 0x5d, 0x95, 0xf4, 0x1a, 0xe0, 0x71, 0x76, 0xc7, 0x38, 0x0c, 0x60, 0xdb, 0x2a, 0xce, 0xdd, 0xee, 0xda, 0x5c, 0x59, 0x80, 0x96, 0x43, 0x62, 0xe3, 0xa8, 0xdd, 0x3f, 0x97, 0x3d, 0x6d, 0x4b, 0x24, 0x1b, 0xcf, 0x91, 0x0c, 0x7f, 0x7a, 0x02, 0xed, 0x3b, 0x60, 0x38, 0x3a, 0x01, 0x02, 0xd8, 0x06, 0x0c, 0x27 }; FieldZq field = FieldZq.CreateFieldZq(modulus); for (int i = 0; i < 20; i++) { FieldZqElement r = field.GetRandomElement(false); FieldZqElement r2 = field.GetElement(r.ToByteArray()); Assert.AreEqual <FieldZqElement>(r, r2); } }
private void RandomElementTest(int fieldSize, bool nonZero, bool checkDistribution) { byte[] modulusBytes = BitConverter.GetBytes(fieldSize); Array.Reverse(modulusBytes); // need big endian FieldZq field = FieldZq.CreateFieldZq(modulusBytes); Dictionary <FieldZqElement, int> counts = new Dictionary <FieldZqElement, int>(); int rangeSize = (nonZero) ? fieldSize - 1 : fieldSize; int iters = (checkDistribution) ? 1000 * rangeSize : 5 * rangeSize; for (int i = 0; i < iters; i++) { FieldZqElement el = field.GetRandomElement(nonZero); if (counts.ContainsKey(el)) { int val = counts[el]; val++; counts.Remove(el); counts.Add(el, val); } else { counts.Add(el, 1); } if (nonZero) { Assert.AreNotEqual(el, field.Zero); } } double expectedHitRate = 1.0f / (double)rangeSize; double errorMargin = .3 * expectedHitRate; foreach (KeyValuePair <FieldZqElement, int> kvp in counts) { double hitRate = (double)kvp.Value / (double)iters; if (Math.Abs(hitRate - expectedHitRate) > errorMargin) { Assert.Fail("Random number generator did not produce a good distribution"); } } }
public void BDBadCompositionTest() { PedersenCommitment[] ped = new PedersenCommitment[2]; ped[0] = new PedersenCommitment(_parameters[0].G, _parameters[0].H, _parameters[0].FieldZq.One, _parameters[0].FieldZq.One, _parameters[0].Group); ped[1] = new PedersenCommitment(_parameters[1].G, _parameters[1].H, _parameters[1].FieldZq.One, _parameters[1].FieldZq.One, _parameters[1].Group); PedersenCommitment composition = ped[0]; FieldZq field = _parameters[0].FieldZq; PrivateType bdproof = new PrivateType(typeof(BitDecompositionProof)); object [] inputParameters = new object[3] { ped, _parameters[0].FieldZq, composition }; bool success = (bool)bdproof.InvokeStatic("ComposeCommitments", inputParameters); Assert.IsFalse(success, "success"); }
public void GetRandomElementsTest() { FieldZq Zq = FieldZq.CreateFieldZq(new byte[] { 0x05 }); // make sure that setting nonZero=true results in no no zero elements. FieldZqElement[] nonZeroElements = Zq.GetRandomElements(30, true); for (int i = 0; i < nonZeroElements.Length; ++i) { Assert.AreNotEqual(Zq.Zero, nonZeroElements[i], "element " + i + " is 0."); } // check that setting nonZero=false results in at least one zero element bool foundNonZero = false; FieldZqElement[] zeroElements = Zq.GetRandomElements(100, false); for (int i = 0; i < zeroElements.Length; ++i) { if (zeroElements[i] == Zq.Zero) { foundNonZero = true; break; } } if (!foundNonZero) { Assert.Inconclusive("GetRandomElements did not create a single zero value. Try running this test again. Chances of failure on correct behavior is 0.0000000002."); } // check that setting maxBitLength=-1 results in at least one element 2, 3, or 4 bool foundLargeElement = false; FieldZqElement[] fullScopeElements = Zq.GetRandomElements(100, false, -1); for (int i = 0; i < fullScopeElements.Length; ++i) { if ((fullScopeElements[i] != Zq.Zero) && fullScopeElements[i] != Zq.One) { foundLargeElement = true; break; } } if (!foundLargeElement) { Assert.Inconclusive("GetRandomElements did not create a single value in the set {2,3,4}. Try running this test again. Chances of failure on correct behavior is 2.6 x 10^-40."); } }