Esempio n. 1
0
        /**
         * Helper function to create IdemixSigningIdentity from a file generated by idemixgen go tool
         *
         * @param mspId
         * @return IdemixSigningIdentity object
         * @throws IOException
         * @throws InvalidProtocolBufferException
         */
        private IdemixSigningIdentity CreateIdemixSigningIdentity(string mspId)
        {
            IdemixMSPSignerConfig signerConfig;

            signerConfig = ReadIdemixMSPConfig(Path.Combine(TEST_PATH, mspId, USER_PATH).Locate(), SIGNER_CONFIG);
            Assert.IsNotNull(signerConfig);

            IssuerPublicKey       ipkProto = ReadIdemixIssuerPublicKey(Path.Combine(TEST_PATH, mspId, VERIFIER_PATH).Locate(), IPK_CONFIG);
            IdemixIssuerPublicKey ipkt     = new IdemixIssuerPublicKey(ipkProto);

            Assert.IsTrue(ipkt.Check());

            KeyPair revPk = ReadIdemixRevocationPublicKey(Path.Combine(TEST_PATH, mspId, VERIFIER_PATH).Locate(), REVOCATION_PUBLIC_KEY);

            BIG skt = BIG.FromBytes(signerConfig.Sk.ToByteArray());

            Credential credProto = Credential.Parser.ParseFrom(signerConfig.Cred);

            Assert.IsNotNull(credProto);

            IdemixCredential credt = new IdemixCredential(credProto);

            CredentialRevocationInformation crit = CredentialRevocationInformation.Parser.ParseFrom(signerConfig.CredentialRevocationInformation);

            return(new IdemixSigningIdentity(ipkt, revPk, mspId, skt, credt, crit, signerConfig.OrganizationalUnitIdentifier, (IdemixRoles)signerConfig.Role));
        }
Esempio n. 2
0
 public IdemixEnrollment(IdemixIssuerPublicKey ipk, KeyPair revocationPk, string mspId, BIG sk, IdemixCredential cred, CredentialRevocationInformation cri, string ou, IdemixRoles roleMask)
 {
     Ipk          = ipk;
     RevocationPk = revocationPk;
     MspId        = mspId;
     Sk           = sk;
     Cred         = cred;
     Cri          = cri;
     Ou           = ou;
     RoleMask     = roleMask;
 }
Esempio n. 3
0
        public IUser GetUser(string id)
        {
            IdemixMSPSignerConfig signerConfig = ReadIdemixMSPConfig(Path.Combine(mspId, USER_PATH + id));
            KeyPair          revocationPk      = ReadIdemixRevocationPublicKey(mspId);
            BIG              sk   = BIG.FromBytes(signerConfig.Sk.ToByteArray());
            IdemixCredential cred = new IdemixCredential(Credential.Parser.ParseFrom(signerConfig.Cred));
            CredentialRevocationInformation cri = CredentialRevocationInformation.Parser.ParseFrom(signerConfig.CredentialRevocationInformation);

            IdemixEnrollment enrollment = new IdemixEnrollment(ipk, revocationPk, mspId, sk, cred, cri, signerConfig.OrganizationalUnitIdentifier, (IdemixRoles)signerConfig.Role);

            return(new IdemixUser(id, mspId, enrollment));
        }
        /**
         * Verifies that the revocation PK for a certain epoch is valid,
         * by checking that it was signed with the long term revocation key
         *
         * @param pk         Public Key
         * @param epochPK    Epoch PK
         * @param epochPkSig Epoch PK Signature
         * @param epoch      Epoch
         * @param alg        Revocation algorithm
         * @return True if valid
         */
        public static bool VerifyEpochPK(KeyPair pk, ECP2 epochPK, byte[] epochPkSig, long epoch, RevocationAlgorithm alg)
        {
            CredentialRevocationInformation cr = new CredentialRevocationInformation();

            cr.RevocationAlg = (int)alg;
            cr.EpochPk       = epochPK;
            cr.Epoch         = epoch;

            byte[] bytesTosign = cr.ToByteArray();
            try
            {
                return(pk.Verify(bytesTosign, epochPkSig, "SHA256withECDSA"));
            }
            catch (Exception e)
            {
                throw new CryptoException("Error during the EpochPK verification", e);
            }
        }
        /**
         * Creates a Credential Revocation Information object
         *
         * @param key              Private key
         * @param unrevokedHandles Array of unrevoked revocation handles
         * @param epoch            The counter (representing a time window) in which this CRI is valid
         * @param alg              Revocation algorithm
         * @return CredentialRevocationInformation object
         */
        public static CredentialRevocationInformation CreateCRI(KeyPair key, BIG[] unrevokedHandles, int epoch, RevocationAlgorithm alg)
        {
            CredentialRevocationInformation cr = new CredentialRevocationInformation();

            cr.RevocationAlg = (int)alg;
            cr.Epoch         = epoch;

            // Create epoch key
            WeakBB.KeyPair keyPair = WeakBB.WeakBBKeyGen();
            if (alg == RevocationAlgorithm.ALG_NO_REVOCATION)
            {
                // Dummy PK in the proto
                cr.EpochPk = IdemixUtils.GenG2.ToProto();
            }
            else
            {
                // Real PK only if we are going to use it
                cr.EpochPk = keyPair.Pk.ToProto();
            }

            // Sign epoch + epoch key with the long term key
            byte[] signed;
            try
            {
                signed        = key.Sign(cr.ToByteArray(), "SHA256withECDSA");
                cr.EpochPkSig = ByteString.CopyFrom(signed);
            }
            catch (Exception e)
            {
                throw new CryptoException("Error processing the signature: ", e);
            }

            if (alg == RevocationAlgorithm.ALG_NO_REVOCATION)
            {
                // build and return the credential information object
                return(cr);
            }
            // If alg not supported, return null
            throw new ArgumentException("Algorithm " + alg.ToString() + " not supported");
        }
