Skip to content

Commit

Permalink
add state info for proofs methods (#211)
Browse files Browse the repository at this point in the history
add state info for proofs methods
  • Loading branch information
ilya-korotya authored Feb 14, 2024
1 parent 8815bf5 commit e56b57e
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 34 deletions.
45 changes: 38 additions & 7 deletions contracts/lib/IdentityBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,17 @@ abstract contract IdentityBase is IOnchainCredentialStatusResolver {
return identity.getClaimProof(claimIndexHash);
}

/**
* @dev Retrieve Claim inclusion or non-inclusion proof for a given claim index with state info.
* @param claimIndexHash - hash of Claim Index
* @return The ClaimsTree inclusion or non-inclusion proof for the claim and state info.
*/
function getClaimProofWithStateInfo(
uint256 claimIndexHash
) public view virtual returns (SmtLib.Proof memory, IdentityLib.StateInfo memory) {
return identity.getClaimProofWithStateInfo(claimIndexHash);
}

/**
* @dev Retrieve Claim inclusion or non-inclusion proof for a given claim index by target root.
* @param claimIndexHash - hash of Claim Index
Expand Down Expand Up @@ -85,6 +96,17 @@ abstract contract IdentityBase is IOnchainCredentialStatusResolver {
return identity.getRevocationProof(revocationNonce);
}

/**
* @dev Retrieve inclusion or non-inclusion proof for a given revocation nonce with state info.
* @param revocationNonce - revocation nonce
* @return The RevocationsTree inclusion or non-inclusion proof for the revocation nonce and state info.
*/
function getRevocationProofWithStateInfo(
uint64 revocationNonce
) public view virtual returns (SmtLib.Proof memory, IdentityLib.StateInfo memory) {
return identity.getRevocationProofWithStateInfo(revocationNonce);
}

/**
* @dev Retrieve inclusion or non-inclusion proof for a given revocation nonce by target root.
* @param revocationNonce - revocation nonce
Expand All @@ -107,14 +129,23 @@ abstract contract IdentityBase is IOnchainCredentialStatusResolver {
}

/**
* @dev Retrieve inclusion or non-inclusion proof for a given claimsTreeRoot.
* @param claimsTreeRoot - claims tree root
* @return The RootsTree inclusion or non-inclusion proof for the claim tree root
* @dev Retrieve inclusion or non-inclusion proof for a given rootsTreeRoot.
* @param rootsTreeRoot - roots tree root
* @return The RootsTree inclusion or non-inclusion proof for the roots tree root
*/
function getRootProof(
uint256 claimsTreeRoot
) public view virtual returns (SmtLib.Proof memory) {
return identity.getRootProof(claimsTreeRoot);
function getRootProof(uint256 rootsTreeRoot) public view virtual returns (SmtLib.Proof memory) {
return identity.getRootProof(rootsTreeRoot);
}

/**
* @dev Retrieve inclusion or non-inclusion proof for a given rootsTreeRoot with state info.
* @param rootsTreeRoot - roots tree root
* @return The RootsTree inclusion or non-inclusion proof for the claim tree root and state info.
*/
function getRootProofWithStateInfo(
uint256 rootsTreeRoot
) public view virtual returns (SmtLib.Proof memory, IdentityLib.StateInfo memory) {
return identity.getRootProofWithStateInfo(rootsTreeRoot);
}

/**
Expand Down
92 changes: 87 additions & 5 deletions contracts/lib/IdentityLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,16 @@ library IdentityLib {
uint256 rootsRoot;
}

/**
* @dev state info
*/
struct StateInfo {
uint256 state;
uint256 claimsRoot;
uint256 revocationsRoot;
uint256 rootsRoot;
}

/**
* @dev Initialization of the library state variables
* @param _stateContractAddr - address of the State contract
Expand Down Expand Up @@ -204,6 +214,30 @@ library IdentityLib {
);
}

/**
* @dev Retrieve Claim inclusion or non-inclusion proof for a given claim index with state info.
* Note that proof is taken for the latest published claims tree root.
* @param claimIndexHash - hash of Claim Index
* @return The ClaimsTree inclusion or non-inclusion proof for the claim and state info
*/
function getClaimProofWithStateInfo(
Data storage self,
uint256 claimIndexHash
) external view returns (SmtLib.Proof memory, StateInfo memory) {
return (
self.trees.claimsTree.getProofByRoot(
claimIndexHash,
self.latestPublishedTreeRoots.claimsRoot
),
StateInfo({
state: self.latestPublishedState,
claimsRoot: self.latestPublishedTreeRoots.claimsRoot,
revocationsRoot: self.latestPublishedTreeRoots.revocationsRoot,
rootsRoot: self.latestPublishedTreeRoots.rootsRoot
})
);
}

/**
* @dev Retrieve Claim inclusion or non-inclusion proof for a given claim index by target root.
* @param claimIndexHash - hash of Claim Index
Expand Down Expand Up @@ -243,6 +277,30 @@ library IdentityLib {
);
}

/**
* @dev Retrieve inclusion or non-inclusion proof for a given revocation nonce with state info.
Note that proof is taken for the latest published revocation tree root.
* @param revocationNonce - revocation nonce
* @return The RevocationsTree inclusion or non-inclusion proof for the claim and state info.
*/
function getRevocationProofWithStateInfo(
Data storage self,
uint64 revocationNonce
) external view returns (SmtLib.Proof memory, StateInfo memory) {
return (
self.trees.revocationsTree.getProofByRoot(
uint256(revocationNonce),
self.latestPublishedTreeRoots.revocationsRoot
),
StateInfo({
state: self.latestPublishedState,
claimsRoot: self.latestPublishedTreeRoots.claimsRoot,
revocationsRoot: self.latestPublishedTreeRoots.revocationsRoot,
rootsRoot: self.latestPublishedTreeRoots.rootsRoot
})
);
}

/**
* @dev Retrieve inclusion or non-inclusion proof for a given revocation nonce by target root.
* @param revocationNonce - revocation nonce
Expand All @@ -266,22 +324,46 @@ library IdentityLib {
}

/**
* @dev Retrieve inclusion or non-inclusion proof for a given claimsTreeRoot.
* @dev Retrieve inclusion or non-inclusion proof for a given rootsTreeRoot.
Note that proof is taken for the latest published roots tree root.
* @param claimsTreeRoot - claims tree root
* @return The RootsTree inclusion or non-inclusion proof for the claim tree root
* @param rootsTreeRoot - roots tree root
* @return The RootsTree inclusion or non-inclusion proof for the roots tree root
*/
function getRootProof(
Data storage self,
uint256 claimsTreeRoot
uint256 rootsTreeRoot
) external view returns (SmtLib.Proof memory) {
return
self.trees.rootsTree.getProofByRoot(
claimsTreeRoot,
rootsTreeRoot,
self.latestPublishedTreeRoots.rootsRoot
);
}

/**
* @dev Retrieve inclusion or non-inclusion proof for a given rootsTreeRoot and state info.
Note that proof is taken for the latest published roots tree root.
* @param rootsTreeRoot - roots tree root
* @return The RootsTree inclusion or non-inclusion proof for the roots tree root and state info.
*/
function getRootProofWithStateInfo(
Data storage self,
uint256 rootsTreeRoot
) external view returns (SmtLib.Proof memory, StateInfo memory) {
return (
self.trees.rootsTree.getProofByRoot(
rootsTreeRoot,
self.latestPublishedTreeRoots.rootsRoot
),
StateInfo({
state: self.latestPublishedState,
claimsRoot: self.latestPublishedTreeRoots.claimsRoot,
revocationsRoot: self.latestPublishedTreeRoots.revocationsRoot,
rootsRoot: self.latestPublishedTreeRoots.rootsRoot
})
);
}

/**
* @dev Retrieve inclusion or non-inclusion proof for a given claimsTreeRoot by target root.
* @param claimsTreeRoot - claims tree root
Expand Down
4 changes: 2 additions & 2 deletions contracts/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion contracts/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@iden3/contracts",
"description": "Smart Contract library for Solidity",
"version": "1.4.5",
"version": "1.4.6",
"files": [
"**/*.sol",
"/build/contracts/*.json",
Expand Down
74 changes: 55 additions & 19 deletions test/onchain-identity/onchain-identity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { expect } from "chai";
import { OnchainIdentityDeployHelper } from "../../helpers/OnchainIdentityDeployHelper";
import { DeployHelper } from "../../helpers/DeployHelper";

describe("Next tests reproduce identity life cycle", function() {
describe("Next tests reproduce identity life cycle", function () {
this.timeout(10000);

let identity;
Expand All @@ -15,12 +15,12 @@ describe("Next tests reproduce identity life cycle", function() {
const deployHelper = await OnchainIdentityDeployHelper.initialize();
const stContracts = await stDeployHelper.deployState();
const contracts = await deployHelper.deployIdentity(
stContracts.state,
stContracts.smtLib,
stContracts.poseidon1,
stContracts.poseidon2,
stContracts.poseidon3,
stContracts.poseidon4
stContracts.state,
stContracts.smtLib,
stContracts.poseidon1,
stContracts.poseidon2,
stContracts.poseidon3,
stContracts.poseidon4
);
identity = contracts.identity;
const idType = await stContracts.state.getDefaultIdType();
Expand All @@ -30,9 +30,7 @@ describe("Next tests reproduce identity life cycle", function() {

describe("create identity", function () {
it("deploy state and identity", async function () {
expect(await identity.getIsOldStateGenesis()).to.be.equal(
true
);
expect(await identity.getIsOldStateGenesis()).to.be.equal(true);
});

it("validate identity's id", async function () {
Expand Down Expand Up @@ -68,13 +66,22 @@ describe("Next tests reproduce identity life cycle", function() {
const isOldStateGenesis = await identity.getIsOldStateGenesis();
expect(isOldStateGenesis).to.be.true;
});
it(
"latest identity state should be empty",
async function () {
latestSavedState = await identity.getLatestPublishedState();
expect(latestSavedState).to.be.equal(0);
}
);
it("latest identity state should be empty", async function () {
latestSavedState = await identity.getLatestPublishedState();
expect(latestSavedState).to.be.equal(0);
});
it("getClaimProofWithStateInfo should return non-existence proof", async function () {
const proof = await identity.getClaimProofWithStateInfo(1);
expect(proof[0].existence).to.be.false;
});
it("getRevocationProofWithStateInfo should return non-existence proof", async function () {
const proof = await identity.getRevocationProofWithStateInfo(1);
expect(proof[0].existence).to.be.false;
});
it("getRootProofWithStateInfo should return non-existence proof", async function () {
const proof = await identity.getRootProofWithStateInfo(1);
expect(proof[0].existence).to.be.false;
});
});

describe("add claim", function () {
Expand Down Expand Up @@ -174,6 +181,20 @@ describe("Next tests reproduce identity life cycle", function() {
latestComputedState = await identity.calcIdentityState();
expect(latestComputedState).to.be.equal(latestSavedState);
});

it("claim proof must exist after publishing and StateInfo should be latest", async function () {
const latestState = await identity.getLatestPublishedState();
const latestClaimTreeRoot = await identity.getLatestPublishedClaimsRoot();
const latestRevocationTreeRoot = await identity.getLatestPublishedRevocationsRoot();
const latestTransitionRootOfRootsTreeRoot = await identity.getLatestPublishedRootsRoot();

const claimProof = await identity.getClaimProofWithStateInfo(1);
expect(claimProof[0].existence).to.be.true;
expect(claimProof[1].state).to.be.equal(latestState);
expect(claimProof[1].claimsRoot).to.be.equal(latestClaimTreeRoot);
expect(claimProof[1].revocationsRoot).to.be.equal(latestRevocationTreeRoot);
expect(claimProof[1].rootsRoot).to.be.equal(latestTransitionRootOfRootsTreeRoot);
});
});

describe("revoke state", function () {
Expand All @@ -195,7 +216,8 @@ describe("Next tests reproduce identity life cycle", function() {
});

it("transit of revocation tree shouldn't update root of roots tree", async function () {
const beforeRevocationRootOfRootsTreeRoot = await identity.getLatestPublishedRevocationsRoot();
const beforeRevocationRootOfRootsTreeRoot =
await identity.getLatestPublishedRevocationsRoot();
expect(beforeRevocationRootOfRootsTreeRoot).to.be.equal(beforeRevocationRevocationTreeRoot);
});

Expand Down Expand Up @@ -226,6 +248,20 @@ describe("Next tests reproduce identity life cycle", function() {
const afterTransitionLatestSavedState = await identity.getLatestPublishedState();
expect(beforeTransitionLatestSavedState).to.be.not.equal(afterTransitionLatestSavedState);
});

it("revocation proof must exist after publishing and StateInfo should be latest", async function () {
const latestState = await identity.getLatestPublishedState();
const latestClaimTreeRoot = await identity.getLatestPublishedClaimsRoot();
const latestRevocationTreeRoot = await identity.getLatestPublishedRevocationsRoot();
const latestTransitionRootOfRootsTreeRoot = await identity.getLatestPublishedRootsRoot();

const revocationProof = await identity.getRevocationProofWithStateInfo(1);
expect(revocationProof[0].existence).to.be.true;
expect(revocationProof[1].state).to.be.equal(latestState);
expect(revocationProof[1].claimsRoot).to.be.equal(latestClaimTreeRoot);
expect(revocationProof[1].revocationsRoot).to.be.equal(latestRevocationTreeRoot);
expect(revocationProof[1].rootsRoot).to.be.equal(latestTransitionRootOfRootsTreeRoot);
});
});
});

Expand Down Expand Up @@ -567,7 +603,7 @@ describe("Genesis state doens't have history of states", () => {
const latestState = await identity.calcIdentityState();
try {
await identity.getRootsByState(latestState);
expect.fail('The transaction should have thrown an error');
expect.fail("The transaction should have thrown an error");
} catch (err: any) {
expect(err.reason).to.be.equal("Roots for this state doesn't exist");
}
Expand Down

0 comments on commit e56b57e

Please sign in to comment.