/** * Construct a new signature from a serialized IdemixSignature * * @param proto a protobuf object representing an IdemixSignature */ public IdemixSignature(Signature proto) { if (proto == null) { throw new ArgumentException("Cannot construct idemix signature from null input"); } aBar = proto.ABar.ToECP(); aPrime = proto.APrime.ToECP(); bPrime = proto.BPrime.ToECP(); nym = proto.Nym.ToECP(); proofC = BIG.FromBytes(proto.ProofC.ToByteArray()); proofSSk = BIG.FromBytes(proto.ProofSSk.ToByteArray()); proofSE = BIG.FromBytes(proto.ProofSE.ToByteArray()); proofSR2 = BIG.FromBytes(proto.ProofSR2.ToByteArray()); proofSR3 = BIG.FromBytes(proto.ProofSR3.ToByteArray()); proofSSPrime = BIG.FromBytes(proto.ProofSSPrime.ToByteArray()); proofSRNym = BIG.FromBytes(proto.ProofSRNym.ToByteArray()); nonce = BIG.FromBytes(proto.Nonce.ToByteArray()); proofSAttrs = new BIG[proto.ProofSAttrs.Count]; for (int i = 0; i < proto.ProofSAttrs.Count; i++) { proofSAttrs[i] = BIG.FromBytes(proto.ProofSAttrs[i].ToByteArray()); } revocationPk = proto.RevocationEpochPk; revocationPKSig = proto.RevocationPkSig.ToByteArray(); epoch = proto.Epoch; nonRevocationProof = proto.NonRevocationProof; }
/* constant time multiply by small integer of length bts - use ladder */ public ECP PinMul(int e, int bts) { if (CURVETYPE == MONTGOMERY) { return(Mul(new BIG(e))); } else { int i, b; ECP P = new ECP(); ECP R0 = new ECP(); ECP R1 = new ECP(); R1.Copy(this); for (i = bts - 1; i >= 0; i--) { b = (e >> i) & 1; P.Copy(R1); P.Add(R0); R0.CSwap(R1, b); R1.Copy(P); R0.Dbl(); R0.CSwap(R1, b); } P.Copy(R0); P.Affine(); return(P); } }
/* Test P == Q */ public bool Equals(ECP Q) { // if (is_infinity() && Q.is_infinity()) return true; // if (is_infinity() || Q.is_infinity()) return false; FP a = new FP(0); // Edits made FP b = new FP(0); a.Copy(x); a.Mul(Q.z); b.Copy(Q.x); b.Mul(z); if (!a.Equals(b)) { return(false); } if (CURVETYPE != MONTGOMERY) { a.Copy(y); a.Mul(Q.z); b.Copy(Q.y); b.Mul(z); if (!a.Equals(b)) { return(false); } } return(true); }
/** * 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())); }
/** * Create Idemix Identity from a Serialized Identity * * @param proto */ public IdemixIdentity(SerializedIdentity proto) { if (proto == null) { throw new ArgumentException("Input must not be null"); } mspId = proto.Mspid; try { logger.Trace("Fetching Idemix Proto"); SerializedIdemixIdentity idemixProto = SerializedIdemixIdentity.Parser.ParseFrom(proto.IdBytes); if (idemixProto == null) { throw new ArgumentException("The identity does not contain a serialized idemix identity"); } logger.Trace("Deserializing Nym and attribute values"); pseudonym = new ECP(BIG.FromBytes(idemixProto.NymX.ToByteArray()), BIG.FromBytes(idemixProto.NymY.ToByteArray())); OrganizationUnit ou = OrganizationUnit.Parser.ParseFrom(idemixProto.Ou); MSPRole role = MSPRole.Parser.ParseFrom(idemixProto.Role); Ou = ou.OrganizationalUnitIdentifier; RoleMask = role.Role.ToIdemixRole(); ipkHash = ou.CertifiersIdentifier.ToByteArray(); logger.Trace("Deserializing Proof"); associationProof = new IdemixSignature(Signature.Parser.ParseFrom(idemixProto.Proof.ToByteArray())); } catch (InvalidProtocolBufferException e) { throw new CryptoException("Cannot deserialize MSP ID", e); } }
/** * Cryptographically verify the IdemixCredRequest * * @param ipk the issuer public key * @return true iff valid */ public bool Check(IdemixIssuerPublicKey ipk) { if (Nym == null || issuerNonce == null || proofC == null || proofS == null || ipk == null) { return(false); } ECP t = ipk.Hsk.Mul(proofS); t.Sub(Nym.Mul(proofC)); byte[] proofData = new byte[0]; proofData = proofData.Append(CREDREQUEST_LABEL.ToBytes()); proofData = proofData.Append(t.ToBytes()); proofData = proofData.Append(ipk.Hsk.ToBytes()); proofData = proofData.Append(Nym.ToBytes()); proofData = proofData.Append(issuerNonce.ToBytes()); proofData = proofData.Append(ipk.Hash); // Hash proofData to hproofdata byte[] hproofdata = proofData.HashModOrder().ToBytes(); return(Enumerable.SequenceEqual(proofC.ToBytes(), hproofdata)); }
/* this-=Q */ public void Sub(ECP Q) { ECP NQ = new ECP(Q); NQ.Neg(); Add(NQ); }
/** * 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)); }
/* this=P */ public void Copy(ECP P) { x.Copy(P.x); if (CURVETYPE != MONTGOMERY) { y.Copy(P.y); } z.Copy(P.z); //INF=P.INF; }
/* convert to hex string */ public string ToRawString() { //if (is_infinity()) return "infinity"; //affine(); ECP W = new ECP(this); if (CURVETYPE == MONTGOMERY) { return("(" + W.x.Redc().ToString() + "," + W.z.Redc().ToString() + ")"); } else { return("(" + W.x.Redc().ToString() + "," + W.y.Redc().ToString() + "," + W.z.Redc().ToString() + ")"); } }
/* Conditional move of Q to P dependant on d */ private void CMove(ECP Q, int d) { x.CMove(Q.x, d); if (CURVETYPE != MONTGOMERY) { y.CMove(Q.y, d); } z.CMove(Q.z, d); // if (CURVETYPE!=EDWARDS) // { // boolean bd; // if (d==0) bd=false; // else bd=true; // INF^=(INF^Q.INF)&bd; // } }
/** * 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; } }
/** * Create Idemix Identity from the following inputs: * * @param mspId is MSP ID sting * @param nym is Identity Mixer Pseudonym * @param ou is OU attribute * @param roleMask is a bitmask that represent all the roles attached to this identity * @param proof is Proof */ public IdemixIdentity(string mspId, IdemixIssuerPublicKey ipk, ECP nym, string ou, IdemixRoles roleMask, IdemixSignature proof) { if (mspId == null) { throw new ArgumentException("MSP ID must not be null"); } if (string.IsNullOrEmpty(mspId)) { throw new ArgumentException("MSP ID must not be empty"); } if (ipk == null) { throw new ArgumentException("Issuer Public Key must not be empty"); } if (nym == null) { throw new ArgumentException("Identity Mixer Pseudonym (nym) must not be null"); } if (ou == null) { throw new ArgumentException("OU attribute must not be null"); } if (string.IsNullOrEmpty(ou)) { throw new ArgumentException("OU attribute must not be empty"); } if (proof == null) { throw new ArgumentException("Proof must not be null"); } this.mspId = mspId; ipkHash = ipk.Hash; pseudonym = nym; Ou = ou; RoleMask = roleMask; associationProof = proof; }
/** * Constructor * * @param sk the secret key of the user * @param issuerNonce a nonce * @param ipk the issuer public key */ public IdemixCredRequest(BIG sk, BIG issuerNonce, IdemixIssuerPublicKey ipk) { if (sk == null) { throw new ArgumentException("Cannot create idemix credrequest from null Secret Key input"); } if (issuerNonce == null) { throw new ArgumentException("Cannot create idemix credrequest from null issuer nonce input"); } if (ipk == null) { throw new ArgumentException("Cannot create idemix credrequest from null Issuer Public Key input"); } RAND rng = IdemixUtils.GetRand(); Nym = ipk.Hsk.Mul(sk); this.issuerNonce = new BIG(issuerNonce); // Create Zero Knowledge Proof BIG rsk = rng.RandModOrder(); ECP t = ipk.Hsk.Mul(rsk); // Make proofData: total 3 elements of G1, each 2*FIELD_BYTES+1 (ECP), // plus length of String array, // plus one BIG byte[] proofData = new byte[0]; proofData = proofData.Append(CREDREQUEST_LABEL.ToBytes()); proofData = proofData.Append(t.ToBytes()); proofData = proofData.Append(ipk.Hsk.ToBytes()); proofData = proofData.Append(Nym.ToBytes()); proofData = proofData.Append(issuerNonce.ToBytes()); proofData = proofData.Append(ipk.Hash); proofC = proofData.HashModOrder(); // Compute proofS = ... proofS = BIG.ModMul(proofC, sk, IdemixUtils.GROUP_ORDER).Plus(rsk); proofS.Mod(IdemixUtils.GROUP_ORDER); }
public static ECP Generator() { ECP G; BIG gx, gy; gx = new BIG(ROM.CURVE_Gx); if (CURVETYPE != MONTGOMERY) { gy = new BIG(ROM.CURVE_Gy); G = new ECP(gx, gy); } else { G = new ECP(gx); } return(G); }
/* convert to hex string */ public override string ToString() { ECP W = new ECP(this); W.Affine(); if (W.IsInfinity()) { return("infinity"); } if (CURVETYPE == MONTGOMERY) { return("(" + W.x.Redc().ToString() + ")"); } else { return("(" + W.x.Redc().ToString() + "," + W.y.Redc().ToString() + ")"); } }
/* Constant time select from pre-computed table */ private void Select(ECP[] W, int b) { ECP MP = new ECP(); int m = b >> 31; int babs = (b ^ m) - m; babs = (babs - 1) / 2; CMove(W[0], Teq(babs, 0)); // conditional move CMove(W[1], Teq(babs, 1)); CMove(W[2], Teq(babs, 2)); CMove(W[3], Teq(babs, 3)); CMove(W[4], Teq(babs, 4)); CMove(W[5], Teq(babs, 5)); CMove(W[6], Teq(babs, 6)); CMove(W[7], Teq(babs, 7)); MP.Copy(this); MP.Neg(); CMove(MP, (int)(m & 1)); }
/** * verify cryptographically verifies the credential * * @param sk the secret key of the user * @param ipk the public key of the issuer * @return true iff valid */ public bool Verify(BIG sk, IdemixIssuerPublicKey ipk) { if (ipk == null || Attrs.Length != ipk.AttributeNames.Length) { return(false); } foreach (byte[] attr in Attrs) { if (attr == null) { return(false); } } ECP bPrime = new ECP(); bPrime.Copy(IdemixUtils.GenG1); bPrime.Add(ipk.Hsk.Mul2(sk, ipk.HRand, S)); for (int i = 0; i < Attrs.Length / 2; i++) { bPrime.Add(ipk.HAttrs[2 * i].Mul2(BIG.FromBytes(Attrs[2 * i]), ipk.HAttrs[2 * i + 1], BIG.FromBytes(Attrs[2 * i + 1]))); } if (Attrs.Length % 2 != 0) { bPrime.Add(ipk.HAttrs[Attrs.Length - 1].Mul(BIG.FromBytes(Attrs[Attrs.Length - 1]))); } if (!B.Equals(bPrime)) { return(false); } ECP2 a = IdemixUtils.GenG2.Mul(E); a.Add(ipk.W); a.Affine(); return(PAIR.FExp(PAIR.Ate(a, A)).Equals(PAIR.FExp(PAIR.Ate(IdemixUtils.GenG2, B)))); }
/** * Constructor * * @param sk the secret key * @param pseudonym the pseudonym with respect to which this signature can be verified * @param ipk the issuer public key * @param msg the message to be signed */ public IdemixPseudonymSignature(BIG sk, IdemixPseudonym pseudonym, IdemixIssuerPublicKey ipk, byte[] msg) { if (sk == null || pseudonym == null || pseudonym.Nym == null || pseudonym.RandNym == null || ipk == null || msg == null) { throw new ArgumentException("Cannot create IdemixPseudonymSignature from null input"); } RAND rng = IdemixUtils.GetRand(); nonce = rng.RandModOrder(); //Construct Zero Knowledge Proof BIG rsk = rng.RandModOrder(); BIG rRNym = rng.RandModOrder(); ECP t = ipk.Hsk.Mul2(rsk, ipk.HRand, rRNym); // 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(pseudonym.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()); proofC = finalProofData.HashModOrder(); proofSSk = new BIG(rsk); proofSSk.Add(BIG.ModMul(proofC, sk, IdemixUtils.GROUP_ORDER)); proofSSk.Mod(IdemixUtils.GROUP_ORDER); proofSRNym = new BIG(rRNym); proofSRNym.Add(BIG.ModMul(proofC, pseudonym.RandNym, IdemixUtils.GROUP_ORDER)); proofSRNym.Mod(IdemixUtils.GROUP_ORDER); }
/* convert to byte array */ public void ToBytes(sbyte[] b, bool compress) { sbyte[] t = new sbyte[BIG.MODBYTES]; ECP W = new ECP(this); W.Affine(); W.x.Redc().ToBytes(t); for (int i = 0; i < BIG.MODBYTES; i++) { b[i + 1] = t[i]; } if (CURVETYPE == MONTGOMERY) { b[0] = 0x06; return; } if (compress) { b[0] = 0x02; if (y.Redc().Parity() == 1) { b[0] = 0x03; } return; } b[0] = 0x04; W.y.Redc().ToBytes(t); for (int i = 0; i < BIG.MODBYTES; i++) { b[i + BIG.MODBYTES + 1] = t[i]; } }
/* Map byte string to curve point */ public static ECP MapIt(sbyte[] h) { BIG q = new BIG(ROM.Modulus); BIG x = BIG.FromBytes(h); x.Mod(q); ECP P; while (true) { while (true) { if (CURVETYPE != MONTGOMERY) { P = new ECP(x, 0); } else { P = new ECP(x); } x.Inc(1); x.Norm(); if (!P.IsInfinity()) { break; } } P.Cfp(); if (!P.IsInfinity()) { break; } } return(P); }
/* Differential Add for Montgomery curves. this+=Q where W is this-Q and is affine. */ public void DAdd(ECP Q, ECP W) { FP A = new FP(x); FP B = new FP(x); FP C = new FP(Q.x); FP D = new FP(Q.x); FP DA = new FP(0); FP CB = new FP(0); A.Add(z); B.Sub(z); C.Add(Q.z); D.Sub(Q.z); A.Norm(); D.Norm(); DA.Copy(D); DA.Mul(A); C.Norm(); B.Norm(); CB.Copy(C); CB.Mul(B); A.Copy(DA); A.Add(CB); A.Norm(); A.Sqr(); B.Copy(DA); B.Sub(CB); B.Norm(); B.Sqr(); x.Copy(A); z.Copy(W.x); z.Mul(B); }
/** * Construct an IdemixIssuerPublicKey from a serialized issuer public key * * @param proto a protobuf representation of an issuer public key */ public IdemixIssuerPublicKey(IssuerPublicKey proto) { // check for bad input if (proto == null) { throw new ArgumentException("Cannot create IdemixIssuerPublicKey from null input"); } if (proto.HAttrs.Count < proto.AttributeNames.Count) { throw new ArgumentException("Serialized IPk does not contain enough HAttr values"); } AttributeNames = new string[proto.AttributeNames.Count]; for (int i = 0; i < proto.AttributeNames.Count; i++) { AttributeNames[i] = proto.AttributeNames[i]; } HAttrs = new ECP[proto.HAttrs.Count]; for (int i = 0; i < proto.HAttrs.Count; i++) { HAttrs[i] = proto.HAttrs[i].ToECP(); } BarG1 = proto.BarG1.ToECP(); BarG2 = proto.BarG2.ToECP(); HRand = proto.HRand.ToECP(); Hsk = proto.HSk.ToECP(); ProofC = BIG.FromBytes(proto.ProofC.ToByteArray()); ProofS = BIG.FromBytes(proto.ProofS.ToByteArray()); W = proto.W.ToECP2(); // Compute Hash of IdemixIssuerPublicKey byte[] serializedIpk = ToProto().ToByteArray(); Hash = serializedIpk.HashModOrder().ToBytes(); }
/* return e.this */ public ECP Mul(BIG e) { if (e.IsZilch() || IsInfinity()) { return(new ECP()); } ECP P = new ECP(); if (CURVETYPE == MONTGOMERY) { /* use Ladder */ int nb, i, b; ECP D = new ECP(); ECP R0 = new ECP(); R0.Copy(this); ECP R1 = new ECP(); R1.Copy(this); R1.Dbl(); D.Copy(this); D.Affine(); nb = e.NBits(); for (i = nb - 2; i >= 0; i--) { b = e.Bit(i); P.Copy(R1); P.DAdd(R0, D); R0.CSwap(R1, b); R1.Copy(P); R0.Dbl(); R0.CSwap(R1, b); } P.Copy(R0); } else { // fixed size windows int i, nb, s, ns; BIG mt = new BIG(); BIG t = new BIG(); ECP Q = new ECP(); ECP C = new ECP(); ECP[] W = new ECP[8]; sbyte[] w = new sbyte[1 + (BIG.NLEN * BIG.BASEBITS + 3) / 4]; //affine(); // precompute table Q.Copy(this); Q.Dbl(); W[0] = new ECP(); W[0].Copy(this); for (i = 1; i < 8; i++) { W[i] = new ECP(); W[i].Copy(W[i - 1]); W[i].Add(Q); } // make exponent odd - add 2P if even, P if odd t.Copy(e); s = t.Parity(); t.Inc(1); t.Norm(); ns = t.Parity(); mt.Copy(t); mt.Inc(1); mt.Norm(); t.CMove(mt, s); Q.CMove(this, ns); C.Copy(Q); nb = 1 + (t.NBits() + 3) / 4; // convert exponent to signed 4-bit window for (i = 0; i < nb; i++) { w[i] = (sbyte)(t.LastBits(5) - 16); t.Dec(w[i]); t.Norm(); t.FShr(4); } w[nb] = (sbyte)t.LastBits(5); P.Copy(W[(w[nb] - 1) / 2]); for (i = nb - 1; i >= 0; i--) { Q.Select(W, w[i]); P.Dbl(); P.Dbl(); P.Dbl(); P.Dbl(); P.Add(Q); } P.Sub(C); // apply correction } P.Affine(); return(P); }
/* this+=Q */ public void Add(ECP Q) { // if (INF) // { // copy(Q); // return; // } // if (Q.INF) return; if (CURVETYPE == WEIERSTRASS) { if (ROM.CURVE_A == 0) { // Edits made //System.out.println("Into add"); int b = 3 * ROM.CURVE_B_I; FP t0 = new FP(x); t0.Mul(Q.x); FP t1 = new FP(y); t1.Mul(Q.y); FP t2 = new FP(z); t2.Mul(Q.z); FP t3 = new FP(x); t3.Add(y); t3.Norm(); FP t4 = new FP(Q.x); t4.Add(Q.y); t4.Norm(); t3.Mul(t4); t4.Copy(t0); t4.Add(t1); t3.Sub(t4); t3.Norm(); t4.Copy(y); t4.Add(z); t4.Norm(); FP x3 = new FP(Q.y); x3.Add(Q.z); x3.Norm(); t4.Mul(x3); x3.Copy(t1); x3.Add(t2); t4.Sub(x3); t4.Norm(); x3.Copy(x); x3.Add(z); x3.Norm(); FP y3 = new FP(Q.x); y3.Add(Q.z); y3.Norm(); x3.Mul(y3); y3.Copy(t0); y3.Add(t2); y3.RSub(x3); y3.Norm(); x3.Copy(t0); x3.Add(t0); t0.Add(x3); t0.Norm(); t2.IMul(b); FP z3 = new FP(t1); z3.Add(t2); z3.Norm(); t1.Sub(t2); t1.Norm(); y3.IMul(b); x3.Copy(y3); x3.Mul(t4); t2.Copy(t3); t2.Mul(t1); x3.RSub(t2); y3.Mul(t0); t1.Mul(z3); y3.Add(t1); t0.Mul(t3); z3.Mul(t4); z3.Add(t0); x.Copy(x3); x.Norm(); y.Copy(y3); y.Norm(); z.Copy(z3); z.Norm(); //System.out.println("Out of add"); } else { FP t0 = new FP(x); FP t1 = new FP(y); FP t2 = new FP(z); FP t3 = new FP(x); FP t4 = new FP(Q.x); FP z3 = new FP(0); FP y3 = new FP(Q.x); FP x3 = new FP(Q.y); FP b = new FP(0); if (ROM.CURVE_B_I == 0) { b.Copy(new FP(new BIG(ROM.CURVE_B))); } t0.Mul(Q.x); //1 t1.Mul(Q.y); //2 t2.Mul(Q.z); //3 t3.Add(y); t3.Norm(); //4 t4.Add(Q.y); t4.Norm(); //5 t3.Mul(t4); //6 t4.Copy(t0); t4.Add(t1); //t4.norm(); //7 t3.Sub(t4); t3.Norm(); //8 t4.Copy(y); t4.Add(z); t4.Norm(); //9 x3.Add(Q.z); x3.Norm(); //10 t4.Mul(x3); //11 x3.Copy(t1); x3.Add(t2); //x3.norm();//12 t4.Sub(x3); t4.Norm(); //13 x3.Copy(x); x3.Add(z); x3.Norm(); //14 y3.Add(Q.z); y3.Norm(); //15 x3.Mul(y3); //16 y3.Copy(t0); y3.Add(t2); //y3.norm();//17 y3.RSub(x3); y3.Norm(); //18 z3.Copy(t2); if (ROM.CURVE_B_I == 0) { z3.Mul(b); //18 } else { z3.IMul(ROM.CURVE_B_I); } x3.Copy(y3); x3.Sub(z3); x3.Norm(); //20 z3.Copy(x3); z3.Add(x3); //z3.norm(); //21 x3.Add(z3); //x3.norm(); //22 z3.Copy(t1); z3.Sub(x3); z3.Norm(); //23 x3.Add(t1); x3.Norm(); //24 if (ROM.CURVE_B_I == 0) { y3.Mul(b); //18 } else { y3.IMul(ROM.CURVE_B_I); } t1.Copy(t2); t1.Add(t2); //t1.norm();//26 t2.Add(t1); //t2.norm();//27 y3.Sub(t2); //y3.norm(); //28 y3.Sub(t0); y3.Norm(); //29 t1.Copy(y3); t1.Add(y3); //t1.norm();//30 y3.Add(t1); y3.Norm(); //31 t1.Copy(t0); t1.Add(t0); //t1.norm(); //32 t0.Add(t1); //t0.norm();//33 t0.Sub(t2); t0.Norm(); //34 t1.Copy(t4); t1.Mul(y3); //35 t2.Copy(t0); t2.Mul(y3); //36 y3.Copy(x3); y3.Mul(z3); //37 y3.Add(t2); //y3.norm();//38 x3.Mul(t3); //39 x3.Sub(t1); //40 z3.Mul(t4); //41 t1.Copy(t3); t1.Mul(t0); //42 z3.Add(t1); x.Copy(x3); x.Norm(); y.Copy(y3); y.Norm(); z.Copy(z3); z.Norm(); } } if (CURVETYPE == EDWARDS) { //System.out.println("Into add"); FP A = new FP(z); FP B = new FP(0); FP C = new FP(x); FP D = new FP(y); FP E = new FP(0); FP F = new FP(0); FP G = new FP(0); A.Mul(Q.z); B.Copy(A); B.Sqr(); C.Mul(Q.x); D.Mul(Q.y); E.Copy(C); E.Mul(D); if (ROM.CURVE_B_I == 0) { FP b = new FP(new BIG(ROM.CURVE_B)); E.Mul(b); } else { E.IMul(ROM.CURVE_B_I); } F.Copy(B); F.Sub(E); G.Copy(B); G.Add(E); if (ROM.CURVE_A == 1) { E.Copy(D); E.Sub(C); } C.Add(D); B.Copy(x); B.Add(y); D.Copy(Q.x); D.Add(Q.y); B.Norm(); D.Norm(); B.Mul(D); B.Sub(C); B.Norm(); F.Norm(); B.Mul(F); x.Copy(A); x.Mul(B); G.Norm(); if (ROM.CURVE_A == 1) { E.Norm(); C.Copy(E); C.Mul(G); } if (ROM.CURVE_A == -1) { C.Norm(); C.Mul(G); } y.Copy(A); y.Mul(C); z.Copy(F); z.Mul(G); //System.out.println("Out of add"); } return; }
public ECP(ECP e) { x = new FP(e.x); y = new FP(e.y); z = new FP(e.z); }
private void Test() { RAND rng = IdemixUtils.GetRand(); // WeakBB test // Random message to sign BIG wbbMessage = rng.RandModOrder(); // Sign the message with keypair secret key ECP wbbSignature = WeakBB.WeakBBSign(setup.wbbKeyPair.Sk, wbbMessage); // Check the signature with valid PK and valid message Assert.IsTrue(WeakBB.weakBBVerify(setup.wbbKeyPair.Pk, wbbSignature, wbbMessage)); // Try to check a random message Assert.IsFalse(WeakBB.weakBBVerify(setup.wbbKeyPair.Pk, wbbSignature, rng.RandModOrder())); // user completes the idemixCredential and checks validity Assert.IsTrue(setup.idemixCredential.Verify(setup.sk, setup.key.Ipk)); // Test serialization of IdemixidemixCredential Assert.IsTrue(new IdemixCredential(setup.idemixCredential.ToProto()).Verify(setup.sk, setup.key.Ipk)); // Create CRI that contains no revocation mechanism int epoch = 0; BIG[] rhIndex = { new BIG(0) }; CredentialRevocationInformation cri = RevocationAuthority.CreateCRI(setup.revocationKeyPair, rhIndex, epoch, RevocationAlgorithm.ALG_NO_REVOCATION); // Create a new unlinkable pseudonym IdemixPseudonym pseudonym = new IdemixPseudonym(setup.sk, setup.key.Ipk); //tcert // Test signing no disclosure bool[] disclosure = { false, false, false, false, false }; byte[] msg = { 1, 2, 3, 4, 5 }; IdemixSignature signature = new IdemixSignature(setup.idemixCredential, setup.sk, pseudonym, setup.key.Ipk, disclosure, msg, 0, cri); Assert.IsNotNull(signature); // Test bad disclosure: Disclosure > number of attributes || Disclosure < number of attributes bool[] badDisclosure = { false, true }; bool[] badDisclosure2 = { true, true, true, true, true, true, true }; try { new IdemixSignature(setup.idemixCredential, setup.sk, pseudonym, setup.key.Ipk, badDisclosure, msg, 0, cri); new IdemixSignature(setup.idemixCredential, setup.sk, pseudonym, setup.key.Ipk, badDisclosure2, msg, 0, cri); Assert.Fail("Expected an ArgumentException"); } catch (ArgumentException) { //ignored /* Do nothing, the expected behaviour is to catch this exception.*/ } // check that the signature is valid Assert.IsTrue(signature.Verify(disclosure, setup.key.Ipk, msg, setup.attrs, 0, setup.revocationKeyPair, epoch)); // Test serialization of IdemixSignature Assert.IsTrue(new IdemixSignature(signature.ToProto()).Verify(disclosure, setup.key.Ipk, msg, setup.attrs, 0, setup.revocationKeyPair, epoch)); // Test signing selective disclosure bool[] disclosure2 = { false, true, true, true, false }; signature = new IdemixSignature(setup.idemixCredential, setup.sk, pseudonym, setup.key.Ipk, disclosure2, msg, 0, cri); Assert.IsNotNull(signature); // check that the signature is valid Assert.IsTrue(signature.Verify(disclosure2, setup.key.Ipk, msg, setup.attrs, 0, setup.revocationKeyPair, epoch)); // Test signature verification with different disclosure Assert.IsFalse(signature.Verify(disclosure, setup.key.Ipk, msg, setup.attrs, 0, setup.revocationKeyPair, epoch)); // test signature verification with different issuer public key Assert.IsFalse(signature.Verify(disclosure2, new IdemixIssuerKey(new [] { "Attr1, Attr2, Attr3, Attr4, Attr5" }).Ipk, msg, setup.attrs, 0, setup.revocationKeyPair, epoch)); // test signature verification with different message byte[] msg2 = { 1, 1, 1 }; Assert.IsFalse(signature.Verify(disclosure2, setup.key.Ipk, msg2, setup.attrs, 0, setup.revocationKeyPair, epoch)); // Sign a message with respect to a pseudonym IdemixPseudonymSignature nymsig = new IdemixPseudonymSignature(setup.sk, pseudonym, setup.key.Ipk, msg); // check that the pseudonym signature is valid Assert.IsTrue(nymsig.Verify(pseudonym.Nym, setup.key.Ipk, msg)); // Test serialization of IdemixPseudonymSignature Assert.IsTrue(new IdemixPseudonymSignature(nymsig.ToProto()).Verify(pseudonym.Nym, setup.key.Ipk, msg)); }
/** * 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)); }
/** * 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); }
/* Return e.this+f.Q */ public ECP Mul2(BIG e, ECP Q, BIG f) { BIG te = new BIG(); BIG tf = new BIG(); BIG mt = new BIG(); ECP S = new ECP(); ECP T = new ECP(); ECP C = new ECP(); ECP[] W = new ECP[8]; sbyte[] w = new sbyte[1 + (BIG.NLEN * BIG.BASEBITS + 1) / 2]; int i, s, ns, nb; sbyte a, b; //affine(); //Q.affine(); te.Copy(e); tf.Copy(f); // precompute table W[1] = new ECP(); W[1].Copy(this); W[1].Sub(Q); W[2] = new ECP(); W[2].Copy(this); W[2].Add(Q); S.Copy(Q); S.Dbl(); W[0] = new ECP(); W[0].Copy(W[1]); W[0].Sub(S); W[3] = new ECP(); W[3].Copy(W[2]); W[3].Add(S); T.Copy(this); T.Dbl(); W[5] = new ECP(); W[5].Copy(W[1]); W[5].Add(T); W[6] = new ECP(); W[6].Copy(W[2]); W[6].Add(T); W[4] = new ECP(); W[4].Copy(W[5]); W[4].Sub(S); W[7] = new ECP(); W[7].Copy(W[6]); W[7].Add(S); // if multiplier is odd, add 2, else add 1 to multiplier, and add 2P or P to correction s = te.Parity(); te.Inc(1); te.Norm(); ns = te.Parity(); mt.Copy(te); mt.Inc(1); mt.Norm(); te.CMove(mt, s); T.CMove(this, ns); C.Copy(T); s = tf.Parity(); tf.Inc(1); tf.Norm(); ns = tf.Parity(); mt.Copy(tf); mt.Inc(1); mt.Norm(); tf.CMove(mt, s); S.CMove(Q, ns); C.Add(S); mt.Copy(te); mt.Add(tf); mt.Norm(); nb = 1 + (mt.NBits() + 1) / 2; // convert exponent to signed 2-bit window for (i = 0; i < nb; i++) { a = (sbyte)(te.LastBits(3) - 4); te.Dec(a); te.Norm(); te.FShr(2); b = (sbyte)(tf.LastBits(3) - 4); tf.Dec(b); tf.Norm(); tf.FShr(2); w[i] = (sbyte)(4 * a + b); } w[nb] = (sbyte)(4 * te.LastBits(3) + tf.LastBits(3)); S.Copy(W[(w[nb] - 1) / 2]); for (i = nb - 1; i >= 0; i--) { T.Select(W, w[i]); S.Dbl(); S.Dbl(); S.Add(T); } S.Sub(C); // apply correction S.Affine(); return(S); }