public JToken CreateProof(CreateProofOptions options, JsonLdProcessorOptions processorOptions)
        {
            var(document, proofs) = options.Document.GetProofs(processorOptions);
            var proof = new BbsBlsSignature2020(proofs.FirstOrDefault() ?? throw new Exception("Proof not found"));

            proof.Context = Constants.SECURITY_CONTEXT_V2_URL;

            var signature    = Convert.FromBase64String(proof.ProofValue);
            var derivedProof = JsonLdProcessor.Compact(new BbsBlsSignatureProof2020(), Constants.SECURITY_CONTEXT_V2_URL, processorOptions);

            var documentStatements = BbsBlsSignature2020Suite.CreateVerifyDocumentData(document, processorOptions);
            var proofStatements    = BbsBlsSignature2020Suite.CreateVerifyProofData(proof, processorOptions);

            var transformedInputDocumentStatements = documentStatements.Select(TransformBlankNodeToId).ToArray();

            var compactInputDocument = Helpers.FromRdf(transformedInputDocumentStatements);

            var revealDocument           = JsonLdProcessor.Frame(compactInputDocument, options.ProofRequest, processorOptions);
            var revealDocumentStatements = BbsBlsSignature2020Suite.CreateVerifyDocumentData(revealDocument, processorOptions);

            var numberOfProofStatements = proofStatements.Count();

            var proofRevealIndicies    = EnumerableFromInt(numberOfProofStatements).ToArray();
            var documentRevealIndicies = revealDocumentStatements.Select(x => Array.IndexOf(transformedInputDocumentStatements, x) + numberOfProofStatements).ToArray();

            if (documentRevealIndicies.Count() != revealDocumentStatements.Count())
            {
                throw new Exception("Some statements in the reveal document not found in original proof");
            }

            var revealIndicies = proofRevealIndicies.Concat(documentRevealIndicies);

            derivedProof["nonce"] = options.Nonce ?? Guid.NewGuid().ToString();

            //Combine all the input statements that
            //were originally signed to generate the proof
            var allInputStatements = proofStatements.Concat(documentStatements);

            var verificationMethod = BbsBlsSignature2020Suite.GetVerificationMethod(proofs.First(), processorOptions);

            var outputProof = BbsProvider.CreateProof(new CreateProofRequest(
                                                          publicKey: verificationMethod.ToBlsKeyPair().GeyBbsKeyPair((uint)allInputStatements.Count()),
                                                          messages: GetProofMessages(allInputStatements.ToArray(), revealIndicies).ToArray(),
                                                          signature: signature,
                                                          blindingFactor: null,
                                                          nonce: derivedProof["nonce"].ToString()));

            // Set the proof value on the derived proof
            derivedProof["proofValue"] = Convert.ToBase64String(outputProof);

            // Set the relevant proof elements on the derived proof from the input proof
            derivedProof["verificationMethod"] = proof["verificationMethod"];
            derivedProof["proofPurpose"]       = proof["proofPurpose"];
            derivedProof["created"]            = proof["created"];

            revealDocument["proof"] = derivedProof;

            return(revealDocument);
        }
        public void FullDemoTest()
        {
            var key       = BbsProvider.GenerateBlsKey();
            var publicKey = key.GeyBbsKeyPair(5);

            var nonce    = "123";
            var messages = new[]
            {
                "message_1",
                "message_2",
                "message_3",
                "message_4",
                "message_5"
            };

            {
                // Sign messages
                var signature = BbsProvider.Sign(new SignRequest(key, messages));

                Assert.NotNull(signature);
                Assert.AreEqual(BbsProvider.SignatureSize, signature.Length);

                // Verify messages
                var verifySignatureResult = BbsProvider.Verify(new VerifyRequest(key, signature, messages));

                Assert.True(verifySignatureResult);

                // Create proof
                var proofMessages1 = new[]
                {
                    new ProofMessage {
                        Message = messages[0], ProofType = ProofMessageType.Revealed
                    },
                    new ProofMessage {
                        Message = messages[1], ProofType = ProofMessageType.Revealed
                    },
                    new ProofMessage {
                        Message = messages[2], ProofType = ProofMessageType.Revealed
                    },
                    new ProofMessage {
                        Message = messages[3], ProofType = ProofMessageType.Revealed
                    },
                    new ProofMessage {
                        Message = messages[4], ProofType = ProofMessageType.Revealed
                    }
                };
                var proofResult = BbsProvider.CreateProof(new CreateProofRequest(publicKey, proofMessages1, signature, null, nonce));

                Assert.NotNull(proofResult);

                // Verify proof of revealed messages
                var indexedMessages1 = new[]
                {
                    new IndexedMessage {
                        Message = messages[0], Index = 0u
                    },
                    new IndexedMessage {
                        Message = messages[1], Index = 1u
                    },
                    new IndexedMessage {
                        Message = messages[2], Index = 2u
                    },
                    new IndexedMessage {
                        Message = messages[3], Index = 3u
                    },
                    new IndexedMessage {
                        Message = messages[4], Index = 4u
                    }
                };
                var verifyResult1 = BbsProvider.VerifyProof(new VerifyProofRequest(publicKey, proofResult, indexedMessages1, nonce));

                Assert.AreEqual(SignatureProofStatus.Success, verifyResult1);
            }

            // Create blinded commitment
            var blindedMessages = new[]
            {
                new IndexedMessage {
                    Index = 0, Message = messages[0]
                }
            };
            var commitment = BbsProvider.CreateBlindedCommitment(new CreateBlindedCommitmentRequest(publicKey, blindedMessages, nonce));

            Assert.NotNull(commitment);

            // Verify blinded commitment
            var verifyResult = BbsProvider.VerifyBlindedCommitment(new VerifyBlindedCommitmentRequest(publicKey, commitment.BlindSignContext.ToArray(), new [] { 0u }, nonce));

            Assert.AreEqual(SignatureProofStatus.Success, verifyResult);

            // Blind sign
            var messagesToSign = new[]
            {
                new IndexedMessage {
                    Index = 1, Message = messages[1]
                },
                new IndexedMessage {
                    Index = 2, Message = messages[2]
                },
                new IndexedMessage {
                    Index = 3, Message = messages[3]
                },
                new IndexedMessage {
                    Index = 4, Message = messages[4]
                }
            };
            var blindedSignature = BbsProvider.BlindSign(new BlindSignRequest(key, publicKey, commitment.Commitment.ToArray(), messagesToSign));

            Assert.NotNull(blindedSignature);
            Assert.AreEqual(BbsProvider.BlindSignatureSize, blindedSignature.Length);

            // Unblind signature
            var unblindedSignature = BbsProvider.UnblindSignature(new UnblindSignatureRequest(blindedSignature, commitment.BlindingFactor.ToArray()));

            Assert.NotNull(unblindedSignature);
            Assert.AreEqual(BbsProvider.SignatureSize, unblindedSignature.Length);

            // Verify signature
            var verifyUnblindedSignatureResult = BbsProvider.Verify(new VerifyRequest(key, unblindedSignature, messages));

            Assert.True(verifyUnblindedSignatureResult);

            // Create proof
            var proofMessages = new[]
            {
                new ProofMessage {
                    Message = messages[0], ProofType = ProofMessageType.Revealed
                },
                new ProofMessage {
                    Message = messages[1], ProofType = ProofMessageType.Revealed
                },
                new ProofMessage {
                    Message = messages[2], ProofType = ProofMessageType.HiddenExternalBlinding
                },
                new ProofMessage {
                    Message = messages[3], ProofType = ProofMessageType.HiddenExternalBlinding
                },
                new ProofMessage {
                    Message = messages[4], ProofType = ProofMessageType.HiddenExternalBlinding
                }
            };

            var proof = BbsProvider.CreateProof(new CreateProofRequest(
                                                    publicKey: publicKey,
                                                    messages: proofMessages,
                                                    signature: unblindedSignature,
                                                    blindingFactor: commitment.BlindingFactor.ToArray(),
                                                    nonce: nonce));

            Assert.NotNull(proof);
            Assert.True(proof.Length > 0);

            // Verify proof
            var indexedMessages = new[]
            {
                new IndexedMessage {
                    Message = messages[0], Index = 0u
                },
                new IndexedMessage {
                    Message = messages[1], Index = 1u
                }
            };

            var verifyProofResult = BbsProvider.VerifyProof(new VerifyProofRequest(publicKey, proof, indexedMessages, nonce));

            Assert.AreEqual(SignatureProofStatus.Success, verifyProofResult);
        }