/**
         * 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));
        }
Beispiel #2
0
        /* final exponentiation - keep separate for multi-pairings and to avoid thrashing stack */
        public static FP12 FExp(FP12 m)
        {
            FP2  f = new FP2(new BIG(ROM.Fra), new BIG(ROM.Frb));
            BIG  x = new BIG(ROM.CURVE_Bnx);
            FP12 r = new FP12(m);

            /* Easy part of final exp */
            FP12 lv = new FP12(r);

            lv.Inverse();
            r.Conj();

            r.mul(lv);
            lv.Copy(r);
            r.Frob(f);
            r.Frob(f);
            r.mul(lv);
            /* Hard part of final exp */
            if (ECP.CURVE_PAIRING_TYPE == ECP.BN)
            {
                FP12 x0, x1, x2, x3, x4, x5;
                lv.Copy(r);
                lv.Frob(f);
                x0 = new FP12(lv);
                x0.Frob(f);
                lv.mul(r);
                x0.mul(lv);
                x0.Frob(f);
                x1 = new FP12(r);
                x1.Conj();
                x4 = r.Pow(x);
                if (ECP.SIGN_OF_X == ECP.POSITIVEX)
                {
                    x4.Conj();
                }

                x3 = new FP12(x4);
                x3.Frob(f);

                x2 = x4.Pow(x);
                if (ECP.SIGN_OF_X == ECP.POSITIVEX)
                {
                    x2.Conj();
                }

                x5 = new FP12(x2);
                x5.Conj();
                lv = x2.Pow(x);
                if (ECP.SIGN_OF_X == ECP.POSITIVEX)
                {
                    lv.Conj();
                }

                x2.Frob(f);
                r.Copy(x2);
                r.Conj();

                x4.mul(r);
                x2.Frob(f);

                r.Copy(lv);
                r.Frob(f);
                lv.mul(r);

                lv.USqr();
                lv.mul(x4);
                lv.mul(x5);
                r.Copy(x3);
                r.mul(x5);
                r.mul(lv);
                lv.mul(x2);
                r.USqr();
                r.mul(lv);
                r.USqr();
                lv.Copy(r);
                lv.mul(x1);
                r.mul(x0);
                lv.USqr();
                r.mul(lv);
                r.Reduce();
            }
            else
            {
                FP12 y0, y1, y2, y3;
                // Ghamman & Fouotsa Method
                y0 = new FP12(r);
                y0.USqr();
                y1 = y0.Pow(x);
                if (ECP.SIGN_OF_X == ECP.NEGATIVEX)
                {
                    y1.Conj();
                }

                x.FShr(1);
                y2 = y1.Pow(x);
                if (ECP.SIGN_OF_X == ECP.NEGATIVEX)
                {
                    y2.Conj();
                }

                x.FShl(1);
                y3 = new FP12(r);
                y3.Conj();
                y1.mul(y3);

                y1.Conj();
                y1.mul(y2);

                y2 = y1.Pow(x);
                if (ECP.SIGN_OF_X == ECP.NEGATIVEX)
                {
                    y2.Conj();
                }

                y3 = y2.Pow(x);
                if (ECP.SIGN_OF_X == ECP.NEGATIVEX)
                {
                    y3.Conj();
                }

                y1.Conj();
                y3.mul(y1);

                y1.Conj();
                y1.Frob(f);
                y1.Frob(f);
                y1.Frob(f);
                y2.Frob(f);
                y2.Frob(f);
                y1.mul(y2);

                y2 = y3.Pow(x);
                if (ECP.SIGN_OF_X == ECP.NEGATIVEX)
                {
                    y2.Conj();
                }

                y2.mul(y0);
                y2.mul(r);

                y1.mul(y2);
                y2.Copy(y3);
                y2.Frob(f);
                y1.mul(y2);
                r.Copy(y1);
                r.Reduce();
            }

            return(r);
        }