Example #1
0
async function onboarding(poolHandle, From, fromWallet, fromDid, to, toWallet, toWalletConfig, toWalletCredentials) {
    console.log(`\"${From}\" > Create and store in Wallet \"${From} ${to}\" DID`);
    let [fromToDid, fromToKey] = await indy.createAndStoreMyDid(fromWallet, {});

    console.log(`\"${From}\" > Send Nym to Ledger for \"${From} ${to}\" DID`);
    await sendNym(poolHandle, fromWallet, fromDid, fromToDid, fromToKey, null);

    console.log(`\"${From}\" > Send connection request to ${to} with \"${From} ${to}\" DID and nonce`);
    let connectionRequest = {
        did: fromToDid,
        nonce: 123456789
    };

    if (!toWallet) {
        console.log(`\"${to}\" > Create wallet"`);
        try {
            await indy.createWallet(toWalletConfig, toWalletCredentials)
        } catch(e) {
            if(e.message !== "WalletAlreadyExistsError") {
                throw e;
            }
        }
        toWallet = await indy.openWallet(toWalletConfig, toWalletCredentials);
    }

    console.log(`\"${to}\" > Create and store in Wallet \"${to} ${From}\" DID`);
    let [toFromDid, toFromKey] = await indy.createAndStoreMyDid(toWallet, {});

    console.log(`\"${to}\" > Get key for did from \"${From}\" connection request`);
    let fromToVerkey = await indy.keyForDid(poolHandle, toWallet, connectionRequest.did);

    console.log(`\"${to}\" > Anoncrypt connection response for \"${From}\" with \"${to} ${From}\" DID, verkey and nonce`);
    let connectionResponse = JSON.stringify({
        'did': toFromDid,
        'verkey': toFromKey,
        'nonce': connectionRequest['nonce']
    });
    let anoncryptedConnectionResponse = await indy.cryptoAnonCrypt(fromToVerkey, Buffer.from(connectionResponse, 'utf8'));

    console.log(`\"${to}\" > Send anoncrypted connection response to \"${From}\"`);

    console.log(`\"${From}\" > Anondecrypt connection response from \"${to}\"`);
    let decryptedConnectionResponse = JSON.parse(Buffer.from(await indy.cryptoAnonDecrypt(fromWallet, fromToKey, anoncryptedConnectionResponse)));

    console.log(`\"${From}\" > Authenticates \"${to}\" by comparision of Nonce`);
    if (connectionRequest['nonce'] !== decryptedConnectionResponse['nonce']) {
        throw Error("nonces don't match!");
    }

    console.log(`\"${From}\" > Send Nym to Ledger for \"${to} ${From}\" DID`);
    await sendNym(poolHandle, fromWallet, fromDid, decryptedConnectionResponse['did'], decryptedConnectionResponse['verkey'], null);

    return [toWallet, fromToKey, toFromDid, toFromKey, decryptedConnectionResponse];
}
Example #2
0
async function getVerinym(poolHandle, From, fromWallet, fromDid, fromToKey, to, toWallet, toFromDid, toFromKey, role) {
    console.log(`\"${to}\" > Create and store in Wallet \"${to}\" new DID"`);
    let [toDid, toKey] = await indy.createAndStoreMyDid(toWallet, {});

    console.log(`\"${to}\" > Authcrypt \"${to} DID info\" for \"${From}\"`);
    let didInfoJson = JSON.stringify({
        'did': toDid,
        'verkey': toKey
    });
    let authcryptedDidInfo = await indy.cryptoAuthCrypt(toWallet, toFromKey, fromToKey, Buffer.from(didInfoJson, 'utf8'));

    console.log(`\"${to}\" > Send authcrypted \"${to} DID info\" to ${From}`);

    console.log(`\"${From}\" > Authdecrypted \"${to} DID info\" from ${to}`);
    let [senderVerkey, authdecryptedDidInfo] =
        await indy.cryptoAuthDecrypt(fromWallet, fromToKey, Buffer.from(authcryptedDidInfo));

    let authdecryptedDidInfoJson = JSON.parse(Buffer.from(authdecryptedDidInfo));
    console.log(`\"${From}\" > Authenticate ${to} by comparision of Verkeys`);
    let retrievedVerkey = await indy.keyForDid(poolHandle, fromWallet, toFromDid);
    if (senderVerkey !== retrievedVerkey) {
        throw Error("Verkey is not the same");
    }

    console.log(`\"${From}\" > Send Nym to Ledger for \"${to} DID\" with ${role} Role`);
    await sendNym(poolHandle, fromWallet, fromDid, authdecryptedDidInfoJson['did'], authdecryptedDidInfoJson['verkey'], role);

    return toDid
}
Example #3
0
async function run() {

    console.log("gettingStarted.js -> started");

    let poolName = 'pool1';
    console.log(`Open Pool Ledger: ${poolName}`);
    let poolGenesisTxnPath = await util.getPoolGenesisTxnPath(poolName);
    let poolConfig = {
        "genesis_txn": poolGenesisTxnPath
    };
    try {
        await indy.createPoolLedgerConfig(poolName, poolConfig);
    } catch(e) {
        if(e.message !== "PoolLedgerConfigAlreadyExistsError") {
            throw e;
        }
    }

    await indy.setProtocolVersion(2)

    let poolHandle = await indy.openPoolLedger(poolName);

    console.log("==============================");
    console.log("=== Getting Trust Anchor credentials for Faber, Acme, Thrift and Government  ==");
    console.log("------------------------------");

    console.log("\"Sovrin Steward\" -> Create wallet");
    let stewardWalletConfig = {'id': 'stewardWalletName'}
    let stewardWalletCredentials = {'key': 'steward_key'}
    try {
        await indy.createWallet(stewardWalletConfig, stewardWalletCredentials)
    } catch(e) {
        if(e.message !== "WalletAlreadyExistsError") {
            throw e;
        }
    }

    let stewardWallet = await indy.openWallet(stewardWalletConfig, stewardWalletCredentials);

    console.log("\"Sovrin Steward\" -> Create and store in Wallet DID from seed");
    let stewardDidInfo = {
        'seed': '000000000000000000000000Steward1'
    };

    let [stewardDid, stewardKey] = await indy.createAndStoreMyDid(stewardWallet, stewardDidInfo);

    console.log("==============================");
    console.log("== Getting Trust Anchor credentials - Government Onboarding  ==");
    console.log("------------------------------");

    let governmentWalletConfig = {'id': 'governmentWallet'}
    let governmentWalletCredentials = {'key': 'government_key'}
    let [governmentWallet, stewardGovernmentKey, governmentStewardDid, governmentStewardKey] = await onboarding(poolHandle, "Sovrin Steward", stewardWallet, stewardDid, "Government", null, governmentWalletConfig, governmentWalletCredentials);

    console.log("==============================");
    console.log("== Getting Trust Anchor credentials - Government getting Verinym  ==");
    console.log("------------------------------");

    let governmentDid = await getVerinym(poolHandle, "Sovrin Steward", stewardWallet, stewardDid,
        stewardGovernmentKey, "Government", governmentWallet, governmentStewardDid,
        governmentStewardKey, 'TRUST_ANCHOR');

    console.log("==============================");
    console.log("== Getting Trust Anchor credentials - Faber Onboarding  ==");
    console.log("------------------------------");

    let faberWalletConfig = {'id': 'faberWallet'}
    let faberWalletCredentials = {'key': 'faber_key'}
    let [faberWallet, stewardFaberKey, faberStewardDid, faberStewardKey] = await onboarding(poolHandle, "Sovrin Steward", stewardWallet, stewardDid, "Faber", null, faberWalletConfig, faberWalletCredentials);

    console.log("==============================");
    console.log("== Getting Trust Anchor credentials - Faber getting Verinym  ==");
    console.log("------------------------------");

    let faberDid = await getVerinym(poolHandle, "Sovrin Steward", stewardWallet, stewardDid, stewardFaberKey,
        "Faber", faberWallet, faberStewardDid, faberStewardKey, 'TRUST_ANCHOR');

    console.log("==============================");
    console.log("== Getting Trust Anchor credentials - Acme Onboarding  ==");
    console.log("------------------------------");

    let acmeWalletConfig = {'id': 'acmeWallet'}
    let acmeWalletCredentials = {'key': 'acme_key'}
    let [acmeWallet, stewardAcmeKey, acmeStewardDid, acmeStewardKey] = await onboarding(poolHandle, "Sovrin Steward", stewardWallet, stewardDid, "Acme", null, acmeWalletConfig, acmeWalletCredentials);

    console.log("==============================");
    console.log("== Getting Trust Anchor credentials - Acme getting Verinym  ==");
    console.log("------------------------------");

    let acmeDid = await getVerinym(poolHandle, "Sovrin Steward", stewardWallet, stewardDid, stewardAcmeKey,
        "Acme", acmeWallet, acmeStewardDid, acmeStewardKey, 'TRUST_ANCHOR');

    console.log("==============================");
    console.log("== Getting Trust Anchor credentials - Thrift Onboarding  ==");
    console.log("------------------------------");

    let thriftWalletConfig = {'id': 'thriftWallet'}
    let thriftWalletCredentials = {'key': 'thrift_key'}
    let [thriftWallet, stewardThriftKey, thriftStewardDid, thriftStewardKey] = await onboarding(poolHandle, "Sovrin Steward", stewardWallet, stewardDid, "Thrift", null, thriftWalletConfig, thriftWalletCredentials);

    console.log("==============================");
    console.log("== Getting Trust Anchor credentials - Thrift getting Verinym  ==");
    console.log("------------------------------");

    let thriftDid = await getVerinym(poolHandle, "Sovrin Steward", stewardWallet, stewardDid, stewardThriftKey,
        "Thrift", thriftWallet, thriftStewardDid, thriftStewardKey, 'TRUST_ANCHOR');

    console.log("==============================");
    console.log("=== Credential Schemas Setup ==");
    console.log("------------------------------");

    console.log("\"Government\" -> Create \"Job-Certificate\" Schema");
    let [jobCertificateSchemaId, jobCertificateSchema] = await indy.issuerCreateSchema(governmentDid, 'Job-Certificate', '0.2',
        ['first_name', 'last_name', 'salary', 'employee_status',
            'experience']);

    console.log("\"Government\" -> Send \"Job-Certificate\" Schema to Ledger");
    await sendSchema(poolHandle, governmentWallet, governmentDid, jobCertificateSchema);

    console.log("\"Government\" -> Create \"Transcript\" Schema");
    let [transcriptSchemaId, transcriptSchema] = await indy.issuerCreateSchema(governmentDid, 'Transcript', '1.2',
        ['first_name', 'last_name', 'degree', 'status',
            'year', 'average', 'ssn']);
    console.log("\"Government\" -> Send \"Transcript\" Schema to Ledger");
    await sendSchema(poolHandle, governmentWallet, governmentDid, transcriptSchema);

    console.log("==============================");
    console.log("=== Faber Credential Definition Setup ==");
    console.log("------------------------------");

    console.log("\"Faber\" -> Get \"Transcript\" Schema from Ledger");
    [, transcriptSchema] = await getSchema(poolHandle, faberDid, transcriptSchemaId);

    console.log("\"Faber\" -> Create and store in Wallet \"Faber Transcript\" Credential Definition");
    let [faberTranscriptCredDefId, faberTranscriptCredDefJson] = await indy.issuerCreateAndStoreCredentialDef(faberWallet, faberDid, transcriptSchema, 'TAG1', 'CL', '{"support_revocation": false}');

    console.log("\"Faber\" -> Send  \"Faber Transcript\" Credential Definition to Ledger");
    await sendCredDef(poolHandle, faberWallet, faberDid, faberTranscriptCredDefJson);

    console.log("==============================");
    console.log("=== Acme Credential Definition Setup ==");
    console.log("------------------------------");

    console.log("\"Acme\" ->  Get from Ledger \"Job-Certificate\" Schema");
    [, jobCertificateSchema] = await getSchema(poolHandle, acmeDid, jobCertificateSchemaId);

    console.log("\"Acme\" -> Create and store in Wallet \"Acme Job-Certificate\" Credential Definition");
    let [acmeJobCertificateCredDefId, acmeJobCertificateCredDefJson] = await indy.issuerCreateAndStoreCredentialDef(acmeWallet, acmeDid, jobCertificateSchema, 'TAG1', 'CL', '{"support_revocation": false}');

    console.log("\"Acme\" -> Send \"Acme Job-Certificate\" Credential Definition to Ledger");
    await sendCredDef(poolHandle, acmeWallet, acmeDid, acmeJobCertificateCredDefJson);

    console.log("==============================");
    console.log("=== Getting Transcript with Faber ==");
    console.log("==============================");
    console.log("== Getting Transcript with Faber - Onboarding ==");
    console.log("------------------------------");

    let aliceWalletConfig = {'id': 'aliceWallet'}
    let aliceWalletCredentials = {'key': 'alice_key'}
    let [aliceWallet, faberAliceKey, aliceFaberDid, aliceFaberKey, faberAliceConnectionResponse] = await onboarding(poolHandle, "Faber", faberWallet, faberDid, "Alice", null, aliceWalletConfig, aliceWalletCredentials);

    console.log("==============================");
    console.log("== Getting Transcript with Faber - Getting Transcript Credential ==");
    console.log("------------------------------");

    console.log("\"Faber\" -> Create \"Transcript\" Credential Offer for Alice");
    let transcriptCredOfferJson = await indy.issuerCreateCredentialOffer(faberWallet, faberTranscriptCredDefId);

    console.log("\"Faber\" -> Get key for Alice did");
    let aliceFaberVerkey = await indy.keyForDid(poolHandle, faberWallet, faberAliceConnectionResponse['did']);

    console.log("\"Faber\" -> Authcrypt \"Transcript\" Credential Offer for Alice");
    let authcryptedTranscriptCredOffer = await indy.cryptoAuthCrypt(faberWallet, faberAliceKey, aliceFaberVerkey, Buffer.from(JSON.stringify(transcriptCredOfferJson),'utf8'));

    console.log("\"Faber\" -> Send authcrypted \"Transcript\" Credential Offer to Alice");

    console.log("\"Alice\" -> Authdecrypted \"Transcript\" Credential Offer from Faber");
    let [faberAliceVerkey, authdecryptedTranscriptCredOfferJson, authdecryptedTranscriptCredOffer] = await authDecrypt(aliceWallet, aliceFaberKey, authcryptedTranscriptCredOffer);

    console.log("\"Alice\" -> Create and store \"Alice\" Master Secret in Wallet");
    let aliceMasterSecretId = await indy.proverCreateMasterSecret(aliceWallet, null);

    console.log("\"Alice\" -> Get \"Faber Transcript\" Credential Definition from Ledger");
    let faberTranscriptCredDef;
    [faberTranscriptCredDefId, faberTranscriptCredDef] = await getCredDef(poolHandle, aliceFaberDid, authdecryptedTranscriptCredOffer['cred_def_id']);

    console.log("\"Alice\" -> Create \"Transcript\" Credential Request for Faber");
    let [transcriptCredRequestJson, transcriptCredRequestMetadataJson] = await indy.proverCreateCredentialReq(aliceWallet, aliceFaberDid, authdecryptedTranscriptCredOfferJson, faberTranscriptCredDef, aliceMasterSecretId);

    console.log("\"Alice\" -> Authcrypt \"Transcript\" Credential Request for Faber");
    let authcryptedTranscriptCredRequest = await indy.cryptoAuthCrypt(aliceWallet, aliceFaberKey, faberAliceVerkey, Buffer.from(JSON.stringify(transcriptCredRequestJson),'utf8'));

    console.log("\"Alice\" -> Send authcrypted \"Transcript\" Credential Request to Faber");

    console.log("\"Faber\" -> Authdecrypt \"Transcript\" Credential Request from Alice");
    let authdecryptedTranscriptCredRequestJson;
    [aliceFaberVerkey, authdecryptedTranscriptCredRequestJson] = await authDecrypt(faberWallet, faberAliceKey, authcryptedTranscriptCredRequest);

    console.log("\"Faber\" -> Create \"Transcript\" Credential for Alice");
    // note that encoding is not standardized by Indy except that 32-bit integers are encoded as themselves. IS-786
    let transcriptCredValues = {
        "first_name": {"raw": "Alice", "encoded": "1139481716457488690172217916278103335"},
        "last_name": {"raw": "Garcia", "encoded": "5321642780241790123587902456789123452"},
        "degree": {"raw": "Bachelor of Science, Marketing", "encoded": "12434523576212321"},
        "status": {"raw": "graduated", "encoded": "2213454313412354"},
        "ssn": {"raw": "123-45-6789", "encoded": "3124141231422543541"},
        "year": {"raw": "2015", "encoded": "2015"},
        "average": {"raw": "5", "encoded": "5"}
    };

    let [transcriptCredJson] = await indy.issuerCreateCredential(faberWallet, transcriptCredOfferJson, authdecryptedTranscriptCredRequestJson, transcriptCredValues, null, -1);

    console.log("\"Faber\" -> Authcrypt \"Transcript\" Credential for Alice");
    let authcryptedTranscriptCredJson = await indy.cryptoAuthCrypt(faberWallet, faberAliceKey, aliceFaberVerkey, Buffer.from(JSON.stringify(transcriptCredJson),'utf8'));

    console.log("\"Faber\" -> Send authcrypted \"Transcript\" Credential to Alice");

    console.log("\"Alice\" -> Authdecrypted \"Transcript\" Credential from Faber");
    let [, authdecryptedTranscriptCredJson] = await authDecrypt(aliceWallet, aliceFaberKey, authcryptedTranscriptCredJson);

    console.log("\"Alice\" -> Store \"Transcript\" Credential from Faber");
    await indy.proverStoreCredential(aliceWallet, null, transcriptCredRequestMetadataJson,
        authdecryptedTranscriptCredJson, faberTranscriptCredDef, null);

    console.log("==============================");
    console.log("=== Apply for the job with Acme ==");
    console.log("==============================");
    console.log("== Apply for the job with Acme - Onboarding ==");
    console.log("------------------------------");
    let acmeAliceKey, aliceAcmeDid, aliceAcmeKey, acmeAliceConnectionResponse;

    [aliceWallet, acmeAliceKey, aliceAcmeDid, aliceAcmeKey, acmeAliceConnectionResponse] = await onboarding(poolHandle, "Acme", acmeWallet, acmeDid, "Alice", aliceWallet, aliceWalletConfig, aliceWalletCredentials);

    console.log("==============================");
    console.log("== Apply for the job with Acme - Transcript proving ==");
    console.log("------------------------------");

    console.log("\"Acme\" -> Create \"Job-Application\" Proof Request");
    let jobApplicationProofRequestJson = {
        'nonce': '1432422343242122312411212',
        'name': 'Job-Application',
        'version': '0.1',
        'requested_attributes': {
            'attr1_referent': {
                'name': 'first_name'
            },
            'attr2_referent': {
                'name': 'last_name'
            },
            'attr3_referent': {
                'name': 'degree',
                'restrictions': [{'cred_def_id': faberTranscriptCredDefId}]
            },
            'attr4_referent': {
                'name': 'status',
                'restrictions': [{'cred_def_id': faberTranscriptCredDefId}]
            },
            'attr5_referent': {
                'name': 'ssn',
                'restrictions': [{'cred_def_id': faberTranscriptCredDefId}]
            },
            'attr6_referent': {
                'name': 'phone_number'
            }
        },
        'requested_predicates': {
            'predicate1_referent': {
                'name': 'average',
                'p_type': '>=',
                'p_value': 4,
                'restrictions': [{'cred_def_id': faberTranscriptCredDefId}]
            }
        }
    };

    console.log("\"Acme\" -> Get key for Alice did");
    let aliceAcmeVerkey = await indy.keyForDid(poolHandle, acmeWallet, acmeAliceConnectionResponse['did']);

    console.log("\"Acme\" -> Authcrypt \"Job-Application\" Proof Request for Alice");
    let authcryptedJobApplicationProofRequestJson = await indy.cryptoAuthCrypt(acmeWallet, acmeAliceKey, aliceAcmeVerkey,Buffer.from(JSON.stringify(jobApplicationProofRequestJson),'utf8'));

    console.log("\"Acme\" -> Send authcrypted \"Job-Application\" Proof Request to Alice");

    console.log("\"Alice\" -> Authdecrypt \"Job-Application\" Proof Request from Acme");
    let [acmeAliceVerkey, authdecryptedJobApplicationProofRequestJson] = await authDecrypt(aliceWallet, aliceAcmeKey, authcryptedJobApplicationProofRequestJson);

    console.log("\"Alice\" -> Get credentials for \"Job-Application\" Proof Request");
    let searchForJobApplicationProofRequest = await indy.proverSearchCredentialsForProofReq(aliceWallet, authdecryptedJobApplicationProofRequestJson, null)

    let credentials = await indy.proverFetchCredentialsForProofReq(searchForJobApplicationProofRequest, 'attr1_referent', 100)
    let credForAttr1 = credentials[0]['cred_info'];

    await indy.proverFetchCredentialsForProofReq(searchForJobApplicationProofRequest, 'attr2_referent', 100)
    let credForAttr2 = credentials[0]['cred_info'];

    await indy.proverFetchCredentialsForProofReq(searchForJobApplicationProofRequest, 'attr3_referent', 100)
    let credForAttr3 = credentials[0]['cred_info'];

    await indy.proverFetchCredentialsForProofReq(searchForJobApplicationProofRequest, 'attr4_referent', 100)
    let credForAttr4 = credentials[0]['cred_info'];

    await indy.proverFetchCredentialsForProofReq(searchForJobApplicationProofRequest, 'attr5_referent', 100)
    let credForAttr5 = credentials[0]['cred_info'];

    await indy.proverFetchCredentialsForProofReq(searchForJobApplicationProofRequest, 'predicate1_referent', 100)
    let credForPredicate1 = credentials[0]['cred_info'];

    await indy.proverCloseCredentialsSearchForProofReq(searchForJobApplicationProofRequest)

    let credsForJobApplicationProof = {};
    credsForJobApplicationProof[`${credForAttr1['referent']}`] = credForAttr1;
    credsForJobApplicationProof[`${credForAttr2['referent']}`] = credForAttr2;
    credsForJobApplicationProof[`${credForAttr3['referent']}`] = credForAttr3;
    credsForJobApplicationProof[`${credForAttr4['referent']}`] = credForAttr4;
    credsForJobApplicationProof[`${credForAttr5['referent']}`] = credForAttr5;
    credsForJobApplicationProof[`${credForPredicate1['referent']}`] = credForPredicate1;

    let [schemasJson, credDefsJson, revocStatesJson] = await proverGetEntitiesFromLedger(poolHandle, aliceFaberDid, credsForJobApplicationProof, 'Alice');

    console.log("\"Alice\" -> Create \"Job-Application\" Proof");
    let jobApplicationRequestedCredsJson = {
        'self_attested_attributes': {
            'attr1_referent': 'Alice',
            'attr2_referent': 'Garcia',
            'attr6_referent': '123-45-6789'
        },
        'requested_attributes': {
            'attr3_referent': {'cred_id': credForAttr3['referent'], 'revealed': true},
            'attr4_referent': {'cred_id': credForAttr4['referent'], 'revealed': true},
            'attr5_referent': {'cred_id': credForAttr5['referent'], 'revealed': true},
        },
        'requested_predicates': {'predicate1_referent': {'cred_id': credForPredicate1['referent']}}
    };

    let jobApplicationProofJson = await indy.proverCreateProof(aliceWallet, authdecryptedJobApplicationProofRequestJson,
        jobApplicationRequestedCredsJson, aliceMasterSecretId,
        schemasJson, credDefsJson, revocStatesJson);

    console.log("\"Alice\" -> Authcrypt \"Job-Application\" Proof for Acme");
    let authcryptedJobApplicationProofJson = await indy.cryptoAuthCrypt(aliceWallet, aliceAcmeKey, acmeAliceVerkey,Buffer.from(JSON.stringify(jobApplicationProofJson),'utf8'));

    console.log("\"Alice\" -> Send authcrypted \"Job-Application\" Proof to Acme");

    console.log("\"Acme\" -> Authdecrypted \"Job-Application\" Proof from Alice");
    let decryptedJobApplicationProofJson, decryptedJobApplicationProof;
    [, decryptedJobApplicationProofJson, decryptedJobApplicationProof] = await authDecrypt(acmeWallet, acmeAliceKey, authcryptedJobApplicationProofJson);

    let revocRefDefsJson, revocRegsJson;
    [schemasJson, credDefsJson, revocRefDefsJson, revocRegsJson] = await verifierGetEntitiesFromLedger(poolHandle, acmeDid, decryptedJobApplicationProof['identifiers'], 'Acme');

    console.log("\"Acme\" -> Verify \"Job-Application\" Proof from Alice");
    assert('Bachelor of Science, Marketing' === decryptedJobApplicationProof['requested_proof']['revealed_attrs']['attr3_referent']['raw']);
    assert('graduated' === decryptedJobApplicationProof['requested_proof']['revealed_attrs']['attr4_referent']['raw']);
    assert('123-45-6789' === decryptedJobApplicationProof['requested_proof']['revealed_attrs']['attr5_referent']['raw']);

    assert('Alice' === decryptedJobApplicationProof['requested_proof']['self_attested_attrs']['attr1_referent']);
    assert('Garcia' === decryptedJobApplicationProof['requested_proof']['self_attested_attrs']['attr2_referent']);
    assert('123-45-6789' === decryptedJobApplicationProof['requested_proof']['self_attested_attrs']['attr6_referent']);

    assert(await indy.verifierVerifyProof(jobApplicationProofRequestJson, decryptedJobApplicationProofJson, schemasJson, credDefsJson, revocRefDefsJson, revocRegsJson));

    console.log("==============================");
    console.log("== Apply for the job with Acme - Getting Job-Certificate Credential ==");
    console.log("------------------------------");

    console.log("\"Acme\" -> Create \"Job-Certificate\" Credential Offer for Alice");
    let jobCertificateCredOfferJson = await indy.issuerCreateCredentialOffer(acmeWallet, acmeJobCertificateCredDefId);

    console.log("\"Acme\" -> Get key for Alice did");
    aliceAcmeVerkey = await indy.keyForDid(poolHandle, acmeWallet, acmeAliceConnectionResponse['did']);

    console.log("\"Acme\" -> Authcrypt \"Job-Certificate\" Credential Offer for Alice");
    let authcryptedJobCertificateCredOffer = await indy.cryptoAuthCrypt(acmeWallet, acmeAliceKey, aliceAcmeVerkey,Buffer.from(JSON.stringify(jobCertificateCredOfferJson),'utf8'));

    console.log("\"Acme\" -> Send authcrypted \"Job-Certificate\" Credential Offer to Alice");

    console.log("\"Alice\" -> Authdecrypted \"Job-Certificate\" Credential Offer from Acme");
    let authdecryptedJobCertificateCredOfferJson, authdecryptedJobCertificateCredOffer;
    [acmeAliceVerkey, authdecryptedJobCertificateCredOfferJson, authdecryptedJobCertificateCredOffer] = await authDecrypt(aliceWallet, aliceAcmeKey, authcryptedJobCertificateCredOffer);

    console.log("\"Alice\" -> Get \"Acme Job-Certificate\" Credential Definition from Ledger");
    let acmeJobCertificateCredDef;
    [, acmeJobCertificateCredDef] = await getCredDef(poolHandle, aliceAcmeDid, authdecryptedJobCertificateCredOffer['cred_def_id']);

    console.log("\"Alice\" -> Create and store in Wallet \"Job-Certificate\" Credential Request for Acme");
    let [jobCertificateCredRequestJson, jobCertificateCredRequestMetadataJson] = await indy.proverCreateCredentialReq(aliceWallet, aliceAcmeDid, authdecryptedJobCertificateCredOfferJson, acmeJobCertificateCredDef, aliceMasterSecretId);

    console.log("\"Alice\" -> Authcrypt \"Job-Certificate\" Credential Request for Acme");
    let authcryptedJobCertificateCredRequestJson = await indy.cryptoAuthCrypt(aliceWallet, aliceAcmeKey, acmeAliceVerkey,Buffer.from(JSON.stringify(jobCertificateCredRequestJson),'utf8'));

    console.log("\"Alice\" -> Send authcrypted \"Job-Certificate\" Credential Request to Acme");

    console.log("\"Acme\" -> Authdecrypt \"Job-Certificate\" Credential Request from Alice");
    let authdecryptedJobCertificateCredRequestJson;
    [aliceAcmeVerkey, authdecryptedJobCertificateCredRequestJson] = await authDecrypt(acmeWallet, acmeAliceKey, authcryptedJobCertificateCredRequestJson);

    console.log("\"Acme\" -> Create \"Job-Certificate\" Credential for Alice");
    let aliceJobCertificateCredValuesJson = {
        "first_name": {"raw": "Alice", "encoded": "245712572474217942457235975012103335"},
        "last_name": {"raw": "Garcia", "encoded": "312643218496194691632153761283356127"},
        "employee_status": {"raw": "Permanent", "encoded": "2143135425425143112321314321"},
        "salary": {"raw": "2400", "encoded": "2400"},
        "experience": {"raw": "10", "encoded": "10"}
    };

    let [jobCertificateCredJson] = await indy.issuerCreateCredential(acmeWallet, jobCertificateCredOfferJson, authdecryptedJobCertificateCredRequestJson, aliceJobCertificateCredValuesJson, null, -1);

    console.log("\"Acme\" ->  Authcrypt \"Job-Certificate\" Credential for Alice");
    let authcryptedJobCertificateCredJson = await indy.cryptoAuthCrypt(acmeWallet, acmeAliceKey, aliceAcmeVerkey,Buffer.from(JSON.stringify(jobCertificateCredJson),'utf8'));

    console.log("\"Acme\" ->  Send authcrypted \"Job-Certificate\" Credential to Alice");

    console.log("\"Alice\" -> Authdecrypted \"Job-Certificate\" Credential from Acme");
    let authdecryptedJobCertificateCredJson;
    [, authdecryptedJobCertificateCredJson] = await authDecrypt(aliceWallet, aliceAcmeKey, authcryptedJobCertificateCredJson);

    console.log("\"Alice\" -> Store \"Job-Certificate\" Credential");
    await indy.proverStoreCredential(aliceWallet, null, jobCertificateCredRequestMetadataJson, authdecryptedJobCertificateCredJson, acmeJobCertificateCredDefJson, null);

    console.log("==============================");
    console.log("=== Apply for the loan with Thrift ==");
    console.log("==============================");
    console.log("== Apply for the loan with Thrift - Onboarding ==");
    console.log("------------------------------");

    let thriftAliceKey, aliceThriftDid, aliceThriftKey, thriftAliceConnectionResponse;
    [aliceWallet, thriftAliceKey, aliceThriftDid, aliceThriftKey, thriftAliceConnectionResponse] = await onboarding(poolHandle, "Thrift", thriftWallet, thriftDid,
        "Alice", aliceWallet, aliceWalletConfig, aliceWalletCredentials);

    console.log("==============================");
    console.log("== Apply for the loan with Thrift - Job-Certificate proving  ==");
    console.log("------------------------------");

    console.log("\"Thrift\" -> Create \"Loan-Application-Basic\" Proof Request");
    let applyLoanProofRequestJson = {
        'nonce': '123432421212',
        'name': 'Loan-Application-Basic',
        'version': '0.1',
        'requested_attributes': {
            'attr1_referent': {
                'name': 'employee_status',
                'restrictions': [{'cred_def_id': acmeJobCertificateCredDefId}]
            }
        },
        'requested_predicates': {
            'predicate1_referent': {
                'name': 'salary',
                'p_type': '>=',
                'p_value': 2000,
                'restrictions': [{'cred_def_id': acmeJobCertificateCredDefId}]
            },
            'predicate2_referent': {
                'name': 'experience',
                'p_type': '>=',
                'p_value': 1,
                'restrictions': [{'cred_def_id': acmeJobCertificateCredDefId}]
            }
        }
    };

    console.log("\"Thrift\" -> Get key for Alice did");
    let aliceThriftVerkey = await indy.keyForDid(poolHandle, thriftWallet, thriftAliceConnectionResponse['did']);

    console.log("\"Thrift\" -> Authcrypt \"Loan-Application-Basic\" Proof Request for Alice");
    let authcryptedApplyLoanProofRequestJson = await indy.cryptoAuthCrypt(thriftWallet, thriftAliceKey, aliceThriftVerkey,Buffer.from(JSON.stringify(applyLoanProofRequestJson),'utf8'));

    console.log("\"Thrift\" -> Send authcrypted \"Loan-Application-Basic\" Proof Request to Alice");

    console.log("\"Alice\" -> Authdecrypt \"Loan-Application-Basic\" Proof Request from Thrift");
    let [thriftAliceVerkey, authdecryptedApplyLoanProofRequestJson] = await authDecrypt(aliceWallet, aliceThriftKey, authcryptedApplyLoanProofRequestJson);

    console.log("\"Alice\" -> Get credentials for \"Loan-Application-Basic\" Proof Request");

    let searchForJApplyLoanProofRequest = await indy.proverSearchCredentialsForProofReq(aliceWallet, authdecryptedApplyLoanProofRequestJson, null)

    credentials = await indy.proverFetchCredentialsForProofReq(searchForJApplyLoanProofRequest, 'attr1_referent', 100)
    credForAttr1 = credentials[0]['cred_info'];

    await indy.proverFetchCredentialsForProofReq(searchForJApplyLoanProofRequest, 'predicate1_referent', 100)
    credForPredicate1 = credentials[0]['cred_info'];

    await indy.proverFetchCredentialsForProofReq(searchForJApplyLoanProofRequest, 'predicate2_referent', 100)
    let credForPredicate2 = credentials[0]['cred_info'];

    await indy.proverCloseCredentialsSearchForProofReq(searchForJApplyLoanProofRequest)

    let credsForApplyLoanProof = {};
    credsForApplyLoanProof[`${credForAttr1['referent']}`] = credForAttr1;
    credsForApplyLoanProof[`${credForPredicate1['referent']}`] = credForPredicate1;
    credsForApplyLoanProof[`${credForPredicate2['referent']}`] = credForPredicate2;

    [schemasJson, credDefsJson, revocStatesJson] = await proverGetEntitiesFromLedger(poolHandle, aliceThriftDid, credsForApplyLoanProof, 'Alice');

    console.log("\"Alice\" -> Create \"Loan-Application-Basic\" Proof");
    let applyLoanRequestedCredsJson = {
        'self_attested_attributes': {},
        'requested_attributes': {
            'attr1_referent': {'cred_id': credForAttr1['referent'], 'revealed': true}
        },
        'requested_predicates': {
            'predicate1_referent': {'cred_id': credForPredicate1['referent']},
            'predicate2_referent': {'cred_id': credForPredicate2['referent']}
        }
    };
    let aliceApplyLoanProofJson = await indy.proverCreateProof(aliceWallet, authdecryptedApplyLoanProofRequestJson,
        applyLoanRequestedCredsJson, aliceMasterSecretId, schemasJson,
        credDefsJson, revocStatesJson);

    console.log("\"Alice\" -> Authcrypt \"Loan-Application-Basic\" Proof for Thrift");
    let authcryptedAliceApplyLoanProofJson = await indy.cryptoAuthCrypt(aliceWallet, aliceThriftKey, thriftAliceVerkey,Buffer.from(JSON.stringify(aliceApplyLoanProofJson),'utf8'));

    console.log("\"Alice\" -> Send authcrypted \"Loan-Application-Basic\" Proof to Thrift");

    console.log("\"Thrift\" -> Authdecrypted \"Loan-Application-Basic\" Proof from Alice");
    let authdecryptedAliceApplyLoanProofJson, authdecryptedAliceApplyLoanProof;
    [, authdecryptedAliceApplyLoanProofJson, authdecryptedAliceApplyLoanProof] = await authDecrypt(thriftWallet, thriftAliceKey, authcryptedAliceApplyLoanProofJson);

    console.log("\"Thrift\" -> Get Schemas, Credential Definitions and Revocation Registries from Ledger required for Proof verifying");

    let revocDefsJson;
    [schemasJson, credDefsJson, revocDefsJson, revocRegsJson] = await verifierGetEntitiesFromLedger(poolHandle, thriftDid,
        authdecryptedAliceApplyLoanProof['identifiers'], 'Thrift');

    console.log("\"Thrift\" -> Verify \"Loan-Application-Basic\" Proof from Alice");
    assert('Permanent' === authdecryptedAliceApplyLoanProof['requested_proof']['revealed_attrs']['attr1_referent']['raw']);

    assert(await indy.verifierVerifyProof(applyLoanProofRequestJson, authdecryptedAliceApplyLoanProofJson, schemasJson, credDefsJson, revocDefsJson, revocRegsJson));

    console.log("==============================");

    console.log("==============================");
    console.log("== Apply for the loan with Thrift - Transcript and Job-Certificate proving  ==");
    console.log("------------------------------");

    console.log("\"Thrift\" -> Create \"Loan-Application-KYC\" Proof Request");
    let applyLoanKycProofRequestJson = {
        'nonce': '123432421212',
        'name': 'Loan-Application-KYC',
        'version': '0.1',
        'requested_attributes': {
            'attr1_referent': {'name': 'first_name'},
            'attr2_referent': {'name': 'last_name'},
            'attr3_referent': {'name': 'ssn'}
        },
        'requested_predicates': {}
    };

    console.log("\"Thrift\" -> Get key for Alice did");
    aliceThriftVerkey = await indy.keyForDid(poolHandle, thriftWallet, thriftAliceConnectionResponse['did']);

    console.log("\"Thrift\" -> Authcrypt \"Loan-Application-KYC\" Proof Request for Alice");
    let authcryptedApplyLoanKycProofRequestJson = await indy.cryptoAuthCrypt(thriftWallet, thriftAliceKey, aliceThriftVerkey,Buffer.from(JSON.stringify(applyLoanKycProofRequestJson),'utf8'));

    console.log("\"Thrift\" -> Send authcrypted \"Loan-Application-KYC\" Proof Request to Alice");

    console.log("\"Alice\" -> Authdecrypt \"Loan-Application-KYC\" Proof Request from Thrift");
    let authdecryptedApplyLoanKycProofRequestJson;
    [thriftAliceVerkey, authdecryptedApplyLoanKycProofRequestJson] = await authDecrypt(aliceWallet, aliceThriftKey, authcryptedApplyLoanKycProofRequestJson);

    console.log("\"Alice\" -> Get credentials for \"Loan-Application-KYC\" Proof Request");

    let searchForApplyLoanKycProofRequest = await indy.proverSearchCredentialsForProofReq(aliceWallet, authdecryptedApplyLoanKycProofRequestJson, null)

    credentials = await indy.proverFetchCredentialsForProofReq(searchForApplyLoanKycProofRequest, 'attr1_referent', 100)
    credForAttr1 = credentials[0]['cred_info'];

    credentials = await indy.proverFetchCredentialsForProofReq(searchForApplyLoanKycProofRequest, 'attr2_referent', 100)
    credForAttr2 = credentials[0]['cred_info'];

    credentials = await indy.proverFetchCredentialsForProofReq(searchForApplyLoanKycProofRequest, 'attr3_referent', 100)
    credForAttr3 = credentials[0]['cred_info'];

    await indy.proverCloseCredentialsSearchForProofReq(searchForApplyLoanKycProofRequest)

    let credsForApplyLoanKycProof = {};
    credsForApplyLoanKycProof[`${credForAttr1['referent']}`] = credForAttr1;
    credsForApplyLoanKycProof[`${credForAttr2['referent']}`] = credForAttr2;
    credsForApplyLoanKycProof[`${credForAttr3['referent']}`] = credForAttr3;

    [schemasJson, credDefsJson, revocStatesJson] = await proverGetEntitiesFromLedger(poolHandle, aliceThriftDid, credsForApplyLoanKycProof, 'Alice');

    console.log("\"Alice\" -> Create \"Loan-Application-KYC\" Proof");

    let applyLoanKycRequestedCredsJson = {
        'self_attested_attributes': {},
        'requested_attributes': {
            'attr1_referent': {'cred_id': credForAttr1['referent'], 'revealed': true},
            'attr2_referent': {'cred_id': credForAttr2['referent'], 'revealed': true},
            'attr3_referent': {'cred_id': credForAttr3['referent'], 'revealed': true}
        },
        'requested_predicates': {}
    };

    let aliceApplyLoanKycProofJson = await indy.proverCreateProof(aliceWallet, authdecryptedApplyLoanKycProofRequestJson,
        applyLoanKycRequestedCredsJson, aliceMasterSecretId,
        schemasJson, credDefsJson, revocStatesJson);

    console.log("\"Alice\" -> Authcrypt \"Loan-Application-KYC\" Proof for Thrift");
    let authcryptedAliceApplyLoanKycProofJson = await indy.cryptoAuthCrypt(aliceWallet, aliceThriftKey, thriftAliceVerkey,Buffer.from(JSON.stringify(aliceApplyLoanKycProofJson),'utf8'));

    console.log("\"Alice\" -> Send authcrypted \"Loan-Application-KYC\" Proof to Thrift");

    console.log("\"Thrift\" -> Authdecrypted \"Loan-Application-KYC\" Proof from Alice");
    let authdecryptedAliceApplyLoanKycProofJson, authdecryptedAliceApplyLoanKycProof;
    [, authdecryptedAliceApplyLoanKycProofJson, authdecryptedAliceApplyLoanKycProof] = await authDecrypt(thriftWallet, thriftAliceKey, authcryptedAliceApplyLoanKycProofJson);

    console.log("\"Thrift\" -> Get Schemas, Credential Definitions and Revocation Registries from Ledger required for Proof verifying");

    [schemasJson, credDefsJson, revocDefsJson, revocRegsJson] = await verifierGetEntitiesFromLedger(poolHandle, thriftDid, authdecryptedAliceApplyLoanKycProof['identifiers'], 'Thrift');

    console.log("\"Thrift\" -> Verify \"Loan-Application-KYC\" Proof from Alice");
    assert('Alice' === authdecryptedAliceApplyLoanKycProof['requested_proof']['revealed_attrs']['attr1_referent']['raw']);
    assert('Garcia' === authdecryptedAliceApplyLoanKycProof['requested_proof']['revealed_attrs']['attr2_referent']['raw']);
    assert('123-45-6789' === authdecryptedAliceApplyLoanKycProof['requested_proof']['revealed_attrs']['attr3_referent']['raw']);

    assert(await indy.verifierVerifyProof(applyLoanKycProofRequestJson, authdecryptedAliceApplyLoanKycProof, schemasJson, credDefsJson, revocDefsJson, revocRegsJson));

    console.log("==============================");

    console.log(" \"Sovrin Steward\" -> Close and Delete wallet");
    await indy.closeWallet(stewardWallet);
    await indy.deleteWallet(stewardWalletConfig, stewardWalletCredentials);

    console.log("\"Government\" -> Close and Delete wallet");
    await indy.closeWallet(governmentWallet);
    await indy.deleteWallet(governmentWalletConfig, governmentWalletCredentials);

    console.log("\"Faber\" -> Close and Delete wallet");
    await indy.closeWallet(faberWallet);
    await indy.deleteWallet(faberWalletConfig, faberWalletCredentials);

    console.log("\"Acme\" -> Close and Delete wallet");
    await indy.closeWallet(acmeWallet);
    await indy.deleteWallet(acmeWalletConfig, acmeWalletCredentials);

    console.log("\"Thrift\" -> Close and Delete wallet");
    await indy.closeWallet(thriftWallet);
    await indy.deleteWallet(thriftWalletConfig, thriftWalletCredentials);

    console.log("\"Alice\" -> Close and Delete wallet");
    await indy.closeWallet(aliceWallet);
    await indy.deleteWallet(aliceWalletConfig, aliceWalletCredentials);

    console.log("Close and Delete pool");
    await indy.closePoolLedger(poolHandle);
    await indy.deletePoolLedgerConfig(poolName);

    console.log("Getting started -> done")
}
async function run() {

    log("Set protocol version 2 to work with Indy Node 1.4")
    await indy.setProtocolVersion(2)

    // 1.
    log('1. Creates a new local pool ledger configuration that is used later when connecting to ledger.')
    const poolName = 'pool'
    const genesisFilePath = await util.getPoolGenesisTxnPath(poolName)
    const poolConfig = {'genesis_txn': genesisFilePath}
    await indy.createPoolLedgerConfig(poolName, poolConfig)

    // 2.
    log('2. Open pool ledger and get handle from libindy')
    const poolHandle = await indy.openPoolLedger(poolName, undefined)

    // 3.
    log('3. Creating new secure wallet')
    const walletName = {"id": "wallet"}
    const walletCredentials = {"key": "wallet_key"}
    await indy.createWallet(walletName, walletCredentials)

    // 4.
    log('4. Open wallet and get handle from libindy')
    const walletHandle = await indy.openWallet(walletName, walletCredentials)

    // 5.
    log('5. Generating and storing steward DID and verkey')
    const stewardSeed = '000000000000000000000000Steward1'
    const did = {'seed': stewardSeed}
    const [stewardDid, stewardVerkey] = await indy.createAndStoreMyDid(walletHandle, did)
    logValue('Steward DID: ', stewardDid)
    logValue('Steward Verkey: ', stewardVerkey)

    // 6.
    log('6. Generating and storing trust anchor DID and verkey')
    const [trustAnchorDid, trustAnchorVerkey] = await indy.createAndStoreMyDid(walletHandle, "{}")
    logValue('Trust anchor DID: ', trustAnchorDid)
    logValue('Trust anchor Verkey: ', trustAnchorVerkey)

    // 7.
    log('7. Building NYM request to add Trust Anchor to the ledger')
    const nymRequest = await indy.buildNymRequest(/*submitter_did*/ stewardDid,
                                                 /*target_did*/ trustAnchorDid,
                                                 /*ver_key*/ trustAnchorVerkey,
                                                 /*alias*/ undefined,
                                                 /*role*/ 'TRUST_ANCHOR')

    // 8.
    log('8. Sending NYM request to the ledger')
    await indy.signAndSubmitRequest(/*pool_handle*/ poolHandle,
                                    /*wallet_handle*/ walletHandle,
                                    /*submitter_did*/ stewardDid,
                                    /*request_json*/ nymRequest)

    // 9.
    log('9. Generating and storing DID and verkey representing a Client that wants to obtain Trust Anchor Verkey')
    const [clientDid, clientVerkey] = await indy.createAndStoreMyDid(walletHandle, "{}")
    logValue('Client DID: ', clientDid)
    logValue('Client Verkey: ', clientVerkey)

    // 10.
    log('10. Building the GET_NYM request to query trust anchor verkey')
    const getNymRequest = await indy.buildGetNymRequest(/*submitter_did*/ clientDid,
                                                         /*target_did*/ trustAnchorDid)

    // 11.
    log('11. Sending the Get NYM request to the ledger')
    const getNymResponse = await indy.submitRequest(/*pool_handle*/ poolHandle,
                                                   /*request_json*/ getNymRequest)

    // 12.
    log('12. Comparing Trust Anchor verkey as written by Steward and as retrieved in GET_NYM response submitted by Client')
    logValue('Written by Steward: ', trustAnchorVerkey)
    const verkeyFromLedger = JSON.parse(getNymResponse['result']['data'])['verkey']
    logValue('Queried from ledger: ', verkeyFromLedger)
    logValue('Matching: ', verkeyFromLedger == trustAnchorVerkey)

    // 13.
    log('13. Closing wallet and pool')
    await indy.closeWallet(walletHandle)
    await indy.closePoolLedger(poolHandle)

    // 14.
    log('14. Deleting created wallet')
    await indy.deleteWallet(walletName, walletCredentials)

    // 15.
    log('15. Deleting pool ledger config')
    await indy.deletePoolLedgerConfig(poolName)


}