accumulator_plus/
lib.rs

1use alloc::vec::Vec;
2use rand;
3
4use std::collections::HashSet;
5
6extern crate alloc;
7use num_bigint::{BigUint, ModInverse, RandPrime};
8
9
10use core::str::FromStr;
11use num_traits::{One, Zero};
12use rand_core::CryptoRngCore;
13
14pub mod subroutines;
15pub mod proofs;
16pub mod witnesses;
17pub mod hashing;
18
19
20pub type Result<T> = core::result::Result<T, Error>;
21
22#[derive(Debug, Eq, PartialEq)]
23#[non_exhaustive]
24pub enum Error {
25    InvalidPrime,
26    NprimesTooSmall,
27    TooFewPrimes,
28
29}
30
31pub struct RsaPrivateKeyComponents {
32    pub n: BigUint,
33    pub e: BigUint,
34    pub d: BigUint,
35    pub primes: Vec<BigUint>,
36}
37
38
39
40#[inline]
41pub(crate) fn compute_private_exponent_euler_totient(
42    primes: &[BigUint],
43    exp: &BigUint,
44) -> Result<BigUint> {
45    if primes.len() < 2 {
46        return Result::Err(Error::InvalidPrime);
47    }
48
49    let mut totient = BigUint::one();
50
51    for prime in primes {
52        totient *= prime - BigUint::one();
53    }
54
55    // NOTE: `mod_inverse` checks if `exp` evenly divides `totient` and returns `None` if so.
56    // This ensures that `exp` is not a factor of any `(prime - 1)`.
57    if let Some(d) = exp.mod_inverse(totient) {
58        Ok(d.to_biguint().unwrap())
59    } else {
60        // `exp` evenly divides `totient`
61        Err(Error::InvalidPrime)
62    }
63}
64
65pub fn generate_multi_prime_key_with_exp<R: CryptoRngCore + ?Sized>(
66    rng: &mut R,
67    nprimes: usize,
68    bit_size: usize,
69    exp: &BigUint,
70) -> Result<RsaPrivateKeyComponents> {
71    if nprimes < 2 {
72        return Err(Error::NprimesTooSmall);
73    }
74
75    if bit_size < 64 {
76        let prime_limit = (1u64 << (bit_size / nprimes) as u64) as f64;
77
78        // pi aproximates the number of primes less than prime_limit
79        let mut pi = prime_limit / (prime_limit.ln() - 1f64);
80        // Generated primes start with 0b11, so we can only use a quarter of them.
81        pi /= 4f64;
82        // Use a factor of two to ensure that key generation terminates in a
83        // reasonable amount of time.
84        pi /= 2f64;
85
86        if pi < nprimes as f64 {
87            return Err(Error::TooFewPrimes);
88        }
89    }
90
91    let mut primes = vec![BigUint::zero(); nprimes];
92    let n_final: BigUint;
93    let d_final: BigUint;
94
95    'next: loop {
96        let mut todo = bit_size;
97        // `gen_prime` should set the top two bits in each prime.
98        // Thus each prime has the form
99        //   p_i = 2^bitlen(p_i) × 0.11... (in base 2).
100        // And the product is:
101        //   P = 2^todo × α
102        // where α is the product of nprimes numbers of the form 0.11...
103        //
104        // If α < 1/2 (which can happen for nprimes > 2), we need to
105        // shift todo to compensate for lost bits: the mean value of 0.11...
106        // is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2
107        // will give good results.
108        if nprimes >= 7 {
109            todo += (nprimes - 2) / 5;
110        }
111
112        for (i, prime) in primes.iter_mut().enumerate() {
113            *prime = rng.gen_prime(todo / (nprimes - i));
114            todo -= prime.bits();
115        }
116
117        // Makes sure that primes is pairwise unequal.
118        for (i, prime1) in primes.iter().enumerate() {
119            for prime2 in primes.iter().take(i) {
120                if prime1 == prime2 {
121                    continue 'next;
122                }
123            }
124        }
125
126        let n = subroutines::prime_product(&primes);
127
128        if n.bits() != bit_size {
129            // This should never happen for nprimes == 2 because
130            // gen_prime should set the top two bits in each prime.
131            // For nprimes > 2 we hope it does not happen often.
132            continue 'next;
133        }
134
135        if let Ok(d) = compute_private_exponent_euler_totient(&primes, exp) {
136            n_final = n;
137            d_final = d;
138            break;
139        }
140    }
141
142    Result::Ok(RsaPrivateKeyComponents {
143        n: n_final,
144        e: exp.clone(),
145        d: d_final,
146        primes,
147    })
148}
149
150pub fn gen_diff_prime_vec(k: usize, bits: usize, s: &mut Vec<BigUint>) {
151    let mut rng = rand::thread_rng();
152    let mut set = HashSet::new();
153    let mut i = 0;
154    if k == 0 {
155        return;
156    }
157    loop {
158        let gi = rng.gen_prime(bits);
159        let si = gi;
160        if set.contains(&si) {
161            continue;
162        }
163        set.insert(si);
164        i += 1;
165        if i >= k { break; }
166    }
167    for x in set {
168        s.push(x);
169    }
170}
171
172pub const EXP: u64 = 65537;
173
174/// Defines the RSA group. Arbitrary set at MODULUS = 13 for testing.
175/// Example (insecure) modulus -> RSA 100: "1522605027922533360535618378132637429718068114961380688657908494580122963258952897654000350692006139"
176pub const MODULUS: &str = "13";
177
178/// Security parameter that represents the size of elements added to the accumulator.
179pub const LAMBDA: u32 = u32::max_value();
180
181#[derive(Clone, PartialEq, Debug)]
182pub struct BezoutPairBigUint {
183    pub coefficient_a: BigUint,
184    pub coefficient_b: BigUint,
185    sign_a: bool, // True indicates negative and false indicates positive
186    sign_b: bool,
187}
188
189
190/// Add a single element to an accumulator.
191pub fn add(state: BigUint, elem: BigUint) -> BigUint {
192    return subroutines::mod_exp_big_uint(&state, &elem, &BigUint::from_str(MODULUS).unwrap());
193}
194
195/// Delete an element from the accumulator given a membership proof.
196pub fn delete(state: BigUint, elem: BigUint, proof: BigUint) -> Option<BigUint> {
197    if subroutines::mod_exp_big_uint(&proof, &elem, &BigUint::from_str(MODULUS).unwrap()) == state {
198        return Some(proof);
199    }
200    return None;
201}
202
203/// Aggregates a set of accumulator elements + witnesses and batch deletes them from the accumulator.
204/// Returns the state after deletion, the product of the deleted elements, and a proof of exponentiation.
205pub fn batch_delete_by_shamir_trick(state: BigUint, elems: &Vec<(BigUint, BigUint)>) -> (BigUint, BigUint, BigUint) {
206    let (mut x_agg, mut new_state) = elems[0].clone();
207    for i in 1..elems.len() {
208        let (x, witness) = elems[i].clone();
209        new_state = subroutines::shamir_trick_big_uint(new_state, witness, x_agg.clone(), x.clone()).unwrap();
210        x_agg *= x;
211    }
212    let proof = proofs::poe_big_uint(&new_state, &x_agg, &state);
213    return (new_state, x_agg, proof);
214}
215
216pub fn batch_delete_by_normal_loop(base_state: BigUint, state: BigUint, elems_pair: &Vec<(BigUint, BigUint)>, elems: &Vec<BigUint>) -> (BigUint, BigUint, BigUint) {
217    let (mut x_agg, mut new_state) = elems_pair[0].clone();
218    if elems_pair.len() == 1 {
219        return (new_state, x_agg, BigUint::from(1u8));
220    }
221    for i in 1 .. elems_pair.len() {
222        x_agg *= elems_pair[i].clone().0;
223    }
224
225    let new_wi_list = subroutines::root_factor_big_uint(base_state.clone(), &elems[elems_pair.len()-1..]);
226    new_state = new_wi_list.get(0).or_else(|| Some(&new_state)).unwrap().clone();
227
228    let proof = proofs::poe_big_uint(&new_state, &x_agg, &state);
229    return (new_state, x_agg, proof);
230
231}
232
233
234
235pub fn batch_auth_by_shamir_trick(vpks: &Vec<BigUint>, vms: &Vec<BigUint>, new_state: &BigUint) -> bool {
236    subroutines::shamir_batch_big_uint(vpks, vms, new_state)
237}
238
239
240pub fn batch_auth_by_normal_loop(vpks: &Vec<BigUint>, vms: &Vec<BigUint>, new_state: &BigUint) -> bool {
241    subroutines::loop_batch_big_uint(vpks, vms, new_state)
242}
243
244
245/// Aggregates a set of accumulator elements + witnesses and batch adds them to the accumulator.
246/// Returns the state after addition, the product of the added elements, and a proof of exponentiation.
247pub fn batch_add_big_uint(state: &BigUint, elems: &Vec<BigUint>) -> (BigUint, BigUint, BigUint) {
248    let mut x_agg = BigUint::from(1u8);
249    for i in 0..elems.len() {
250        x_agg *= &elems[i];
251    }
252
253    let new_state = subroutines::mod_exp_big_uint(state, &x_agg, &BigUint::from_str(MODULUS).unwrap());
254    // let proof = proofs::poe(state, &x_agg, &new_state);
255    // return (new_state, x_agg, proof);
256    return (new_state, x_agg, BigUint::from(1u8));
257}
258
259
260
261#[cfg(test)]
262mod tests{
263    use num_bigint::BigUint;
264    use crate::{generate_multi_prime_key_with_exp, EXP};
265
266    #[test]
267    fn gen_prims(){
268        let prime_key_with_exp = generate_multi_prime_key_with_exp(&mut rand::thread_rng(),
269                                                       3,
270                                                       56,
271                                                       &BigUint::from(EXP));
272        let key_components = prime_key_with_exp.unwrap();
273        println!("{}", &key_components.n);
274        println!("{}", &key_components.e);
275        println!("{}", &key_components.d);
276        println!("{:?}", &key_components.primes);
277
278    }
279
280
281}
282
283