Skip to content

Commit c7409cc

Browse files
committed
update add bjj credential and test
1 parent bb236e3 commit c7409cc

File tree

2 files changed

+141
-49
lines changed

2 files changed

+141
-49
lines changed

src/identity/identity-wallet.ts

+79-48
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,14 @@ export type IdentityCreationOptions = {
7070
method?: string;
7171
blockchain?: string;
7272
networkId?: string;
73+
} & AuthBJJCredentialCreationOptions;
74+
75+
/**
76+
* Options for creating Auth BJJ credential
77+
* seed - seed to generate BJJ key pair
78+
* revocationOpts -
79+
*/
80+
export type AuthBJJCredentialCreationOptions = {
7381
revocationOpts: {
7482
id: string;
7583
type: CredentialStatusType;
@@ -82,12 +90,16 @@ export type IdentityCreationOptions = {
8290
seed?: Uint8Array;
8391
};
8492

93+
/**
94+
* Options for creating Ethereum based identity
95+
*/
8596
export type EthereumBasedIdentityCreationOptions = IdentityCreationOptions & {
8697
ethereumBasedIdentityOpts?: {
8798
ethSigner?: Signer;
8899
createBjjCredential?: boolean;
89100
};
90101
};
102+
91103
/**
92104
* Options for RevocationInfoOptions.
93105
*/
@@ -420,12 +432,14 @@ export interface IIdentityWallet {
420432
*
421433
* @param {DID} did - identifier of the user
422434
* @param {TreeState} oldTreeState - old tree state of the user
435+
* @param {boolean} isOldTreeState - if the old state is genesis
423436
* @param {Signer} ethSigner - signer to sign the transaction
424437
* @param {object} opts - additional options
425438
*/
426439
addBJJAuthCredential(
427440
did: DID,
428441
oldTreeState: TreeState,
442+
isOldTreeStateGenesis: boolean,
429443
ethSigner: Signer,
430444
opts?: object
431445
): Promise<W3CCredential>;
@@ -510,14 +524,22 @@ export class IdentityWallet implements IIdentityWallet {
510524
did: DID,
511525
pubKey: PublicKey,
512526
authClaim: Claim,
513-
currentState: Hash,
527+
oldTreeState: TreeState,
514528
revocationOpts: { id: string; type: CredentialStatusType }
515529
): Promise<W3CCredential> {
516530
const claimsTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(
517531
did.string(),
518532
MerkleTreeType.Claims
519533
);
520534

535+
const ctr = await claimsTree.root();
536+
537+
const currentState = hashElems([
538+
ctr.bigInt(),
539+
oldTreeState.revocationRoot.bigInt(),
540+
oldTreeState.rootOfRoots.bigInt()
541+
]);
542+
521543
const authData = authClaim.getExpirationDate();
522544
const expiration = authData ? getUnixTimestamp(authData) : 0;
523545

@@ -539,35 +561,40 @@ export class IdentityWallet implements IIdentityWallet {
539561
}
540562
};
541563

542-
const schema = JSON.parse(VerifiableConstants.AUTH.AUTH_BJJ_CREDENTIAL_SCHEMA_JSON);
543-
let credential: W3CCredential = new W3CCredential();
544-
try {
545-
credential = this._credentialWallet.createCredential(did, request, schema);
546-
} catch (e) {
547-
throw new Error(`Error create w3c credential ${(e as Error).message}`);
548-
}
549-
550-
const index = authClaim.hIndex();
551-
const ctr = await claimsTree.root();
564+
// Check if has already an auth credential
565+
const authCredentials = await this._credentialWallet.getAllAuthBJJCredentials(did);
552566

553-
const { proof } = await claimsTree.generateProof(index, ctr);
567+
let credential: W3CCredential = new W3CCredential();
568+
if (authCredentials.length === 0) {
569+
const schema = JSON.parse(VerifiableConstants.AUTH.AUTH_BJJ_CREDENTIAL_SCHEMA_JSON);
570+
try {
571+
credential = this._credentialWallet.createCredential(did, request, schema);
572+
} catch (e) {
573+
throw new Error(`Error create w3c credential ${(e as Error).message}`);
574+
}
554575

555-
const mtpProof: Iden3SparseMerkleTreeProof = new Iden3SparseMerkleTreeProof({
556-
mtp: proof,
557-
issuerData: {
558-
id: did,
559-
state: {
560-
rootOfRoots: ZERO_HASH,
561-
revocationTreeRoot: ZERO_HASH,
562-
claimsTreeRoot: ctr,
563-
value: currentState
564-
}
565-
},
566-
coreClaim: authClaim
567-
});
576+
const index = authClaim.hIndex();
577+
const { proof } = await claimsTree.generateProof(index, ctr);
568578

569-
credential.proof = [mtpProof];
579+
const mtpProof: Iden3SparseMerkleTreeProof = new Iden3SparseMerkleTreeProof({
580+
mtp: proof,
581+
issuerData: {
582+
id: did,
583+
state: {
584+
rootOfRoots: oldTreeState.rootOfRoots,
585+
revocationTreeRoot: oldTreeState.revocationRoot,
586+
claimsTreeRoot: ctr,
587+
value: currentState
588+
}
589+
},
590+
coreClaim: authClaim
591+
});
570592

593+
credential.proof = [mtpProof];
594+
} else {
595+
// credential with sigProof signed with previous auth bjj credential
596+
credential = await this.issueCredential(did, request);
597+
}
571598
return credential;
572599
}
573600

@@ -594,11 +621,9 @@ export class IdentityWallet implements IIdentityWallet {
594621
MerkleTreeType.Claims
595622
);
596623

597-
const currentState = hashElems([
598-
(await claimsTree.root()).bigInt(),
599-
ZERO_HASH.bigInt(),
600-
ZERO_HASH.bigInt()
601-
]);
624+
const ctr = await claimsTree.root();
625+
626+
const currentState = hashElems([ctr.bigInt(), ZERO_HASH.bigInt(), ZERO_HASH.bigInt()]);
602627

603628
const didType = buildDIDType(
604629
opts.method || DidMethod.Iden3,
@@ -614,7 +639,12 @@ export class IdentityWallet implements IIdentityWallet {
614639
did,
615640
pubKey,
616641
authClaim,
617-
currentState,
642+
{
643+
revocationRoot: ZERO_HASH,
644+
claimsRoot: ctr,
645+
state: currentState,
646+
rootOfRoots: ZERO_HASH
647+
},
618648
opts.revocationOpts
619649
);
620650

@@ -689,7 +719,7 @@ export class IdentityWallet implements IIdentityWallet {
689719
rootOfRoots: ZERO_HASH
690720
};
691721

692-
credential = await this.addBJJAuthCredential(did, oldTreeState, ethSigner, opts);
722+
credential = await this.addBJJAuthCredential(did, oldTreeState, true, ethSigner, opts);
693723
}
694724

695725
return {
@@ -1351,6 +1381,7 @@ export class IdentityWallet implements IIdentityWallet {
13511381
async addBJJAuthCredential(
13521382
did: DID,
13531383
oldTreeState: TreeState,
1384+
isOldStateGenesis: boolean,
13541385
ethSigner: Signer,
13551386
opts: IdentityCreationOptions,
13561387
prover?: IZKProver // it will be needed in case of non ethereum identities
@@ -1365,33 +1396,33 @@ export class IdentityWallet implements IIdentityWallet {
13651396
const { hi, hv } = authClaim.hiHv();
13661397
await this._storage.mt.addToMerkleTree(did.string(), MerkleTreeType.Claims, hi, hv);
13671398

1368-
const claimsTree = await this._storage.mt.getMerkleTreeByIdentifierAndType(
1369-
did.string(),
1370-
MerkleTreeType.Claims
1371-
);
1372-
1373-
const stateAuthClaim = hashElems([
1374-
(await claimsTree.root()).bigInt(),
1375-
oldTreeState.revocationRoot.bigInt(),
1376-
oldTreeState.rootOfRoots.bigInt()
1377-
]);
1378-
1379-
const credential = await this.createAuthBJJCredential(
1399+
let credential = await this.createAuthBJJCredential(
13801400
did,
13811401
pubKey,
13821402
authClaim,
1383-
stateAuthClaim,
1403+
oldTreeState,
13841404
opts.revocationOpts
13851405
);
13861406

1387-
await this.transitState(did, oldTreeState, true, ethSigner, prover);
1407+
const txId = await this.transitState(did, oldTreeState, isOldStateGenesis, ethSigner, prover);
1408+
const credsWithIden3MTPProof = await this.generateIden3SparseMerkleTreeProof(
1409+
did,
1410+
[credential],
1411+
txId
1412+
);
1413+
await this._credentialWallet.saveAll(credsWithIden3MTPProof);
1414+
1415+
const credRefreshed = await this._credentialWallet.findById(credential.id);
1416+
if (!credRefreshed) {
1417+
throw new Error('Credential not found in credential wallet');
1418+
}
1419+
credential = credRefreshed;
13881420

13891421
await this.publishRevocationInfoByCredentialStatusType(did, opts.revocationOpts.type, {
13901422
rhsUrl: opts.revocationOpts.id,
13911423
onChain: opts.revocationOpts.onChain
13921424
});
13931425

1394-
await this._credentialWallet.save(credential);
13951426
return credential;
13961427
}
13971428
}

tests/identity/id.test.ts

+62-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
/* eslint-disable no-console */
2+
import path from 'path';
23
import {
34
IdentityWallet,
45
byteEncoder,
@@ -10,7 +11,11 @@ import {
1011
CredentialStatusResolverRegistry,
1112
RHSResolver,
1213
CredentialStatusType,
13-
EthStateStorage
14+
EthStateStorage,
15+
FSCircuitStorage,
16+
NativeProver,
17+
Iden3SparseMerkleTreeProof,
18+
BJJSignatureProof2021
1419
} from '../../src';
1520
import {
1621
MOCK_STATE_STORAGE,
@@ -197,4 +202,60 @@ describe('identity', () => {
197202

198203
expect((await claimsTree.root()).bigInt()).not.to.equal(0);
199204
});
205+
206+
it('add auth bjj credential', async () => {
207+
const { did, credential } = await createIdentity(idWallet);
208+
expect(did.string()).to.equal(expectedDID);
209+
210+
const proof = await idWallet.generateCredentialMtp(did, credential);
211+
expect(proof.proof.existence).to.equal(true);
212+
213+
const circuitStorage = new FSCircuitStorage({
214+
dirname: path.join(__dirname, '../proofs/testdata')
215+
});
216+
const prover = new NativeProver(circuitStorage);
217+
218+
const ethSigner = new Wallet(WALLET_KEY, (dataStorage.states as EthStateStorage).provider);
219+
const opts = {
220+
seed: SEED_USER,
221+
revocationOpts: {
222+
type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof,
223+
id: RHS_URL
224+
}
225+
};
226+
227+
const treesModel = await idWallet.getDIDTreeModel(did);
228+
const [ctrHex, rtrHex, rorTrHex] = await Promise.all([
229+
treesModel.claimsTree.root(),
230+
treesModel.revocationTree.root(),
231+
treesModel.rootsTree.root()
232+
]);
233+
234+
const oldTreeState = {
235+
state: treesModel.state,
236+
claimsRoot: ctrHex,
237+
revocationRoot: rtrHex,
238+
rootOfRoots: rorTrHex
239+
};
240+
241+
expect(credential?.proof).not.to.be.undefined;
242+
expect((credential?.proof as unknown[])[0]).to.instanceOf(Iden3SparseMerkleTreeProof);
243+
expect((credential?.proof as unknown[]).length).to.equal(1);
244+
245+
const credential2 = await idWallet.addBJJAuthCredential(
246+
did,
247+
oldTreeState,
248+
false,
249+
ethSigner,
250+
opts,
251+
prover
252+
);
253+
expect(credential2?.proof).not.to.be.undefined;
254+
expect((credential2?.proof as unknown[]).length).to.equal(2);
255+
expect((credential2?.proof as unknown[])[0]).to.instanceOf(BJJSignatureProof2021);
256+
expect((credential2?.proof as unknown[])[1]).to.instanceOf(Iden3SparseMerkleTreeProof);
257+
258+
const proof2 = await idWallet.generateCredentialMtp(did, credential2);
259+
expect(proof2.proof.existence).to.equal(true);
260+
});
200261
});

0 commit comments

Comments
 (0)