/** * check whether the issuer public key is correct * * @return true iff valid */ public bool Check() { // check formalities of IdemixIssuerPublicKey if (AttributeNames == null || Hsk == null || HRand == null || HAttrs == null || BarG1 == null || BarG1.IsInfinity() || BarG2 == null || HAttrs.Length < AttributeNames.Length) { return(false); } for (int i = 0; i < AttributeNames.Length; i++) { if (HAttrs[i] == null) { return(false); } } // check proofs ECP2 t1 = IdemixUtils.GenG2.Mul(ProofS); ECP t2 = BarG1.Mul(ProofS); t1.Add(W.Mul(BIG.ModNeg(ProofC, IdemixUtils.GROUP_ORDER))); t2.Add(BarG2.Mul(BIG.ModNeg(ProofC, IdemixUtils.GROUP_ORDER))); // Generating proofData that will contain 3 elements in G1 (of size 2*FIELD_BYTES+1)and 3 elements in G2 (of size 4 * FIELD_BYTES) byte[] proofData = new byte[0]; proofData = proofData.Append(t1.ToBytes()); proofData = proofData.Append(t2.ToBytes()); proofData = proofData.Append(IdemixUtils.GenG2.ToBytes()); proofData = proofData.Append(BarG1.ToBytes()); proofData = proofData.Append(W.ToBytes()); proofData = proofData.Append(BarG2.ToBytes()); // Hash proofData to hproofdata and compare with proofC return(Enumerable.SequenceEqual(proofData.HashModOrder().ToBytes(), ProofC.ToBytes())); }
/** * Verify this IdemixPseudonymSignature * * @param nym the pseudonym with respect to which the signature is verified * @param ipk the issuer public key * @param msg the message that should be signed in this signature * @return true iff valid */ public bool Verify(ECP nym, IdemixIssuerPublicKey ipk, byte[] msg) { if (nym == null || ipk == null || msg == null) { return(false); } ECP t = ipk.Hsk.Mul2(proofSSk, ipk.HRand, proofSRNym); t.Sub(nym.Mul(proofC)); // create array for proof data that will contain the sign label, 2 ECPs (each of length 2* FIELD_BYTES + 1), the ipk hash and the message byte[] proofData = new byte[0]; proofData = proofData.Append(NYM_SIGN_LABEL.ToBytes()); proofData = proofData.Append(t.ToBytes()); proofData = proofData.Append(nym.ToBytes()); proofData = proofData.Append(ipk.Hash); proofData = proofData.Append(msg); BIG cvalue = proofData.HashModOrder(); byte[] finalProofData = new byte[0]; finalProofData = finalProofData.Append(cvalue.ToBytes()); finalProofData = finalProofData.Append(nonce.ToBytes()); byte[] hashedProofData = finalProofData.HashModOrder().ToBytes(); return(Enumerable.SequenceEqual(proofC.ToBytes(), hashedProofData)); }
/** * Constructor creating a new credential * * @param key the issuer key pair * @param m a credential request * @param attrs an array of attribute values as BIG */ public IdemixCredential(IdemixIssuerKey key, IdemixCredRequest m, BIG[] attrs) { if (key == null || key.Ipk == null || m == null || attrs == null) { throw new ArgumentException("Cannot create idemix credential from null input"); } if (attrs.Length != key.Ipk.AttributeNames.Length) { throw new ArgumentException("Amount of attribute values does not match amount of attributes in issuer public key"); } RAND rng = IdemixUtils.GetRand(); // Place a BBS+ signature on the user key and the attribute values // (For BBS+, see "Constant-Size Dynamic k-TAA" by Man Ho Au, Willy Susilo, Yi Mu) E = rng.RandModOrder(); S = rng.RandModOrder(); B = new ECP(); B.Copy(IdemixUtils.GenG1); B.Add(m.Nym); B.Add(key.Ipk.HRand.Mul(S)); for (int i = 0; i < attrs.Length / 2; i++) { B.Add(key.Ipk.HAttrs[2 * i].Mul2(attrs[2 * i], key.Ipk.HAttrs[2 * i + 1], attrs[2 * i + 1])); } if (attrs.Length % 2 != 0) { B.Add(key.Ipk.HAttrs[attrs.Length - 1].Mul(attrs[attrs.Length - 1])); } BIG exp = new BIG(key.Isk).Plus(E); exp.Mod(IdemixUtils.GROUP_ORDER); exp.InvModp(IdemixUtils.GROUP_ORDER); A = B.Mul(exp); Attrs = new byte[attrs.Length][]; for (int i = 0; i < attrs.Length; i++) { byte[] b = new byte[IdemixUtils.FIELD_BYTES]; attrs[i].ToBytes(b); Attrs[i] = b; } }
/** * Verify this signature * * @param disclosure an array indicating which attributes it expects to be disclosed * @param ipk the issuer public key * @param msg the message that should be signed in this signature * @param attributeValues BIG array where attributeValues[i] contains the desired attribute value for the i-th attribute if its disclosed * @param rhIndex index of the attribute that represents the revocation-handle * @param revPk the long term public key used to authenticate CRIs * @param epoch monotonically increasing counter representing a time window * @return true iff valid */ // ReSharper disable once ParameterHidesMember public bool Verify(bool[] disclosure, IdemixIssuerPublicKey ipk, byte[] msg, BIG[] attributeValues, int rhIndex, KeyPair revPk, int epoch) { if (disclosure == null || ipk == null || msg == null || attributeValues == null || attributeValues.Length != ipk.AttributeNames.Length || disclosure.Length != ipk.AttributeNames.Length) { return(false); } for (int i = 0; i < ipk.AttributeNames.Length; i++) { if (disclosure[i] && attributeValues[i] == null) { return(false); } } int[] hiddenIndices = HiddenIndices(disclosure); if (proofSAttrs.Length != hiddenIndices.Length) { return(false); } if (aPrime.IsInfinity()) { return(false); } if (nonRevocationProof.RevocationAlg >= Enum.GetValues(typeof(RevocationAlgorithm)).Length) { throw new ArgumentException("CRI specifies unknown revocation algorithm"); } RevocationAlgorithm revocationAlgorithm = (RevocationAlgorithm)nonRevocationProof.RevocationAlg; if (disclosure[rhIndex]) { throw new ArgumentException("Attribute " + rhIndex + " is disclosed but also used a revocation handle attribute, which should remain hidden"); } // Verify EpochPK if (!RevocationAuthority.VerifyEpochPK(revPk, revocationPk, revocationPKSig, epoch, revocationAlgorithm)) { // Signature is based on an invalid revocation epoch public key return(false); } FP12 temp1 = PAIR.Ate(ipk.W, aPrime); FP12 temp2 = PAIR.Ate(IdemixUtils.GenG2, aBar); temp2.Inverse(); temp1.mul(temp2); if (!PAIR.FExp(temp1).IsUnity()) { return(false); } ECP t1 = aPrime.Mul2(proofSE, ipk.HRand, proofSR2); ECP temp = new ECP(); temp.Copy(aBar); temp.Sub(bPrime); t1.Sub(PAIR.G1Mul(temp, proofC)); ECP t2 = PAIR.G1Mul(ipk.HRand, proofSSPrime); t2.Add(bPrime.Mul2(proofSR3, ipk.Hsk, proofSSk)); for (int i = 0; i < hiddenIndices.Length / 2; i++) { t2.Add(ipk.HAttrs[hiddenIndices[2 * i]].Mul2(proofSAttrs[2 * i], ipk.HAttrs[hiddenIndices[2 * i + 1]], proofSAttrs[2 * i + 1])); } if (hiddenIndices.Length % 2 != 0) { t2.Add(PAIR.G1Mul(ipk.HAttrs[hiddenIndices[hiddenIndices.Length - 1]], proofSAttrs[hiddenIndices.Length - 1])); } temp = new ECP(); temp.Copy(IdemixUtils.GenG1); for (int i = 0; i < disclosure.Length; i++) { if (disclosure[i]) { temp.Add(PAIR.G1Mul(ipk.HAttrs[i], attributeValues[i])); } } t2.Add(PAIR.G1Mul(temp, proofC)); ECP t3 = ipk.Hsk.Mul2(proofSSk, ipk.HRand, proofSRNym); t3.Sub(nym.Mul(proofC)); // Check with non-revoked-verifier INonRevocationVerifier nonRevokedVerifier = NonRevocationVerifier.GetNonRevocationVerifier(revocationAlgorithm); int hiddenRHIndex = Array.IndexOf(hiddenIndices, rhIndex); if (hiddenRHIndex < 0) { // rhIndex is not present, set to last index position hiddenRHIndex = hiddenIndices.Length; } BIG proofSRh = proofSAttrs[hiddenRHIndex]; byte[] nonRevokedProofBytes = nonRevokedVerifier.RecomputeFSContribution(nonRevocationProof, proofC, revocationPk.ToECP2(), proofSRh); if (nonRevokedProofBytes == null) { return(false); } // create proofData such that it can contain the sign label, 7 elements in G1 (each of size 2*FIELD_BYTES+1), // the ipk hash, the disclosure array, and the message byte[] proofData = new byte[0]; proofData = proofData.Append(SIGN_LABEL.ToBytes()); proofData = proofData.Append(t1.ToBytes()); proofData = proofData.Append(t2.ToBytes()); proofData = proofData.Append(t3.ToBytes()); proofData = proofData.Append(aPrime.ToBytes()); proofData = proofData.Append(aBar.ToBytes()); proofData = proofData.Append(bPrime.ToBytes()); proofData = proofData.Append(nym.ToBytes()); proofData = proofData.Append(ipk.Hash); proofData = proofData.Append(disclosure); proofData = proofData.Append(msg); BIG cvalue = proofData.HashModOrder(); byte[] finalProofData = new byte[0]; finalProofData = finalProofData.Append(cvalue.ToBytes()); finalProofData = finalProofData.Append(nonce.ToBytes()); byte[] hashedProofData = finalProofData.HashModOrder().ToBytes(); return(Enumerable.SequenceEqual(proofC.ToBytes(), hashedProofData)); }
/** * Constructor * * @param attributeNames the names of attributes as String array (must not contain duplicates) * @param isk the issuer secret key */ public IdemixIssuerPublicKey(string[] attributeNames, BIG isk) { // check null input if (attributeNames == null || isk == null) { throw new ArgumentException("Cannot create IdemixIssuerPublicKey from null input"); } // Checking if attribute names are unique HashSet <string> map = new HashSet <string>(); foreach (string item in attributeNames) { if (map.Contains(item)) { throw new ArgumentException("Attribute " + item + " appears multiple times in attributeNames"); } map.Add(item); } RAND rng = IdemixUtils.GetRand(); // Attaching Attribute Names array correctly AttributeNames = attributeNames; // Computing W value W = IdemixUtils.GenG2.Mul(isk); // Filling up HAttributes correctly in Issuer Public Key, length // preserving HAttrs = new ECP[attributeNames.Length]; for (int i = 0; i < attributeNames.Length; i++) { HAttrs[i] = IdemixUtils.GenG1.Mul(rng.RandModOrder()); } // Generating Hsk value Hsk = IdemixUtils.GenG1.Mul(rng.RandModOrder()); // Generating HRand value HRand = IdemixUtils.GenG1.Mul(rng.RandModOrder()); // Generating BarG1 value BarG1 = IdemixUtils.GenG1.Mul(rng.RandModOrder()); // Generating BarG2 value BarG2 = BarG1.Mul(isk); // Zero Knowledge Proofs // Computing t1 and t2 values with random local variable r for later use BIG r = rng.RandModOrder(); ECP2 t1 = IdemixUtils.GenG2.Mul(r); ECP t2 = BarG1.Mul(r); // Generating proofData that will contain 3 elements in G1 (of size 2*FIELD_BYTES+1)and 3 elements in G2 (of size 4 * FIELD_BYTES) byte[] proofData = new byte[0]; proofData = proofData.Append(t1.ToBytes()); proofData = proofData.Append(t2.ToBytes()); proofData = proofData.Append(IdemixUtils.GenG2.ToBytes()); proofData = proofData.Append(BarG1.ToBytes()); proofData = proofData.Append(W.ToBytes()); proofData = proofData.Append(BarG2.ToBytes()); // Hashing proofData to proofC ProofC = proofData.HashModOrder(); // Computing ProofS = (ProofC*isk) + r mod GROUP_ORDER ProofS = BIG.ModMul(ProofC, isk, IdemixUtils.GROUP_ORDER).Plus(r); ProofS.Mod(IdemixUtils.GROUP_ORDER); // Compute Hash of IdemixIssuerPublicKey byte[] serializedIpk = ToProto().ToByteArray(); Hash = serializedIpk.HashModOrder().ToBytes(); }