pythnet_sdk/accumulators/
mul.rs

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