Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manage ethereum based identities #200

Merged
merged 38 commits into from
Apr 12, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
9895873
create ethereum based identities
daveroga Mar 21, 2024
5aeda0e
fix rebase
daveroga Mar 22, 2024
3e96c51
remove log
daveroga Mar 22, 2024
6f0c5ac
pass parameter for ethereum identity
daveroga Mar 22, 2024
2c375b2
update state transition ethereum identities
daveroga Mar 27, 2024
c638453
method update for testing in Mumbai deployment
daveroga Mar 27, 2024
dca0556
update auth test with integration test for ethereum identities
daveroga Mar 27, 2024
2bf7b91
restore method helper iden3
daveroga Mar 27, 2024
8ec2133
update current state when creating auth credential in ethereum identi…
daveroga Mar 28, 2024
a86992c
remove unused import
daveroga Mar 28, 2024
7e43f84
add test ethereum identity flow (not integration)
daveroga Mar 28, 2024
39a2dfa
remove only in test
daveroga Mar 28, 2024
c048e0b
update mumbai for aloy
daveroga Apr 2, 2024
b31c69b
update id test
daveroga Apr 2, 2024
a68a6dd
changes proposed from review
daveroga Apr 2, 2024
d6740c1
update tests
daveroga Apr 3, 2024
17a4bf1
suggested changes from review
daveroga Apr 3, 2024
bf4d208
throw error if not ethSigner
daveroga Apr 3, 2024
f7e784d
add transit state logic to identiy wallet
daveroga Apr 3, 2024
8819374
typo and make new function to add bjj key and transit state
daveroga Apr 3, 2024
42c2c25
fix sec256k1 private key generation less than 32 bytes
daveroga Apr 4, 2024
4a1030a
updates from reviewed comments
daveroga Apr 4, 2024
48e126a
updates from review comments
daveroga Apr 5, 2024
368fdf8
updates from review
daveroga Apr 5, 2024
a19871a
update prover parameter in identity wallet
daveroga Apr 5, 2024
bb236e3
separate creation options for createIdentity and createEthereumBasedI…
daveroga Apr 5, 2024
c7409cc
update add bjj credential and test
daveroga Apr 8, 2024
cc25463
update core claim in mtp proof and revocation
daveroga Apr 8, 2024
a6eba8a
add key rotation use case test
daveroga Apr 8, 2024
2b29963
remove only in test
daveroga Apr 8, 2024
e6f1187
add transit state after revoke credential
daveroga Apr 8, 2024
60a0c50
update query proof with v3
daveroga Apr 9, 2024
571234c
check issue credentials in issuer revocation keys
daveroga Apr 9, 2024
f6728c9
revoke user keys and check
daveroga Apr 9, 2024
a48de78
changes
daveroga Apr 10, 2024
c652718
add function to get mtp from core claim
vmidyllic Apr 10, 2024
38fad21
fix
vmidyllic Apr 10, 2024
ca6cf87
remove level of nested structure
daveroga Apr 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/identity/identity-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
getRandomBytes,
Poseidon
} from '@iden3/js-crypto';
import { Hash, hashElems, ZERO_HASH } from '@iden3/js-merkletree';
import { hashElems, ZERO_HASH } from '@iden3/js-merkletree';
import { generateProfileDID, subjectPositionIndex } from './common';
import * as uuid from 'uuid';
import { JSONSchema, JsonSchemaValidator, cacheLoader } from '../schema-processor';
Expand Down Expand Up @@ -1391,6 +1391,11 @@ export class IdentityWallet implements IIdentityWallet {
prover?: IZKProver // it will be needed in case of non ethereum identities
): Promise<W3CCredential> {
opts.seed = opts.seed ?? getRandomBytes(32);
opts.revocationOpts.nonce =
opts.revocationOpts.nonce ??
(isOldStateGenesis
? 0
: opts.revocationOpts.nonce ?? new DataView(getRandomBytes(12).buffer).getUint32(0));

const { authClaim, pubKey } = await this.createAuthCoreClaim(
opts.revocationOpts.nonce ?? 0,
Expand Down
301 changes: 300 additions & 1 deletion tests/handlers/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ import {
W3CCredential,
Sec256k1Provider,
StateInfo,
hexToBytes
hexToBytes,
NativeProver
} from '../../src';
import { Token } from '@iden3/js-jwz';
import { Blockchain, DID, DidMethod, NetworkId } from '@iden3/js-iden3-core';
Expand Down Expand Up @@ -1911,4 +1912,302 @@ describe('auth', () => {

await authHandler.handleAuthorizationResponse(response, request, testOpts);
});

it('auth flow identity (profile) with circuits V3', async () => {
const profileDID = await idWallet.createProfile(userDID, 777, issuerDID.string());

const claimReq: CredentialRequest = {
credentialSchema:
'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/kyc-nonmerklized.json',
type: 'KYCAgeCredential',
credentialSubject: {
id: userDID.string(),
birthday: 19960424,
documentType: 99
},
expiration: 2793526400,
revocationOpts: {
type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof,
id: RHS_URL
}
};
const issuerCred = await idWallet.issueCredential(issuerDID, claimReq);
const employeeCredRequest: CredentialRequest = {
credentialSchema:
'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/KYCEmployee-v101.json',
type: 'KYCEmployee',
credentialSubject: {
id: profileDID.string(),
ZKPexperiance: true,
hireDate: '2023-12-11',
position: 'boss',
salary: 200,
documentType: 1
},
revocationOpts: {
type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof,
id: RHS_URL
}
};
const employeeCred = await idWallet.issueCredential(issuerDID, employeeCredRequest);

await credWallet.saveAll([employeeCred, issuerCred]);

const res = await idWallet.addCredentialsToMerkleTree([employeeCred], issuerDID);
await idWallet.publishStateToRHS(issuerDID, RHS_URL);

const ethSigner = new ethers.Wallet(
WALLET_KEY,
(dataStorage.states as EthStateStorage).provider
);

const txId = await proofService.transitState(
issuerDID,
res.oldTreeState,
true,
dataStorage.states,
ethSigner
);

const credsWithIden3MTPProof = await idWallet.generateIden3SparseMerkleTreeProof(
issuerDID,
res.credentials,
txId
);

await credWallet.saveAll(credsWithIden3MTPProof);

const proofReqs: ZeroKnowledgeProofRequest[] = [
{
id: 1,
circuitId: CircuitId.AtomicQueryV3,
optional: false,
query: {
proofType: ProofType.BJJSignature,
allowedIssuers: ['*'],
type: 'KYCAgeCredential',
context:
'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-nonmerklized.jsonld',
credentialSubject: {
documentType: {
$eq: 99
}
}
}
},
{
id: 2,
circuitId: CircuitId.LinkedMultiQuery10,
optional: false,
query: {
groupId: 1,
proofType: ProofType.Iden3SparseMerkleTreeProof,
allowedIssuers: ['*'],
type: 'KYCEmployee',
context:
'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld',
credentialSubject: {
documentType: {
$eq: 1
},
position: {
$eq: 'boss',
$ne: 'employee'
}
}
}
},
{
id: 3,
circuitId: CircuitId.AtomicQueryV3,
optional: false,
query: {
groupId: 1,
proofType: ProofType.BJJSignature,
allowedIssuers: ['*'],
type: 'KYCEmployee',
context:
'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld',
credentialSubject: {
hireDate: {
$eq: '2023-12-11'
}
}
},
params: {
nullifierSessionId: '12345'
}
}
];

const authReqBody: AuthorizationRequestMessageBody = {
callbackUrl: 'http://localhost:8080/callback?id=1234442-123123-123123',
reason: 'reason',
message: 'mesage',
did_doc: {},
scope: proofReqs
};

const id = uuid.v4();
const authReq: AuthorizationRequestMessage = {
id,
typ: PROTOCOL_CONSTANTS.MediaType.PlainMessage,
type: PROTOCOL_CONSTANTS.PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_REQUEST_MESSAGE_TYPE,
thid: id,
body: authReqBody,
from: issuerDID.string()
};

const msgBytes = byteEncoder.encode(JSON.stringify(authReq));
const authRes = await authHandler.handleAuthorizationRequest(userDID, msgBytes);
// console.log(JSON.stringify(authRes.authResponse));
const tokenStr = authRes.token;
// console.log(tokenStr);
expect(tokenStr).to.be.a('string');
const token = await Token.parse(tokenStr);
expect(token).to.be.a('object');
});

it.only('key rotation use case', async () => {
const claimReq: CredentialRequest = {
credentialSchema:
'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/kyc-nonmerklized.json',
type: 'KYCAgeCredential',
credentialSubject: {
id: userDID.string(),
birthday: 19960424,
documentType: 99
},
expiration: 2793526400,
revocationOpts: {
type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof,
id: RHS_URL
}
};
const issuerCred = await idWallet.issueCredential(issuerDID, claimReq);

await credWallet.save(issuerCred);

const proofReq: ZeroKnowledgeProofRequest = {
id: 1,
circuitId: CircuitId.AtomicQuerySigV2,
optional: false,
query: {
allowedIssuers: ['*'],
type: claimReq.type,
context:
'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-nonmerklized.jsonld',
credentialSubject: {
documentType: {
$eq: 99
}
}
}
};

const authReqBody: AuthorizationRequestMessageBody = {
callbackUrl: 'http://localhost:8080/callback?id=1234442-123123-123123',
reason: 'reason',
message: 'mesage',
did_doc: {},
scope: [proofReq as ZeroKnowledgeProofRequest]
};

const handleAuthorizationRequest = async (
userDID: DID,
authReqBody: AuthorizationRequestMessageBody
) => {
const id = uuid.v4();
const authReq: AuthorizationRequestMessage = {
id,
typ: PROTOCOL_CONSTANTS.MediaType.PlainMessage,
type: PROTOCOL_CONSTANTS.PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_REQUEST_MESSAGE_TYPE,
thid: id,
body: authReqBody,
from: issuerDID.string()
};

const msgBytes = byteEncoder.encode(JSON.stringify(authReq));
const authRes = await authHandler.handleAuthorizationRequest(userDID, msgBytes);
expect(authRes.token).to.be.a('string');
const token = await Token.parse(authRes.token);
expect(token).to.be.a('object');
};

await handleAuthorizationRequest(userDID, authReqBody);

// add second Bjj auth credential
const circuitStorage = new FSCircuitStorage({
dirname: path.join(__dirname, '../proofs/testdata')
});
const prover = new NativeProver(circuitStorage);

const ethSigner = new ethers.Wallet(
WALLET_KEY,
(dataStorage.states as EthStateStorage).provider
);
const opts = {
seed: SEED_USER,
revocationOpts: {
type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof,
id: RHS_URL
}
};

const treesModel = await idWallet.getDIDTreeModel(issuerDID);
const [ctrHex, rtrHex, rorTrHex] = await Promise.all([
treesModel.claimsTree.root(),
treesModel.revocationTree.root(),
treesModel.rootsTree.root()
]);

const oldTreeState = {
state: treesModel.state,
claimsRoot: ctrHex,
revocationRoot: rtrHex,
rootOfRoots: rorTrHex
};

// add k2 auth credential (we have k1 already)
const credential2 = await idWallet.addBJJAuthCredential(
issuerDID,
oldTreeState,
false,
ethSigner,
opts,
prover
);

expect(credential2?.proof).not.to.be.undefined;

// get actual auth credential (k1)
const { authCredential: issuerAuthCredential } = await idWallet.getActualAuthCredential(
issuerDID
);

// revoke k1 auth credential
const nonce = await idWallet.revokeCredential(issuerDID, issuerAuthCredential);
await idWallet.publishStateToRHS(issuerDID, RHS_URL, [nonce]);

daveroga marked this conversation as resolved.
Show resolved Hide resolved
await handleAuthorizationRequest(userDID, authReqBody);

// get actual auth credential (k2)
const { authCredential: issuerAuthCredential2 } = await idWallet.getActualAuthCredential(
issuerDID
);

expect(issuerAuthCredential2).to.be.deep.equal(credential2);

// revoke k2 auth credential
const nonce2 = await idWallet.revokeCredential(issuerDID, issuerAuthCredential2);
await idWallet.publishStateToRHS(issuerDID, RHS_URL, [nonce2]);

// check that we don't have auth credentials now
await expect(idWallet.getActualAuthCredential(issuerDID)).to.rejectedWith(
daveroga marked this conversation as resolved.
Show resolved Hide resolved
'no auth credentials found'
);

// should this work?
await handleAuthorizationRequest(userDID, authReqBody);
});
});
3 changes: 1 addition & 2 deletions tests/identity/id.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,8 +318,7 @@ describe('identity', () => {
const afterRevokeProofNRcredential = await idWallet.generateNonRevocationMtp(did, credential);
expect(afterRevokeProofNRcredential.proof.existence).to.equal(true);

// credential2 was generated with sigproof from credential, so it should be revoked as well
const afterRevokeProofNRcredential2 = await idWallet.generateNonRevocationMtp(did, credential2);
expect(afterRevokeProofNRcredential2.proof.existence).to.equal(true);
expect(afterRevokeProofNRcredential2.proof.existence).to.equal(false);
});
});
Loading