Esempio n. 6
0
        /**
         * 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);
        }
 public byte[] GetFSContribution(BIG rh, BIG rRh, CredentialRevocationInformation cri)
 {
     return(empty);
 }
Esempio n. 8
0
            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));
            }
Esempio n. 9
0
        /**
         * Create new Idemix Signing Identity with a fresh pseudonym
         *
         * @param ipk          issuer public key
         * @param revocationPk the issuer's long term revocation public key
         * @param mspId        MSP identifier
         * @param sk           user's secret
         * @param cred         idemix credential
         * @param cri          the credential revocation information
         * @param ou           is OU attribute
         * @param role         is role attribute
         * @throws CryptoException
         * @throws InvalidArgumentException
         */
        public IdemixSigningIdentity(IdemixIssuerPublicKey ipk, KeyPair revocationPk, string mspId, BIG sk, IdemixCredential cred, CredentialRevocationInformation cri, string ou, IdemixRoles role)
        {
            // input checks
            if (ipk == null)
            {
                throw new ArgumentException("Issuer Public Key (IPK) must not be null");
            }
            if (revocationPk == null)
            {
                throw new ArgumentException("Revocation PK must not be null");
            }
            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 (ou == null)
            {
                throw new ArgumentException("OU must not be null");
            }
            if (string.IsNullOrEmpty(ou))
            {
                throw new ArgumentException("OU must not be empty");
            }
            if (sk == null)
            {
                throw new ArgumentException("SK must not be null");
            }
            if (cred == null)
            {
                throw new ArgumentException("Credential must not be null");
            }
            if (cri == null)
            {
                throw new ArgumentException("Credential revocation information must not be null");
            }

            logger.Trace($"Verifying public key with hash: [{BitConverter.ToString(ipk.Hash).Replace("-", "")}] \nAttributes: [{string.Join(",", ipk.AttributeNames)}]");

            if (!ipk.Check())
            {
                CryptoException e = new CryptoException("Issuer public key is not valid");
                logger.Error("", e);
                throw e;
            }

            this.ipk = ipk;
            this.sk  = sk;
            this.cri = cri;

            logger.Trace("Verifying the credential");

            // cryptographically verify credential
            // (check if the issuer's signature is valid)
            if (!cred.Verify(sk, ipk))
            {
                CryptoException e = new CryptoException("Credential is not cryptographically valid");
                logger.Error("", e);
                throw e;
            }

            logger.Trace("Checking attributes");

            // attribute checks
            // 4 attributes are expected:
            // - organization unit (disclosed)
            // - role: admin or member (disclosed)
            // - enrollment id (hidden, for future auditing feature and authorization with CA)
            // - revocation handle (hidden, for future revocation support)
            if (cred.Attrs.Length != 4)
            {
                throw new CryptoException($"Error: There are {cred.Attrs.Length} attributes and the expected are 4");
            }

            byte[] ouBytes   = cred.Attrs[0];
            byte[] roleBytes = cred.Attrs[1];
            byte[] eIdBytes  = cred.Attrs[2];
            byte[] rHBytes   = cred.Attrs[3];

            BIG[] attributes = new BIG[4];
            attributes[0] = BIG.FromBytes(ouBytes);
            attributes[1] = BIG.FromBytes(roleBytes);
            attributes[2] = BIG.FromBytes(eIdBytes);
            attributes[3] = BIG.FromBytes(rHBytes);

            // check that the OU string matches the credential's attribute value
            if (!ou.ToBytes().HashModOrder().ToBytes().SequenceEqual(ouBytes))
            {
                throw new ArgumentException("the OU string does not match the credential");
            }

            // check that the role matches the credential's attribute value
            if (!new BIG((int)role).ToBytes().SequenceEqual(roleBytes))
            {
                throw new ArgumentException("the role does not match the credential");
            }

            logger.Trace("Generating fresh pseudonym and proof");
            // generate a fresh pseudonym
            Pseudonym = new IdemixPseudonym(this.sk, this.ipk);

            // generate a fresh proof of possession of a credential
            // with respect to a freshly generated pseudonym
            Proof = new IdemixSignature(cred, this.sk, Pseudonym, this.ipk, disclosedFlags, msgEmpty, rhIndex, cri);
            logger.Trace("Verifying the proof");
            // verify the proof
            if (!Proof.Verify(disclosedFlags, this.ipk, msgEmpty, attributes, rhIndex, revocationPk, (int)cri.Epoch))
            {
                throw new CryptoException("Generated proof of identity is not valid");
            }

            logger.Trace("Generating the Identity Object");
            // generate a fresh identity with new pseudonym
            idemixIdentity = new IdemixIdentity(mspId, this.ipk, Pseudonym.Nym, ou, role, Proof);
            logger.Trace(idemixIdentity.ToString());
        }
