Exemple #1
0
        public static GroupElement MultiModPow(Group group, GroupElement[] bases, BigInteger[] exponents)
        {
            if (bases == null || exponents == null || bases.Length != exponents.Length)
            {
                throw new ArgumentException();
            }

            GroupElement ge = group.Identity;

            for (int i = 0; i < bases.Length; i++)
            {
                ge = ge.Multiply(bases[i].Exponentiate(exponents[i]));
            }
            return(ge);
        }
Exemple #2
0
        internal static BigInteger GenerateSetMembershipChallenge(HashAlgorithm hash, BigInteger q, Group Gq, GroupElement g, GroupElement g1, BigInteger[] S, GroupElement tildeCid, GroupElement[] a)
        {
            object[]   protocolArray = { g, g1, S, tildeCid, a };
            BigInteger c             = HashToZq(hash, ConcatArrays(new object[][] { GetGroupDescription(Gq), protocolArray }), q);

            return(c);
        }
Exemple #3
0
        public static BigInteger GenerateRevocationChallenge(HashAlgorithm hash, BigInteger q, GroupElement g, GroupElement g1, GroupElement gt, GroupElement K, GroupElement tildeCid, GroupElement X, GroupElement Y, GroupElement Cd, GroupElement T1, GroupElement T2, GroupElement T3)
        {
            object[]   hashArray = new object[] { g, g1, gt, K, tildeCid, X, Y, Cd, T1, T2, T3 };
            BigInteger c         = HashToZq(hash, hashArray, q);

            return(c);
        }
Exemple #4
0
        // H(UID_p, UID_t, H, Cxb, E1, E2, Cxb’, E1’, E2’, additionalInfo)
        public static BigInteger GenerateIdEscrowChallenge(HashAlgorithm hash, BigInteger q, byte[] UIDp, byte[] UIDt, GroupElement H, GroupElement Cxb, GroupElement E1, GroupElement E2, GroupElement CxbPrime, GroupElement E1Prime, GroupElement E2Prime, byte[] additionalInfo)
        {
            object[]   hashArray = new object[] { UIDp, UIDt, H, Cxb, E1, E2, CxbPrime, E1Prime, E2Prime, additionalInfo };
            BigInteger c         = HashToZq(hash, hashArray, q);

            return(c);
        }
Exemple #5
0
        public static void GenerateChallenge(int d, HashAlgorithm hash, BigInteger q, byte[] UIDt, byte[] a, int p, byte[] ap, GroupElement Ps, byte[] m, byte[] md, int[] D, BigInteger[] x, int[] C, GroupElement[] tildeC, byte[][] tildeA, out BigInteger c, out byte[] cp)
        {
            int pPrime = (p == d) ? 0 : p;

            object[] hashArray = new object[] { UIDt, a, D, x, C, tildeC, tildeA, pPrime, ap, Ps, m };
            cp = HashToBytes(hash, hashArray);
            c  = HashToZq(hash, new object[] { new byte[][] { cp, md } }, q);
        }
Exemple #6
0
 public static byte[] ComputeTokenID(HashAlgorithm hash, GroupElement h, GroupElement sigmaZPrime, BigInteger sigmaCPrime, BigInteger sigmaRPrime)
 {
     return(HashToBytes(hash, new object[] { h, sigmaZPrime, sigmaCPrime, sigmaRPrime }));
 }
Exemple #7
0
        public static BigInteger ComputeXt(HashAlgorithm hash, byte[] UIDp, Group Gq, GroupElement[] g, GroupElement g_d, byte[] e, byte[] S, byte[] TI, out byte[] P)
        {
            bool deviceSupported = (g_d != null);

            GroupElement[] gToHash = new GroupElement[g.Length + (deviceSupported ? 1 : 0)];
            for (int i = 0; i < g.Length; i++)
            {
                gToHash[i] = g[i];
            }
            if (deviceSupported)
            {
                gToHash[g.Length] = g_d;
            }

            object[] preGqArray  = new object[] { UIDp };
            object[] postGqArray = new object[] { gToHash, e, S };
            object[] GqArray     = null;
            if (Gq is SubGroup)
            {
                SubGroup subgroup = (SubGroup)Gq;
                GqArray = new object[] { subgroup.P, subgroup.Order, subgroup.Generator.ToByteArray() };
            }
            else if (Gq is P256ECGroup)
            {
                FpCurve curve = (FpCurve)RecommendedParameters.P256.parameters.Curve;
                GqArray = new object[] { curve.Q, curve.A.ToBigInteger(), curve.B.ToBigInteger(), RecommendedParameters.P256.g, RecommendedParameters.P256.parameters.N, BigInteger.One };
            }
            P = HashToBytes(hash, ConcatArrays(new object[][] { preGqArray, GqArray, postGqArray }));

            BigInteger xt = HashToZq(hash, new object[] { (byte)1, P, TI }, Gq.Order);

            return(xt);
        }
Exemple #8
0
 public abstract GroupElement Multiply(GroupElement other);
Exemple #9
0
 public override GroupElement Multiply(GroupElement other)
 {
     return(new SubgroupElement(i.Multiply((other as SubgroupElement).i).Mod(subgroup.P), subgroup));
 }
Exemple #10
0
 public override GroupElement Multiply(GroupElement other)
 {
     return(new ECElement(point.Add((other as ECElement).point) as FpPoint));
 }
