Skip to content

Commit a6eba8a

Browse files
committed
add key rotation use case test
1 parent cc25463 commit a6eba8a

File tree

3 files changed

+307
-4
lines changed

3 files changed

+307
-4
lines changed

src/identity/identity-wallet.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import {
2121
getRandomBytes,
2222
Poseidon
2323
} from '@iden3/js-crypto';
24-
import { Hash, hashElems, ZERO_HASH } from '@iden3/js-merkletree';
24+
import { hashElems, ZERO_HASH } from '@iden3/js-merkletree';
2525
import { generateProfileDID, subjectPositionIndex } from './common';
2626
import * as uuid from 'uuid';
2727
import { JSONSchema, JsonSchemaValidator, cacheLoader } from '../schema-processor';
@@ -1391,6 +1391,11 @@ export class IdentityWallet implements IIdentityWallet {
13911391
prover?: IZKProver // it will be needed in case of non ethereum identities
13921392
): Promise<W3CCredential> {
13931393
opts.seed = opts.seed ?? getRandomBytes(32);
1394+
opts.revocationOpts.nonce =
1395+
opts.revocationOpts.nonce ??
1396+
(isOldStateGenesis
1397+
? 0
1398+
: opts.revocationOpts.nonce ?? new DataView(getRandomBytes(12).buffer).getUint32(0));
13941399

13951400
const { authClaim, pubKey } = await this.createAuthCoreClaim(
13961401
opts.revocationOpts.nonce ?? 0,

tests/handlers/auth.test.ts

+300-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ import {
3939
W3CCredential,
4040
Sec256k1Provider,
4141
StateInfo,
42-
hexToBytes
42+
hexToBytes,
43+
NativeProver
4344
} from '../../src';
4445
import { Token } from '@iden3/js-jwz';
4546
import { Blockchain, DID, DidMethod, NetworkId } from '@iden3/js-iden3-core';
@@ -1911,4 +1912,302 @@ describe('auth', () => {
19111912

19121913
await authHandler.handleAuthorizationResponse(response, request, testOpts);
19131914
});
1915+
1916+
it('auth flow identity (profile) with circuits V3', async () => {
1917+
const profileDID = await idWallet.createProfile(userDID, 777, issuerDID.string());
1918+
1919+
const claimReq: CredentialRequest = {
1920+
credentialSchema:
1921+
'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/kyc-nonmerklized.json',
1922+
type: 'KYCAgeCredential',
1923+
credentialSubject: {
1924+
id: userDID.string(),
1925+
birthday: 19960424,
1926+
documentType: 99
1927+
},
1928+
expiration: 2793526400,
1929+
revocationOpts: {
1930+
type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof,
1931+
id: RHS_URL
1932+
}
1933+
};
1934+
const issuerCred = await idWallet.issueCredential(issuerDID, claimReq);
1935+
const employeeCredRequest: CredentialRequest = {
1936+
credentialSchema:
1937+
'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/KYCEmployee-v101.json',
1938+
type: 'KYCEmployee',
1939+
credentialSubject: {
1940+
id: profileDID.string(),
1941+
ZKPexperiance: true,
1942+
hireDate: '2023-12-11',
1943+
position: 'boss',
1944+
salary: 200,
1945+
documentType: 1
1946+
},
1947+
revocationOpts: {
1948+
type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof,
1949+
id: RHS_URL
1950+
}
1951+
};
1952+
const employeeCred = await idWallet.issueCredential(issuerDID, employeeCredRequest);
1953+
1954+
await credWallet.saveAll([employeeCred, issuerCred]);
1955+
1956+
const res = await idWallet.addCredentialsToMerkleTree([employeeCred], issuerDID);
1957+
await idWallet.publishStateToRHS(issuerDID, RHS_URL);
1958+
1959+
const ethSigner = new ethers.Wallet(
1960+
WALLET_KEY,
1961+
(dataStorage.states as EthStateStorage).provider
1962+
);
1963+
1964+
const txId = await proofService.transitState(
1965+
issuerDID,
1966+
res.oldTreeState,
1967+
true,
1968+
dataStorage.states,
1969+
ethSigner
1970+
);
1971+
1972+
const credsWithIden3MTPProof = await idWallet.generateIden3SparseMerkleTreeProof(
1973+
issuerDID,
1974+
res.credentials,
1975+
txId
1976+
);
1977+
1978+
await credWallet.saveAll(credsWithIden3MTPProof);
1979+
1980+
const proofReqs: ZeroKnowledgeProofRequest[] = [
1981+
{
1982+
id: 1,
1983+
circuitId: CircuitId.AtomicQueryV3,
1984+
optional: false,
1985+
query: {
1986+
proofType: ProofType.BJJSignature,
1987+
allowedIssuers: ['*'],
1988+
type: 'KYCAgeCredential',
1989+
context:
1990+
'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-nonmerklized.jsonld',
1991+
credentialSubject: {
1992+
documentType: {
1993+
$eq: 99
1994+
}
1995+
}
1996+
}
1997+
},
1998+
{
1999+
id: 2,
2000+
circuitId: CircuitId.LinkedMultiQuery10,
2001+
optional: false,
2002+
query: {
2003+
groupId: 1,
2004+
proofType: ProofType.Iden3SparseMerkleTreeProof,
2005+
allowedIssuers: ['*'],
2006+
type: 'KYCEmployee',
2007+
context:
2008+
'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld',
2009+
credentialSubject: {
2010+
documentType: {
2011+
$eq: 1
2012+
},
2013+
position: {
2014+
$eq: 'boss',
2015+
$ne: 'employee'
2016+
}
2017+
}
2018+
}
2019+
},
2020+
{
2021+
id: 3,
2022+
circuitId: CircuitId.AtomicQueryV3,
2023+
optional: false,
2024+
query: {
2025+
groupId: 1,
2026+
proofType: ProofType.BJJSignature,
2027+
allowedIssuers: ['*'],
2028+
type: 'KYCEmployee',
2029+
context:
2030+
'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v101.json-ld',
2031+
credentialSubject: {
2032+
hireDate: {
2033+
$eq: '2023-12-11'
2034+
}
2035+
}
2036+
},
2037+
params: {
2038+
nullifierSessionId: '12345'
2039+
}
2040+
}
2041+
];
2042+
2043+
const authReqBody: AuthorizationRequestMessageBody = {
2044+
callbackUrl: 'http://localhost:8080/callback?id=1234442-123123-123123',
2045+
reason: 'reason',
2046+
message: 'mesage',
2047+
did_doc: {},
2048+
scope: proofReqs
2049+
};
2050+
2051+
const id = uuid.v4();
2052+
const authReq: AuthorizationRequestMessage = {
2053+
id,
2054+
typ: PROTOCOL_CONSTANTS.MediaType.PlainMessage,
2055+
type: PROTOCOL_CONSTANTS.PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_REQUEST_MESSAGE_TYPE,
2056+
thid: id,
2057+
body: authReqBody,
2058+
from: issuerDID.string()
2059+
};
2060+
2061+
const msgBytes = byteEncoder.encode(JSON.stringify(authReq));
2062+
const authRes = await authHandler.handleAuthorizationRequest(userDID, msgBytes);
2063+
// console.log(JSON.stringify(authRes.authResponse));
2064+
const tokenStr = authRes.token;
2065+
// console.log(tokenStr);
2066+
expect(tokenStr).to.be.a('string');
2067+
const token = await Token.parse(tokenStr);
2068+
expect(token).to.be.a('object');
2069+
});
2070+
2071+
it.only('key rotation use case', async () => {
2072+
const claimReq: CredentialRequest = {
2073+
credentialSchema:
2074+
'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/kyc-nonmerklized.json',
2075+
type: 'KYCAgeCredential',
2076+
credentialSubject: {
2077+
id: userDID.string(),
2078+
birthday: 19960424,
2079+
documentType: 99
2080+
},
2081+
expiration: 2793526400,
2082+
revocationOpts: {
2083+
type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof,
2084+
id: RHS_URL
2085+
}
2086+
};
2087+
const issuerCred = await idWallet.issueCredential(issuerDID, claimReq);
2088+
2089+
await credWallet.save(issuerCred);
2090+
2091+
const proofReq: ZeroKnowledgeProofRequest = {
2092+
id: 1,
2093+
circuitId: CircuitId.AtomicQuerySigV2,
2094+
optional: false,
2095+
query: {
2096+
allowedIssuers: ['*'],
2097+
type: claimReq.type,
2098+
context:
2099+
'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-nonmerklized.jsonld',
2100+
credentialSubject: {
2101+
documentType: {
2102+
$eq: 99
2103+
}
2104+
}
2105+
}
2106+
};
2107+
2108+
const authReqBody: AuthorizationRequestMessageBody = {
2109+
callbackUrl: 'http://localhost:8080/callback?id=1234442-123123-123123',
2110+
reason: 'reason',
2111+
message: 'mesage',
2112+
did_doc: {},
2113+
scope: [proofReq as ZeroKnowledgeProofRequest]
2114+
};
2115+
2116+
const handleAuthorizationRequest = async (
2117+
userDID: DID,
2118+
authReqBody: AuthorizationRequestMessageBody
2119+
) => {
2120+
const id = uuid.v4();
2121+
const authReq: AuthorizationRequestMessage = {
2122+
id,
2123+
typ: PROTOCOL_CONSTANTS.MediaType.PlainMessage,
2124+
type: PROTOCOL_CONSTANTS.PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_REQUEST_MESSAGE_TYPE,
2125+
thid: id,
2126+
body: authReqBody,
2127+
from: issuerDID.string()
2128+
};
2129+
2130+
const msgBytes = byteEncoder.encode(JSON.stringify(authReq));
2131+
const authRes = await authHandler.handleAuthorizationRequest(userDID, msgBytes);
2132+
expect(authRes.token).to.be.a('string');
2133+
const token = await Token.parse(authRes.token);
2134+
expect(token).to.be.a('object');
2135+
};
2136+
2137+
await handleAuthorizationRequest(userDID, authReqBody);
2138+
2139+
// add second Bjj auth credential
2140+
const circuitStorage = new FSCircuitStorage({
2141+
dirname: path.join(__dirname, '../proofs/testdata')
2142+
});
2143+
const prover = new NativeProver(circuitStorage);
2144+
2145+
const ethSigner = new ethers.Wallet(
2146+
WALLET_KEY,
2147+
(dataStorage.states as EthStateStorage).provider
2148+
);
2149+
const opts = {
2150+
seed: SEED_USER,
2151+
revocationOpts: {
2152+
type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof,
2153+
id: RHS_URL
2154+
}
2155+
};
2156+
2157+
const treesModel = await idWallet.getDIDTreeModel(issuerDID);
2158+
const [ctrHex, rtrHex, rorTrHex] = await Promise.all([
2159+
treesModel.claimsTree.root(),
2160+
treesModel.revocationTree.root(),
2161+
treesModel.rootsTree.root()
2162+
]);
2163+
2164+
const oldTreeState = {
2165+
state: treesModel.state,
2166+
claimsRoot: ctrHex,
2167+
revocationRoot: rtrHex,
2168+
rootOfRoots: rorTrHex
2169+
};
2170+
2171+
// add k2 auth credential (we have k1 already)
2172+
const credential2 = await idWallet.addBJJAuthCredential(
2173+
issuerDID,
2174+
oldTreeState,
2175+
false,
2176+
ethSigner,
2177+
opts,
2178+
prover
2179+
);
2180+
2181+
expect(credential2?.proof).not.to.be.undefined;
2182+
2183+
// get actual auth credential (k1)
2184+
const { authCredential: issuerAuthCredential } = await idWallet.getActualAuthCredential(
2185+
issuerDID
2186+
);
2187+
2188+
// revoke k1 auth credential
2189+
const nonce = await idWallet.revokeCredential(issuerDID, issuerAuthCredential);
2190+
await idWallet.publishStateToRHS(issuerDID, RHS_URL, [nonce]);
2191+
2192+
await handleAuthorizationRequest(userDID, authReqBody);
2193+
2194+
// get actual auth credential (k2)
2195+
const { authCredential: issuerAuthCredential2 } = await idWallet.getActualAuthCredential(
2196+
issuerDID
2197+
);
2198+
2199+
expect(issuerAuthCredential2).to.be.deep.equal(credential2);
2200+
2201+
// revoke k2 auth credential
2202+
const nonce2 = await idWallet.revokeCredential(issuerDID, issuerAuthCredential2);
2203+
await idWallet.publishStateToRHS(issuerDID, RHS_URL, [nonce2]);
2204+
2205+
// check that we don't have auth credentials now
2206+
await expect(idWallet.getActualAuthCredential(issuerDID)).to.rejectedWith(
2207+
'no auth credentials found'
2208+
);
2209+
2210+
// should this work?
2211+
await handleAuthorizationRequest(userDID, authReqBody);
2212+
});
19142213
});

tests/identity/id.test.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -318,8 +318,7 @@ describe('identity', () => {
318318
const afterRevokeProofNRcredential = await idWallet.generateNonRevocationMtp(did, credential);
319319
expect(afterRevokeProofNRcredential.proof.existence).to.equal(true);
320320

321-
// credential2 was generated with sigproof from credential, so it should be revoked as well
322321
const afterRevokeProofNRcredential2 = await idWallet.generateNonRevocationMtp(did, credential2);
323-
expect(afterRevokeProofNRcredential2.proof.existence).to.equal(true);
322+
expect(afterRevokeProofNRcredential2.proof.existence).to.equal(false);
324323
});
325324
});

0 commit comments

Comments
 (0)