-
Notifications
You must be signed in to change notification settings - Fork 18
Expand file tree
/
Copy pathSource.cpp
More file actions
277 lines (225 loc) · 8.46 KB
/
Copy pathSource.cpp
File metadata and controls
277 lines (225 loc) · 8.46 KB
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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#include <stdio.h>
#include <random>
#include <array>
#define Assert(x) if (!x) ((int*)nullptr)[0] = 0;
// how many bits there are in the secret key. Increase for more security
const size_t c_keyLength = 8;
// determines the epsilon by making sure this many operations can be preformed
// without the noise getting larger than 0.5
const size_t c_numOperations = 16;
//=================================================================================
template <size_t X, size_t Y, size_t Z> using TArray3D = std::array<std::array<std::array<float, Z>, Y>, X>;
//=================================================================================
void WaitForEnter()
{
printf("Press Enter to quit");
fflush(stdin);
getchar();
}
//=================================================================================
// Replace these with something crypto secure if desired
float RandomFloat ()
{
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_real_distribution<> dis(-1, 1);
return float(dis(gen));
}
bool RandomBit ()
{
static std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_int_distribution<> dis(0, 1);
return dis(gen) == 1;
}
int RandomInt (int min, int max)
{
static std::random_device rd;
static std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(min, max);
return dis(gen);
}
//=================================================================================
template <size_t KEYLENGTH, size_t NUMOPERATIONS>
class CFHEEncryptedBit
{
public:
void XOR (const CFHEEncryptedBit<KEYLENGTH, NUMOPERATIONS>& rhs)
{
for (size_t i = 0; i < KEYLENGTH; ++i)
m_value[i] = std::remainder(m_value[i] + rhs.m_value[i], 2.0f);
m_estimatedError += rhs.m_estimatedError;
}
void AND ()
{
}
float GetEstimatedError () const
{
return m_estimatedError;
}
private:
template <size_t KEYLENGTH, size_t NUMOPERATIONS>
friend class CFHEPrivateKey;
CFHEEncryptedBit (const std::array<bool, KEYLENGTH>& key, bool value)
{
const float c_epsilon = 0.49f / float(NUMOPERATIONS);
const float c_desiredValue = value == true ? 1.0f : 0.0f;
m_estimatedError = c_epsilon;
// generate the starting random float vector
// making it go from -1 to 1, and taking the abs val of the result means that
// values wrap around from -1 to 1 so are continuious at both 0 and 1.
for (size_t i = 0; i < KEYLENGTH; ++i)
m_value[i] = RandomFloat();
// adjust the dot product to what we want it to be, but make sure that we
// preserve noise on the result, keeping it within c_epsilon.
float difference = c_desiredValue - DotProductModulo2(key);
size_t index = GetRandomKeyIndexSetTrue(key);
difference += m_value[index] * c_epsilon; // preserve noise. use the random number that was there to determine noise level!
m_value[index] = std::remainder(m_value[index] + difference, 2.0f);
// make sure we encrypted it correctly
Assert(Decrypt(key) == value);
}
bool Decrypt (const std::array<bool, KEYLENGTH>& key, float *error = nullptr) const
{
float rawValue = DotProductModulo2(key);
// Note we are only returning the error for demonstration purposes. Doing this in a real setup would
// damage your security!
if (error != nullptr)
*error = abs(rawValue - round(rawValue));
float value = abs(round(rawValue));
if (value == 1.0f)
return true;
else
return false;
}
float DotProductModulo2 (const std::array<bool, KEYLENGTH>& key) const
{
float sum = 0.0f;
for (size_t i = 0; i < KEYLENGTH; ++i)
{
if (key[i])
sum += m_value[i];
}
return std::remainder(sum, 2.0f);
}
size_t GetRandomKeyIndexSetTrue (const std::array<bool, KEYLENGTH>& key) const
{
size_t index = RandomInt(0, KEYLENGTH-1);
while (!key[index])
index = (index + 1) % KEYLENGTH;
return index;
}
std::array<float, KEYLENGTH> m_value;
// not needed for functionality, just here for demonstration purposes
float m_estimatedError;
};
//=================================================================================
template <size_t KEYLENGTH, size_t NUMOPERATIONS>
class CFHEPrivateKey
{
public:
CFHEPrivateKey ()
{
// make sure there's at least one bit set to true
bool hasAnySet = false;
do
{
for (size_t i = 0; i < KEYLENGTH; ++i)
{
m_key[i] = RandomBit();
if (m_key[i])
hasAnySet = true;
}
}
while (!hasAnySet);
// Calculate the multiplication helper
CalculateMultiplicationHelper();
}
CFHEEncryptedBit<KEYLENGTH, NUMOPERATIONS> EncryptBit (bool value)
{
return CFHEEncryptedBit<KEYLENGTH, NUMOPERATIONS>(m_key, value);
}
bool DecryptBit (const CFHEEncryptedBit<KEYLENGTH, NUMOPERATIONS>& value)
{
return value.Decrypt(m_key);
}
bool DecryptBit(const CFHEEncryptedBit<KEYLENGTH, NUMOPERATIONS>& value, float &error)
{
return value.Decrypt(m_key, &error);
}
const TArray3D<KEYLENGTH, KEYLENGTH, KEYLENGTH>& GetMultiplicationHelper() const
{
return m_multiplicationHelper;
}
private:
void CalculateMultiplicationHelper()
{
for (size_t i = 0; i < KEYLENGTH; ++i)
{
for (size_t j = 0; j < KEYLENGTH; ++j)
{
for (size_t k = 0; k < KEYLENGTH; ++k)
{
}
}
}
}
std::array<bool, KEYLENGTH> m_key;
TArray3D<KEYLENGTH, KEYLENGTH, KEYLENGTH> m_multiplicationHelper;
};
typedef CFHEPrivateKey<c_keyLength, c_numOperations> TPrivateKey;
typedef CFHEEncryptedBit<c_keyLength, c_numOperations> TEncryptedBit;
//=================================================================================
int main (int argc, char **argv)
{
TPrivateKey privateKey;
/*
TEncryptedBit trueBit = privateKey.EncryptBit(true);
TEncryptedBit falseBit = privateKey.EncryptBit(false);
for (int i = 0; i < 100000; ++i)
{
trueBit = privateKey.EncryptBit(true);
falseBit = privateKey.EncryptBit(false);
if (privateKey.DecryptBit(trueBit) != true)
Assert(false);
if (privateKey.DecryptBit(falseBit) != false)
Assert(false);
}
*/
TEncryptedBit trueBit = privateKey.EncryptBit(true);
TEncryptedBit trueBit2 = privateKey.EncryptBit(true);
TEncryptedBit falseBit = privateKey.EncryptBit(false);
TEncryptedBit falseBit2 = privateKey.EncryptBit(false);
falseBit.XOR(trueBit);
float errorEstimated1 = falseBit.GetEstimatedError();
float errorActual1;
bool decryptedValue1 = privateKey.DecryptBit(falseBit, errorActual1);
int ijkl = 0;
falseBit.XOR(trueBit2);
float errorEstimated2 = falseBit.GetEstimatedError();
float errorActual2;
bool decryptedValue2 = privateKey.DecryptBit(falseBit, errorActual2);
ijkl = 0;
// WaitForEnter();
}
/*
TODO:
* while doing operations, make it show internal values as well as estimated error? (#define to turn on verbose mode or something maybe?)
* make decryption report actual error as well as the value
* make AND work
* make XOR work
* figure out how the "correction" thing works to remove error (or figure out unleveled stuff!)
* make it keep track of error, by having an internal float it adds epsilon to etc
* template parameters for best performance?
* multi bit operations? like an N bit adder. abstracting from the basic stuff
* test doing a NOT by having m_value[index] = 1.0f - m_value[index]
* unit tests for encryption / decryption and the operations
* learn about zero error and gaussian elimination, and how error creeps in even if zero error
* could reduce this to no error, and do bools only as an even simpler example!
* can also do bit rotation
* not sure how to do bit shifting though, because we'd need to pad with zeros. don't have a zero (i guess we could ask for one!)
* post:
* mention proof of concept only
* should read up to figure out correct security parameters etc
* maybe 2 posts - first is simpler somewhat homomorphic encryption, second is fully? where to do more advanced circuits? probably on 1st one
*/