@@ -66,6 +66,125 @@ library Ics23 {
6666 });
6767 }
6868
69+ enum VerifyChainedNonMembershipError {
70+ None,
71+ NonExistenceProofIsNil,
72+ ExistenceProofIsNil,
73+ InvalidProofRoot,
74+ KeyMismatch,
75+ ValueMismatch,
76+ InvalidSpec,
77+ InvalidIntermediateProofRoot,
78+ IntermateProofRootMismatch,
79+ RootMismatch,
80+ VerifyLeft,
81+ VerifyRight,
82+ LeftAndRightKeyEmpty,
83+ RightKeyRange,
84+ LeftKeyRange,
85+ RightProofLeftMost,
86+ LeftProofRightMost,
87+ IsLeftNeighbor
88+ }
89+
90+ function verifyChainedNonMembership (
91+ IbcCoreCommitmentV1MerkleProof.Data memory merkleProof ,
92+ bytes memory root ,
93+ bytes [] memory path
94+ ) internal pure returns (VerifyChainedNonMembershipError) {
95+ CosmosIcs23V1ProofSpec.Data memory iavlSpec = getIavlProofSpec ();
96+ CosmosIcs23V1ProofSpec.Data
97+ memory tendermintSpec = getTendermintProofSpec ();
98+
99+ CosmosIcs23V1CommitmentProof.Data memory proof = merkleProof.proofs[0 ];
100+ CosmosIcs23V1NonExistenceProof.Data memory nonExistenceProof = proof
101+ .nonexist;
102+ if (CosmosIcs23V1NonExistenceProof.isNil (nonExistenceProof)) {
103+ return VerifyChainedNonMembershipError.NonExistenceProofIsNil;
104+ }
105+
106+ (bytes memory subroot , Proof.CalculateRootError rCode ) = Proof
107+ .calculateRoot (proof);
108+ if (rCode != Proof.CalculateRootError.None) {
109+ return VerifyChainedNonMembershipError.InvalidProofRoot;
110+ }
111+
112+ bytes memory key = path[path.length - 1 ];
113+ Proof.VerifyNonExistenceError vCode = Proof.verify (
114+ nonExistenceProof,
115+ iavlSpec,
116+ subroot,
117+ key
118+ );
119+
120+ // Map non existence error to non membership error
121+ if (vCode != Proof.VerifyNonExistenceError.None) {
122+ if (vCode == Proof.VerifyNonExistenceError.VerifyLeft) {
123+ return VerifyChainedNonMembershipError.VerifyLeft;
124+ } else if (
125+ vCode == Proof.VerifyNonExistenceError.LeftAndRightKeyEmpty
126+ ) {
127+ return VerifyChainedNonMembershipError.LeftAndRightKeyEmpty;
128+ } else if (vCode == Proof.VerifyNonExistenceError.RightKeyRange) {
129+ return VerifyChainedNonMembershipError.RightKeyRange;
130+ } else if (vCode == Proof.VerifyNonExistenceError.LeftKeyRange) {
131+ return VerifyChainedNonMembershipError.LeftKeyRange;
132+ } else if (
133+ vCode == Proof.VerifyNonExistenceError.RightProofLeftMost
134+ ) {
135+ return VerifyChainedNonMembershipError.RightProofLeftMost;
136+ } else if (
137+ vCode == Proof.VerifyNonExistenceError.LeftProofRightMost
138+ ) {
139+ return VerifyChainedNonMembershipError.LeftProofRightMost;
140+ } else if (vCode == Proof.VerifyNonExistenceError.IsLeftNeighbor) {
141+ return VerifyChainedNonMembershipError.IsLeftNeighbor;
142+ }
143+
144+ revert (
145+ "verifyChainedNonMembership: non exhaustive pattern matching on VerifyNonExistenceError "
146+ );
147+ }
148+
149+ VerifyChainedMembershipError mCode = verifyChainedMembershipAt (
150+ merkleProof,
151+ root,
152+ path,
153+ subroot,
154+ 1
155+ );
156+
157+ // Map membership error to non membership error
158+ if (mCode != VerifyChainedMembershipError.None) {
159+ if (mCode == VerifyChainedMembershipError.ExistenceProofIsNil) {
160+ return VerifyChainedNonMembershipError.ExistenceProofIsNil;
161+ } else if (mCode == VerifyChainedMembershipError.InvalidProofRoot) {
162+ return VerifyChainedNonMembershipError.InvalidProofRoot;
163+ } else if (mCode == VerifyChainedMembershipError.KeyMismatch) {
164+ return VerifyChainedNonMembershipError.KeyMismatch;
165+ } else if (mCode == VerifyChainedMembershipError.ValueMismatch) {
166+ return VerifyChainedNonMembershipError.ValueMismatch;
167+ } else if (mCode == VerifyChainedMembershipError.InvalidSpec) {
168+ return VerifyChainedNonMembershipError.InvalidSpec;
169+ } else if (
170+ mCode ==
171+ VerifyChainedMembershipError.InvalidIntermediateProofRoot
172+ ) {
173+ return
174+ VerifyChainedNonMembershipError
175+ .InvalidIntermediateProofRoot;
176+ } else if (mCode == VerifyChainedMembershipError.RootMismatch) {
177+ return VerifyChainedNonMembershipError.RootMismatch;
178+ }
179+
180+ revert (
181+ "verifyChainedNonMembership: non exhaustive pattern matching on VerifyChainedMembershipError "
182+ );
183+ }
184+
185+ return VerifyChainedNonMembershipError.None;
186+ }
187+
69188 enum VerifyChainedMembershipError {
70189 None,
71190 ExistenceProofIsNil,
@@ -83,12 +202,22 @@ library Ics23 {
83202 bytes memory root ,
84203 bytes [] memory path ,
85204 bytes memory value
205+ ) internal pure returns (VerifyChainedMembershipError) {
206+ return verifyChainedMembershipAt (merkleProof, root, path, value, 0 );
207+ }
208+
209+ function verifyChainedMembershipAt (
210+ IbcCoreCommitmentV1MerkleProof.Data memory merkleProof ,
211+ bytes memory root ,
212+ bytes [] memory path ,
213+ bytes memory value ,
214+ uint256 index
86215 ) internal pure returns (VerifyChainedMembershipError) {
87216 CosmosIcs23V1ProofSpec.Data memory iavlSpec = getIavlProofSpec ();
88217 CosmosIcs23V1ProofSpec.Data
89218 memory tendermintSpec = getTendermintProofSpec ();
90219 bytes memory subroot = value;
91- for (uint256 i = 0 ; i < merkleProof.proofs.length ; i++ ) {
220+ for (uint256 i = index ; i < merkleProof.proofs.length ; i++ ) {
92221 CosmosIcs23V1CommitmentProof.Data memory proof = merkleProof.proofs[
93222 i
94223 ];
@@ -110,9 +239,10 @@ library Ics23 {
110239 * Path is provided as /a/b/c, we need to pop until reaching the root
111240 */
112241 bytes memory key = path[path.length - i - 1 ];
242+
113243 Proof.VerifyExistenceError vCode = Proof.verify (
114244 existenceProof,
115- i == (path. length - 1 ) ? tendermintSpec : iavlSpec ,
245+ i == 0 ? iavlSpec : tendermintSpec ,
116246 subroot,
117247 key,
118248 value
0 commit comments