Exemple #11
0
        internal static void GenerateTestVectors(string uidp, Formatter formater, bool subgroup, bool supportDevice, bool lite, int maxAttribIndex, int[] D)
        {
            if (formater.type != Formatter.Type.doc)
            {
                throw new ArgumentException("Test vectors can only be printed with a doc formatter");
            }

            int n = maxAttribIndex;
            int t = n + 1; // the token information field index
            int d = n + 2; // the device field index

            //
            // hash input formatting
            //
            string UIDh = "SHA-256";

            formater.PrintText("UIDh", UIDh);
            HashAlgorithm hash = HashAlgorithm.Create(UIDh);

            //
            // Setup
            //

            Group Gq;

            if (subgroup)
            {
                Gq = new SubGroup(RecommendedParameters.L2048N256.p, RecommendedParameters.L2048N256.q, RecommendedParameters.L2048N256.g, RecommendedParameters.L2048N256.Oid);
            }
            else
            {
                Gq = new P256ECGroup();
            }
            BigInteger q = Gq.Order;

            // issuer setup
            byte[] UIDp = Encoding.UTF8.GetBytes(uidp);
            formater.PrintHex("UIDp", UIDp);

            formater.PrintText("GroupName", Gq.OID);

            BigInteger y0 = ProtocolHelper.GetRandom(q, true);

            formater.PrintBigInteger("y0", y0);

            GroupElement[] generators = new GroupElement[n + 2];
            generators[0] = Gq.Generator.Exponentiate(y0);
            generators[0].Print("g0", formater);
            GroupElement deviceGenerator;

            if (subgroup)
            {
                SubGroup sgGq = (SubGroup)Gq;
                for (int i = 1; i <= n; i++)
                {
                    // we use the recommended parameters for the g_i
                    generators[i] = new SubgroupElement(RecommendedParameters.L2048N256.g_i[i - 1], sgGq);
                }
                generators[t]   = new SubgroupElement(RecommendedParameters.L2048N256.g_t, sgGq);
                deviceGenerator = new SubgroupElement(RecommendedParameters.L2048N256.g_d, sgGq);
            }
            else
            {
                for (int i = 1; i <= n; i++)
                {
                    // we use the recommended parameters for the g_i
                    generators[i] = new ECElement(RecommendedParameters.P256.g_i[i - 1]); // g_i is zero-based
                }
                generators[t]   = new ECElement(RecommendedParameters.P256.g_t);
                deviceGenerator = new ECElement(RecommendedParameters.P256.g_d);
            }


            byte[] e = { 0x00, 0x01, 0x01, 0x00, 0x00 };
            for (int i = 0; i < e.Length; i++)
            {
                formater.PrintHex("e" + (i + 1), new byte[] { e[i] });
            }

            string SValue = "Issuer parameters specification";

            byte[] S = Encoding.UTF8.GetBytes(SValue);
            formater.PrintHex("S", S);

            //
            // ID Escrow - Auditor setup
            //

            BigInteger   ie_x = null;
            GroupElement ie_H = null;

            byte[] ie_additionalInfo = null;
            if (!lite) // TODO: only print if hasCommitment is true
            {
                ie_x = ProtocolHelper.GetRandom(q);
                formater.PrintBigInteger("ie_x", ie_x);
                ie_H = Gq.Generator.Exponentiate(ie_x);
                ie_H.Print("ie_H", formater);
                String ie_additionalInfoValue = "ID Escrow policy";
                ie_additionalInfo = Encoding.UTF8.GetBytes(ie_additionalInfoValue);
                formater.PrintHex("ie_additionalInfo", ie_additionalInfo);
            }

            //
            // Revocation Authority setup
            //

            BigInteger   r_delta = null;
            GroupElement r_K     = null;

            BigInteger[] r_R = null;
            GroupElement r_V = null;

            if (!lite)  // TODO: only print if hasCommitment is true
            {
                r_delta = ProtocolHelper.GetRandom(q);
                formater.PrintBigInteger("r_delta", r_delta);
                // K = g^delta
                r_K = Gq.Generator.Exponentiate(r_delta);
                r_K.Print("r_K", formater);
                // revoked values
                r_R = new BigInteger[4];
                BigInteger vExponentAccumulator = BigInteger.One;
                for (int i = 0; i < r_R.Length; i++)
                {
                    r_R[i] = ProtocolHelper.GetRandom(q);
                    formater.PrintBigInteger("r_R" + (i + 1), r_R[i]);
                    // V = gt ^ Prod_{x \in R} (delta + x)
                    vExponentAccumulator = vExponentAccumulator.Multiply(r_delta.Add(r_R[i]).Mod(q)).Mod(q);
                }
                r_V = generators[t].Exponentiate(vExponentAccumulator);
                r_V.Print("r_V", formater);
            }

            //
            // Issuance
            //

            // issuance protocol input
            byte[][] A =
            {
                new BigInteger("1234567890", 10).ToByteArray(), // user unique ID, direct-encoding
                Encoding.UTF8.GetBytes("Alice Smith"),          // name, hashed
                Encoding.UTF8.GetBytes("USA"),                  // country of residence, hashed
                new byte[] { 0x02 },                            // level, direct-encoding
                new BigInteger("25", 10).ToByteArray()          // age, direct-encoding
            };
            for (int i = 0; i < A.Length; i++)
            {
                formater.PrintHex("A" + (i + 1), A[i]);
            }

            byte[] TI = Encoding.UTF8.GetBytes("Token information field value");
            formater.PrintHex("TI", TI);
            byte[] PI = Encoding.UTF8.GetBytes("Prover information field value");
            formater.PrintHex("PI", PI);

            BigInteger[] x  = new BigInteger[n + 2];
            BigInteger   xd = null;

            x[0] = BigInteger.One;
            for (int i = 0; i < n; i++)
            {
                x[i + 1] = ProtocolHelper.ComputeXi(hash, q, e[i], A[i]);
                formater.PrintBigInteger("x" + (i + 1), x[i + 1]);
            }

            byte[] P;
            x[t] = ProtocolHelper.ComputeXt(hash, UIDp, Gq, generators, supportDevice ? deviceGenerator : null, e, S, TI, out P);
            formater.PrintHex("P", P);
            formater.PrintBigInteger("xt", x[t]);

            // device info
            GroupElement hd = Gq.Identity;

            if (supportDevice)
            {
                xd = ProtocolHelper.ComputeXi(hash, q, (byte)1, Encoding.UTF8.GetBytes("Device secret"));
                formater.PrintBigInteger("xd", xd);
                hd = deviceGenerator.Exponentiate(xd);
                hd.Print("hd", formater);
            }

            GroupElement gamma = ProtocolHelper.MultiModPow(Gq, generators, x);

            if (supportDevice)
            {
                gamma = gamma.Multiply(hd);
            }
            gamma.Print("gamma", formater);

            // issuer precomputations
            GroupElement sigmaZ = gamma.Exponentiate(y0);

            sigmaZ.Print("sigmaZ", formater);

            BigInteger issuerW = ProtocolHelper.GetRandom(q);

            formater.PrintBigInteger("w", issuerW);

            GroupElement sigmaA = Gq.Generator.Exponentiate(issuerW);

            sigmaA.Print("sigmaA", formater);

            GroupElement sigmaB = gamma.Exponentiate(issuerW);

            sigmaB.Print("sigmaB", formater);

            // user precomputations
            BigInteger alpha = ProtocolHelper.GetRandom(q, true);

            formater.PrintBigInteger("alpha", alpha);
            BigInteger beta1 = ProtocolHelper.GetRandom(q);

            formater.PrintBigInteger("beta1", beta1);
            BigInteger beta2 = ProtocolHelper.GetRandom(q);

            formater.PrintBigInteger("beta2", beta2);

            GroupElement h = gamma.Exponentiate(alpha);

            h.Print("h", formater);

            BigInteger alphaInverse = alpha.ModInverse(q);

            formater.PrintBigInteger("alphaInverse", alphaInverse);

            // user second message computations
            GroupElement sigmaZPrime = sigmaZ.Exponentiate(alpha);

            sigmaZPrime.Print("sigmaZPrime", formater);
            GroupElement sigmaAPrime = generators[0].Exponentiate(beta1).Multiply(Gq.Generator.Exponentiate(beta2)).Multiply(sigmaA);

            sigmaAPrime.Print("sigmaAPrime", formater);
            GroupElement sigmaBPrime = sigmaZPrime.Exponentiate(beta1).Multiply(h.Exponentiate(beta2)).Multiply(sigmaB.Exponentiate(alpha));

            sigmaBPrime.Print("sigmaBPrime", formater);
            BigInteger sigmaCPrime = ProtocolHelper.HashToZq(hash, new object[] { h, PI, sigmaZPrime, sigmaAPrime, sigmaBPrime }, q);

            formater.PrintBigInteger("sigmaCPrime", sigmaCPrime);
            BigInteger sigmaC = sigmaCPrime.Add(beta1).Mod(q);

            formater.PrintBigInteger("sigmaC", sigmaC);

            // issuer third message computations
            BigInteger sigmaR = sigmaC.Multiply(y0).Add(issuerW).Mod(q);

            formater.PrintBigInteger("sigmaR", sigmaR);

            // user token generation computations
            BigInteger sigmaRPrime = sigmaR.Add(beta2).Mod(q);

            formater.PrintBigInteger("sigmaRPrime", sigmaRPrime);

            // token signature verification
            if (!(sigmaAPrime.Multiply(sigmaBPrime)).Equals(
                    ((Gq.Generator.Multiply(h)).Exponentiate(sigmaRPrime)).Multiply(
                        (generators[0].Multiply(sigmaZPrime)).Exponentiate(sigmaCPrime.Negate().Mod(q))))
                )
            {
                throw new Exception("signature is invalid");
            }

            //
            // Presentation
            //

            // parameters
            formater.PrintSet("D", D);

            int[] U = new int[n - D.Length];
            int   dIndex = 0, uIndex = 0;

            for (int i = 1; i <= n; i++)
            {
                if (D.Length > 0 && D[dIndex] == i)
                {
                    // i is disclosed, skip
                    dIndex++;
                }
                else
                {
                    // i is undisclosed, add to U
                    U[uIndex++] = i;
                }
            }
            formater.PrintSet("U", U);
            // we commit to the first undisclosed index, if any
            bool hasCommitment = !lite && U.Length > 0;

            if (hasCommitment && (U.Length < 2 || !U.Contains <int>(1) || !U.Contains <int>(4)))
            {
                // we can't commit to attributes 1 and 4
                throw new ArgumentException("U must have at least two elements");
            }
            int[] C = hasCommitment ? new int[] { 1, 4 } : new int[] { };
            if (hasCommitment)
            {
                formater.PrintSet("C", C);
            }
            // p is the first committed attribute (if any), or the device attribute if device-protected
            int p = hasCommitment ? (supportDevice ? d : C[0]) : 0;

            if (hasCommitment)
            {
                formater.PrintText("p", supportDevice ? "d" : p.ToString());
            }
            byte[] s = Encoding.UTF8.GetBytes("VerifierUID");
            if (hasCommitment)
            {
                formater.PrintHex("s", s);
            }
            byte[] m = Encoding.UTF8.GetBytes("VerifierUID+random data");
            formater.PrintHex("m", m);
            byte[] md = Encoding.UTF8.GetBytes("Direct message");
            formater.PrintHex("md", md);

            // Prover's precomputation
            BigInteger[]   w         = new BigInteger[n + 2 + (supportDevice ? 1 : 0)];
            BigInteger[]   tildeO    = new BigInteger[C.Length];
            BigInteger[]   tildeW    = new BigInteger[C.Length];
            GroupElement[] tildeC    = new GroupElement[C.Length];
            byte[][]       tildeA    = new byte[C.Length][];
            GroupElement[] bases     = new GroupElement[U.Length + 1 + (supportDevice ? 1 : 0)];
            BigInteger[]   exponents = new BigInteger[U.Length + 1 + (supportDevice ? 1 : 0)];
            w[0] = ProtocolHelper.GetRandom(q);
            formater.PrintBigInteger("w0", w[0]);
            GroupElement ad      = null;
            BigInteger   wdPrime = null;
            GroupElement Ps      = null;
            GroupElement gs      = null;
            GroupElement apPrime = null;

            if (p > 0 && s != null && hasCommitment)
            {
                gs = ProtocolHelper.GenerateScopeElement(Gq, s, formater);
                gs.Print("gs", formater);
            }
            if (supportDevice)
            {
                w[d] = ProtocolHelper.GetRandom(q);
                formater.PrintBigInteger("wd", w[d]);

                // Device's commitment
                wdPrime = ProtocolHelper.GetRandom(q);
                formater.PrintBigInteger("wdPrime", wdPrime);
                ad = deviceGenerator.Exponentiate(wdPrime);
                ad.Print("ad", formater);

                if (hasCommitment)
                {
                    // Device's pseudonym
                    apPrime = gs.Exponentiate(wdPrime);
                    apPrime.Print("apPrime", formater);
                    Ps = gs.Exponentiate(xd);
                    Ps.Print("Ps", formater);
                }
            }

            // Presentation proof generation
            bases[0]     = h;
            exponents[0] = w[0];
            if (supportDevice)
            {
                bases[1]     = deviceGenerator;
                exponents[1] = w[d];
            }
            for (int i = 0; i < U.Length; i++)
            {
                int index = U[i];
                w[index] = ProtocolHelper.GetRandom(q);
                formater.PrintBigInteger("w" + index, w[index]);
                bases[i + 1 + (supportDevice ? 1 : 0)]     = generators[index];
                exponents[i + 1 + (supportDevice ? 1 : 0)] = w[index];
            }
            GroupElement aInput = ProtocolHelper.MultiModPow(Gq, bases, exponents);

            if (supportDevice)
            {
                aInput = aInput.Multiply(ad);
            }
            byte[] a = ProtocolHelper.HashToBytes(hash, new Object[] { aInput });
            formater.PrintHex("a", a);
            byte[] ap = null;

            // Generate commitments
            for (int i = 0; i < C.Length; i++)
            {
                int index = C[i];
                tildeO[i] = ProtocolHelper.GetRandom(q);
                formater.PrintBigInteger("tildeO" + index, tildeO[i]);
                tildeW[i] = ProtocolHelper.GetRandom(q);
                formater.PrintBigInteger("tildeW" + index, tildeW[i]);
                bases = new GroupElement[2] {
                    Gq.Generator, generators[1]
                };
                exponents = new BigInteger[2] {
                    x[index], tildeO[i]
                };
                tildeC[i] = ProtocolHelper.MultiModPow(Gq, bases, exponents);
                tildeC[i].Print("tildeC" + index, formater);
                exponents = new BigInteger[2] {
                    w[index], tildeW[i]
                };
                tildeA[i] = ProtocolHelper.HashToBytes(hash, new object[] { ProtocolHelper.MultiModPow(Gq, bases, exponents) });
                formater.PrintHex("tildeA" + index, tildeA[i]);
            }

            // compute pseudonym
            if (p > 0 && s != null)
            {
                GroupElement apInput = gs.Exponentiate(w[p]);
                if (p == d)
                {
                    apInput = apInput.Multiply(apPrime);
                }
                ap = ProtocolHelper.HashToBytes(hash, new Object[] { apInput });
                formater.PrintHex("ap", ap);
                if (p != d)
                {
                    Ps = gs.Exponentiate(x[p]);
                    Ps.Print("Ps", formater);
                }
            }
            BigInteger[] disclosedX = new BigInteger[D.Length];
            for (int i = 0; i < D.Length; i++)
            {
                disclosedX[i] = x[D[i]];
            }
            byte[] UIDt = ProtocolHelper.ComputeTokenID(hash, h, sigmaZPrime, sigmaCPrime, sigmaRPrime);
            formater.PrintHex("UIDt", UIDt);
            BigInteger c;

            byte[] cp;
            ProtocolHelper.GenerateChallenge(d, hash, q, UIDt, a, p, ap, Ps, m, md, D, disclosedX, C, tildeC, tildeA, out c, out cp);
            formater.PrintHex("cp", cp);
            formater.PrintBigInteger("c", c);
            BigInteger[] r = new BigInteger[n + 3];
            r[0] = c.Multiply(alphaInverse).Add(w[0]).Mod(q);
            formater.PrintBigInteger("r0", r[0]);
            for (int i = 0; i < U.Length; i++)
            {
                int index = U[i];
                r[index] = c.Negate().Mod(q).Multiply(x[index]).Add(w[index]).Mod(q);
                formater.PrintBigInteger("r" + index, r[index]);
            }

            if (supportDevice)
            {
                // Device response computation
                BigInteger rdPrime = c.Negate().Mod(q).Multiply(xd).Add(wdPrime).Mod(q);
                formater.PrintBigInteger("rdPrime", rdPrime);
                // a_d = g_d^r'_d h_d^c
                GroupElement validation = deviceGenerator.Exponentiate(rdPrime).Multiply(hd.Exponentiate(c));
                if (!ad.Equals(validation))
                {
                    throw new Exception("invalid device response");
                }

                r[d] = rdPrime.Add(w[d]).Mod(q);
                formater.PrintBigInteger("rd", r[d]);
            }

            BigInteger[] tildeR = new BigInteger[C.Length];
            for (int i = 0; i < C.Length; i++)
            {
                int index = C[i];
                tildeR[i] = c.Negate().Mod(q).Multiply(tildeO[i]).Add(tildeW[i]).Mod(q);
                formater.PrintBigInteger("tildeR" + index, tildeR[i]);
            }

            //
            // ID Escrow - Veriable encryption
            //
            int          ie_bIndex = 0, commitmentIndex = 0;
            BigInteger   ie_r = null, ie_xbPrime = null, ie_rPrime = null, ie_obPrime = null, ie_c = null, ie_rxb = null, ie_rr = null, ie_rob = null;
            GroupElement ie_E1 = null, ie_E2 = null, ie_CxbPrime = null, ie_E1Prime = null, ie_E2Prime = null;

            if (hasCommitment)
            {
                ie_bIndex = 1; // x1 is used as ID escrow attribute
                formater.PrintText("ie_b", ie_bIndex.ToString());
                commitmentIndex = 0;

                ie_r = ProtocolHelper.GetRandom(q);
                formater.PrintBigInteger("ie_r", ie_r);

                ie_E1 = Gq.Generator.Exponentiate(ie_r);
                ie_E1.Print("ie_E1", formater);
                ie_E2 = Gq.Generator.Exponentiate(x[1]).Multiply(ie_H.Exponentiate(ie_r));
                ie_E2.Print("ie_E2", formater);

                ie_xbPrime = ProtocolHelper.GetRandom(q);
                formater.PrintBigInteger("ie_xbPrime", ie_xbPrime);
                ie_rPrime = ProtocolHelper.GetRandom(q);
                formater.PrintBigInteger("ie_rPrime", ie_rPrime);
                ie_obPrime = ProtocolHelper.GetRandom(q);
                formater.PrintBigInteger("ie_obPrime", ie_obPrime);
                ie_CxbPrime = Gq.Generator.Exponentiate(ie_xbPrime).Multiply(generators[1].Exponentiate(ie_obPrime));
                ie_CxbPrime.Print("ie_CxbPrime", formater);
                ie_E1Prime = Gq.Generator.Exponentiate(ie_rPrime);
                ie_E1Prime.Print("ie_E1Prime", formater);
                ie_E2Prime = Gq.Generator.Exponentiate(ie_xbPrime).Multiply(ie_H.Exponentiate(ie_rPrime));
                ie_E2Prime.Print("ie_E2Prime", formater);
                ie_c = ProtocolHelper.GenerateIdEscrowChallenge(hash, q, UIDp, UIDt, ie_H, tildeC[commitmentIndex], ie_E1, ie_E2, ie_CxbPrime, ie_E1Prime, ie_E2Prime, ie_additionalInfo);
                formater.PrintBigInteger("ie_c", ie_c);
                ie_rxb = ie_c.Negate().Mod(q).Multiply(x[ie_bIndex]).Add(ie_xbPrime).Mod(q);
                formater.PrintBigInteger("ie_rxb", ie_rxb);
                ie_rr = ie_c.Negate().Mod(q).Multiply(ie_r).Add(ie_rPrime).Mod(q);
                formater.PrintBigInteger("ie_rr", ie_rr);
                ie_rob = ie_c.Negate().Mod(q).Multiply(tildeO[commitmentIndex]).Add(ie_obPrime).Mod(q);
                formater.PrintBigInteger("ie_rob", ie_rob);
            }

            //
            // Revocation
            //
            int        r_id = 0;
            BigInteger r_d = null, r_cPrime = null;

            BigInteger[] r_t = new BigInteger[2 + 1], r_k = new BigInteger[6 + 1], r_s = new BigInteger[6 + 1]; // we waste index 0 for readability
            GroupElement r_W = null, r_Q = null, r_X = null, r_Y = null, r_Cd = null, r_T1 = null, r_T2 = null, r_T3 = null;

            if (hasCommitment)
            {
                r_id = 1; // x1 is used as revocation attribute
                formater.PrintText("r_id", r_id.ToString());

                // compute revocation witness

                r_d = BigInteger.One;
                BigInteger deltaPlusXid         = r_delta.Add(x[r_id]); // delta + x_id
                BigInteger wExponentAccumulator = BigInteger.One;
                for (int i = 0; i < r_R.Length; i++)
                {
                    // rd = Prod_{x \in R}(x - xid)
                    // r_d = r_d.Multiply(r_delta.Add(r_R[i])).Mod(deltaPlusXid); // TODO (FIXME): delete, old calculation
                    r_d = r_d.Multiply(r_R[i].Subtract(x[r_id]).Mod(q)).Mod(q);
                    wExponentAccumulator = wExponentAccumulator.Multiply(r_delta.Add(r_R[i])).Mod(q);
                }
                formater.PrintBigInteger("r_d", r_d);
                BigInteger wExponent = wExponentAccumulator.Subtract(r_d).Mod(q).Multiply(
                    r_delta.Add(x[r_id]).ModInverse(q)
                    ).Mod(q);
                // W = gt ^ [( Prod_{x \in R}(delta + x)-d ) / (delta + x_id)]
                r_W = generators[t].Exponentiate(wExponent);
                r_W.Print("r_W", formater);
                // Q = V W^(-x_id) gt^(-d)
                r_Q = r_V.Multiply(r_W.Exponentiate(x[r_id].Negate())).Multiply(generators[t].Exponentiate(r_d.Negate()));
                r_Q.Print("r_Q", formater);

                // compute non-revocation proof
                for (int i = 1; i <= 2; i++)
                {
                    r_t[i] = ProtocolHelper.GetRandom(q);
                    formater.PrintBigInteger("r_t" + i, r_t[i]);
                }
                for (int i = 1; i <= 6; i++)
                {
                    r_k[i] = ProtocolHelper.GetRandom(q);
                    formater.PrintBigInteger("r_k" + i, r_k[i]);
                }
                // X = W g^t1
                r_X = r_W.Multiply(Gq.Generator.Exponentiate(r_t[1]));
                r_X.Print("r_X", formater);
                // Y = Q K^t1
                r_Y = r_Q.Multiply(r_K.Exponentiate(r_t[1]));
                r_Y.Print("r_Y", formater);
                // Cd = gt^d g1^t2
                r_Cd = generators[t].Exponentiate(r_d).Multiply(generators[1].Exponentiate(r_t[2]));
                r_Cd.Print("r_Cd", formater);
                // w = d^(-1) mod q
                BigInteger r_w = r_d.ModInverse(q);
                formater.PrintBigInteger("r_w", r_w);
                // z = t1 tildaO_id - t2 mod q
                BigInteger r_z = r_t[1].Multiply(tildeO[commitmentIndex]).Mod(q).Subtract(r_t[2]).Mod(q);
                formater.PrintBigInteger("r_z", r_z);
                // z' = -t2 w mod q
                BigInteger r_zPrime = r_t[2].Negate().Multiply(r_w).Mod(q);
                formater.PrintBigInteger("r_zPrime", r_zPrime);
                // T1 = X^k1 (tildeC_id K)^-k2 g1^k3
                r_T1 =
                    r_X.Exponentiate(r_k[1]).Multiply(
                        tildeC[commitmentIndex].Multiply(r_K).Exponentiate(r_k[2].Negate()).Multiply(
                            generators[1].Exponentiate(r_k[3])));
                r_T1.Print("r_T1", formater);
                // T2 = g^k1 g1^k4
                r_T2 = Gq.Generator.Exponentiate(r_k[1]).Multiply(generators[1].Exponentiate(r_k[4]));
                r_T2.Print("r_T2", formater);
                // T3 = Cd^k5 g1^k6
                r_T3 = r_Cd.Exponentiate(r_k[5]).Multiply(generators[1].Exponentiate(r_k[6]));
                r_T3.Print("r_T3", formater);
                // c' = H(g, g1, gt, K, tildeC_id, X, Y, Cd, T1, T2, T3)
                r_cPrime = ProtocolHelper.GenerateRevocationChallenge(hash, q, Gq.Generator, generators[1], generators[t], r_K, tildeC[commitmentIndex], r_X, r_Y, r_Cd, r_T1, r_T2, r_T3);
                formater.PrintBigInteger("r_cPrime", r_cPrime);
                BigInteger r_cPrimeNegate = r_cPrime.Negate().Mod(q);
                // s1 = -c x_id + k1 mod q
                // s2 = -c t1 + k2 mod q
                // s3 = -c z + k3 mod q
                // s4 = -c tildeO_id + k4 mod q
                // s5 = -c w + k5 mod q
                // s6 = -c z' + k6 mod q
                BigInteger[] r_sVariable = { null, x[r_id], r_t[1], r_z, tildeO[commitmentIndex], r_w, r_zPrime };
                for (int i = 1; i <= 6; i++)
                {
                    r_s[i] = r_cPrimeNegate.Multiply(r_sVariable[i]).Add(r_k[i]).Mod(q);
                    formater.PrintBigInteger("r_s" + i, r_s[i]);
                }
            }

            //
            // Set membership
            //

            int        sm_x_index = 0, sm_i = 0;
            int        smCommitmentIndex = 1; // x4 (2nd committed value) is used for set membership proof
            BigInteger sm_challenge      = null;

            BigInteger[]   sm_S = null, sm_c = null, sm_r = null;
            GroupElement[] sm_a = null;
            if (hasCommitment)
            {
                // x4 is used as the committed attribute
                sm_x_index = 4;
                formater.PrintText("sm_x_index", sm_x_index.ToString());

                sm_i = 2; // x4 is the 2nd value in the set
                formater.PrintText("sm_i", sm_i.ToString());

                int sm_n = 3; // size of the attribute set
                formater.PrintText("sm_n", sm_n.ToString());

                // attribute set
                sm_S = new BigInteger[sm_n];
                for (int i = 1; i <= sm_S.Length; i++)
                {
                    sm_S[i - 1] = new BigInteger(i.ToString(), 10);
                    formater.PrintBigInteger("sm_s" + i, sm_S[i - 1]);
                }

                // SetMembershipProve
                sm_a = new GroupElement[sm_S.Length];
                sm_c = new BigInteger[sm_S.Length];
                sm_r = new BigInteger[sm_S.Length];
                BigInteger sm_sumC = BigInteger.Zero;
                for (int i = 1; i <= sm_S.Length; i++)
                {
                    if (i == sm_i)
                    {
                        continue;
                    }
                    sm_c[i - 1] = ProtocolHelper.GetRandom(q, true);
                    formater.PrintBigInteger("sm_c" + i, sm_c[i - 1]);
                    sm_sumC     = sm_sumC.Add(sm_c[i - 1]).Mod(q);
                    sm_r[i - 1] = ProtocolHelper.GetRandom(q, true);
                    formater.PrintBigInteger("sm_r" + i, sm_r[i - 1]);
                    sm_a[i - 1] =
                        generators[1].Exponentiate(sm_r[i - 1]).Multiply(
                            Gq.Generator.Exponentiate(sm_S[i - 1].Multiply(sm_c[i - 1]).Mod(q)).Multiply(
                                tildeC[smCommitmentIndex].Exponentiate(sm_c[i - 1].Negate().Mod(q))));
                    sm_a[i - 1].Print("sm_a" + i, formater);
                }
                BigInteger sm_w = ProtocolHelper.GetRandom(q, true);
                formater.PrintBigInteger("sm_w", sm_w);
                sm_a[sm_i - 1] = generators[1].Exponentiate(sm_w);
                sm_a[sm_i - 1].Print("sm_a" + sm_i, formater);
                sm_challenge =
                    ProtocolHelper.GenerateSetMembershipChallenge(hash, q, Gq, Gq.Generator, generators[1], sm_S, tildeC[smCommitmentIndex], sm_a);
                formater.PrintBigInteger("sm_c", sm_challenge);
                sm_c[sm_i - 1] = sm_challenge.Subtract(sm_sumC).Mod(q);
                formater.PrintBigInteger("sm_c" + sm_i, sm_c[sm_i - 1]);
                sm_r[sm_i - 1] = sm_c[sm_i - 1].Multiply(tildeO[smCommitmentIndex]).Add(sm_w).Mod(q);
                formater.PrintBigInteger("sm_r" + sm_i, sm_r[sm_i - 1]);
            }

            //
            // Proof verification
            //

            // Verifier's U-Prove token signature verification
            BigInteger digest = ProtocolHelper.HashToZq(hash, new object[] {
                h,
                PI,
                sigmaZPrime,
                Gq.Generator.Exponentiate(sigmaRPrime).Multiply(generators[0].Exponentiate(sigmaCPrime.Negate().Mod(q))),
                h.Exponentiate(sigmaRPrime).Multiply(sigmaZPrime.Exponentiate(sigmaCPrime.Negate().Mod(q)))
            }, q);

            if (!sigmaCPrime.Equals(digest))
            {
                throw new Exception("invalid signature");
            }

            // Verifier's proof verification
            bases        = new GroupElement[D.Length + 2];
            exponents    = new BigInteger[D.Length + 2];
            bases[0]     = generators[0];
            exponents[0] = BigInteger.One;
            bases[1]     = generators[t];
            exponents[1] = x[t];
            for (int i = 0; i < D.Length; i++)
            {
                int index = D[i];
                bases[i + 2]     = generators[index];
                exponents[i + 2] = x[index];
            }
            GroupElement temp = ProtocolHelper.MultiModPow(Gq, bases, exponents);

            bases        = new GroupElement[U.Length + 2 + (supportDevice ? 1 : 0)];
            exponents    = new BigInteger[U.Length + 2 + (supportDevice ? 1 : 0)];
            bases[0]     = temp;
            exponents[0] = c.Negate().Mod(q);
            bases[1]     = h;
            exponents[1] = r[0];
            if (supportDevice)
            {
                bases[2]     = deviceGenerator;
                exponents[2] = r[d];
            }
            for (int i = 0; i < U.Length; i++)
            {
                int index = U[i];
                bases[i + 2 + (supportDevice ? 1 : 0)]     = generators[index];
                exponents[i + 2 + (supportDevice ? 1 : 0)] = r[index];
            }
            GroupElement digest2Input = ProtocolHelper.MultiModPow(Gq, bases, exponents);

            byte[] digest2 = ProtocolHelper.HashToBytes(hash, new object[] { digest2Input });
            if (!a.SequenceEqual(digest2))
            {
                throw new Exception("invalid proof");
            }
            if (hasCommitment)
            {
                // verify pseudonym
                bases = new GroupElement[2] {
                    Ps, gs
                };
                exponents = new BigInteger[2] {
                    c, r[p]
                };
                digest2Input = ProtocolHelper.MultiModPow(Gq, bases, exponents);
                digest2      = ProtocolHelper.HashToBytes(hash, new object[] { digest2Input });
                if (!ap.SequenceEqual(digest2))
                {
                    throw new Exception("invalid pseudonym");
                }

                // verify commitment
                for (int i = 0; i < C.Length; i++)
                {
                    int index = C[i];
                    bases = new GroupElement[3] {
                        tildeC[i], Gq.Generator, generators[1]
                    };
                    exponents = new BigInteger[3] {
                        c, r[index], tildeR[i]
                    };
                    digest2Input = ProtocolHelper.MultiModPow(Gq, bases, exponents);
                    digest2      = ProtocolHelper.HashToBytes(hash, new object[] { digest2Input });
                    if (!tildeA[i].SequenceEqual(digest2))
                    {
                        throw new Exception("invalid commitment: " + index);
                    }
                }

                //
                // ID Escrow - Verifier validation
                //

                GroupElement ie_CxBDoublePrime = Gq.Generator.Exponentiate(ie_rxb).Multiply(generators[1].Exponentiate(ie_rob)).Multiply(tildeC[commitmentIndex].Exponentiate(ie_c));
                GroupElement ie_E1DoublePrime  = Gq.Generator.Exponentiate(ie_rr).Multiply(ie_E1.Exponentiate(ie_c));
                GroupElement ie_E2DoublePrime  = Gq.Generator.Exponentiate(ie_rxb).Multiply(ie_H.Exponentiate(ie_rr)).Multiply(ie_E2.Exponentiate(ie_c));
                BigInteger   ie_cPrime         = ProtocolHelper.GenerateIdEscrowChallenge(hash, q, UIDp, UIDt, ie_H, tildeC[commitmentIndex], ie_E1, ie_E2, ie_CxBDoublePrime, ie_E1DoublePrime, ie_E2DoublePrime, ie_additionalInfo);
                if (!ie_c.Equals(ie_cPrime))
                {
                    throw new Exception("invalid ID escrow encryption");
                }

                //
                // ID Escrow - Auditor decryption
                //

                GroupElement ie_PE = ie_E2.Multiply(ie_E1.Exponentiate(ie_x.Negate()));
                if (!Gq.Generator.Exponentiate(x[ie_bIndex]).Equals(ie_PE))
                {
                    throw new Exception("invalid ID escrow decryption");
                }

                //
                // Revocation : verify non-revocation proof
                //

                // T1 = (V Y^-1 Cd^-1)^c' X^s1 (tildeC_id K)^-s2 g1^s3
                GroupElement r_T1_2 =
                    (r_V.Multiply(r_Y.Exponentiate(BigInteger.One.Negate())).Multiply(r_Cd.Exponentiate(BigInteger.One.Negate()))).Exponentiate(r_cPrime).Multiply(
                        r_X.Exponentiate(r_s[1])).Multiply(
                        tildeC[commitmentIndex].Multiply(r_K).Exponentiate(r_s[2].Negate())).Multiply(
                        generators[1].Exponentiate(r_s[3]));
                // T2 = tildeC_id^c' g^s1 g1^s4
                GroupElement r_T2_2 =
                    tildeC[commitmentIndex].Exponentiate(r_cPrime).Multiply(Gq.Generator.Exponentiate(r_s[1])).Multiply(generators[1].Exponentiate(r_s[4]));
                // T3 = gt^c' Cd^s5 g1^s6
                GroupElement r_T3_2 =
                    generators[t].Exponentiate(r_cPrime).Multiply(r_Cd.Exponentiate(r_s[5])).Multiply(generators[1].Exponentiate(r_s[6]));
                BigInteger r_cPrime_2 = ProtocolHelper.GenerateRevocationChallenge(hash, q, Gq.Generator, generators[1], generators[t], r_K, tildeC[commitmentIndex], r_X, r_Y, r_Cd, r_T1_2, r_T2_2, r_T3_2);
                if (!r_cPrime.Equals(r_cPrime_2) || !r_Y.Equals(r_X.Exponentiate(r_delta)))
                {
                    throw new Exception("invalid non-revocation proof");
                }

                //
                // Set membership proof verification
                //
                BigInteger sm_challenge_2 = ProtocolHelper.GenerateSetMembershipChallenge(hash, q, Gq, Gq.Generator, generators[1], sm_S, tildeC[smCommitmentIndex], sm_a);
                if (!sm_challenge_2.Equals(sm_challenge))
                {
                    throw new Exception("invalid membership challenge");
                }
                BigInteger sm_sumC_2 = BigInteger.Zero;
                // c_n is not serialized, so we recalculate it from the challenge and the other c values
                for (int i = 0; i < sm_c.Length - 1; i++)
                {
                    sm_sumC_2 = sm_sumC_2.Add(sm_c[i]);
                }
                // c_n = c - \sum_{1 <= j < n} (c_j) mod q
                sm_c[sm_c.Length - 1] = sm_challenge_2.Subtract(sm_sumC_2).Mod(q); // replace c_n
                for (int i = 0; i < sm_r.Length; i++)
                {
                    if (!generators[1].Exponentiate(sm_r[i]).Equals(
                            tildeC[smCommitmentIndex].Exponentiate(sm_c[i]).Multiply(
                                Gq.Generator.Exponentiate(sm_c[i].Multiply(sm_S[i]).Negate().Mod(q)).Multiply(
                                    sm_a[i]))
                            ))
                    {
                        throw new Exception("invalid membership proof");
                    }
                }
            }
        }