@@ -707,3 +707,189 @@ func TestIsEmptyProofOverlapAbsenceProof(t *testing.T) {
707
707
})
708
708
}
709
709
}
710
+
711
+ // TestVerifyNamespace_ShortAbsenceProof_Valid checks whether VerifyNamespace
712
+ // can correctly verify short namespace absence proofs
713
+ func TestVerifyNamespace_ShortAbsenceProof_Valid (t * testing.T ) {
714
+ // create a Merkle tree with 8 leaves
715
+ tree := exampleNMT (1 , true , 1 , 2 , 3 , 4 , 6 , 7 , 8 , 9 )
716
+ qNS := []byte {5 } // does not belong to the tree
717
+ root , err := tree .Root ()
718
+ assert .NoError (t , err )
719
+ // In the following illustration, nodes are suffixed with the range
720
+ // of leaves they cover, with the upper bound being non-inclusive.
721
+ // For example, Node3_4 denotes a node that covers the 3rd leaf (excluding the 4th leaf),
722
+ // while Node4_6 represents the node that covers the 4th and 5th leaves.
723
+ //
724
+ // Node0_8 Tree Root
725
+ // / \
726
+ // / \
727
+ // Node0_4 Node4_8 Non-Leaf Node
728
+ // / \ / \
729
+ // / \ / \
730
+ // Node0_2 Node2_4 Node4_6 Node6_8 Non-Leaf Node
731
+ // / \ / \ / \ / \
732
+ // Node0_1 Node1_2 Node2_3 Node3_4 Node4_5 Node5_6 Node6_7 Node7_8 Leaf Hash
733
+ // 1 2 3 4 6 7 8 9 Leaf namespace
734
+ // 0 1 2 3 4 5 6 7 Leaf index
735
+
736
+ // nodes needed for the full absence proof of qNS
737
+ Node4_5 := tree .leafHashes [4 ]
738
+ Node5_6 := tree .leafHashes [5 ]
739
+ Node6_8 , err := tree .computeRoot (6 , 8 )
740
+ assert .NoError (t , err )
741
+ Node0_4 , err := tree .computeRoot (0 , 4 )
742
+ assert .NoError (t , err )
743
+
744
+ // nodes needed for the short absence proof of qNS; the proof of inclusion
745
+ // of the parent of Node4_5
746
+
747
+ Node4_6 , err := tree .computeRoot (4 , 6 )
748
+ assert .NoError (t , err )
749
+
750
+ // nodes needed for another short absence parent of qNS; the proof of
751
+ // inclusion of the grandparent of Node4_5
752
+ Node4_8 , err := tree .computeRoot (4 , 8 )
753
+ assert .NoError (t , err )
754
+
755
+ tests := []struct {
756
+ name string
757
+ qNID []byte
758
+ leafHash []byte
759
+ nodes [][]byte
760
+ start int
761
+ end int
762
+ }{
763
+ {
764
+ name : "valid full absence proof" ,
765
+ qNID : qNS ,
766
+ leafHash : Node4_5 ,
767
+ nodes : [][]byte {Node0_4 , Node5_6 , Node6_8 },
768
+ start : 4 , // the index position of leafHash at its respective level
769
+ end : 5 ,
770
+ },
771
+ {
772
+ name : "valid short absence proof: one level higher" ,
773
+ qNID : qNS ,
774
+ leafHash : Node4_6 ,
775
+ nodes : [][]byte {Node0_4 , Node6_8 },
776
+ start : 2 , // the index position of leafHash at its respective level
777
+ end : 3 ,
778
+ },
779
+ {
780
+ name : "valid short absence proof: two levels higher" ,
781
+ qNID : qNS ,
782
+ leafHash : Node4_8 ,
783
+ nodes : [][]byte {Node0_4 },
784
+ start : 1 , // the index position of leafHash at its respective level
785
+ end : 2 ,
786
+ },
787
+ }
788
+ for _ , tt := range tests {
789
+ t .Run (tt .name , func (t * testing.T ) {
790
+ proof := Proof {
791
+ leafHash : tt .leafHash ,
792
+ nodes : tt .nodes ,
793
+ start : tt .start ,
794
+ end : tt .end ,
795
+ }
796
+
797
+ res := proof .VerifyNamespace (sha256 .New (), qNS , nil , root )
798
+ assert .True (t , res )
799
+ })
800
+ }
801
+ }
802
+
803
+ // TestVerifyNamespace_ShortAbsenceProof_Invalid checks whether VerifyNamespace rejects invalid short absence proofs.
804
+ func TestVerifyNamespace_ShortAbsenceProof_Invalid (t * testing.T ) {
805
+ // create a Merkle tree with 8 leaves
806
+ tree := exampleNMT (1 , true , 1 , 2 , 3 , 4 , 6 , 8 , 8 , 8 )
807
+ qNS := []byte {7 } // does not belong to the tree
808
+ root , err := tree .Root ()
809
+ assert .NoError (t , err )
810
+ // In the following illustration, nodes are suffixed with the range
811
+ // of leaves they cover, with the upper bound being non-inclusive.
812
+ // For example, Node3_4 denotes a node that covers the 3rd leaf (excluding the 4th leaf),
813
+ // while Node4_6 represents the node that covers the 4th and 5th leaves.
814
+ //
815
+ // Node0_8 Tree Root
816
+ // / \
817
+ // / \
818
+ // Node0_4 Node4_8 Non-Leaf Node
819
+ // / \ / \
820
+ // / \ / \
821
+ // Node0_2 Node2_4 Node4_6 Node6_8 Non-Leaf Node
822
+ // / \ / \ / \ / \
823
+ // Node0_1 Node1_2 Node2_3 Node3_4 Node4_5 Node5_6 Node6_7 Node7_8 Leaf Hash
824
+ // 1 2 3 4 6 8 8 8 Leaf namespace
825
+ // 0 1 2 3 4 5 6 7 Leaf index
826
+
827
+ // nodes needed for the full absence proof of qNS
828
+ Node5_6 := tree .leafHashes [5 ]
829
+ Node4_5 := tree .leafHashes [4 ]
830
+ Node6_8 , err := tree .computeRoot (6 , 8 )
831
+ assert .NoError (t , err )
832
+ Node0_4 , err := tree .computeRoot (0 , 4 )
833
+ assert .NoError (t , err )
834
+
835
+ // nodes needed for the short absence proof of qNS; the proof of inclusion of the parent of Node5_6;
836
+ // the verification should fail since the namespace range o Node4_6, the parent, has overlap with the qNS i.e., 7
837
+ Node4_6 , err := tree .computeRoot (4 , 6 )
838
+ assert .NoError (t , err )
839
+
840
+ // nodes needed for another short absence parent of qNS; the proof of inclusion of the grandparent of Node5_6
841
+ // the verification should fail since the namespace range of Node4_8, the grandparent, has overlap with the qNS i.e., 7
842
+ Node4_8 , err := tree .computeRoot (4 , 8 )
843
+ assert .NoError (t , err )
844
+
845
+ tests := []struct {
846
+ name string
847
+ qNID []byte
848
+ leafHash []byte
849
+ nodes [][]byte
850
+ start int
851
+ end int
852
+ want bool
853
+ }{
854
+ {
855
+ name : "valid full absence proof" ,
856
+ qNID : qNS ,
857
+ leafHash : Node5_6 ,
858
+ nodes : [][]byte {Node0_4 , Node4_5 , Node6_8 },
859
+ start : 5 , // the index position of leafHash at its respective level
860
+ end : 6 ,
861
+ want : true ,
862
+ },
863
+ {
864
+ name : "invalid short absence proof: one level higher" ,
865
+ qNID : qNS ,
866
+ leafHash : Node4_6 ,
867
+ nodes : [][]byte {Node0_4 , Node6_8 },
868
+ start : 2 , // the index position of leafHash at its respective level
869
+ end : 3 ,
870
+ want : false ,
871
+ },
872
+ {
873
+ name : "invalid short absence proof: two levels higher" ,
874
+ qNID : qNS ,
875
+ leafHash : Node4_8 ,
876
+ nodes : [][]byte {Node0_4 },
877
+ start : 1 , // the index position of leafHash at its respective level
878
+ end : 2 ,
879
+ want : false ,
880
+ },
881
+ }
882
+ for _ , tt := range tests {
883
+ t .Run (tt .name , func (t * testing.T ) {
884
+ proof := Proof {
885
+ leafHash : tt .leafHash ,
886
+ nodes : tt .nodes ,
887
+ start : tt .start ,
888
+ end : tt .end ,
889
+ }
890
+
891
+ res := proof .VerifyNamespace (sha256 .New (), qNS , nil , root )
892
+ assert .Equal (t , tt .want , res )
893
+ })
894
+ }
895
+ }
0 commit comments