1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#[encrypted_library]
mod arcis_library {
struct ArcisRNGUtils;
impl ArcisRNGUtils {
#[arcis_circuit = "bitwise_and"]
fn bitwise_and(a: u128, b: u128) -> u128 {}
#[arcis_circuit = "lowest_bigger_power_of_two_minus_one"]
fn lowest_bigger_power_of_two_minus_one(a: u128) -> u128 {}
}
/// This struct gives access to randomness operations.
/// ```
/// use arcis::*;
///
/// #[encrypted]
/// mod circuits {
/// use arcis::*;
///
/// #[instruction]
/// pub fn doc_arcis_rng(s: Shared) -> (Enc<Shared, bool>, [u8; 32], Enc<Mxe, [u128; 3]>, bool) {
/// let random_bool = ArcisRNG::bool();
///
/// // Generates an u128 with bit width 3.
/// let first_integer = ArcisRNG::gen_integer_from_width(3);
/// // 0 <= first_integer < 2^3 = 8
///
/// // Generates an integer between 17 and 27, both included.
/// // Will try 24 times with each attempt having > 1/2 chance of success.
/// // So chance of failure is below 2^-24.
/// let (second_integer, did_it_work) = ArcisRNG::gen_integer_in_range(17, 27, 24);
///
/// let mut u128_array = [first_integer, second_integer, 42];
/// // Shuffles a slice in-place.
/// ArcisRNG::shuffle(&mut u128_array);
///
/// // Generates uniformly an [u8; 32].
/// let u8_array = ArcisRNG::gen_uniform::<[u8;32]>(); // You need to put the type there.
/// // Our interpreter does not have type inference and needs to know the type right away.
///
/// // Does not work:
/// // let b: bool = ArcisRNG::gen_uniform(); // We do not do type inference.
/// // let random_float = ArcisRNG::gen_uniform::<f64>(); // floats cannot be generated uniformly.
///
/// // You can send the randomness to someone.
/// let enc_bool = s.from_arcis(random_bool);
///
/// // Or reveal it to the world.
/// let revealed_u8_array = u8_array.reveal();
///
/// // Or keep it for later.
/// let stored_shuffled_u128_array = Mxe::get().from_arcis(u128_array);
///
/// (enc_bool, revealed_u8_array, stored_shuffled_u128_array, did_it_work.reveal())
/// }
/// }
/// ```
pub struct ArcisRNG;
impl ArcisRNG {
fn gen_and_reject(max: u128) -> (u128, bool) {
let lbpotmo = ArcisRNGUtils::lowest_bigger_power_of_two_minus_one(max);
let rand = Self::gen_integer_from_width(128);
let rand = ArcisRNGUtils::bitwise_and(rand, lbpotmo);
if rand <= max {
(rand, true)
} else {
(0, false)
}
}
/// Generates an integer between `min` and `max`, inclusive.
/// It tries `n_attempts` times, with each attempt having > 1/2 chance of success.
/// Produces incorrect results if `min > max`.
/// Returns `(min, false)` in case of failure, `(result, true)` in case of success.
/// Note that `n_attempts` must be known at compile time.
pub fn gen_integer_in_range(min: u128, max: u128, n_attempts: usize) -> (u128, bool) {
let range = max - min;
let mut res = 0;
let mut success = false;
for _ in 0..n_attempts {
let (r, s) = Self::gen_and_reject(range);
if !success {
res = r;
success = s;
}
}
(res + min, success)
}
}
}