1use light_utils::{bigint::bigint_to_be_bytes_array, UtilsError};
2use num_bigint::{BigUint, ToBigUint};
3use num_traits::{FromBytes, ToPrimitive};
4use std::{
5 alloc::{self, handle_alloc_error, Layout},
6 cmp::Ordering,
7 marker::Send,
8 mem,
9 ptr::NonNull,
10};
11use thiserror::Error;
12
13pub mod zero_copy;
14
15pub const ITERATIONS: usize = 20;
16
17#[derive(Debug, Error, PartialEq)]
18pub enum HashSetError {
19 #[error("The hash set is full, cannot add any new elements")]
20 Full,
21 #[error("The provided element is already in the hash set")]
22 ElementAlreadyExists,
23 #[error("The provided element doesn't exist in the hash set")]
24 ElementDoesNotExist,
25 #[error("Could not convert the index from/to usize")]
26 UsizeConv,
27 #[error("Integer overflow")]
28 IntegerOverflow,
29 #[error("Invalid buffer size, expected {0}, got {1}")]
30 BufferSize(usize, usize),
31 #[error("Utils: big integer conversion error")]
32 Utils(#[from] UtilsError),
33}
34
35#[cfg(feature = "solana")]
36impl From<HashSetError> for u32 {
37 fn from(e: HashSetError) -> u32 {
38 match e {
39 HashSetError::Full => 9001,
40 HashSetError::ElementAlreadyExists => 9002,
41 HashSetError::ElementDoesNotExist => 9003,
42 HashSetError::UsizeConv => 9004,
43 HashSetError::IntegerOverflow => 9005,
44 HashSetError::BufferSize(_, _) => 9006,
45 HashSetError::Utils(e) => e.into(),
46 }
47 }
48}
49
50#[cfg(feature = "solana")]
51impl From<HashSetError> for solana_program::program_error::ProgramError {
52 fn from(e: HashSetError) -> Self {
53 solana_program::program_error::ProgramError::Custom(e.into())
54 }
55}
56
57#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
58pub struct HashSetCell {
59 pub value: [u8; 32],
60 pub sequence_number: Option<usize>,
61}
62
63unsafe impl Send for HashSet {}
64
65impl HashSetCell {
66 pub fn value_bytes(&self) -> [u8; 32] {
68 self.value
69 }
70
71 pub fn value_biguint(&self) -> BigUint {
73 BigUint::from_bytes_be(self.value.as_slice())
74 }
75
76 pub fn sequence_number(&self) -> Option<usize> {
78 self.sequence_number
79 }
80
81 pub fn is_marked(&self) -> bool {
83 self.sequence_number.is_some()
84 }
85
86 pub fn is_valid(&self, current_sequence_number: usize) -> bool {
98 match self.sequence_number {
99 Some(sequence_number) => match sequence_number.cmp(¤t_sequence_number) {
100 Ordering::Less | Ordering::Equal => false,
101 Ordering::Greater => true,
102 },
103 None => true,
104 }
105 }
106}
107
108#[derive(Debug)]
109pub struct HashSet {
110 capacity: usize,
112 pub sequence_threshold: usize,
116
117 buckets: NonNull<Option<HashSetCell>>,
120}
121
122unsafe impl Send for HashSetCell {}
123
124impl HashSet {
125 pub fn non_dyn_fields_size() -> usize {
127 mem::size_of::<usize>()
129 + mem::size_of::<usize>()
131 }
132
133 pub fn size_in_account(capacity_values: usize) -> usize {
135 let dyn_fields_size = Self::non_dyn_fields_size();
136
137 let buckets_size_unaligned = mem::size_of::<Option<HashSetCell>>() * capacity_values;
138 let buckets_size = buckets_size_unaligned + mem::align_of::<usize>()
140 - (buckets_size_unaligned % mem::align_of::<usize>());
141
142 dyn_fields_size + buckets_size
143 }
144
145 pub fn new(capacity_values: usize, sequence_threshold: usize) -> Result<Self, HashSetError> {
147 let layout = Layout::array::<Option<HashSetCell>>(capacity_values).unwrap();
149 let values_ptr = unsafe { alloc::alloc(layout) as *mut Option<HashSetCell> };
150 if values_ptr.is_null() {
151 handle_alloc_error(layout);
152 }
153 let values = NonNull::new(values_ptr).unwrap();
154 for i in 0..capacity_values {
155 unsafe {
156 std::ptr::write(values_ptr.add(i), None);
157 }
158 }
159
160 Ok(HashSet {
161 sequence_threshold,
162 capacity: capacity_values,
163 buckets: values,
164 })
165 }
166
167 pub unsafe fn from_bytes_copy(bytes: &mut [u8]) -> Result<Self, HashSetError> {
181 if bytes.len() < Self::non_dyn_fields_size() {
182 return Err(HashSetError::BufferSize(
183 Self::non_dyn_fields_size(),
184 bytes.len(),
185 ));
186 }
187
188 let capacity = usize::from_le_bytes(bytes[0..8].try_into().unwrap());
189 let sequence_threshold = usize::from_le_bytes(bytes[8..16].try_into().unwrap());
190 let expected_size = Self::size_in_account(capacity);
191 if bytes.len() != expected_size {
192 return Err(HashSetError::BufferSize(expected_size, bytes.len()));
193 }
194
195 let buckets_layout = Layout::array::<Option<HashSetCell>>(capacity).unwrap();
196 let buckets_dst_ptr = unsafe { alloc::alloc(buckets_layout) as *mut Option<HashSetCell> };
199 if buckets_dst_ptr.is_null() {
200 handle_alloc_error(buckets_layout);
201 }
202 let buckets = NonNull::new(buckets_dst_ptr).unwrap();
203 for i in 0..capacity {
204 std::ptr::write(buckets_dst_ptr.add(i), None);
205 }
206
207 let offset = Self::non_dyn_fields_size() + mem::size_of::<usize>();
208 let buckets_src_ptr = bytes.as_ptr().add(offset) as *const Option<HashSetCell>;
209 std::ptr::copy(buckets_src_ptr, buckets_dst_ptr, capacity);
210
211 Ok(Self {
212 capacity,
213 sequence_threshold,
214 buckets,
215 })
216 }
217
218 fn probe_index(&self, value: &BigUint, iteration: usize) -> usize {
219 let iteration = iteration + self.capacity / 10;
221 let probe_index = (value
222 + iteration.to_biguint().unwrap() * iteration.to_biguint().unwrap())
223 % self.capacity.to_biguint().unwrap();
224 probe_index.to_usize().unwrap()
225 }
226
227 pub fn get_bucket(&self, index: usize) -> Option<&Option<HashSetCell>> {
230 if index >= self.capacity {
231 return None;
232 }
233 let bucket = unsafe { &*self.buckets.as_ptr().add(index) };
234 Some(bucket)
235 }
236
237 pub fn get_bucket_mut(&mut self, index: usize) -> Option<&mut Option<HashSetCell>> {
240 if index >= self.capacity {
241 return None;
242 }
243 let bucket = unsafe { &mut *self.buckets.as_ptr().add(index) };
244 Some(bucket)
245 }
246
247 pub fn get_unmarked_bucket(&self, index: usize) -> Option<&Option<HashSetCell>> {
250 let bucket = self.get_bucket(index);
251 let is_unmarked = match bucket {
252 Some(Some(bucket)) => !bucket.is_marked(),
253 Some(None) => false,
254 None => false,
255 };
256 if is_unmarked {
257 bucket
258 } else {
259 None
260 }
261 }
262
263 pub fn get_capacity(&self) -> usize {
264 self.capacity
265 }
266
267 fn insert_into_occupied_cell(
268 &mut self,
269 value_index: usize,
270 value: &BigUint,
271 current_sequence_number: usize,
272 ) -> Result<bool, HashSetError> {
273 let bucket = self.get_bucket_mut(value_index).unwrap();
275
276 match bucket {
277 Some(bucket) => {
279 if let Some(element_sequence_number) = bucket.sequence_number {
284 if current_sequence_number >= element_sequence_number {
285 *bucket = HashSetCell {
286 value: bigint_to_be_bytes_array(value)?,
287 sequence_number: None,
288 };
289 return Ok(true);
290 }
291 }
292 if &BigUint::from_be_bytes(bucket.value.as_slice()) == value {
295 return Err(HashSetError::ElementAlreadyExists);
296 }
297 }
298 None => unreachable!(),
302 }
303 Ok(false)
304 }
305
306 pub fn insert(
314 &mut self,
315 value: &BigUint,
316 current_sequence_number: usize,
317 ) -> Result<usize, HashSetError> {
318 let index_bucket = self.find_element_iter(value, current_sequence_number, 0, ITERATIONS)?;
319 let (index, is_new) = match index_bucket {
320 Some(index) => index,
321 None => {
322 return Err(HashSetError::Full);
323 }
324 };
325
326 match is_new {
327 false => {
329 if self.insert_into_occupied_cell(index, value, current_sequence_number)? {
330 return Ok(index);
331 }
332 }
333 true => {
334 let bucket = self.get_bucket_mut(index).unwrap();
336
337 *bucket = Some(HashSetCell {
338 value: bigint_to_be_bytes_array(value)?,
339 sequence_number: None,
340 });
341 return Ok(index);
342 }
343 }
344 Err(HashSetError::Full)
345 }
346
347 pub fn find_element_index(
352 &self,
353 value: &BigUint,
354 current_sequence_number: Option<usize>,
355 ) -> Result<Option<usize>, HashSetError> {
356 for i in 0..ITERATIONS {
357 let probe_index = self.probe_index(value, i);
358 let bucket = self.get_bucket(probe_index).unwrap();
360 match bucket {
361 Some(bucket) => {
362 if &bucket.value_biguint() == value {
363 match current_sequence_number {
364 Some(current_sequence_number) => {
367 if bucket.is_valid(current_sequence_number) {
368 return Ok(Some(probe_index));
369 }
370 continue;
371 }
372 None => return Ok(Some(probe_index)),
373 }
374 }
375 continue;
376 }
377 None => {
380 return Ok(None);
381 }
382 }
383 }
384
385 Ok(None)
386 }
387
388 pub fn find_element(
389 &self,
390 value: &BigUint,
391 current_sequence_number: Option<usize>,
392 ) -> Result<Option<(&HashSetCell, usize)>, HashSetError> {
393 let index = self.find_element_index(value, current_sequence_number)?;
394 match index {
395 Some(index) => {
396 let bucket = self.get_bucket(index).unwrap();
397 match bucket {
398 Some(bucket) => Ok(Some((bucket, index))),
399 None => Ok(None),
400 }
401 }
402 None => Ok(None),
403 }
404 }
405
406 pub fn find_element_mut(
407 &mut self,
408 value: &BigUint,
409 current_sequence_number: Option<usize>,
410 ) -> Result<Option<(&mut HashSetCell, usize)>, HashSetError> {
411 let index = self.find_element_index(value, current_sequence_number)?;
412 match index {
413 Some(index) => {
414 let bucket = self.get_bucket_mut(index).unwrap();
415 match bucket {
416 Some(bucket) => Ok(Some((bucket, index))),
417 None => Ok(None),
418 }
419 }
420 None => Ok(None),
421 }
422 }
423
424 pub fn find_element_iter(
430 &mut self,
431 value: &BigUint,
432 current_sequence_number: usize,
433 start_iter: usize,
434 num_iterations: usize,
435 ) -> Result<Option<(usize, bool)>, HashSetError> {
436 let mut first_free_element: Option<(usize, bool)> = None;
437 for i in start_iter..start_iter + num_iterations {
438 let probe_index = self.probe_index(value, i);
439 let bucket = self.get_bucket(probe_index).unwrap();
440
441 match bucket {
442 Some(bucket) => {
443 let is_valid = bucket.is_valid(current_sequence_number);
444 if first_free_element.is_none() && !is_valid {
445 first_free_element = Some((probe_index, false));
446 }
447 if is_valid && &bucket.value_biguint() == value {
448 return Err(HashSetError::ElementAlreadyExists);
449 } else {
450 continue;
451 }
452 }
453 None => {
454 if first_free_element.is_none() {
457 first_free_element = Some((probe_index, true));
458 }
459 break;
463 }
464 }
465 }
466 Ok(first_free_element)
467 }
468
469 pub fn first(
471 &self,
472 current_sequence_number: usize,
473 ) -> Result<Option<&HashSetCell>, HashSetError> {
474 for i in 0..self.capacity {
475 let bucket = self.get_bucket(i).unwrap();
477 if let Some(bucket) = bucket {
478 if bucket.is_valid(current_sequence_number) {
479 return Ok(Some(bucket));
480 }
481 }
482 }
483
484 Ok(None)
485 }
486
487 pub fn first_no_seq(&self) -> Result<Option<(HashSetCell, u16)>, HashSetError> {
489 for i in 0..self.capacity {
490 let bucket = self.get_bucket(i).unwrap();
492
493 if let Some(bucket) = bucket {
494 if bucket.sequence_number.is_none() {
495 return Ok(Some((*bucket, i as u16)));
496 }
497 }
498 }
499
500 Ok(None)
501 }
502
503 pub fn contains(
505 &self,
506 value: &BigUint,
507 sequence_number: Option<usize>,
508 ) -> Result<bool, HashSetError> {
509 let element = self.find_element(value, sequence_number)?;
510 Ok(element.is_some())
511 }
512
513 pub fn mark_with_sequence_number(
515 &mut self,
516 index: usize,
517 sequence_number: usize,
518 ) -> Result<(), HashSetError> {
519 let sequence_threshold = self.sequence_threshold;
520 let element = self
521 .get_bucket_mut(index)
522 .ok_or(HashSetError::ElementDoesNotExist)?;
523
524 match element {
525 Some(element) => {
526 element.sequence_number = Some(sequence_number + sequence_threshold);
527 Ok(())
528 }
529 None => Err(HashSetError::ElementDoesNotExist),
530 }
531 }
532
533 pub fn iter(&self) -> HashSetIterator {
535 HashSetIterator {
536 hash_set: self,
537 current: 0,
538 }
539 }
540}
541
542impl Drop for HashSet {
543 fn drop(&mut self) {
544 unsafe {
547 let layout = Layout::array::<Option<HashSetCell>>(self.capacity).unwrap();
548 alloc::dealloc(self.buckets.as_ptr() as *mut u8, layout);
549 }
550 }
551}
552
553impl PartialEq for HashSet {
554 fn eq(&self, other: &Self) -> bool {
555 self.capacity.eq(&other.capacity)
556 && self.sequence_threshold.eq(&other.sequence_threshold)
557 && self.iter().eq(other.iter())
558 }
559}
560
561pub struct HashSetIterator<'a> {
562 hash_set: &'a HashSet,
563 current: usize,
564}
565
566impl<'a> Iterator for HashSetIterator<'a> {
567 type Item = (usize, &'a HashSetCell);
568
569 fn next(&mut self) -> Option<Self::Item> {
570 while self.current < self.hash_set.get_capacity() {
571 let element_index = self.current;
572 self.current += 1;
573
574 if let Some(Some(cur_element)) = self.hash_set.get_bucket(element_index) {
575 return Some((element_index, cur_element));
576 }
577 }
578 None
579 }
580}
581
582#[cfg(test)]
583mod test {
584 use ark_bn254::Fr;
585 use ark_ff::UniformRand;
586 use rand::{thread_rng, Rng};
587
588 use crate::zero_copy::HashSetZeroCopy;
589
590 use super::*;
591
592 #[test]
593 fn test_is_valid() {
594 let mut rng = thread_rng();
595
596 let cell = HashSetCell {
597 value: [0u8; 32],
598 sequence_number: None,
599 };
600 assert_eq!(cell.is_valid(0), true);
602 for _ in 0..100 {
603 let seq: usize = rng.gen();
604 assert_eq!(cell.is_valid(seq), true);
605 }
606
607 let cell = HashSetCell {
608 value: [0u8; 32],
609 sequence_number: Some(2400),
610 };
611 for i in 0..2400 {
613 assert_eq!(cell.is_valid(i), true);
614 }
615 for i in 2400..10000 {
616 assert_eq!(cell.is_valid(i), false);
617 }
618 }
619
620 #[test]
623 fn test_hash_set_manual() {
624 let mut hs = HashSet::new(256, 4).unwrap();
625
626 let element_1_1 = 1.to_biguint().unwrap();
629 let index_1_1 = hs.insert(&element_1_1, 0).unwrap();
630 hs.mark_with_sequence_number(index_1_1, 1).unwrap();
631
632 assert_eq!(hs.contains(&element_1_1, Some(1)).unwrap(), true);
634 assert!(matches!(
637 hs.insert(&element_1_1, 1),
638 Err(HashSetError::ElementAlreadyExists)
639 ));
640
641 let element_2_3 = 3.to_biguint().unwrap();
645 let element_2_6 = 6.to_biguint().unwrap();
646 let element_2_8 = 8.to_biguint().unwrap();
647 let element_2_9 = 9.to_biguint().unwrap();
648 let index_2_3 = hs.insert(&element_2_3, 1).unwrap();
649 let index_2_6 = hs.insert(&element_2_6, 1).unwrap();
650 let index_2_8 = hs.insert(&element_2_8, 1).unwrap();
651 let index_2_9 = hs.insert(&element_2_9, 1).unwrap();
652 assert_eq!(hs.contains(&element_2_3, Some(2)).unwrap(), true);
653 assert_eq!(hs.contains(&element_2_6, Some(2)).unwrap(), true);
654 assert_eq!(hs.contains(&element_2_8, Some(2)).unwrap(), true);
655 assert_eq!(hs.contains(&element_2_9, Some(2)).unwrap(), true);
656 hs.mark_with_sequence_number(index_2_3, 2).unwrap();
657 hs.mark_with_sequence_number(index_2_6, 2).unwrap();
658 hs.mark_with_sequence_number(index_2_8, 2).unwrap();
659 hs.mark_with_sequence_number(index_2_9, 2).unwrap();
660 assert!(matches!(
661 hs.insert(&element_2_3, 2),
662 Err(HashSetError::ElementAlreadyExists)
663 ));
664 assert!(matches!(
665 hs.insert(&element_2_6, 2),
666 Err(HashSetError::ElementAlreadyExists)
667 ));
668 assert!(matches!(
669 hs.insert(&element_2_8, 2),
670 Err(HashSetError::ElementAlreadyExists)
671 ));
672 assert!(matches!(
673 hs.insert(&element_2_9, 2),
674 Err(HashSetError::ElementAlreadyExists)
675 ));
676
677 let element_3_11 = 11.to_biguint().unwrap();
678 let element_3_13 = 13.to_biguint().unwrap();
679 let element_3_21 = 21.to_biguint().unwrap();
680 let element_3_29 = 29.to_biguint().unwrap();
681 let index_3_11 = hs.insert(&element_3_11, 2).unwrap();
682 let index_3_13 = hs.insert(&element_3_13, 2).unwrap();
683 let index_3_21 = hs.insert(&element_3_21, 2).unwrap();
684 let index_3_29 = hs.insert(&element_3_29, 2).unwrap();
685 assert_eq!(hs.contains(&element_3_11, Some(3)).unwrap(), true);
686 assert_eq!(hs.contains(&element_3_13, Some(3)).unwrap(), true);
687 assert_eq!(hs.contains(&element_3_21, Some(3)).unwrap(), true);
688 assert_eq!(hs.contains(&element_3_29, Some(3)).unwrap(), true);
689 hs.mark_with_sequence_number(index_3_11, 3).unwrap();
690 hs.mark_with_sequence_number(index_3_13, 3).unwrap();
691 hs.mark_with_sequence_number(index_3_21, 3).unwrap();
692 hs.mark_with_sequence_number(index_3_29, 3).unwrap();
693 assert!(matches!(
694 hs.insert(&element_3_11, 3),
695 Err(HashSetError::ElementAlreadyExists)
696 ));
697 assert!(matches!(
698 hs.insert(&element_3_13, 3),
699 Err(HashSetError::ElementAlreadyExists)
700 ));
701 assert!(matches!(
702 hs.insert(&element_3_21, 3),
703 Err(HashSetError::ElementAlreadyExists)
704 ));
705 assert!(matches!(
706 hs.insert(&element_3_29, 3),
707 Err(HashSetError::ElementAlreadyExists)
708 ));
709
710 let element_4_93 = 93.to_biguint().unwrap();
711 let element_4_65 = 64.to_biguint().unwrap();
712 let element_4_72 = 72.to_biguint().unwrap();
713 let element_4_15 = 15.to_biguint().unwrap();
714 let index_4_93 = hs.insert(&element_4_93, 3).unwrap();
715 let index_4_65 = hs.insert(&element_4_65, 3).unwrap();
716 let index_4_72 = hs.insert(&element_4_72, 3).unwrap();
717 let index_4_15 = hs.insert(&element_4_15, 3).unwrap();
718 assert_eq!(hs.contains(&element_4_93, Some(4)).unwrap(), true);
719 assert_eq!(hs.contains(&element_4_65, Some(4)).unwrap(), true);
720 assert_eq!(hs.contains(&element_4_72, Some(4)).unwrap(), true);
721 assert_eq!(hs.contains(&element_4_15, Some(4)).unwrap(), true);
722 hs.mark_with_sequence_number(index_4_93, 4).unwrap();
723 hs.mark_with_sequence_number(index_4_65, 4).unwrap();
724 hs.mark_with_sequence_number(index_4_72, 4).unwrap();
725 hs.mark_with_sequence_number(index_4_15, 4).unwrap();
726
727 assert!(matches!(
734 hs.insert(&element_1_1, 4),
735 Err(HashSetError::ElementAlreadyExists)
736 ));
737 assert!(matches!(
738 hs.insert(&element_2_3, 5),
739 Err(HashSetError::ElementAlreadyExists)
740 ));
741 assert!(matches!(
742 hs.insert(&element_2_6, 5),
743 Err(HashSetError::ElementAlreadyExists)
744 ));
745 assert!(matches!(
746 hs.insert(&element_2_8, 5),
747 Err(HashSetError::ElementAlreadyExists)
748 ));
749 assert!(matches!(
750 hs.insert(&element_2_9, 5),
751 Err(HashSetError::ElementAlreadyExists)
752 ));
753 hs.insert(&element_1_1, 5).unwrap();
754 hs.insert(&element_2_3, 6).unwrap();
755 hs.insert(&element_2_6, 6).unwrap();
756 hs.insert(&element_2_8, 6).unwrap();
757 hs.insert(&element_2_9, 6).unwrap();
758 }
759
760 #[test]
762 fn test_hash_set_random() {
763 let mut hs = HashSet::new(6857, 2400).unwrap();
764
765 assert_eq!(hs.first(0).unwrap(), None);
767 let mut rng = thread_rng();
768 let mut seq = 0;
769 let nullifiers: [BigUint; 24000] =
770 std::array::from_fn(|_| BigUint::from(Fr::rand(&mut rng)));
771 for nf_chunk in nullifiers.chunks(2400) {
772 for nullifier in nf_chunk.iter() {
773 assert_eq!(hs.contains(&nullifier, Some(seq)).unwrap(), false);
774 let index = hs.insert(&nullifier, seq as usize).unwrap();
775 assert_eq!(hs.contains(&nullifier, Some(seq)).unwrap(), true);
776
777 let nullifier_bytes = bigint_to_be_bytes_array(&nullifier).unwrap();
778
779 let element = hs
780 .find_element(&nullifier, Some(seq))
781 .unwrap()
782 .unwrap()
783 .0
784 .clone();
785 assert_eq!(
786 element,
787 HashSetCell {
788 value: bigint_to_be_bytes_array(&nullifier).unwrap(),
789 sequence_number: None,
790 }
791 );
792 assert_eq!(element.value_bytes(), nullifier_bytes);
793 assert_eq!(&element.value_biguint(), nullifier);
794 assert_eq!(element.sequence_number(), None);
795 assert!(!element.is_marked());
796 assert!(element.is_valid(seq));
797
798 hs.mark_with_sequence_number(index, seq).unwrap();
799 let element = hs
800 .find_element(&nullifier, Some(seq))
801 .unwrap()
802 .unwrap()
803 .0
804 .clone();
805
806 assert_eq!(
807 element,
808 HashSetCell {
809 value: nullifier_bytes,
810 sequence_number: Some(2400 + seq)
811 }
812 );
813 assert_eq!(element.value_bytes(), nullifier_bytes);
814 assert_eq!(&element.value_biguint(), nullifier);
815 assert_eq!(element.sequence_number(), Some(2400 + seq));
816 assert!(element.is_marked());
817 assert!(element.is_valid(seq));
818
819 assert!(matches!(
822 hs.insert(&nullifier, seq as usize + 2399),
823 Err(HashSetError::ElementAlreadyExists),
824 ));
825 seq += 1;
826 }
827 seq += 2400;
828 }
829 }
830
831 fn hash_set_from_bytes_copy<
832 const CAPACITY: usize,
833 const SEQUENCE_THRESHOLD: usize,
834 const OPERATIONS: usize,
835 >() {
836 let mut hs_1 = HashSet::new(CAPACITY, SEQUENCE_THRESHOLD).unwrap();
837
838 let mut rng = thread_rng();
839
840 let mut bytes = vec![0u8; HashSet::size_in_account(CAPACITY)];
842 rng.fill(bytes.as_mut_slice());
843
844 {
846 let mut hs_2 = unsafe {
847 HashSetZeroCopy::from_bytes_zero_copy_init(&mut bytes, CAPACITY, SEQUENCE_THRESHOLD)
848 .unwrap()
849 };
850
851 for seq in 0..OPERATIONS {
852 let value = BigUint::from(Fr::rand(&mut rng));
853 hs_1.insert(&value, seq).unwrap();
854 hs_2.insert(&value, seq).unwrap();
855 }
856
857 assert_eq!(hs_1, *hs_2);
858 }
859
860 {
862 let hs_2 = unsafe { HashSet::from_bytes_copy(&mut bytes).unwrap() };
863 assert_eq!(hs_1, hs_2);
864 }
865 }
866
867 #[test]
868 fn test_hash_set_from_bytes_copy_6857_2400_3600() {
869 hash_set_from_bytes_copy::<6857, 2400, 3600>()
870 }
871
872 #[test]
873 fn test_hash_set_from_bytes_copy_9601_2400_5000() {
874 hash_set_from_bytes_copy::<9601, 2400, 5000>()
875 }
876
877 fn hash_set_full<const CAPACITY: usize, const SEQUENCE_THRESHOLD: usize>() {
878 for _ in 0..100 {
879 let mut hs = HashSet::new(CAPACITY, SEQUENCE_THRESHOLD).unwrap();
880
881 let mut rng = rand::thread_rng();
882
883 for i in 0..CAPACITY {
886 let value = BigUint::from(Fr::rand(&mut rng));
887 match hs.insert(&value, 0) {
888 Ok(index) => hs.mark_with_sequence_number(index, 0).unwrap(),
889 Err(e) => {
890 assert!(matches!(e, HashSetError::Full));
891 println!("initial insertions: {i}: failed, stopping");
892 break;
893 }
894 }
895 }
896
897 for i in 0..1000 {
901 let value = BigUint::from(Fr::rand(&mut rng));
902 let res = hs.insert(&value, 0);
903 if res.is_err() {
904 assert!(matches!(res, Err(HashSetError::Full)));
905 } else {
906 println!("secondary insertions: {i}: apparent success with value: {value:?}");
907 }
908 }
909
910 for i in 0..1000 {
913 let value = BigUint::from(Fr::rand(&mut rng));
914 let sequence_number = rng.gen_range(0..hs.sequence_threshold);
917 let res = hs.insert(&value, sequence_number);
918 if res.is_err() {
919 assert!(matches!(res, Err(HashSetError::Full)));
920 } else {
921 println!("tertiary insertions: {i}: surprising success with value: {value:?}");
922 }
923 }
924
925 for i in 0..CAPACITY {
928 let value = BigUint::from(Fr::rand(&mut rng));
929 if let Err(e) = hs.insert(&value, SEQUENCE_THRESHOLD + i) {
930 assert!(matches!(e, HashSetError::Full));
931 println!("insertions after fillup: {i}: failed, stopping");
932 break;
933 }
934 }
935 }
936 }
937
938 #[test]
939 fn test_hash_set_full_6857_2400() {
940 hash_set_full::<6857, 2400>()
941 }
942
943 #[test]
944 fn test_hash_set_full_9601_2400() {
945 hash_set_full::<9601, 2400>()
946 }
947
948 #[test]
949 fn test_hash_set_element_does_not_exist() {
950 let mut hs = HashSet::new(4800, 2400).unwrap();
951
952 let mut rng = thread_rng();
953
954 for _ in 0..1000 {
955 let index = rng.gen_range(0..4800);
956
957 let res = hs.mark_with_sequence_number(index, 0);
959 assert!(matches!(res, Err(HashSetError::ElementDoesNotExist)));
960 }
961
962 for _ in 0..1000 {
963 let value = BigUint::from(Fr::rand(&mut rng));
966 let index = hs.insert(&value, 0).unwrap();
967 hs.mark_with_sequence_number(index, 1).unwrap();
968 }
969 }
970
971 #[test]
972 fn test_hash_set_iter_manual() {
973 let mut hs = HashSet::new(6857, 2400).unwrap();
974
975 let nullifier_1 = 945635_u32.to_biguint().unwrap();
976 let nullifier_2 = 3546656654734254353455_u128.to_biguint().unwrap();
977 let nullifier_3 = 543543656564_u64.to_biguint().unwrap();
978 let nullifier_4 = 43_u8.to_biguint().unwrap();
979 let nullifier_5 = 0_u8.to_biguint().unwrap();
980 let nullifier_6 = 65423_u32.to_biguint().unwrap();
981 let nullifier_7 = 745654665_u32.to_biguint().unwrap();
982 let nullifier_8 = 97664353453465354645645465_u128.to_biguint().unwrap();
983 let nullifier_9 = 453565465464565635475_u128.to_biguint().unwrap();
984 let nullifier_10 = 543645654645_u64.to_biguint().unwrap();
985
986 hs.insert(&nullifier_1, 0).unwrap();
987 hs.insert(&nullifier_2, 0).unwrap();
988 hs.insert(&nullifier_3, 0).unwrap();
989 hs.insert(&nullifier_4, 0).unwrap();
990 hs.insert(&nullifier_5, 0).unwrap();
991 hs.insert(&nullifier_6, 0).unwrap();
992 hs.insert(&nullifier_7, 0).unwrap();
993 hs.insert(&nullifier_8, 0).unwrap();
994 hs.insert(&nullifier_9, 0).unwrap();
995 hs.insert(&nullifier_10, 0).unwrap();
996
997 let inserted_nullifiers = hs
998 .iter()
999 .map(|(_, nullifier)| nullifier.value_biguint())
1000 .collect::<Vec<_>>();
1001 assert_eq!(inserted_nullifiers.len(), 10);
1002 assert_eq!(inserted_nullifiers[0], nullifier_7);
1003 assert_eq!(inserted_nullifiers[1], nullifier_3);
1004 assert_eq!(inserted_nullifiers[2], nullifier_10);
1005 assert_eq!(inserted_nullifiers[3], nullifier_1);
1006 assert_eq!(inserted_nullifiers[4], nullifier_8);
1007 assert_eq!(inserted_nullifiers[5], nullifier_5);
1008 assert_eq!(inserted_nullifiers[6], nullifier_4);
1009 assert_eq!(inserted_nullifiers[7], nullifier_2);
1010 assert_eq!(inserted_nullifiers[8], nullifier_9);
1011 assert_eq!(inserted_nullifiers[9], nullifier_6);
1012 }
1013
1014 fn hash_set_iter_random<
1015 const INSERTIONS: usize,
1016 const CAPACITY: usize,
1017 const SEQUENCE_THRESHOLD: usize,
1018 >() {
1019 let mut hs = HashSet::new(CAPACITY, SEQUENCE_THRESHOLD).unwrap();
1020 let mut rng = thread_rng();
1021
1022 let nullifiers: [BigUint; INSERTIONS] =
1023 std::array::from_fn(|_| BigUint::from(Fr::rand(&mut rng)));
1024
1025 for nullifier in nullifiers.iter() {
1026 hs.insert(&nullifier, 0).unwrap();
1027 }
1028
1029 let mut sorted_nullifiers = nullifiers.iter().collect::<Vec<_>>();
1030 let mut inserted_nullifiers = hs
1031 .iter()
1032 .map(|(_, nullifier)| nullifier.value_biguint())
1033 .collect::<Vec<_>>();
1034 sorted_nullifiers.sort();
1035 inserted_nullifiers.sort();
1036
1037 let inserted_nullifiers = inserted_nullifiers.iter().collect::<Vec<&BigUint>>();
1038 assert_eq!(inserted_nullifiers.len(), INSERTIONS);
1039 assert_eq!(sorted_nullifiers.as_slice(), inserted_nullifiers.as_slice());
1040 }
1041
1042 #[test]
1043 fn test_hash_set_iter_random_6857_2400() {
1044 hash_set_iter_random::<3500, 6857, 2400>()
1045 }
1046
1047 #[test]
1048 fn test_hash_set_iter_random_9601_2400() {
1049 hash_set_iter_random::<5000, 9601, 2400>()
1050 }
1051
1052 #[test]
1053 fn test_hash_set_get_bucket() {
1054 let mut hs = HashSet::new(6857, 2400).unwrap();
1055
1056 for i in 0..3600 {
1057 let bn_i = i.to_biguint().unwrap();
1058 hs.insert(&bn_i, i).unwrap();
1059 }
1060 let mut unused_indices = vec![true; 6857];
1061 for i in 0..3600 {
1062 let bn_i = i.to_biguint().unwrap();
1063 let i = hs.find_element_index(&bn_i, None).unwrap().unwrap();
1064 let element = hs.get_bucket(i).unwrap().unwrap();
1065 assert_eq!(element.value_biguint(), bn_i);
1066 unused_indices[i] = false;
1067 }
1068 for i in unused_indices.iter().enumerate() {
1070 if *i.1 {
1071 assert!(hs.get_bucket(i.0).unwrap().is_none());
1072 }
1073 }
1074 for i in 6857..10_000 {
1076 assert!(hs.get_bucket(i).is_none());
1077 }
1078 }
1079
1080 #[test]
1081 fn test_hash_set_get_bucket_mut() {
1082 let mut hs = HashSet::new(6857, 2400).unwrap();
1083
1084 for i in 0..3600 {
1085 let bn_i = i.to_biguint().unwrap();
1086 hs.insert(&bn_i, i).unwrap();
1087 }
1088 let mut unused_indices = vec![false; 6857];
1089
1090 for i in 0..3600 {
1091 let bn_i = i.to_biguint().unwrap();
1092 let i = hs.find_element_index(&bn_i, None).unwrap().unwrap();
1093
1094 let element = hs.get_bucket_mut(i).unwrap();
1095 assert_eq!(element.unwrap().value_biguint(), bn_i);
1096 unused_indices[i] = true;
1097
1098 *element = Some(HashSetCell {
1100 value: [0_u8; 32],
1101 sequence_number: None,
1102 });
1103 }
1104
1105 for (i, is_used) in unused_indices.iter().enumerate() {
1106 if *is_used {
1107 let element = hs.get_bucket_mut(i).unwrap().unwrap();
1108 assert_eq!(element.value_bytes(), [0_u8; 32]);
1109 }
1110 }
1111 for (i, is_used) in unused_indices.iter().enumerate() {
1113 if !*is_used {
1114 assert!(hs.get_bucket_mut(i).unwrap().is_none());
1115 }
1116 }
1117 for i in 6857..10_000 {
1119 assert!(hs.get_bucket_mut(i).is_none());
1120 }
1121 }
1122
1123 #[test]
1124 fn test_hash_set_get_unmarked_bucket() {
1125 let mut hs = HashSet::new(6857, 2400).unwrap();
1126
1127 (0..3600).for_each(|i| {
1130 let bn_i = i.to_biguint().unwrap();
1131 hs.insert(&bn_i, i).unwrap();
1132 });
1133
1134 for i in 0..3600 {
1135 let i = hs
1136 .find_element_index(&i.to_biguint().unwrap(), None)
1137 .unwrap()
1138 .unwrap();
1139 let element = hs.get_unmarked_bucket(i);
1140 assert!(element.is_some());
1141 }
1142
1143 for i in 0..3600 {
1145 let index = hs
1146 .find_element_index(&i.to_biguint().unwrap(), None)
1147 .unwrap()
1148 .unwrap();
1149 hs.mark_with_sequence_number(index, i).unwrap();
1150 }
1151
1152 for i in 0..3600 {
1153 let i = hs
1154 .find_element_index(&i.to_biguint().unwrap(), None)
1155 .unwrap()
1156 .unwrap();
1157 let element = hs.get_unmarked_bucket(i);
1158 assert!(element.is_none());
1159 }
1160 }
1161
1162 #[test]
1163 fn test_hash_set_first_no_seq() {
1164 let mut hs = HashSet::new(6857, 2400).unwrap();
1165
1166 for i in 0..3600 {
1169 let bn_i = i.to_biguint().unwrap();
1170 hs.insert(&bn_i, i).unwrap();
1171
1172 let element = hs.first_no_seq().unwrap().unwrap();
1173 assert_eq!(element.0.value_biguint(), 0.to_biguint().unwrap());
1174 }
1175 }
1176}