/** * 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())); }
/* Multiply P by e in group G2 */ public static ECP2 G2Mul(ECP2 P, BIG e) { ECP2 R; if (USE_GS_G2) { ECP2[] Q = new ECP2[4]; FP2 f = new FP2(new BIG(ROM.Fra), new BIG(ROM.Frb)); if (ECP.SEXTIC_TWIST == ECP.M_TYPE) { f.Inverse(); f.Norm(); } BIG q = new BIG(ROM.CURVE_Order); BIG[] u = GS(e); BIG t = new BIG(0); int i, np, nn; //P.affine(); Q[0] = new ECP2(); Q[0].Copy(P); for (i = 1; i < 4; i++) { Q[i] = new ECP2(); Q[i].Copy(Q[i - 1]); Q[i].Frob(f); } for (i = 0; i < 4; i++) { np = u[i].NBits(); t.Copy(BIG.ModNeg(u[i], q)); nn = t.NBits(); if (nn < np) { u[i].Copy(t); Q[i].Neg(); } u[i].Norm(); //Q[i].affine(); } R = ECP2.Mul4(Q, u); } else { R = P.Mul(e); } return(R); }
/* Galbraith & Scott Method */ public static BIG[] GS(BIG e) { BIG[] u = new BIG[4]; if (ECP.CURVE_PAIRING_TYPE == ECP.BN) { int i, j; BIG t = new BIG(0); BIG q = new BIG(ROM.CURVE_Order); BIG[] v = new BIG[4]; for (i = 0; i < 4; i++) { t.Copy(new BIG(ROM.CURVE_WB[i])); DBIG d = BIG.Mul(t, e); v[i] = new BIG(d.Div(q)); u[i] = new BIG(0); } u[0].Copy(e); for (i = 0; i < 4; i++) { for (j = 0; j < 4; j++) { t.Copy(new BIG(ROM.CURVE_BB[j][i])); t.Copy(BIG.ModMul(v[j], t, q)); u[i].Add(q); u[i].Sub(t); u[i].Mod(q); } } } else { BIG q = new BIG(ROM.CURVE_Order); BIG x = new BIG(ROM.CURVE_Bnx); BIG w = new BIG(e); for (int i = 0; i < 3; i++) { u[i] = new BIG(w); u[i].Mod(x); w.Div(x); } u[3] = new BIG(w); if (ECP.SIGN_OF_X == ECP.NEGATIVEX) { u[1].Copy(BIG.ModNeg(u[1], q)); u[3].Copy(BIG.ModNeg(u[3], q)); } } return(u); }
/* Multiply P by e in group G1 */ public static ECP G1Mul(ECP P, BIG e) { ECP R; if (USE_GLV) { //P.affine(); R = new ECP(); R.Copy(P); int np, nn; ECP Q = new ECP(); Q.Copy(P); Q.Affine(); BIG q = new BIG(ROM.CURVE_Order); FP cru = new FP(new BIG(ROM.CURVE_Cru)); BIG t = new BIG(0); BIG[] u = Glv(e); Q.GetX().Mul(cru); np = u[0].NBits(); t.Copy(BIG.ModNeg(u[0], q)); nn = t.NBits(); if (nn < np) { u[0].Copy(t); R.Neg(); } np = u[1].NBits(); t.Copy(BIG.ModNeg(u[1], q)); nn = t.NBits(); if (nn < np) { u[1].Copy(t); Q.Neg(); } u[0].Norm(); u[1].Norm(); R = R.Mul2(u[0], Q, u[1]); } else { R = P.Mul(e); } return(R); }
/* f=f^e */ /* Note that this method requires a lot of RAM! Better to use compressed XTR method, see FP4.java */ public static FP12 GTPow(FP12 d, BIG e) { FP12 r; if (USE_GS_GT) { FP12[] g = new FP12[4]; FP2 f = new FP2(new BIG(ROM.Fra), new BIG(ROM.Frb)); BIG q = new BIG(ROM.CURVE_Order); BIG t = new BIG(0); int i, np, nn; BIG[] u = GS(e); g[0] = new FP12(d); for (i = 1; i < 4; i++) { g[i] = new FP12(0); g[i].Copy(g[i - 1]); g[i].Frob(f); } for (i = 0; i < 4; i++) { np = u[i].NBits(); t.Copy(BIG.ModNeg(u[i], q)); nn = t.NBits(); if (nn < np) { u[i].Copy(t); g[i].Conj(); } u[i].Norm(); } r = FP12.Pow4(g, u); } else { r = d.Pow(e); } return(r); }
/** * Create a new IdemixSignature by proving knowledge of a credential * * @param c the credential used to create an idemix signature * @param sk the signer's secret key * @param pseudonym a pseudonym of the signer * @param ipk the issuer public key * @param disclosure a bool-array that steers the disclosure of attributes * @param msg the message to be signed * @param rhIndex the index of the attribute that represents the revocation handle * @param cri the credential revocation information that allows the signer to prove non-revocation */ public IdemixSignature(IdemixCredential c, BIG sk, IdemixPseudonym pseudonym, IdemixIssuerPublicKey ipk, bool[] disclosure, byte[] msg, int rhIndex, CredentialRevocationInformation cri) { if (c == null || sk == null || pseudonym == null || pseudonym.Nym == null || pseudonym.RandNym == null || ipk == null || disclosure == null || msg == null || cri == null) { throw new ArgumentException("Cannot construct idemix signature from null input"); } if (disclosure.Length != c.Attrs.Length) { throw new ArgumentException("Disclosure length must be the same as the number of attributes"); } if (cri.RevocationAlg >= Enum.GetValues(typeof(RevocationAlgorithm)).Length) { throw new ArgumentException("CRI specifies unknown revocation algorithm"); } if (cri.RevocationAlg != (int)RevocationAlgorithm.ALG_NO_REVOCATION && disclosure[rhIndex]) { throw new ArgumentException("Attribute " + rhIndex + " is disclosed but also used a revocation handle attribute, which should remain hidden"); } RevocationAlgorithm revocationAlgorithm = (RevocationAlgorithm)cri.RevocationAlg; int[] hiddenIndices = HiddenIndices(disclosure); RAND rng = IdemixUtils.GetRand(); // Start signature BIG r1 = rng.RandModOrder(); BIG r2 = rng.RandModOrder(); BIG r3 = new BIG(r1); r3.InvModp(IdemixUtils.GROUP_ORDER); nonce = rng.RandModOrder(); aPrime = PAIR.G1Mul(c.A, r1); aBar = PAIR.G1Mul(c.B, r1); aBar.Sub(PAIR.G1Mul(aPrime, c.E)); bPrime = PAIR.G1Mul(c.B, r1); bPrime.Sub(PAIR.G1Mul(ipk.HRand, r2)); BIG sPrime = new BIG(c.S); sPrime.Add(BIG.ModNeg(BIG.ModMul(r2, r3, IdemixUtils.GROUP_ORDER), IdemixUtils.GROUP_ORDER)); sPrime.Mod(IdemixUtils.GROUP_ORDER); //Construct Zero Knowledge Proof BIG rsk = rng.RandModOrder(); BIG re = rng.RandModOrder(); BIG rR2 = rng.RandModOrder(); BIG rR3 = rng.RandModOrder(); BIG rSPrime = rng.RandModOrder(); BIG rRNym = rng.RandModOrder(); BIG[] rAttrs = new BIG[hiddenIndices.Length]; for (int i = 0; i < hiddenIndices.Length; i++) { rAttrs[i] = rng.RandModOrder(); } // Compute non-revoked proof INonRevocationProver prover = NonRevocationProver.GetNonRevocationProver(revocationAlgorithm); int hiddenRHIndex = Array.IndexOf(hiddenIndices, rhIndex); if (hiddenRHIndex < 0) { // rhIndex is not present, set to last index position hiddenRHIndex = hiddenIndices.Length; } byte[] nonRevokedProofHashData = prover.GetFSContribution(BIG.FromBytes(c.Attrs[rhIndex]), rAttrs[hiddenRHIndex], cri); if (nonRevokedProofHashData == null) { throw new Exception("Failed to compute non-revoked proof"); } ECP t1 = aPrime.Mul2(re, ipk.HRand, rR2); ECP t2 = PAIR.G1Mul(ipk.HRand, rSPrime); t2.Add(bPrime.Mul2(rR3, ipk.Hsk, rsk)); for (int i = 0; i < hiddenIndices.Length / 2; i++) { t2.Add(ipk.HAttrs[hiddenIndices[2 * i]].Mul2(rAttrs[2 * i], ipk.HAttrs[hiddenIndices[2 * i + 1]], rAttrs[2 * i + 1])); } if (hiddenIndices.Length % 2 != 0) { t2.Add(PAIR.G1Mul(ipk.HAttrs[hiddenIndices[hiddenIndices.Length - 1]], rAttrs[hiddenIndices.Length - 1])); } ECP t3 = ipk.Hsk.Mul2(rsk, ipk.HRand, rRNym); // 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(pseudonym.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()); proofC = finalProofData.HashModOrder(); proofSSk = rsk.ModAdd(BIG.ModMul(proofC, sk, IdemixUtils.GROUP_ORDER), IdemixUtils.GROUP_ORDER); proofSE = re.ModSub(BIG.ModMul(proofC, c.E, IdemixUtils.GROUP_ORDER), IdemixUtils.GROUP_ORDER); proofSR2 = rR2.ModAdd(BIG.ModMul(proofC, r2, IdemixUtils.GROUP_ORDER), IdemixUtils.GROUP_ORDER); proofSR3 = rR3.ModSub(BIG.ModMul(proofC, r3, IdemixUtils.GROUP_ORDER), IdemixUtils.GROUP_ORDER); proofSSPrime = rSPrime.ModAdd(BIG.ModMul(proofC, sPrime, IdemixUtils.GROUP_ORDER), IdemixUtils.GROUP_ORDER); proofSRNym = rRNym.ModAdd(BIG.ModMul(proofC, pseudonym.RandNym, IdemixUtils.GROUP_ORDER), IdemixUtils.GROUP_ORDER); nym = new ECP(); nym.Copy(pseudonym.Nym); proofSAttrs = new BIG[hiddenIndices.Length]; for (int i = 0; i < hiddenIndices.Length; i++) { proofSAttrs[i] = new BIG(rAttrs[i]); proofSAttrs[i].Add(BIG.ModMul(proofC, BIG.FromBytes(c.Attrs[hiddenIndices[i]]), IdemixUtils.GROUP_ORDER)); proofSAttrs[i].Mod(IdemixUtils.GROUP_ORDER); } // include non-revocation proof in signature revocationPk = cri.EpochPk; revocationPKSig = cri.EpochPkSig.ToByteArray(); epoch = cri.Epoch; nonRevocationProof = prover.GetNonRevocationProof(proofC); }
/** * Modsub takes input BIGs a, b, m and returns a-b modulo m * * @param a the minuend of the modular subtraction * @param b the subtrahend of the modular subtraction * @param m the modulus * @return returns a-b (mod m) */ public static BIG ModSub(this BIG a, BIG b, BIG m) { return(a.ModAdd(BIG.ModNeg(b, m), m)); }