pythnet_sdk/accumulators/
mul.rs

1//! A multiplication based Accumulator (should not use, example only)
2
3use crate::{
4    accumulators::Accumulator,
5    hashers::{prime::PrimeHasher, Hasher},
6};
7
8/// A multiplication based Accumulator
9///
10/// This accumulator relies on the quasi-commutative nature of the multiplication operator. It's
11/// here mostly as a an example to gain intuition for how accumulators should function. This
12/// implementation relies on the fact that `/` can be used to "remove" an element but typically an
13/// accumulator cannot rely on having a shortcut, and must re-accumulate sans the element being
14/// proved to be a member.
15pub struct MulAccumulator<H: Hasher> {
16    pub accumulator: H::Hash,
17    pub items: Vec<H::Hash>,
18}
19
20impl<'a> Accumulator<'a> for MulAccumulator<PrimeHasher> {
21    type Proof = <PrimeHasher as Hasher>::Hash;
22
23    fn prove(&self, item: &[u8]) -> Option<Self::Proof> {
24        let bytes = u128::from_be_bytes(PrimeHasher::hashv(&[item]));
25        let acc = u128::from_be_bytes(self.accumulator);
26        Some((acc / bytes).to_be_bytes())
27    }
28
29    fn check(&self, proof: Self::Proof, item: &[u8]) -> bool {
30        let bytes = u128::from_be_bytes(PrimeHasher::hashv(&[item]));
31        let proof = u128::from_be_bytes(proof);
32        proof * bytes == u128::from_be_bytes(self.accumulator)
33    }
34
35    fn from_set(items: impl Iterator<Item = &'a [u8]>) -> Option<Self> {
36        let primes: Vec<[u8; 16]> = items.map(|i| PrimeHasher::hashv(&[i])).collect();
37        Some(Self {
38            items: primes.clone(),
39            accumulator: primes.into_iter().reduce(|acc, v| {
40                u128::to_be_bytes(u128::from_be_bytes(acc) * u128::from_be_bytes(v))
41            })?,
42        })
43    }
44}
45
46#[cfg(test)]
47mod test {
48    use {super::*, std::collections::HashSet};
49
50    #[test]
51    fn test_membership() {
52        let mut set: HashSet<&[u8]> = HashSet::new();
53
54        // Create some random elements (converted to bytes). All accumulators store arbitrary bytes
55        // so that we can target any account (or subset of accounts).
56        let item_a = 33usize.to_be_bytes();
57        let item_b = 54usize.to_be_bytes();
58        let item_c = 2usize.to_be_bytes();
59        let item_d = 88usize.to_be_bytes();
60
61        // Insert the bytes into the Accumulate type.
62        set.insert(&item_a);
63        set.insert(&item_b);
64        set.insert(&item_c);
65
66        println!();
67
68        // Create an Accumulator. Test Membership.
69        {
70            let accumulator = MulAccumulator::<PrimeHasher>::from_set(set.into_iter()).unwrap();
71            let proof = accumulator.prove(&item_a).unwrap();
72            assert!(accumulator.check(proof, &item_a));
73            assert!(!accumulator.check(proof, &item_d));
74        }
75    }
76}