Esempio n. 10
0
        public static void Setup(TestContext context)
        {
            // Parse crypto material from files
            IdemixMSPSignerConfig signerConfig = null;

            try
            {
                signerConfig = ReadIdemixMSPConfig(Path.Combine(TEST_PATH, MSP1OU1, USER_PATH).Locate(), SIGNER_CONFIG);
            }
            catch (System.Exception e)
            {
                Assert.Fail("Unexpected exception while reading signerconfig: " + e.Message);
            }

            Assert.IsNotNull(signerConfig);

            try
            {
                revocationPk = ReadIdemixRevocationPublicKey(Path.Combine(TEST_PATH, MSP1OU1, VERIFIER_PATH).Locate(), REVOCATION_PUBLIC_KEY);
            }
            catch (System.Exception e)
            {
                Assert.Fail("Unexpected exception while reading revocation public key: " + e.Message);
            }

            Assert.IsNotNull(revocationPk);

            IssuerPublicKey ipkProto = null;

            try
            {
                ipkProto = ReadIdemixIssuerPublicKey(Path.Combine(TEST_PATH, MSP1OU1, VERIFIER_PATH).Locate(), IPK_CONFIG);
            }
            catch (IOException e1)
            {
                Assert.Fail("Unexpected exception while reading revocation public key" + e1.Message);
            }

            ipk = new IdemixIssuerPublicKey(ipkProto);
            Assert.IsTrue(ipk.Check());

            sk = BIG.FromBytes(signerConfig.Sk.ToByteArray());

            Credential credProto = null;

            try
            {
                credProto = Credential.Parser.ParseFrom(signerConfig.Cred);
            }
            catch (InvalidProtocolBufferException)
            {
                Assert.Fail("Could not parse a credential");
            }

            Assert.IsNotNull(credProto);

            cred = new IdemixCredential(credProto);

            try
            {
                cri = CredentialRevocationInformation.Parser.ParseFrom(signerConfig.CredentialRevocationInformation);
            }
            catch (InvalidProtocolBufferException e)
            {
                Assert.Fail("failed to extract cri from signer config: " + e.Message);
            }

            Assert.IsNotNull(cri);

            try
            {
                signingIdentity = new IdemixSigningIdentity(ipk, revocationPk, MSP1OU1, sk, cred, cri, OU1, IdemixRoles.MEMBER);
            }
            catch (System.Exception e) when(e is CryptoException || e is ArgumentException)
            {
                Assert.Fail("Could not create Idemix Signing Identity" + e.Message);
            }

            Assert.IsNotNull(signingIdentity);

            nym = signingIdentity.Pseudonym;

            nymPublic = nym.Nym;

            proof = signingIdentity.Proof;
        }