This repository has been archived by the owner. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsampler.c
executable file
·168 lines (142 loc) · 4.08 KB
/
sampler.c
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <assert.h>
#include <stdlib.h>
#include "sampler.h"
#include "tables.h"
#include "entropy.h"
/* Initialize sampler:
* - return true if success/false if error
* - false means that the parameters sigma/ell/precisions are not supported */
bool sampler_init(sampler_t *sampler, uint32_t sigma, uint32_t ell, uint32_t precision, entropy_t *entropy) {
sampler->entropy = entropy;
sampler->sigma = sigma;
sampler->ell = ell;
sampler->precision = precision;
sampler->columns = sampler->precision / 8;
sampler->c = get_table(sigma, ell, precision);
if (sampler->c != NULL) {
sampler->k_sigma = get_k_sigma(sigma, precision);
sampler->k_sigma_bits = get_k_sigma_bits(sigma, precision);
return true;
}
return false;
}
/* Sampling Bernoulli_c with c a constant in [0, 1]
* - p = array of bytes (encoding c in big-endian format)
* - p must have as many bytes as sampler->columns (= precision/8) */
bool sampler_ber(sampler_t *sampler, const uint8_t *p) {
uint32_t i;
uint8_t uc;
assert(sampler != NULL && p != NULL);
for(i = 0; i < sampler->columns; i++) {
uc = entropy_random_uint8(sampler->entropy);
if (uc < p[i]) return true;
if (uc > p[i]) return false;
}
return true; // default value
}
/* Sampling Bernoulli_E with E = exp(-x/(2*sigma*sigma)).
* Algorithm 8 from DDLL */
bool sampler_ber_exp(sampler_t* sampler, uint32_t x) {
const uint8_t* row;
uint32_t mask;
uint32_t ri;
bool bit;
ri = sampler->ell - 1;
mask = 1u << ri;
row = sampler->c + (ri * sampler->columns);
while (mask > 0) {
if (x & mask) {
bit = sampler_ber(sampler, row);
if(!bit) return false;
}
mask >>= 1;
row -= sampler->columns;
}
return true;
}
#if 0
// NOT USED YET
/* Sampling Bernoulli_E with E = exp(-x/(2*sigma*sigma))
* in constant time. */
bool sampler_ber_exp_ct(sampler_t* sampler, uint32_t x) {
const uint8_t* row;
uint32_t xi;
uint32_t i;
bool bit;
uint32_t ret = 1;
xi = x;
row = sampler->c;
for ( i = sampler->ell - 1; i!=0; i--) {
bit = sampler_ber(sampler, row);
ret = ret * (1-(xi&1)+bit*(xi&1));
xi >>= 1;
row += sampler->columns;
}
return (bool) ret;
}
#endif
/* Sampling Bernoulli_C with C = 1/cosh(x/(sigma*sigma)) */
bool sampler_ber_cosh(sampler_t* sampler, int32_t x) {
bool bit;
// How do we know this does not overflow/underflow?
x = x < 0 ? -x : x;
x <<= 1;
while (true) {
bit = sampler_ber_exp(sampler, (uint32_t)x);
if (bit) return true;
bit = entropy_random_bit(sampler->entropy);
if (!bit) {
bit = sampler_ber_exp(sampler, (uint32_t)x);
if (!bit) return false;
}
}
}
/* Sample a non-negative integer according to the binary discrete Gaussian distribution. */
#define MAX_SAMPLE_COUNT 16
uint32_t sampler_pos_binary(sampler_t *sampler) {
uint32_t u, i;
restart:
if (entropy_random_bit(sampler->entropy)) {
return 0;
}
for (i=1; i <= MAX_SAMPLE_COUNT; i++) {
u = entropy_random_bits(sampler->entropy, 2*i - 1);
if (u == 0) {
return i;
}
if (u != 1) {
goto restart;
}
}
return 0; // default value. Extremely unlikely to ever be reached
}
/* Sampling the Gaussian distribution exp(-x^2/(2*sigma*sigma)) returns the sampled value. */
int32_t sampler_gauss(sampler_t *sampler) {
uint32_t u, e, x, y;
int32_t val_pos;
while (true) {
x = sampler_pos_binary(sampler);
do {
y = entropy_random_bits(sampler->entropy, sampler->k_sigma_bits);
} while (y >= sampler->k_sigma);
e = y * (y + 2u * sampler->k_sigma * x);
u = entropy_random_bit(sampler->entropy);
// don't restart if both hold:
// 1. (x, y) != (0, 0) or u = 1
// 2. sampler_ber_exp(sampler, e) = 1
if (x | y | u) {
if (sampler_ber_exp(sampler, e)) break; // lazy sample
}
}
val_pos = (int32_t)(sampler->k_sigma * x + y);
return u ? val_pos : - val_pos;
}
#if 0
// TO BE DONE
/* Sampling the Gaussian distribution exp(-x^2/(2*sigma*sigma)) using a cumulative distribution table
returns the sampled value. */
int32_t sampler_gauss_CDT(sampler_t *sampler) {
assert(0);
return 0;
}
#endif