-
Notifications
You must be signed in to change notification settings - Fork 0
/
Approximation.h
523 lines (454 loc) · 18.1 KB
/
Approximation.h
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
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
/*
* File: Approximation.h
* Author: ph4r05
*
* Created on May 16, 2014, 10:21 AM
*/
#ifndef APPROXIMATION_H
#define APPROXIMATION_H
#include <iostream>
#include <stdio.h>
#include <limits.h>
#include <vector>
#include <algorithm>
#include <iomanip>
#include <cstring>
#include "base.h"
#include "ICipher.h"
// Maximum order of terms.
#define MAX_ORDER 6
// Maximal order used during cube attack.
#define MAX_SUPERPOLY_ORDER 4
//
// FGb
//
#include "faugere/fgb.h"
#include "CombinatorialIndexer.h"
#include "FGbHelper.h"
// NTL library.
#include <NTL/vec_vec_GF2.h>
#include <NTL/vec_GF2.h>
// Boost serialization
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/list.hpp>
class CubeRelations_t;
class CubeRelations_vector;
class Approximation {
private:
ICipher * cip;
// Cache polynomial coefficients for low order.
// Indexing is as follows coefficients[order][coefficient_index][polyout].
// Where order is the order of terms represented in the structure.
// coefficient_index is the order number of the combination of variables
// in particular term, terms follow lexicographic order.
// polyout: Output block for polynomials. Each bit in this block
// tells whether in the particular polynomial given term is present or not.
//
// Size of this array can be precomputed from the cipher.
// Let iw = input width of the cipher in bytes (message+key).
// Let ow = output width of the cipher in bytes.
//
// Then second dimension is number of all possible terms with specified order ord.
// In particular it is Binomial(8*iw, ord).
// Third dimension is ceil(ow/sizeof(ulong)).
// In order to optimize memory storage/access of/to this structure
// 2nd and 3rd dimension are merged to one.
std::vector<ULONG> coefficients[MAX_ORDER];
// Limit on the term order for storage.
// Only terms of order/degree less than or equals to this limit will
// be stored and evaluated.
uint orderLimit;
// Flag telling whether to dump coefficients to the file or not.
bool dumpCoefsToFile;
// Byte width of the input cipher.
// Key block size + message block size.
ULONG byteWidth;
// Number of bits needed to store the
uint logBitInputWidth;
// Size of the output block of the cipher in ulong types.
ULONG outputWidthUlong;
// Size of the input block (message+key) of the cipher in ulong types.
ULONG inputWidthUlong;
// Combinatorial indexer - helps with computing index of combinations and vice versa.
CombinatorialIndexer combIndexer;
// FGb helper class.
FGbHelper fgb;
// Number of threads to use for parallelized computation.
uint threadCount;
// Number of key-bits set to zero.
uint keybitsToZero;
// Bitmap of polynomials to take into consideration (for example during GB solving).
ULONG * poly2take;
// Hamming weight of the poly2take.
uint numPolyActive;
// Signal blocking variables.
sigset_t pendingSignals, blockingMask;
// Verbosity level
uint verboseLvl;
public:
Approximation(uint orderLimit);
virtual ~Approximation();
/**
* Computes coefficients for polynomial approximation.
* Init has to be called before this function.
* Memory for coefficient is allocated in this step.
*/
void computeCoefficients(std::vector<ULONG> * coefficients);
/**
* Initialization of the internal pre-computed tables.
*/
void init();
/**
* Evaluates function determined by coefficients
* @param input
* @param output
* @param iBuff input ULONG buffer to use (has to be allocated to exact size)
* @param oBuff output ULONG buffer to use (has to be allocated to exact size)
* @return
*/
int evaluateCoefficients(const std::vector<ULONG> * coefficients,
const unsigned char * input, unsigned char * output, ULONG * iBuff, ULONG * oBuff) const;
/**
* Partially evaluates approximated function on a given input.
* Result is again a function, but with smaller number of variables.
*
* @param newVariables Number of the variables in a new partially evaluated function.
* @param variablesValueMask Variables bit mask for evaluation (we have values for them.)
* Hamming_weight(variablesValueMask) = bitWIdth - newVariables.
* @param iBuff Input to the evaluation. Values for variables to evaluate.
* Only masked values are taken into consideration.
* @param coeffEval Storage provided by the caller to store the new function in.
* @return
*/
int partialEvaluation(const std::vector<ULONG> * coefficients,
uint numVariables, ULONG * variablesValueMask, ULONG * iBuff, std::vector<ULONG> * coeffEval) const;
/**
* Tests polynomial approximation of the cipher.
* Pre-computed coefficients are used.
* @return
*/
int testPolynomialApproximation(unsigned long numSamples) const;
/**
* Performs self test on determined coefficient values.
* For low degree input we have to obtain exactly the same results from
* cipher and from the approximation function.
*
* @return
*/
int selftestApproximation(unsigned long numSamples) const;
/**
* Simple test for combination indexing correctness.
*/
int selftestIndexing() const;
/**
* Computes maximal number of terms the polynomial with given number
* of variables and with the defined maximal order can have.
* @return
*/
ULONG numberOfTerms(ULONG variables, ULONG maxOrder) const;
/**
Procedure for solving equation for keys with using GB.
* FGb has to be initialized before and deinitialized after calling this method!
*/
void solveKeyGrobner(uint samples, bool dumpInputBase=false, bool selfTest=false, int basisReduction=0) const;
int solveGb(uint numVariables, Dpol* basis, uint numPoly, uchar * solvedKey) const;
/**
* Function computes subCube of a given term specified by termWeight and
* term bitmask (with 1 on positions corresponding to a variable present in
* term to cube).
*
* Finput is function input that will be used for cube process in target
* function evaluation, except bits specified in termMask, those will be
* always set accordingly to the cubing. Term bits has to be set to 0!
*
* Function allows parallelization, does not modify any internal state,
* can be configured to compute only a sub-cube (each x-th term in the cube).
*
* Result is XOR of all possible terms constructible from given term.
*
* Result is written to the subcube argument.
*
* Function
*
* @param termWeight Term to cube, number of variables, Hamming weight of its bitmask.
* @param termMask Term to cube, bitmask
* @param finput Input for the function evaluation (contains keys).
* @param subcube Output buffer.
* @param step Parallelization. (i*step) + offset
* @param offset Parallelization. (i*step) + offset
* @param doSubCubes If true, also the cubes of size N-1 are computed.
* @return
*/
int subCubeTerm(uint termWeight, const ULONG * termMask, const uchar * finput, ULONG * subcube,
uint step, uint offset, uint subCubes, bool precompKey) const;
/**
* Threaded variant of subCubeTerm.
* Difference: Key is assumed to be constant, saved in finput...
*
* @param termWeight
* @param termMask
* @param finput
* @param subcube
* @param step
* @param offset
* @param doSubCubes
* @return
*/
int subCubeTermThreaded(uint termWeight, const ULONG * termMask, const uchar * finput, ULONG * subcube, uint subCubes) const;
/**
* Returns cache file name for the cube attack with specified settings.
* @param wPlain
* @param wKey
* @return
*/
std::string getCubeCacheName(uint wPlain, uint wKey) const;
/**
* Loads cube attack archive to the cube relations vector.
* @param fname
* @param
* @return
*/
int readCubeArchive(const char * fname, CubeRelations_vector & vct) const;
/**
* Writes complete cube relations vector to the given file.
* Blocks sigterm, sigquit, sigint signals to avoid archive corruption
* during save procedure.
*
* @param fname
* @param vct
* @return
*/
int writeCubeArchive(const char * fname, CubeRelations_vector & vct) const;
/**
* Write given relation to the archive.
*
* @param fname
* @param vct
* @param wKey
* @param termMask
* @param keyCubes
* @param isSuperpoly
* @return
*/
int writeRelationToArchive(const char * fname, CubeRelations_vector & vct,
uint wKey, ULONG * termMask, std::vector<ULONG> * keyCubes, ULONG * isSuperpoly) const;
/**
* Dumps function defined by the order vectors to the stream in plaintext.
*
* @param c
* @param coefficients
* @param maxOrder
*/
ULONG dumpCoefficients(std::ostream & c, const std::vector<ULONG> * coefficients, uint maxOrder, uint numVariables, uint polyIdx, uint fmt=1) const;
/**
* Dumps function representation of a multiple function in a polynomial form.
*
* @param c Output stream to write data to.
* @param coefficients Storage structure for polynomial representation.
* @param maxOrder Maximum order of a polynomial terms to dump.
* @param numVariables Number of variables in one polynomial (describes structure).
* @param numPoly Number of polynomials to dump.
* @param nonNullOnly if true only non-null polynomials will be dumped.
* @param fmt formatting: 1=polynomial textual, 2=ASCII binary, 3=binary
* @return
*/
ULONG dumpOutputFunctions(std::ostream & c, const std::vector<ULONG> * coefficients, uint maxOrder,
uint numVariables, uint numPoly, bool nonNullOnly=true, uint fmt=1) const;
/**
* Dumps plaintext cube to the ASCII.
*
* @param wPlain
* @param wKey
* @param startOrder
* @param stopOrder
* @param termMask
* @param keyCubes
* @param isSuperpoly
* @return
*/
ULONG dumpPlaintextCube(std::ostream & c, ULONG * pcube, uint pcubeSize) const;
/**
* Generate array of bit positions from left to right.
* @param termBitPositions
* @param bitWidth
* @param termMask
* @return
*/
uint genBitPosMask(uint * termBitPositions, uint bitWidth, const ULONG* termMask, uint termWeight) const;
/**
* On provided plaintext part performs cube computation on key variables.
* Plaintext remains fixed during the computation (stored in termMask),
* key cube starts from order <b>startOrder</b> and stops in order
* <b>stopOrder</b> inclusively.
*
* keyCubes and isSuperpoly has to be already initialized. No memory reset
* is performed so this can be called to finish a computation, e.g.,
* to compute quadratic cube on already computed linear cube.
* Results are stored to these variables and these variables are used
* for computation (e.g., for computing quadratic key cube, results for
* linear key cube are used).
*
* isSuperpoly is standard ULONG array of size outputWidthUlong,
* keyCubes is array of vectors, each vector for each order of computation.
*
* No sub-cubes are computed (no optimization).
*
* @param wPlain
* @param wKey
* @param startOrder
* @param stopOrder
* @param termMask
* @param keyCubes
* @param isSuperpoly
* @return
*/
int keyCube(uint wPlain, uint wKey, uint startOrder, uint stopOrder,
const ULONG * termMask, std::vector<ULONG> * keyCubes, ULONG * isSuperpoly) const;
/**
* Computes key cube on the given data.
* Suitable for parallelization since has step & offset for particular combination
* to perform.
*
* Computes only one order since problem is very difficult to parallelize
* across multiple orders.
*
* @param wPlain Hamming weight of the plaintext cube.
* @param wKey Hamming weight of the key cube to compute.
* @param orderCtr Order of the terms.
* @param subCubesLimit Number of sub cubes to compute in parallel.
* @param curSubCube Computational sub-cube in use.
* @param step Number of threads used during this computation.
* @param offset Offset to use in parallelized computation.
* @param termMask Plaintext term mask.
* @param keyCubes KeyCubes to use & to store result to.
* @param isSuperpoly Is super poly signalizing register.
* @return
*/
int keyCubePart(uint wPlain, uint wKey, uint orderCtr,
uint subCubesLimit, uint curSubCube, uint step, uint offset,
const ULONG * termMask, std::vector<ULONG> * keyCubes, ULONG * isSuperpoly) const;
/**
* Cube attack.
*
* @param wPlain
* @param wKey
* @param numRelations
* @param subCubesLimit
* @param saveRelations
* @param dumpAllRelations If true all relations (also null ones) will be dumped.
If true, cube attack will not work, just for randomness test of the
coefficient distribution.
* @return
*/
int cubeAttack(uint wPlain, uint wKey, uint numRelations, uint subCubesLimit,
bool saveRelations=true, bool dumpAllRelations=false) const;
/**
* Online phase of the cube attack. Key is fixed, goal is to determine it.
* We have to determine b_t for each relation:
*
* \Sum_{v \in C_t} f(v,x) = b_t
* a_1x_1 + a_2x_2 + \dots + a_nx_n + c = b_t (this is for one relation)
*
* From this we get system of n variables and more than n equations we want
* to solve with GB or Gaussian elimination.
*
* @param keyRelationsVector
* @param input Input block with prepared MAC key.
* @param solution Recovered key will be stored here
* @return
*/
long cubeOnlineAttack(CubeRelations_vector & keyRelationsVector, const uchar * input, uchar * solvedKey) const;
/**
* Returns current date time as a formatted string.
* @return
*/
const std::string currentDateTime() const;
/**
* Initializes FGb library.
* @param numVariables
*/
void initFGb(uint numVariables) const;
/**
* Deinitializes FGb library.
*/
void deinitFGb() const;
/**
* Reset FGb internal memory.
* @param output
* @param size
* @param iBuff
*/
void resetFGb() const;
/**
* Returns number of variables for current cipher and key-bits-to-zero setting.
* @return
*/
uint getNumVariables() const;
std::vector<ULONG> * getCoefficients() { return coefficients; }
ICipher * getCipher() const { return cip; }
void setCipher(ICipher * cip);
uint getOrderLimit() const { return orderLimit; }
uint getThreadCount() const { return threadCount; }
void setThreadCount(uint threadCount) { this->threadCount = threadCount; }
uint getKeybitsToZero() const { return keybitsToZero; }
void setKeybitsToZero(uint keybitsToZero) { this->keybitsToZero = keybitsToZero; }
void setPoly2Take(const std::vector<std::string> & map);
bool isPoly2Take(uint polyIdx) const;
uint getVerboseLvl() const { return verboseLvl; }
void setVerboseLvl(uint verboseLvl) { this->verboseLvl = verboseLvl; }
void genMessages();
};
class CubeRelations_t {
public:
// Public variables (plaintext bits)
std::vector<ULONG> termMask;
// Bitmask of output polynomials having superpoly in this polynomial.
std::vector<ULONG> isSuperpoly;
// Hamming weight of the vector above.
uint numSuperpolys;
// Size of the key cube.
uint wkey;
// Superpolys for each output polynomial (vectorized representation).
std::vector<ULONG> superpolys[MAX_SUPERPOLY_ORDER];
CubeRelations_t() {}
virtual ~CubeRelations_t() {}
friend class boost::serialization::access;
// When the class Archive corresponds to an output archive, the
// & operator is defined similar to <<. Likewise, when the class Archive
// is a type of input archive the & operator is defined similar to >>.
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & BOOST_SERIALIZATION_NVP(termMask);
ar & BOOST_SERIALIZATION_NVP(isSuperpoly);
ar & BOOST_SERIALIZATION_NVP(numSuperpolys);
ar & BOOST_SERIALIZATION_NVP(wkey);
ar & BOOST_SERIALIZATION_NVP(superpolys);
}
};
class CubeRelations_vector {
public:
// Public variables (plaintext bits).
std::vector<CubeRelations_t> stor;
// Total number of relations stored (for all polynomials together).
uint totalRelations;
CubeRelations_vector() : totalRelations(0) {}
virtual ~CubeRelations_vector() {}
std::vector<CubeRelations_t> & get() { return stor; }
uint getTotal() const { return totalRelations; }
void setTotal(uint t) { this->totalRelations = t; }
uint * getTotalPtr() { return &totalRelations; }
friend class boost::serialization::access;
// When the class Archive corresponds to an output archive, the
// & operator is defined similar to <<. Likewise, when the class Archive
// is a type of input archive the & operator is defined similar to >>.
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & BOOST_SERIALIZATION_NVP(totalRelations);
ar & BOOST_SERIALIZATION_NVP(stor);
}
};
#endif /* APPROXIMATION_H */