From 32950fe8d4ba4df6c9ba8b51afcf057c87250bd2 Mon Sep 17 00:00:00 2001 From: Marcel Keller Date: Thu, 4 Nov 2021 16:22:45 +1100 Subject: [PATCH] Maintenance. --- BMR/RealProgramParty.hpp | 2 - BMR/Register.h | 3 + CHANGELOG.md | 9 ++ CONFIG | 4 +- Compiler/GC/types.py | 2 + Compiler/allocator.py | 2 + Compiler/floatingpoint.py | 2 + Compiler/instructions.py | 109 +++++++++++++++++++++- Compiler/instructions_base.py | 12 ++- Compiler/ml.py | 136 +++++++++++++++++++++------ Compiler/program.py | 3 +- Compiler/types.py | 150 ++++++++++++++++++++++++------ ECDSA/fake-spdz-ecdsa-party.cpp | 4 +- ECDSA/mascot-ecdsa-party.cpp | 2 + ECDSA/ot-ecdsa-party.hpp | 2 - FHEOffline/PairwiseMachine.cpp | 1 + FHEOffline/Producer.cpp | 3 + GC/AtlasSecret.cpp | 7 -- GC/AtlasShare.h | 2 - GC/CcdPrep.h | 10 +- GC/CcdPrep.hpp | 1 + GC/CcdShare.h | 7 -- GC/FakeSecret.h | 2 + GC/MaliciousCcdShare.h | 7 -- GC/NoShare.h | 13 ++- GC/Processor.h | 2 +- GC/Processor.hpp | 20 ++-- GC/RepPrep.h | 1 - GC/RepPrep.hpp | 7 -- GC/RuntimeBranching.h | 5 + GC/Secret.h | 4 +- GC/Secret.hpp | 6 -- GC/SemiHonestRepPrep.h | 4 - GC/SemiPrep.cpp | 5 - GC/SemiPrep.h | 1 - GC/SemiSecret.h | 3 + GC/ShareSecret.h | 3 + GC/ShareThread.h | 7 +- GC/ShareThread.hpp | 33 +++---- GC/Thread.hpp | 6 +- GC/ThreadMaster.hpp | 10 ++ GC/TinierShare.h | 5 - GC/TinierSharePrep.h | 3 - GC/TinierSharePrep.hpp | 11 +-- GC/TinyPrep.hpp | 2 + GC/TinySecret.h | 22 +++++ GC/TinyShare.h | 7 -- Machines/TripleMachine.cpp | 2 +- Machines/emulate.cpp | 3 + Machines/real-bmr-party.cpp | 2 + Makefile | 29 +++--- Math/FixedVec.h | 5 + Math/Integer.h | 4 + Math/Integer.hpp | 15 +++ Math/gf2n.cpp | 8 ++ Math/gf2n.h | 2 + Math/gf2nlong.h | 23 +++++ Math/gfpvar.cpp | 8 +- Math/gfpvar.h | 2 + Networking/CryptoPlayer.cpp | 52 ++++++++--- Networking/CryptoPlayer.h | 1 - Networking/Player.h | 3 +- Networking/sockets.cpp | 4 +- Networking/ssl_sockets.h | 6 +- OT/NPartyTripleGenerator.hpp | 6 ++ Processor/DataPositions.cpp | 7 ++ Processor/Data_Files.h | 32 ++++++- Processor/Data_Files.hpp | 43 ++++++++- Processor/Input.h | 13 +++ Processor/InputTuple.h | 5 + Processor/Instruction.h | 11 +-- Processor/Instruction.hpp | 70 ++++++++------ Processor/Machine.h | 10 +- Processor/Machine.hpp | 21 ++--- Processor/Memory.h | 27 ++++-- Processor/Memory.hpp | 34 +++---- Processor/OfflineMachine.hpp | 8 +- Processor/Online-Thread.h | 2 +- Processor/Online-Thread.hpp | 8 +- Processor/OnlineMachine.hpp | 2 +- Processor/OnlineOptions.cpp | 95 ++++++++++--------- Processor/OnlineOptions.h | 2 + Processor/PrepBase.cpp | 7 -- Processor/Processor.h | 48 +++++----- Processor/Processor.hpp | 37 +++----- Processor/ProcessorBase.cpp | 15 ++- Processor/ProcessorBase.h | 7 +- Processor/ProcessorBase.hpp | 3 +- Processor/RingMachine.hpp | 2 +- Programs/Source/mnist_49.mpc | 1 + Programs/Source/mnist_full_A.mpc | 1 + Programs/Source/mnist_full_B.mpc | 1 + Programs/Source/mnist_full_C.mpc | 1 + Programs/Source/mnist_full_D.mpc | 1 + Programs/Source/tf.mpc | 2 + Protocols/Atlas.h | 4 + Protocols/AtlasPrep.h | 4 + Protocols/Beaver.h | 3 + Protocols/ChaiGearPrep.h | 3 + Protocols/CowGearPrep.h | 3 + Protocols/FakePrep.h | 10 ++ Protocols/FakeProtocol.h | 69 ++++++++++++++ Protocols/Hemi.h | 3 + Protocols/Hemi.hpp | 3 + Protocols/HemiMatrixPrep.h | 3 + Protocols/HemiPrep.h | 3 + Protocols/HemiShare.h | 1 + Protocols/HighGearKeyGen.h | 3 + Protocols/HighGearKeyGen.hpp | 4 + Protocols/LowGearKeyGen.h | 6 ++ Protocols/LowGearKeyGen.hpp | 3 + Protocols/MAC_Check.h | 18 ++++ Protocols/MAC_Check.hpp | 8 +- Protocols/MAC_Check_Base.h | 13 ++- Protocols/MalRepRingPrep.h | 7 ++ Protocols/MaliciousRepMC.h | 3 + Protocols/MaliciousRepPrep.h | 6 ++ Protocols/MaliciousShamirMC.h | 3 + Protocols/MamaPrep.h | 3 + Protocols/MascotPrep.h | 12 +++ Protocols/NoShare.h | 1 + Protocols/PostSacrifice.h | 3 + Protocols/Rep4.h | 3 + Protocols/RepRingOnlyEdabitPrep.h | 3 + Protocols/Replicated.h | 19 ++++ Protocols/ReplicatedInput.h | 6 ++ Protocols/ReplicatedMC.h | 3 + Protocols/ReplicatedPrep.h | 37 +++++++- Protocols/ReplicatedPrep.hpp | 43 ++++++--- Protocols/ReplicatedPrep2k.h | 3 + Protocols/RingOnlyPrep.h | 3 + Protocols/SPDZ.h | 3 + Protocols/Semi2k.h | 3 + Protocols/SemiInput.h | 3 + Protocols/SemiMC.h | 6 ++ Protocols/SemiPrep.h | 3 + Protocols/SemiPrep2k.h | 3 + Protocols/Shamir.h | 3 + Protocols/Shamir.hpp | 6 +- Protocols/ShamirInput.h | 7 ++ Protocols/ShamirMC.h | 6 ++ Protocols/ShuffleSacrifice.h | 3 + Protocols/SohoPrep.h | 3 + Protocols/Spdz2kPrep.h | 3 + Protocols/SpdzWise.h | 3 + Protocols/SpdzWiseInput.h | 3 + Protocols/SpdzWisePrep.h | 3 + Protocols/SpdzWiseRing.h | 3 + Protocols/SpdzWiseRingPrep.h | 4 + Protocols/SpdzWiseShare.h | 1 + Protocols/SpdzWiseShare.hpp | 6 ++ Protocols/dabit.h | 5 + Protocols/fake-stuff.h | 16 +++- Protocols/fake-stuff.hpp | 54 ++--------- README.md | 23 +++-- Scripts/run-common.sh | 2 +- Scripts/yao.sh | 14 +-- Tools/Buffer.cpp | 38 ++++++-- Tools/Buffer.h | 41 +++++++- Tools/Exceptions.cpp | 28 +++++- Tools/Exceptions.h | 23 +++-- Tools/aes-arm.h | 32 +++---- Tools/cpu_support.h | 7 ++ Utils/Check-Offline-Z2k.cpp | 3 + Utils/Check-Offline.cpp | 6 +- Utils/Fake-Offline.cpp | 53 +++-------- Utils/check-passive.cpp | 4 + Yao/YaoEvalWire.cpp | 30 +++++- Yao/YaoEvalWire.h | 1 + Yao/YaoEvaluator.cpp | 3 +- Yao/YaoGarbleWire.cpp | 36 ++++++- Yao/YaoGarbleWire.h | 2 + Yao/YaoGarbler.cpp | 9 ++ Yao/YaoPlayer.cpp | 58 ++---------- compile.py | 2 +- doc/Doxyfile | 2 +- doc/_static/custom.css | 3 + doc/add-protocol.rst | 6 +- doc/conf.py | 3 + doc/gen-instructions.py | 2 +- doc/instructions.rst | 1 - doc/low-level.rst | 148 +++++++++++++++++++++++++++++ doc/networking.rst | 2 + doc/non-linear.rst | 42 ++++++++- doc/troubleshooting.rst | 23 ++++- 185 files changed, 1818 insertions(+), 654 deletions(-) create mode 100644 doc/_static/custom.css diff --git a/BMR/RealProgramParty.hpp b/BMR/RealProgramParty.hpp index 22438deb4..0c97f9bd8 100644 --- a/BMR/RealProgramParty.hpp +++ b/BMR/RealProgramParty.hpp @@ -112,8 +112,6 @@ RealProgramParty::RealProgramParty(int argc, const char** argv) : garble_processor.reset(program); this->processor.open_input_file(N.my_num(), 0); - T::bit_type::mac_key_type::init_field(); - GC::ShareThread share_thread(N, online_opts, *P, 0, usage); shared_proc = new SubProcessor(dummy_proc, *MC, *prep, *P); auto& inputter = shared_proc->input; diff --git a/BMR/Register.h b/BMR/Register.h index 886155d79..4d0c1b074 100644 --- a/BMR/Register.h +++ b/BMR/Register.h @@ -243,6 +243,9 @@ class Phase template static T get_input(int from, GC::Processor& processor, int n_bits) { return T::input(from, processor.get_input(n_bits), n_bits); } + template + static void reveal_inst(GC::Processor& processor, const vector& args) + { processor.reveal(args); } template static void convcbit(Integer& dest, const GC::Clear& source, T&) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e23aaa68..8c9be9e5b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ The changelog explains changes pulled through from the private development repository. Bug fixes and small enhancements are committed between releases and not documented here. +## 0.2.8 (Nov 4, 2021) + +- Tested on Apple laptop with ARM chip +- Restore trusted client interface +- Directly accessible softmax function +- Signature in preprocessing files to reduce confusing errors +- Improved error messages for connection issues +- Documentation of low-level share types and protocol pairs + ## 0.2.7 (Sep 17, 2021) - Optimized matrix multiplication in Hemi diff --git a/CONFIG b/CONFIG index 5f12d2c33..ba6855ea9 100644 --- a/CONFIG +++ b/CONFIG @@ -88,7 +88,9 @@ CPPFLAGS = $(CFLAGS) LD = $(CXX) ifeq ($(OS), Darwin) +# for boost with OpenSSL 3 +CFLAGS += -Wno-error=deprecated-declarations ifeq ($(USE_NTL),1) -CFLAGS += -Wno-error=unused-parameter +CFLAGS += -Wno-error=unused-parameter -Wno-error=deprecated-copy endif endif diff --git a/Compiler/GC/types.py b/Compiler/GC/types.py index a1384475b..6a5e39f13 100644 --- a/Compiler/GC/types.py +++ b/Compiler/GC/types.py @@ -309,6 +309,8 @@ def __invert__(self): res = type(self)() inst.notcb(self.n, res, self) return res + def __eq__(self, other): + raise CompilerError('equality not implemented') def print_reg(self, desc=''): inst.print_regb(self, desc) def print_reg_plain(self): diff --git a/Compiler/allocator.py b/Compiler/allocator.py index 6a1472d7b..7ce9896b1 100644 --- a/Compiler/allocator.py +++ b/Compiler/allocator.py @@ -19,6 +19,8 @@ def __init__(self): self.by_address = {} def by_size(self, size): + if size >= 2 ** 32: + raise CompilerError('size exceeds addressing capability') return self.by_logsize[int(math.log(size, 2))][size] def push(self, address, size): diff --git a/Compiler/floatingpoint.py b/Compiler/floatingpoint.py index 66de0859a..a15a62dd9 100644 --- a/Compiler/floatingpoint.py +++ b/Compiler/floatingpoint.py @@ -290,6 +290,7 @@ def BitDecRing(a, k, m): return [types.sint.conv(bit) for bit in reversed(bits)][::-1] def BitDecFieldRaw(a, k, m, kappa, bits_to_compute=None): + instructions_base.set_global_vector_size(a.size) r_dprime = types.sint() r_prime = types.sint() c = types.cint() @@ -298,6 +299,7 @@ def BitDecFieldRaw(a, k, m, kappa, bits_to_compute=None): pow2 = two_power(k + kappa) asm_open(c, pow2 + two_power(k) + a - two_power(m)*r_dprime - r_prime) res = r[0].bit_adder(r, list(r[0].bit_decompose_clear(c,m))) + instructions_base.reset_global_vector_size() return res def BitDecField(a, k, m, kappa, bits_to_compute=None): diff --git a/Compiler/instructions.py b/Compiler/instructions.py index 0cd9e6b59..8069b0ffb 100644 --- a/Compiler/instructions.py +++ b/Compiler/instructions.py @@ -1496,6 +1496,14 @@ class cond_print_plain(base.IOInstruction): code = base.opcodes['CONDPRINTPLAIN'] arg_format = ['c', 'c', 'c'] + def __init__(self, *args, **kwargs): + base.Instruction.__init__(self, *args, **kwargs) + self.size = args[1].size + args[2].set_size(self.size) + + def get_code(self): + return base.Instruction.get_code(self, self.size) + class print_int(base.IOInstruction): """ Output clear integer register. @@ -1591,7 +1599,16 @@ def has_var_args(self): return True class readsockets(base.IOInstruction): - """Read a variable number of secret shares + MACs from socket for a client id and store in registers""" + """ Read a variable number of secret shares (potentially with MAC) + from a socket for a client id and store them in registers. If the + protocol uses MACs, the client should be different for every party. + + :param: client id (regint) + :param: vector size (int) + :param: source (sint) + :param: (repeat source)... + + """ __slots__ = [] code = base.opcodes['READSOCKETS'] arg_format = tools.chain(['ci','int'], itertools.repeat('sw')) @@ -1628,6 +1645,25 @@ class writesocketc(base.IOInstruction): def has_var_args(self): return True +class writesockets(base.IOInstruction): + """ Write a variable number of secret shares (potentially with MAC) + from registers into a socket for a specified client id. If the + protocol uses MACs, the client should be different for every party. + + :param: client id (regint) + :param: message type (must be 0) + :param: vector size (int) + :param: source (sint) + :param: (repeat source)... + + """ + __slots__ = [] + code = base.opcodes['WRITESOCKETS'] + arg_format = tools.chain(['ci', 'int', 'int'], itertools.repeat('s')) + + def has_var_args(self): + return True + class writesocketshare(base.IOInstruction): """ Write a variable number of shares (without MACs) from secret registers into socket for a specified client id. @@ -2384,5 +2420,76 @@ def expand(self): subs(a, self.args[1], self.args[2]) comparison.LTZ(self.args[0], a, self.args[3], self.args[4]) +# placeholder for documentation +class cisc: + """ Meta instruction for emulation. This instruction is only generated + when using ``-K`` with ``compile.py``. The header looks as follows: + + :param: number of arguments after name plus one + :param: name (16 bytes, zero-padded) + + Currently, the following names are supported: + + LTZ + Less than zero. + + :param: number of arguments in this unit (must be 6) + :param: vector size + :param: result (sint) + :param: input (sint) + :param: bit length + :param: (ignored) + :param: (repeat)... + + Trunc + Truncation. + + :param: number of arguments in this unit (must be 8) + :param: vector size + :param: result (sint) + :param: input (sint) + :param: bit length + :param: number of bits to truncate + :param: (ignored) + :param: 0 for unsigned or 1 for signed + :param: (repeat)... + + FPDiv + Fixed-point division. Division by zero results in zero without error. + + :param: number of arguments in this unit (must be at least 7) + :param: vector size + :param: result (sint) + :param: dividend (sint) + :param: divisor (sint) + :param: (ignored) + :param: fixed-point precision + :param: (repeat)... + + exp2_fx + Fixed-point power of two. + + :param: number of arguments in this unit (must be at least 6) + :param: vector size + :param: result (sint) + :param: exponent (sint) + :param: (ignored) + :param: fixed-point precision + :param: (repeat)... + + log2_fx + Fixed-point logarithm with base 2. + + :param: number of arguments in this unit (must be at least 6) + :param: vector size + :param: result (sint) + :param: input (sint) + :param: (ignored) + :param: fixed-point precision + :param: (repeat)... + + """ + code = base.opcodes['CISC'] + # hack for circular dependency from Compiler import comparison diff --git a/Compiler/instructions_base.py b/Compiler/instructions_base.py index 66b55fd9d..38fd97d29 100644 --- a/Compiler/instructions_base.py +++ b/Compiler/instructions_base.py @@ -481,7 +481,16 @@ def new_instructions(self, size, regs): def expand_merged(self, skip): if function.__name__ in skip: - return [self], 0 + good = True + for call in self.calls: + if not good: + break + for arg in call[0]: + if isinstance(arg, program.curr_tape.Register) and \ + not issubclass(type(self.calls[0][0][0]), type(arg)): + good = False + if good: + return [self], 0 tape = program.curr_tape block = tape.BasicBlock(tape, None, None) tape.active_basicblock = block @@ -520,6 +529,7 @@ def get_bytes(self): String.check(name) res += String.encode(name) for call in self.calls: + call[1].pop('nearest', None) assert not call[1] res += int_to_bytes(len(call[0]) + 2) res += int_to_bytes(call[0][0].size) diff --git a/Compiler/ml.py b/Compiler/ml.py index 42389ae83..a8be2d533 100644 --- a/Compiler/ml.py +++ b/Compiler/ml.py @@ -155,6 +155,26 @@ def op(a, b): return comp.if_else(a[0], b[0]), comp.if_else(a[1], b[1]) return tree_reduce(op, enumerate(x))[0] +def softmax(x): + """ Softmax. + + :param x: vector or list of sfix + :returns: sfix vector + """ + return softmax_from_exp(exp_for_softmax(x)[0]) + +def exp_for_softmax(x): + m = util.max(x) + mv = m.expand_to_vector(len(x)) + try: + x = x.get_vector() + except AttributeError: + x = sfix(x) + return (x - mv > -get_limit(x)).if_else(exp(x - mv), 0), m + +def softmax_from_exp(x): + return x / sum(x) + report_progress = False def progress(x): @@ -464,10 +484,7 @@ def _(i): self.losses[i] = -sfix.dot_product( self.Y[batch[i]].get_vector(), log_e(div)) else: - m = util.max(self.X[i]) - mv = m.expand_to_vector(d_out) - x = self.X[i].get_vector() - e = (x - mv > -get_limit(x)).if_else(exp(x - mv), 0) + e, m = exp_for_softmax(self.X[i]) self.exp[i].assign_vector(e) if self.compute_loss: true_X = sfix.dot_product(self.Y[batch[i]], self.X[i]) @@ -532,11 +549,8 @@ def _(j): return @for_range_opt_multithread(self.n_threads, len(batch)) def _(i): - for j in range(d_out): - dividend = self.exp[i][j] - divisor = sum(self.exp[i]) - div = (divisor > 0.1).if_else(dividend / divisor, 0) - self.nabla_X[i][j] = (-self.Y[batch[i]][j] + div) + div = softmax_from_exp(self.exp[i]) + self.nabla_X[i][:] = -self.Y[batch[i]][:] + div self.maybe_debug_backward(batch) def maybe_debug_backward(self, batch): @@ -588,7 +602,7 @@ class DenseBase(Layer): nablas = lambda self: (self.nabla_W, self.nabla_b) def output_weights(self): - print_ln('%s', self.W.reveal_nested()) + self.W.print_reveal_nested() print_ln('%s', self.b.reveal_nested()) def backward_params(self, f_schur_Y, batch): @@ -1316,7 +1330,7 @@ def input_from(self, player, raw=False): self.bias.input_from(player, raw=raw) def output_weights(self): - print_ln('%s', self.weights.reveal_nested()) + self.weights.print_reveal_nested() print_ln('%s', self.bias.reveal_nested()) def dot_product(self, iv, wv, out_y, out_x, out_c): @@ -1942,7 +1956,12 @@ def _(_): for label, X in enumerate(self.X_by_label): indices = regint.Array(n * n_per_epoch) indices_by_label.append(indices) - indices.assign(regint.inc(len(indices), 0, 1, 1, len(X))) + indices.assign(regint.inc(len(X))) + missing = len(indices) - len(X) + if missing: + indices.assign_vector( + regint.get_random(int(math.log2(len(X))), size=missing), + base=len(X)) if self.always_shuffle or n_per_epoch > 1: indices.shuffle() loss_sum = MemValue(sfix(0)) @@ -2050,6 +2069,8 @@ def run_by_args(self, program, n_runs, batch_size, test_X, test_Y, self.time_layers = 'time_layers' in program.args self.revealing_correctness = not 'no_acc' in program.args self.layers[-1].compute_loss = not 'no_loss' in program.args + if 'full_cisc' in program.args: + program.options.keep_cisc = 'FPDiv,exp2_fx,log2_fx' model_input = 'model_input' in program.args acc_first = model_input and not 'train_first' in program.args if model_input: @@ -2058,12 +2079,14 @@ def run_by_args(self, program, n_runs, batch_size, test_X, test_Y, else: self.reset() if 'one_iter' in program.args: + print_float_prec(16) self.output_weights() print_ln('loss') - print_ln('%s', self.eval( - self.layers[0].X.get_part(0, batch_size)).reveal_nested()) + self.eval( + self.layers[0].X.get_part(0, batch_size), + batch_size=batch_size).print_reveal_nested() for layer in self.layers: - print_ln('%s', layer.X.get_part(0, batch_size).reveal_nested()) + layer.X.get_part(0, batch_size).print_reveal_nested() print_ln('%s', self.layers[-1].Y.get_part(0, batch_size).reveal_nested()) batch = Array.create_from(regint.inc(batch_size)) self.forward(batch=batch, training=True) @@ -2083,9 +2106,10 @@ def _(i): return N = self.layers[0].X.sizes[0] n_trained = (N + batch_size - 1) // batch_size * batch_size - print_ln('train_acc: %s (%s/%s)', - cfix(self.n_correct, k=63, f=31) / n_trained, - self.n_correct, n_trained) + if not acc_first: + print_ln('train_acc: %s (%s/%s)', + cfix(self.n_correct, k=63, f=31) / n_trained, + self.n_correct, n_trained) if test_X and test_Y: n_test = len(test_Y) n_correct, loss = self.reveal_correctness(test_X, test_Y, @@ -2500,16 +2524,30 @@ def predict(self, x, batch_size=None): batch_size = min(batch_size, self.batch_size) return self.opt.eval(x, batch_size=batch_size) -def solve_linear(A, b, n_iterations, progress=False): - """ Iterative linear solution approximation. """ +def solve_linear(A, b, n_iterations, progress=False, n_threads=None, + stop=False, already_symmetric=False, precond=False): + """ Iterative linear solution approximation for :math:`Ax=b`. + + :param progress: print some information on the progress (implies revealing) + :param n_threads: number of threads to use + :param stop: whether to stop when converged (implies revealing) + + """ assert len(b) == A.sizes[0] x = sfix.Array(A.sizes[1]) x.assign_vector(sfix.get_random(-1, 1, size=len(x))) - AtA = sfix.Matrix(len(x), len(x)) - AtA[:] = A.direct_trans_mul(A) + if already_symmetric: + AtA = A + r = Array.create_from(b - AtA * x) + else: + AtA = sfix.Matrix(len(x), len(x)) + A.trans_mul_to(A, AtA, n_threads=n_threads) + r = Array.create_from(A.transpose() * b - AtA * x) + if precond: + return solve_linear_diag_precond(AtA, b, x, r, n_iterations, + progress, stop) v = sfix.Array(A.sizes[1]) v.assign_all(0) - r = Array.create_from(A.transpose() * b - AtA * x) Av = sfix.Array(len(x)) @for_range(n_iterations) def _(i): @@ -2523,10 +2561,43 @@ def _(i): if progress: print_ln('%s alpha=%s vr=%s v_norm=%s', i, alpha.reveal(), vr.reveal(), v_norm.reveal()) + if stop: + return (alpha > 0).reveal() return x -def mr(A, n_iterations): - """ Iterative matrix inverse approximation. """ +def solve_linear_diag_precond(A, b, x, r, n_iterations, progress=False, + stop=False): + m = 1 / A.diag() + mr = Array.create_from(m * r[:]) + d = Array.create_from(mr) + @for_range(n_iterations) + def _(i): + Ad = A * d + d_norm = sfix.dot_product(d, Ad) + alpha = (d_norm == 0).if_else(0, sfix.dot_product(r, mr) / d_norm) + x[:] = x[:] + alpha * d[:] + r_norm = sfix.dot_product(r, mr) + r[:] = r[:] - alpha * Ad + tmp = m * r[:] + beta = (r_norm == 0).if_else(0, sfix.dot_product(r, tmp) / r_norm) + mr[:] = tmp + d[:] = tmp + beta * d + if progress: + print_ln('%s alpha=%s beta=%s r_norm=%s d_norm=%s', i, + alpha.reveal(), beta.reveal(), r_norm.reveal(), + d_norm.reveal()) + if stop: + return (alpha > 0).reveal() + return x + +def mr(A, n_iterations, stop=False): + """ Iterative matrix inverse approximation. + + :param A: matrix to invert + :param n_iterations: maximum number of iterations + :param stop: whether to stop when converged (implies revealing) + + """ assert len(A.sizes) == 2 assert A.sizes[0] == A.sizes[1] M = A.same_shape() @@ -2536,5 +2607,18 @@ def _(i): e = sfix.Array(n) e.assign_all(0) e[i] = 1 - M[i] = solve_linear(A, e, n_iterations) + M[i] = solve_linear(A, e, n_iterations, stop=stop) return M.transpose() + +def var(x): + """ Variance. """ + mean = MemValue(type(x[0])(0)) + @for_range_opt(len(x)) + def _(i): + mean.iadd(x[i]) + mean /= len(x) + res = MemValue(type(x[0])(0)) + @for_range_opt(len(x)) + def _(i): + res.iadd((x[i] - mean.read()) ** 2) + return res.read() diff --git a/Compiler/program.py b/Compiler/program.py index ebc1601c8..19ce52480 100644 --- a/Compiler/program.py +++ b/Compiler/program.py @@ -690,8 +690,9 @@ def add_usage(self, req_node): def expand_cisc(self): new_instructions = [] - if self.parent.program.options.keep_cisc: + if self.parent.program.options.keep_cisc != None: skip = ['LTZ', 'Trunc'] + skip += self.parent.program.options.keep_cisc.split(',') else: skip = [] for inst in self.instructions: diff --git a/Compiler/types.py b/Compiler/types.py index 917eba752..151c805ea 100644 --- a/Compiler/types.py +++ b/Compiler/types.py @@ -1161,7 +1161,7 @@ def print_if(self, string): cond_print_str(self, string) def output_if(self, cond): - cond_print_plain(self.conv(cond), self, cint(0)) + cond_print_plain(self.conv(cond), self, cint(0, size=self.size)) class cgf2n(_clear, _gf2n): @@ -1922,14 +1922,7 @@ def load_other(self, val): r = self.get_dabit() movs(self, r[0].bit_xor((r[1] ^ val).reveal().to_regint_by_bit())) elif isinstance(val, sbitvec): - assert(sum(x.n for x in val.v) == self.size) - for val_part, base in zip(val, range(0, self.size, 64)): - left = min(64, self.size - base) - r = self.get_dabit(size=left) - v = regint(size=left) - bitdecint_class(regint((r[1] ^ val_part).reveal()), *v) - part = r[0].bit_xor(v) - vmovs(left, self.get_vector(base, left), part) + movs(self, sint.bit_compose(val)) else: self.load_clear(self.clear_type(val)) @@ -1939,6 +1932,8 @@ def bit_compose(cls, bits): :param bits: iterable of any type convertible to sint """ from Compiler.GC.types import sbits, sbitintvec + if isinstance(bits, sbits): + bits = bits.bit_decompose() bits = list(bits) if (program.use_edabit() or program.use_split()) and isinstance(bits[0], sbits): if program.use_edabit(): @@ -2112,6 +2107,11 @@ class sint(_secret, _int): thereof or sbits/sbitvec/sfix) :param size: vector size (int), defaults to 1 or size of list + When converting :py:class:`~Compiler.GC.types.sbits`, the result is a + vector of bits, and when converting + :py:class:`~Compiler.GC.types.sbitvec`, the result is a vector of values + with bit length equal the length of the input. + """ __slots__ = [] instruction_type = 'modp' @@ -2278,6 +2278,17 @@ def read_from_socket(cls, client_id, n=1): else: return res + @vectorized_classmethod + def write_to_socket(cls, client_id, values, + message_type=ClientMessageType.NoType): + """ Send a list of shares and MAC shares to a client socket. + + :param client_id: regint + :param values: list of sint + + """ + writesockets(client_id, message_type, values[0].size, *values) + @vectorize def write_share_to_socket(self, client_id, message_type=ClientMessageType.NoType): """ Send only share to socket """ @@ -2339,6 +2350,7 @@ def direct_matrix_mul(cls, A, B, n, m, l, reduce=None, indices=None): @vectorize_init def __init__(self, val=None, size=None): + from .GC.types import sbitvec if isinstance(val, personal): size = val._v.size super(sint, self).__init__('s', size=size) @@ -2346,6 +2358,8 @@ def __init__(self, val=None, size=None): elif isinstance(val, _fix): super(sint, self).__init__('s', size=val.v.size) self.load_other(val.v.round(val.k, val.f)) + elif isinstance(val, sbitvec): + super(sint, self).__init__('s', val=val, size=val[0].n) else: super(sint, self).__init__('s', val=val, size=size) @@ -3747,13 +3761,14 @@ def __rtruediv__(self, other): other = parse_type(other, self.k, self.f) return other / self + @vectorize def print_plain(self): """ Clear fixed-point output. """ print_float_plain(cint.conv(self.v), cint(-self.f), \ cint(0), cint(0), cint(0)) def output_if(self, cond): - cond_print_plain(cint.conv(cond), self.v, cint(-self.f)) + cond_print_plain(cint.conv(cond), self.v, cint(-self.f, size=self.size)) @vectorize def binary_output(self, player=None): @@ -4028,7 +4043,8 @@ def set_precision_from_args(cls, program, adapt_ring=False): print('Nearest rounding instead of proabilistic ' 'for fixed-point computation') cls.round_nearest = True - if adapt_ring and program.options.ring: + if adapt_ring and program.options.ring \ + and 'fix_ring' not in program.args: need = 2 ** int(math.ceil(math.log(2 * cls.k, 2))) if need != int(program.options.ring): print('Changing computation modulus to 2^%d' % need) @@ -4094,6 +4110,8 @@ def __init__(self, _v=None, k=None, f=None, size=None): elif isinstance(_v, (MemValue, MemFix)): #this is a memvalue object self.v = type(self)(_v.read()).v + elif isinstance(_v, (list, tuple)): + self.v = self.int_type(list(self.conv(x).v for x in _v)) else: raise CompilerError('cannot convert %s to sfix' % _v) if not isinstance(self.v, self.int_type): @@ -4250,7 +4268,7 @@ def get_raw_input_from(cls, player): return cls._new(cls.int_type.get_raw_input_from(player)) @vectorized_classmethod - def get_random(cls, lower, upper): + def get_random(cls, lower, upper, symmetric=True): """ Uniform secret random number around centre of bounds. Actual range can be smaller but never larger. @@ -4261,8 +4279,19 @@ def get_random(cls, lower, upper): log_range = int(math.log(upper - lower, 2)) n_bits = log_range + cls.f average = lower + 0.5 * (upper - lower) - lower = average - 0.5 * 2 ** log_range - return cls._new(cls.int_type.get_random_int(n_bits)) + lower + real_range = (2 ** (n_bits) - 1) / 2 ** cls.f + lower = average - 0.5 * real_range + real_lower = round(lower * 2 ** cls.f) / 2 ** cls.f + r = cls._new(cls.int_type.get_random_int(n_bits)) + lower + if symmetric: + lowest = math.floor(lower * 2 ** cls.f) / 2 ** cls.f + print('randomness range [%f,%f], fringes half the probability' % \ + (lowest, lowest + 2 ** log_range)) + return cls.int_type.get_random_bit().if_else(r, -r + 2 * average) + else: + print('randomness range [%f,%f], %d bits' % \ + (real_lower, real_lower + real_range, n_bits)) + return r @classmethod def direct_matrix_mul(cls, A, B, n, m, l, reduce=True, indices=None): @@ -4985,6 +5014,7 @@ class cfloat(object): """ Helper class for printing revealed sfloats. """ __slots__ = ['v', 'p', 'z', 's', 'nan'] + @vectorize_init def __init__(self, v, p=None, z=None, s=None, nan=0): """ Parameters as with :py:class:`sfloat` but public. """ if s is None: @@ -4993,6 +5023,11 @@ def __init__(self, v, p=None, z=None, s=None, nan=0): parts = [cint.conv(x) for x in (v, p, z, s, nan)] self.v, self.p, self.z, self.s, self.nan = parts + @property + def size(self): + return self.v.size + + @vectorize def print_float_plain(self): """ Output. """ print_float_plain(self.v, self.p, self.z, self.s, self.nan) @@ -5389,15 +5424,7 @@ def __neg__(self): def shuffle(self): """ Insecure shuffle in place. """ - if self.value_type == regint: - self.assign(self.get_vector().shuffle()) - else: - @library.for_range(len(self)) - def _(i): - j = regint.get_random(64) % (len(self) - i) - tmp = self[i] - self[i] = self[i + j] - self[i + j] = tmp + self.assign_vector(self.get(regint.inc(len(self)).shuffle())) def reveal(self): """ Reveal the whole array. @@ -5411,6 +5438,13 @@ def reveal_list(self): reveal_nested = reveal_list + def print_reveal_nested(self, end='\n'): + """ Reveal and print as list. + + :param end: string to print after (default: line break) + """ + library.print_str('%s' + end, self.get_vector().reveal()) + def reveal_to_binary_output(self, player=None): """ Reveal to binary output if supported by type. @@ -5449,6 +5483,8 @@ def __str__(self): class SubMultiArray(_vectorizable): """ Multidimensional array functionality. Don't construct this directly, use :py:class:`MultiArray` instead. """ + check_indices = True + def __init__(self, sizes, value_type, address, index, debug=None): self.sizes = tuple(sizes) self.value_type = _get_type(value_type) @@ -5458,7 +5494,6 @@ def __init__(self, sizes, value_type, address, index, debug=None): self.address = None self.sub_cache = {} self.debug = debug - self.check_indices = True if debug: library.print_ln_if(self.address + reduce(operator.mul, self.sizes) * self.value_type.n_elements() > program.allocated_mem[self.value_type.reg_type], 'AOF%d:' % len(self.sizes) + self.debug) @@ -5467,8 +5502,6 @@ def __getitem__(self, index): :param index: public (regint/cint/int) :return: :py:class:`Array` if one-dimensional, :py:class:`SubMultiArray` otherwise""" - if util.is_constant(index) and index >= self.sizes[0]: - raise StopIteration if isinstance(index, slice) and index == slice(None): return self.get_vector() key = program.curr_block, str(index) @@ -5490,7 +5523,9 @@ def __getitem__(self, index): self.sub_cache[key] = \ SubMultiArray(self.sizes[1:], self.value_type, \ self.address, index, debug=self.debug) - return self.sub_cache[key] + res = self.sub_cache[key] + res.check_indices = self.check_indices + return res def __setitem__(self, index, other): """ Part assignment. @@ -5505,6 +5540,9 @@ def __len__(self): """ Size of top dimension. """ return self.sizes[0] + def __iter__(self): + return (self[i] for i in range(len(self))) + def assign_all(self, value): """ Assign the same value to all entries. @@ -5877,6 +5915,38 @@ def direct_trans_mul(self, other, reduce=True, indices=None): self.address, other.address, None, 1, other.sizes[1], reduce=reduce, indices=indices) + def trans_mul_to(self, other, res, n_threads=None): + """ + Matrix multiplication with the transpose of :py:obj:`self` + in the virtual machine. + + :param self: :py:class:`Matrix` / 2-dimensional :py:class:`MultiArray` + :param other: :py:class:`Matrix` / 2-dimensional :py:class:`MultiArray` + :param res: matrix of matching dimension to store result + :param n_threads: number of threads (default: single thread) + """ + @library.for_range_multithread(n_threads, 1, self.sizes[1]) + def _(i): + indices = [regint(i), regint.inc(self.sizes[0])] + indices += [regint.inc(i) for i in other.sizes] + res[i] = self.direct_trans_mul(other, indices=indices) + + def mul_trans_to(self, other, res, n_threads=None): + """ + Matrix multiplication with the transpose of :py:obj:`other` + in the virtual machine. + + :param self: :py:class:`Matrix` / 2-dimensional :py:class:`MultiArray` + :param other: :py:class:`Matrix` / 2-dimensional :py:class:`MultiArray` + :param res: matrix of matching dimension to store result + :param n_threads: number of threads (default: single thread) + """ + @library.for_range_multithread(n_threads, 1, self.sizes[0]) + def _(i): + indices = [regint(i), regint.inc(self.sizes[1])] + indices += [regint.inc(i) for i in reversed(other.sizes)] + res[i] = self.direct_mul_trans(other, indices=indices) + def direct_mul_to_matrix(self, other): """ Matrix multiplication in the virtual machine. @@ -5992,6 +6062,13 @@ def trace(self): assert self.sizes[0] == self.sizes[1] return sum(self[i][i] for i in range(self.sizes[0])) + def diag(self): + """ Matrix diagonal. """ + assert len(self.sizes) == 2 + assert self.sizes[0] == self.sizes[1] + n = self.sizes[0] + return self.array.get(regint.inc(n, 0, n + 1)) + def reveal_list(self): """ Reveal as list. """ return list(self.get_vector().reveal()) @@ -6007,6 +6084,21 @@ def f(sizes): return [f(sizes[1:]) for i in range(sizes[0])] return f(self.sizes) + def print_reveal_nested(self, end='\n'): + """ Reveal and print as nested list. + + :param end: string to print after (default: line break) + """ + if self.total_size() < program.options.budget: + library.print_str('%s' + end, self.reveal_nested()) + else: + library.print_str('[') + @library.for_range(len(self) - 1) + def _(i): + self[i].print_reveal_nested(end=', ') + self[len(self) - 1].print_reveal_nested(end='') + library.print_str(']' + end) + def reveal_to_binary_output(self, player=None): """ Reveal to binary output if supported by type. @@ -6042,6 +6134,10 @@ class MultiArray(SubMultiArray): a[2][:] = a[0][:] * a[1][:] """ + @staticmethod + def disable_index_checks(): + SubMultiArray.check_indices = False + def __init__(self, sizes, value_type, debug=None, address=None, alloc=True): if isinstance(address, Array): self.array = address diff --git a/ECDSA/fake-spdz-ecdsa-party.cpp b/ECDSA/fake-spdz-ecdsa-party.cpp index 6cc2fbcc8..f0e3257c6 100644 --- a/ECDSA/fake-spdz-ecdsa-party.cpp +++ b/ECDSA/fake-spdz-ecdsa-party.cpp @@ -3,6 +3,8 @@ * */ +#define NO_MIXED_CIRCUITS + #include "Networking/Server.h" #include "Networking/CryptoPlayer.h" #include "Math/gfp.h" @@ -49,8 +51,6 @@ int main(int argc, const char** argv) ArithmeticProcessor _({}, 0); BaseMachine machine; machine.ot_setups.push_back({P, false}); - GC::ShareThread thread(N, - OnlineOptions::singleton, P, {}, usage); SubProcessor proc(_, MCp, prep, P); pShare sk, __; diff --git a/ECDSA/mascot-ecdsa-party.cpp b/ECDSA/mascot-ecdsa-party.cpp index dc2edab31..87573593b 100644 --- a/ECDSA/mascot-ecdsa-party.cpp +++ b/ECDSA/mascot-ecdsa-party.cpp @@ -3,6 +3,8 @@ * */ +#define NO_MIXED_CIRCUITS + #include "GC/TinierSecret.h" #include "GC/TinyMC.h" #include "GC/VectorInput.h" diff --git a/ECDSA/ot-ecdsa-party.hpp b/ECDSA/ot-ecdsa-party.hpp index 1c4a442ae..58f35d4b0 100644 --- a/ECDSA/ot-ecdsa-party.hpp +++ b/ECDSA/ot-ecdsa-party.hpp @@ -106,8 +106,6 @@ void run(int argc, const char** argv) typename pShare::Direct_MC MCp(keyp); ArithmeticProcessor _({}, 0); typename pShare::TriplePrep sk_prep(0, usage); - GC::ShareThread thread(N, - OnlineOptions::singleton, P, {}, usage); SubProcessor sk_proc(_, MCp, sk_prep, P); pShare sk, __; // synchronize diff --git a/FHEOffline/PairwiseMachine.cpp b/FHEOffline/PairwiseMachine.cpp index 6ac3a82d4..e41fe1837 100644 --- a/FHEOffline/PairwiseMachine.cpp +++ b/FHEOffline/PairwiseMachine.cpp @@ -6,6 +6,7 @@ #include "FHEOffline/PairwiseMachine.h" #include "Tools/benchmarking.h" #include "Protocols/fake-stuff.h" +#include "Tools/Bundle.h" #include "Protocols/fake-stuff.hpp" diff --git a/FHEOffline/Producer.cpp b/FHEOffline/Producer.cpp index 5714b7224..9b143dd66 100644 --- a/FHEOffline/Producer.cpp +++ b/FHEOffline/Producer.cpp @@ -167,6 +167,8 @@ string open_prep_file(ofstream& outf, string data_type, int my_num, int thread_n throw runtime_error("cannot create directory " + dir); string file = prep_filename(data_type, my_num, thread_num, initial, dir); outf.open(file.c_str(),ios::out | ios::binary | (clear ? ios::trunc : ios::app)); + if (clear) + file_signature>().output(outf); if (outf.fail()) { throw file_error(file); } return file; } @@ -516,6 +518,7 @@ InputProducer::InputProducer(const Player& P, int thread_num, if (thread_num) file << "-" << thread_num; outf[j].open(file.str().c_str(), ios::out | ios::binary); + file_signature>().output(outf[j]); if (outf[j].fail()) { throw file_error(file.str()); diff --git a/GC/AtlasSecret.cpp b/GC/AtlasSecret.cpp index 2c396bfbc..92f290f31 100644 --- a/GC/AtlasSecret.cpp +++ b/GC/AtlasSecret.cpp @@ -24,11 +24,4 @@ AtlasShare::AtlasShare(const AtlasSecret& other) : { } -void AtlasShare::random() -{ - AtlasSecret tmp; - this->get_party().DataF.get_one(DATA_BIT, tmp); - *this = tmp.get_reg(0); -} - } diff --git a/GC/AtlasShare.h b/GC/AtlasShare.h index bad9e10eb..4b68dd4f3 100644 --- a/GC/AtlasShare.h +++ b/GC/AtlasShare.h @@ -63,8 +63,6 @@ class AtlasShare : public ::AtlasShare>, public ShareSecret { typename T::part_type::LivePrep part_prep; SubProcessor* part_proc; - ShareThread& thread; public: - CcdPrep(DataPositions& usage, ShareThread& thread) : - BufferPrep(usage), part_prep(usage, thread), part_proc(0), - thread(thread) + static const bool use_part = true; + + CcdPrep(DataPositions& usage) : + BufferPrep(usage), part_prep(usage), part_proc(0) { } CcdPrep(SubProcessor*, DataPositions& usage) : - CcdPrep(usage, ShareThread::s()) + CcdPrep(usage) { } diff --git a/GC/CcdPrep.hpp b/GC/CcdPrep.hpp index 62f0f097e..f9535350b 100644 --- a/GC/CcdPrep.hpp +++ b/GC/CcdPrep.hpp @@ -23,6 +23,7 @@ CcdPrep::~CcdPrep() template void CcdPrep::set_protocol(typename T::Protocol& protocol) { + auto& thread = ShareThread::s(); assert(thread.MC); part_proc = new SubProcessor( thread.MC->get_part_MC(), part_prep, protocol.get_part().P); diff --git a/GC/CcdShare.h b/GC/CcdShare.h index cd6c3618f..aececad0a 100644 --- a/GC/CcdShare.h +++ b/GC/CcdShare.h @@ -74,13 +74,6 @@ class CcdShare : public ShamirShare, public ShareSecret> *this = input; } - void random() - { - CcdSecret tmp; - ShareThread>::s().DataF.get_one(DATA_BIT, tmp); - *this = tmp.get_reg(0); - } - This& operator^=(const This& other) { *this += other; diff --git a/GC/FakeSecret.h b/GC/FakeSecret.h index e3820e06d..73013efa5 100644 --- a/GC/FakeSecret.h +++ b/GC/FakeSecret.h @@ -136,6 +136,8 @@ class FakeSecret : public ShareInterface, public BitVec void andrs(int n, const FakeSecret& x, const FakeSecret& y) { *this = BitVec(x.a * (y.a & 1)).mask(n); } + void xor_bit(int i, FakeSecret bit) { *this ^= bit << i; } + void invert(int n, const FakeSecret& x) { *this = BitVec(~x.a).mask(n); } void random_bit() { a = random() % 2; } diff --git a/GC/MaliciousCcdShare.h b/GC/MaliciousCcdShare.h index 6f9410961..9dc63fc63 100644 --- a/GC/MaliciousCcdShare.h +++ b/GC/MaliciousCcdShare.h @@ -79,13 +79,6 @@ class MaliciousCcdShare: public MaliciousShamirShare, public ShareSecret< *this = input; } - void random() - { - MaliciousCcdSecret tmp; - ShareThread>::s().DataF.get_one(DATA_BIT, tmp); - *this = tmp.get_reg(0); - } - This& operator^=(const This& other) { *this += other; diff --git a/GC/NoShare.h b/GC/NoShare.h index 9bffccd5e..f60eccd75 100644 --- a/GC/NoShare.h +++ b/GC/NoShare.h @@ -7,12 +7,12 @@ #define GC_NOSHARE_H_ #include "Processor/DummyProtocol.h" -#include "BMR/Register.h" -#include "Tools/SwitchableOutput.h" #include "Protocols/ShareInterface.h" class InputArgs; class ArithmeticProcessor; +class BlackHole; +class SwitchableOutput; namespace GC { @@ -110,7 +110,7 @@ class NoShare : public ShareInterface typedef NoShare small_type; - typedef BlackHole out_type; + typedef SwitchableOutput out_type; static const bool is_real = false; @@ -124,6 +124,11 @@ class NoShare : public ShareInterface return "no"; } + static void specification(octetStream&) + { + fail(); + } + static int size() { return 0; @@ -172,6 +177,8 @@ class NoShare : public ShareInterface NoShare get_bit(int) const { fail(); return {}; } + void xor_bit(int, NoShare) const { fail(); } + void invert(int, NoShare) { fail(); } NoShare mask(int) const { fail(); return {}; } diff --git a/GC/Processor.h b/GC/Processor.h index e759cf05f..2dddf8df2 100644 --- a/GC/Processor.h +++ b/GC/Processor.h @@ -27,7 +27,7 @@ class Processor : public ::ProcessorBase, public GC::RuntimeBranching static int check_args(const vector& args, int n); template - static void check_input(const U& in, int n_bits); + static void check_input(const U& in, const int* params); Machine* machine; Memories& memories; diff --git a/GC/Processor.hpp b/GC/Processor.hpp index b1539b04f..016352d3e 100644 --- a/GC/Processor.hpp +++ b/GC/Processor.hpp @@ -89,15 +89,15 @@ U GC::Processor::get_long_input(const int* params, else res = input_proc.get_input>(interactive, ¶ms[1]).items[0]; - int n_bits = *params; - check_input(res, n_bits); + check_input(res, params); return res; } template template -void GC::Processor::check_input(const U& in, int n_bits) +void GC::Processor::check_input(const U& in, const int* params) { + int n_bits = *params; auto test = in >> (n_bits - 1); if (n_bits == 1) { @@ -106,9 +106,17 @@ void GC::Processor::check_input(const U& in, int n_bits) } else if (not (test == 0 or test == -1)) { - throw runtime_error( - "input too large for a " + std::to_string(n_bits) - + "-bit signed integer: " + to_string(in)); + if (params[1] == 0) + throw runtime_error( + "input out of range for a " + std::to_string(n_bits) + + "-bit signed integer: " + to_string(in)); + else + throw runtime_error( + "input out of range for a " + to_string(n_bits) + + "-bit fixed-point number with " + + to_string(params[1]) + "-bit precision: " + + to_string( + mpf_class(bigint(in)) * exp2(-params[1]))); } } diff --git a/GC/RepPrep.h b/GC/RepPrep.h index 34419de79..8806e7306 100644 --- a/GC/RepPrep.h +++ b/GC/RepPrep.h @@ -22,7 +22,6 @@ class RepPrep : public PersonalPrep, ShiftableTripleBuffer ReplicatedBase* protocol; public: - RepPrep(DataPositions& usage, ShareThread& thread); RepPrep(DataPositions& usage, int input_player = PersonalPrep::SECURE); ~RepPrep(); diff --git a/GC/RepPrep.hpp b/GC/RepPrep.hpp index 5b2facacc..1c91fd395 100644 --- a/GC/RepPrep.hpp +++ b/GC/RepPrep.hpp @@ -16,13 +16,6 @@ namespace GC { -template -RepPrep::RepPrep(DataPositions& usage, ShareThread& thread) : - RepPrep(usage) -{ - (void) thread; -} - template RepPrep::RepPrep(DataPositions& usage, int input_player) : PersonalPrep(usage, input_player), protocol(0) diff --git a/GC/RuntimeBranching.h b/GC/RuntimeBranching.h index 20e062e8f..6ba0faf06 100644 --- a/GC/RuntimeBranching.h +++ b/GC/RuntimeBranching.h @@ -31,6 +31,11 @@ class RuntimeBranching { tainted = true; } + + bool is_tainted() + { + return tainted; + } }; } /* namespace GC */ diff --git a/GC/Secret.h b/GC/Secret.h index f97ad7b3f..6b37aa21c 100644 --- a/GC/Secret.h +++ b/GC/Secret.h @@ -84,7 +84,6 @@ class Secret template static void store_clear_in_dynamic(U& mem, const vector& accesses) { T::store_clear_in_dynamic(mem, accesses); } - static void output(T& reg); template static void load(vector< ReadAccess >& accesses, const U& mem); @@ -113,7 +112,7 @@ class Secret { T::inputbvec(processor, input_proc, args); } template static void reveal_inst(Processor& processor, const vector& args) - { processor.reveal(args); } + { T::reveal_inst(processor, args); } template static void trans(Processor& processor, int n_inputs, const vector& args); @@ -148,7 +147,6 @@ class Secret } void invert(int n, const Secret& x); void and_(int n, const Secret& x, const Secret& y, bool repeat); - void andrs(int n, const Secret& x, const Secret& y) { and_(n, x, y, true); } template void reveal(size_t n_bits, U& x); diff --git a/GC/Secret.hpp b/GC/Secret.hpp index 562cc32ca..01c70247c 100644 --- a/GC/Secret.hpp +++ b/GC/Secret.hpp @@ -119,12 +119,6 @@ void Secret::store(U& mem, T::store(mem, accesses); } -template -void Secret::output(T& reg) -{ - reg.output(); -} - template Secret::Secret() { diff --git a/GC/SemiHonestRepPrep.h b/GC/SemiHonestRepPrep.h index 1d1be8307..1a1bd90d1 100644 --- a/GC/SemiHonestRepPrep.h +++ b/GC/SemiHonestRepPrep.h @@ -15,10 +15,6 @@ namespace GC class SemiHonestRepPrep : public RepPrep { public: - SemiHonestRepPrep(DataPositions& usage, ShareThread&) : - RepPrep(usage) - { - } SemiHonestRepPrep(DataPositions& usage, bool = false) : RepPrep(usage) { diff --git a/GC/SemiPrep.cpp b/GC/SemiPrep.cpp index 32e756096..9fc3f4918 100644 --- a/GC/SemiPrep.cpp +++ b/GC/SemiPrep.cpp @@ -16,11 +16,6 @@ namespace GC { -SemiPrep::SemiPrep(DataPositions& usage, ShareThread&) : - SemiPrep(usage) -{ -} - SemiPrep::SemiPrep(DataPositions& usage, bool) : BufferPrep(usage), triple_generator(0) { diff --git a/GC/SemiPrep.h b/GC/SemiPrep.h index 60751c382..97214c28d 100644 --- a/GC/SemiPrep.h +++ b/GC/SemiPrep.h @@ -26,7 +26,6 @@ class SemiPrep : public BufferPrep, ShiftableTripleBuffer& thread); SemiPrep(DataPositions& usage, bool = true); ~SemiPrep(); diff --git a/GC/SemiSecret.h b/GC/SemiSecret.h index f8252f53e..ae10b5222 100644 --- a/GC/SemiSecret.h +++ b/GC/SemiSecret.h @@ -73,6 +73,9 @@ class SemiSecret : public SemiShare, public ShareSecret void xor_(int n, const SemiSecret& x, const SemiSecret& y) { *this = BitVec(x ^ y).mask(n); } + void xor_bit(int i, const SemiSecret& bit) + { *this ^= bit << i; } + void reveal(size_t n_bits, Clear& x); SemiSecret lsb() diff --git a/GC/ShareSecret.h b/GC/ShareSecret.h index 357f91f08..9ea0d2f68 100644 --- a/GC/ShareSecret.h +++ b/GC/ShareSecret.h @@ -161,6 +161,9 @@ class RepSecretBase : public FixedVec, public ShareSecret This get_bit(int i) { return (*this >> i) & 1; } + + void xor_bit(int i, const This& bit) + { *this ^= bit << i; } }; template diff --git a/GC/ShareThread.h b/GC/ShareThread.h index 86b1d95cb..5f995e808 100644 --- a/GC/ShareThread.h +++ b/GC/ShareThread.h @@ -32,9 +32,9 @@ class ShareThread Preprocessing& DataF; - ShareThread(const Names& N, OnlineOptions& opts, DataPositions& usage); - ShareThread(const Names& N, OnlineOptions& opts, Player& P, - typename T::mac_key_type mac_key, DataPositions& usage); + ShareThread(Preprocessing& prep); + ShareThread(Preprocessing& prep, Player& P, + typename T::mac_key_type mac_key); virtual ~ShareThread(); virtual typename T::MC* new_mc(typename T::mac_key_type mac_key) @@ -54,6 +54,7 @@ class StandaloneShareThread : public ShareThread, public Thread DataPositions usage; StandaloneShareThread(int i, ThreadMaster& master); + ~StandaloneShareThread(); void pre_run(); void post_run() { ShareThread::post_run(); } diff --git a/GC/ShareThread.hpp b/GC/ShareThread.hpp index c484e9e28..14d496115 100644 --- a/GC/ShareThread.hpp +++ b/GC/ShareThread.hpp @@ -18,26 +18,28 @@ namespace GC template StandaloneShareThread::StandaloneShareThread(int i, ThreadMaster& master) : - ShareThread(master.N, master.opts, usage), Thread(i, master) + ShareThread(*Preprocessing::get_new(master.opts.live_prep, + master.N, usage)), + Thread(i, master) { } template -ShareThread::ShareThread(const Names& N, OnlineOptions& opts, DataPositions& usage) : - P(0), MC(0), protocol(0), DataF( - opts.live_prep ? - *static_cast*>(new typename T::LivePrep( - usage, *this)) : - *static_cast*>(new BitPrepFiles(N, - get_prep_sub_dir(PREP_DIR, N.num_players()), - usage, BaseMachine::thread_num))) +StandaloneShareThread::~StandaloneShareThread() { + delete &this->DataF; } template -ShareThread::ShareThread(const Names& N, OnlineOptions& opts, Player& P, - typename T::mac_key_type mac_key, DataPositions& usage) : - ShareThread(N, opts, usage) +ShareThread::ShareThread(Preprocessing& prep) : + P(0), MC(0), protocol(0), DataF(prep) +{ +} + +template +ShareThread::ShareThread(Preprocessing& prep, Player& P, + typename T::mac_key_type mac_key) : + ShareThread(prep) { pre_run(P, mac_key); } @@ -45,7 +47,6 @@ ShareThread::ShareThread(const Names& N, OnlineOptions& opts, Player& P, template ShareThread::~ShareThread() { - delete &DataF; if (MC) delete MC; if (protocol) @@ -76,12 +77,6 @@ void ShareThread::post_run() { protocol->check(); MC->Check(*this->P); -#ifndef INSECURE -#ifdef VERBOSE - cerr << "Removing used pre-processed data" << endl; -#endif - DataF.prune(); -#endif } template diff --git a/GC/Thread.hpp b/GC/Thread.hpp index 38f3d4326..5487c41b2 100644 --- a/GC/Thread.hpp +++ b/GC/Thread.hpp @@ -58,10 +58,8 @@ void Thread::run() P = new PlainPlayer(N, id); processor.open_input_file(N.my_num(), thread_num, master.opts.cmd_private_input_file); - processor.out.activate(N.my_num() == 0 or master.opts.interactive); - processor.setup_redirection(P->my_num(), thread_num, master.opts); - if (processor.stdout_redirect_file.is_open()) - processor.out.redirect_to_file(processor.stdout_redirect_file); + processor.setup_redirection(P->my_num(), thread_num, master.opts, + processor.out); done.push(0); pre_run(); diff --git a/GC/ThreadMaster.hpp b/GC/ThreadMaster.hpp index 5f16229c0..060e9f118 100644 --- a/GC/ThreadMaster.hpp +++ b/GC/ThreadMaster.hpp @@ -58,6 +58,16 @@ Thread* ThreadMaster::new_thread(int i) template void ThreadMaster::run() { +#ifndef INSECURE + if (not opts.live_prep) + { + cerr + << "Preprocessing from file not supported by binary virtual machines" + << endl; + exit(1); + } +#endif + P = new PlainPlayer(N, "main"); machine.load_schedule(progname); diff --git a/GC/TinierShare.h b/GC/TinierShare.h index 4a57bc46c..f65835d88 100644 --- a/GC/TinierShare.h +++ b/GC/TinierShare.h @@ -106,11 +106,6 @@ class TinierShare: public Share_, SemiShare>, party.MC->get_alphai()); } - void random() - { - *this = get_party().DataF.get_part().get_bit(); - } - This lsb() const { return *this; diff --git a/GC/TinierSharePrep.h b/GC/TinierSharePrep.h index b2fbf9aac..34beaf6fb 100644 --- a/GC/TinierSharePrep.h +++ b/GC/TinierSharePrep.h @@ -25,7 +25,6 @@ class TinierSharePrep : public PersonalPrep MascotParams params; typedef typename T::whole_type secret_type; - ShareThread& thread; void buffer_triples(); void buffer_squares() { throw not_implemented(); } @@ -39,8 +38,6 @@ class TinierSharePrep : public PersonalPrep void init_real(Player& P); public: - TinierSharePrep(DataPositions& usage, ShareThread& thread, - int input_player = PersonalPrep::SECURE); TinierSharePrep(DataPositions& usage, int input_player = PersonalPrep::SECURE); TinierSharePrep(SubProcessor*, DataPositions& usage); diff --git a/GC/TinierSharePrep.hpp b/GC/TinierSharePrep.hpp index 10711b70b..57e759b9c 100644 --- a/GC/TinierSharePrep.hpp +++ b/GC/TinierSharePrep.hpp @@ -15,16 +15,8 @@ namespace GC template TinierSharePrep::TinierSharePrep(DataPositions& usage, int input_player) : - TinierSharePrep(usage, ShareThread::s(), input_player) -{ -} - -template -TinierSharePrep::TinierSharePrep(DataPositions& usage, - ShareThread& thread, int input_player) : PersonalPrep(usage, input_player), triple_generator(0), - real_triple_generator(0), - thread(thread) + real_triple_generator(0) { } @@ -87,6 +79,7 @@ void TinierSharePrep::buffer_inputs(int player) template void GC::TinierSharePrep::buffer_bits() { + auto& thread = ShareThread::s(); this->bits.push_back( BufferPrep::get_random_from_inputs(thread.P->num_players())); } diff --git a/GC/TinyPrep.hpp b/GC/TinyPrep.hpp index eae76ab59..2b8a11b79 100644 --- a/GC/TinyPrep.hpp +++ b/GC/TinyPrep.hpp @@ -14,6 +14,7 @@ template void TinierSharePrep::init_real(Player& P) { assert(real_triple_generator == 0); + auto& thread = ShareThread::s(); real_triple_generator = new typename T::whole_type::TripleGenerator( BaseMachine::s().fresh_ot_setup(), P.N, -1, OnlineOptions::singleton.batch_size, 1, params, @@ -24,6 +25,7 @@ void TinierSharePrep::init_real(Player& P) template void TinierSharePrep::buffer_secret_triples() { + auto& thread = ShareThread::s(); auto& triple_generator = real_triple_generator; assert(triple_generator != 0); params.generateBits = false; diff --git a/GC/TinySecret.h b/GC/TinySecret.h index cbd15ee43..9b6c84782 100644 --- a/GC/TinySecret.h +++ b/GC/TinySecret.h @@ -58,6 +58,11 @@ class VectorSecret : public Secret return part_type::size() * default_length; } + static void specification(octetStream& os) + { + T::specification(os); + } + static void read_or_generate_mac_key(string directory, const Player& P, mac_key_type& key) { @@ -150,6 +155,17 @@ class VectorSecret : public Secret return this->get_reg(i); } + void xor_bit(size_t i, const T& bit) + { + if (i < this->get_regs().size()) + XOR(this->get_reg(i), this->get_reg(i), bit); + else + { + this->resize_regs(i + 1); + this->get_reg(i) = bit; + } + } + void output(ostream& s, bool human = true) const { assert(this->get_regs().size() == default_length); @@ -179,6 +195,12 @@ class VectorSecret : public Secret { inputter.finalize(from, n_bits).mask(*this, n_bits); } + + void random_bit() + { + auto& thread = GC::ShareThread::s(); + *this = thread.DataF.get_part().get_bit(); + } }; template diff --git a/GC/TinyShare.h b/GC/TinyShare.h index 0562e7f1c..5712de618 100644 --- a/GC/TinyShare.h +++ b/GC/TinyShare.h @@ -74,13 +74,6 @@ class TinyShare : public Spdz2kShare<1, S>, public ShareSecret> *this = super::constant(input, party.P->my_num(), party.MC->get_alphai()); } - - void random() - { - TinySecret tmp; - this->get_party().DataF.get_one(DATA_BIT, tmp); - *this = tmp.get_reg(0); - } }; } /* namespace GC */ diff --git a/Machines/TripleMachine.cpp b/Machines/TripleMachine.cpp index b3044d5a4..82cde5e8d 100644 --- a/Machines/TripleMachine.cpp +++ b/Machines/TripleMachine.cpp @@ -158,8 +158,8 @@ GeneratorThread* TripleMachine::new_generator(OTTripleSetup& setup, int i, { if (output and i == 0) { - T::clear::template generate_setup(PREP_DIR, nplayers, 128); prep_data_dir = get_prep_sub_dir(PREP_DIR, nplayers); + T::clear::write_setup(prep_data_dir); write_mac_key(prep_data_dir, my_num, nplayers, mac_key); } diff --git a/Machines/emulate.cpp b/Machines/emulate.cpp index d70e0fe2b..8525b0671 100644 --- a/Machines/emulate.cpp +++ b/Machines/emulate.cpp @@ -59,6 +59,9 @@ int main(int argc, const char** argv) online_opts.live_prep, online_opts).run(); \ break; X(64) X(128) X(256) X(192) X(384) X(512) +#ifdef RING_SIZE + X(RING_SIZE) +#endif #undef X default: cerr << "Not compiled for " << R << "-bit rings" << endl; diff --git a/Machines/real-bmr-party.cpp b/Machines/real-bmr-party.cpp index dd13d1731..42000ddf8 100644 --- a/Machines/real-bmr-party.cpp +++ b/Machines/real-bmr-party.cpp @@ -3,6 +3,8 @@ * */ +#define NO_MIXED_CIRCUITS + #include "BMR/RealProgramParty.hpp" #include "Machines/SPDZ.hpp" diff --git a/Makefile b/Makefile index fcfbee413..9d634c0e9 100644 --- a/Makefile +++ b/Makefile @@ -97,16 +97,15 @@ replicated: rep-field rep-ring rep-bin spdz2k: spdz2k-party.x ot-offline.x Check-Offline-Z2k.x galois-degree.x Fake-Offline.x mascot: mascot-party.x spdz2k mama-party.x -tldr: - -echo ARCH = -march=native >> CONFIG.mine - $(MAKE) mascot-party.x - ifeq ($(OS), Darwin) tldr: mac-setup else -tldr: mpir +tldr: mpir linux-machine-setup endif +tldr: + $(MAKE) mascot-party.x + ifeq ($(MACHINE), aarch64) tldr: simde/simde endif @@ -144,8 +143,6 @@ static-release: static-dir $(patsubst Machines/%.cpp, static/%.x, $(wildcard Mac Fake-ECDSA.x: ECDSA/Fake-ECDSA.cpp ECDSA/P256Element.o $(COMMON) Processor/PrepBase.o $(CXX) -o $@ $^ $(CFLAGS) $(LDLIBS) -Check-Offline.x: $(PROCESSOR) - ot.x: $(OT) $(COMMON) Machines/OText_main.o Machines/OTMachine.o $(LIBSIMPLEOT) $(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS) @@ -285,11 +282,21 @@ mpir: mpir-setup -echo MY_CFLAGS += -I./local/include >> CONFIG.mine -echo MY_LDLIBS += -Wl,-rpath -Wl,$(CURDIR)/local/lib -L$(CURDIR)/local/lib >> CONFIG.mine -mac-setup: +mac-setup: mac-machine-setup brew install openssl boost libsodium mpir yasm ntl - -echo MY_CFLAGS += -I/usr/local/opt/openssl/include >> CONFIG.mine - -echo MY_LDLIBS += -L/usr/local/opt/openssl/lib >> CONFIG.mine - -echo USE_NTL = 1 >> CONFIG.mine + -echo MY_CFLAGS += -I/usr/local/opt/openssl/include -I/opt/homebrew/opt/openssl/include -I/opt/homebrew/include >> CONFIG.mine + -echo MY_LDLIBS += -L/usr/local/opt/openssl/lib -L/opt/homebrew/lib -L/opt/homebrew/opt/openssl/lib >> CONFIG.mine +# -echo USE_NTL = 1 >> CONFIG.mine + +ifeq ($(MACHINE), aarch64) +mac-machine-setup: + -echo ARCH = >> CONFIG.mine +linux-machine-setup: + -echo ARCH = -march=armv8.2-a+crypto >> CONFIG.mine +else +mac-machine-setup: +linux-machine-setup: +endif simde/simde: git submodule update --init simde diff --git a/Math/FixedVec.h b/Math/FixedVec.h index de9360664..55983e0b0 100644 --- a/Math/FixedVec.h +++ b/Math/FixedVec.h @@ -49,6 +49,11 @@ class FixedVec return string(1, T::type_char()); } + static void specification(octetStream& os) + { + T::specification(os); + } + template static FixedVec Mul(const FixedVec& a, const V& b) { diff --git a/Math/Integer.h b/Math/Integer.h index 5308e6537..8104724c0 100644 --- a/Math/Integer.h +++ b/Math/Integer.h @@ -35,6 +35,8 @@ class IntBase : public ValueInterface static int length() { return N_BITS; } static string type_string() { return "integer"; } + static void specification(octetStream& os); + static void init_default(int lgp) { (void)lgp; } static bool allows(Dtype type) { return type <= DATA_BIT; } @@ -126,6 +128,8 @@ class Integer : public IntBase Integer(const bigint& x) { *this = (x > 0) ? x.get_ui() : -x.get_ui(); } template Integer(const Z2& x) : Integer(x.get_limb(0)) {} + template + Integer(const SignedZ2& x); template Integer(const gfp_& x); Integer(int128 x) : Integer(x.get_lower()) {} diff --git a/Math/Integer.hpp b/Math/Integer.hpp index e48ad93a2..12d42ae43 100644 --- a/Math/Integer.hpp +++ b/Math/Integer.hpp @@ -8,6 +8,12 @@ template const int IntBase::N_BITS; +template +inline void IntBase::specification(octetStream& os) +{ + os.store(sizeof(T)); +} + template void IntBase::output(ostream& s,bool human) const { @@ -42,6 +48,15 @@ void Integer::reqbl(int n) } } +template +Integer::Integer(const SignedZ2& x) +{ + if (K < N_BITS and x.negative()) + a = -(-x).get_limb(0); + else + a = x.get_limb(0); +} + inline Integer::Integer(const Integer& x, int n_bits) { diff --git a/Math/gf2n.cpp b/Math/gf2n.cpp index 797d60db0..1a6fe41d1 100644 --- a/Math/gf2n.cpp +++ b/Math/gf2n.cpp @@ -139,6 +139,14 @@ void gf2n_::init_multiplication() } +template +void gf2n_::specification(octetStream& os) +{ + os.store(sizeof(U)); + os.store(degree()); +} + + /* Takes 8bit x and y and returns the 16 bit product in c1 and c0 ans = (c1<<8)^c0 where c1 and c0 are 8 bit diff --git a/Math/gf2n.h b/Math/gf2n.h index 13c3e3e73..add8627cf 100644 --- a/Math/gf2n.h +++ b/Math/gf2n.h @@ -76,6 +76,8 @@ class gf2n_ : public ValueInterface static string type_short() { return "2"; } static string type_string() { return "gf2n_"; } + static void specification(octetStream& os); + static int size() { return sizeof(a); } static int size_in_bits() { return sizeof(a) * 8; } diff --git a/Math/gf2nlong.h b/Math/gf2nlong.h index 9848a862b..85a668a74 100644 --- a/Math/gf2nlong.h +++ b/Math/gf2nlong.h @@ -171,6 +171,29 @@ class gf2n_long : public gf2n_ } }; +#if defined(__aarch64__) && defined(__clang__) +inline __m128i my_slli(int128 x, int i) +{ + if (i < 64) + return int128(x.get_upper() << i, x.get_lower() << i).a; + else + return int128().a; +} + +inline __m128i my_srli(int128 x, int i) +{ + if (i < 64) + return int128(x.get_upper() >> i, x.get_lower() >> i).a; + else + return int128().a; +} + +#undef _mm_slli_epi64 +#undef _mm_srli_epi64 +#define _mm_slli_epi64 my_slli +#define _mm_srli_epi64 my_srli +#endif + inline int128 int128::operator<<(const int& other) const { int128 res(_mm_slli_epi64(a, other)); diff --git a/Math/gfpvar.cpp b/Math/gfpvar.cpp index 45db4e5d9..368bca4b4 100644 --- a/Math/gfpvar.cpp +++ b/Math/gfpvar.cpp @@ -15,7 +15,7 @@ Zp_Data gfpvar_::ZpD; template string gfpvar_::type_string() { - return "gfpvar"; + return "gfp"; } template @@ -30,6 +30,12 @@ char gfpvar_::type_char() return 'p'; } +template +void gfpvar_::specification(octetStream& os) +{ + os.store(pr()); +} + template int gfpvar_::length() { diff --git a/Math/gfpvar.h b/Math/gfpvar.h index 41d1ce2ba..438a935e5 100644 --- a/Math/gfpvar.h +++ b/Math/gfpvar.h @@ -44,6 +44,8 @@ class gfpvar_ static string type_short(); static char type_char(); + static void specification(octetStream& os); + static int length(); static int size(); static int size_in_bits(); diff --git a/Networking/CryptoPlayer.cpp b/Networking/CryptoPlayer.cpp index 3794b69e9..d0b289b36 100644 --- a/Networking/CryptoPlayer.cpp +++ b/Networking/CryptoPlayer.cpp @@ -14,21 +14,43 @@ void check_ssl_file(string filename) "You can use `Scripts/setup-ssl.sh `."); } -void ssl_error(string side, string pronoun, string other, string server) +void ssl_error(string side, string other, string me) { cerr << side << "-side handshake with " << other - << " failed. Make sure " << pronoun - << " have the necessary certificate (" << PREP_DIR << server - << ".pem in the default configuration)," + << " failed. Make sure both sides " + << " have the necessary certificate (" << PREP_DIR << me + << ".pem in the default configuration on their side and " + << PREP_DIR << other << ".pem on ours)," << " and run `c_rehash ` on its location." << endl << "The certificates should be the same on every host. " << "Also make sure that it's still valid. Certificates generated " << "with `Scripts/setup-ssl.sh` expire after a month." << endl; + cerr << "See also " + "https://mp-spdz.readthedocs.io/en/latest/troubleshooting.html" + "#handshake-failures" << endl; + + string ids[2]; + ids[side == "Client"] = other; + ids[side != "Client"] = me; + cerr << "Signature (should match the other side): "; + for (int i = 0; i < 2; i++) + { + auto filename = PREP_DIR + ids[i] + ".pem"; + ifstream cert(filename); + stringstream buffer; + buffer << cert.rdbuf(); + if (buffer.str().empty()) + cerr << "<'" << filename << "' not found>"; + else + cerr << octetStream(buffer.str()).hash(); + if (i == 0) + cerr << "/"; + } + cerr << endl; } CryptoPlayer::CryptoPlayer(const Names& Nms, const string& id_base) : - MultiPlayer(Nms), plaintext_player(Nms, id_base), - other_player(Nms, id_base + "recv"), + MultiPlayer(Nms), ctx("P" + to_string(my_num())) { sockets.resize(num_players()); @@ -36,6 +58,16 @@ CryptoPlayer::CryptoPlayer(const Names& Nms, const string& id_base) : senders.resize(num_players()); receivers.resize(num_players()); + vector plaintext_sockets[2]; + + for (int i = 0; i < 2; i++) + { + PlainPlayer player(Nms, id_base + (i ? "recv" : "")); + plaintext_sockets[i] = player.sockets; + close_client_socket(player.socket(my_num())); + player.sockets.clear(); + } + for (int i = 0; i < (int)sockets.size(); i++) { if (i == my_num()) @@ -47,9 +79,9 @@ CryptoPlayer::CryptoPlayer(const Names& Nms, const string& id_base) : continue; } - sockets[i] = new ssl_socket(io_service, ctx, plaintext_player.socket(i), + sockets[i] = new ssl_socket(io_service, ctx, plaintext_sockets[0][i], "P" + to_string(i), "P" + to_string(my_num()), i < my_num()); - other_sockets[i] = new ssl_socket(io_service, ctx, other_player.socket(i), + other_sockets[i] = new ssl_socket(io_service, ctx, plaintext_sockets[1][i], "P" + to_string(i), "P" + to_string(my_num()), i < my_num()); senders[i] = new Sender(i < my_num() ? sockets[i] : other_sockets[i]); @@ -64,10 +96,6 @@ CryptoPlayer::CryptoPlayer(const Names& Nms, int id_base) : CryptoPlayer::~CryptoPlayer() { - close_client_socket(plaintext_player.socket(my_num())); - close_client_socket(other_player.socket(my_num())); - plaintext_player.sockets.clear(); - other_player.sockets.clear(); for (int i = 0; i < num_players(); i++) { delete sockets[i]; diff --git a/Networking/CryptoPlayer.h b/Networking/CryptoPlayer.h index d3bf80bfe..287f5c66f 100644 --- a/Networking/CryptoPlayer.h +++ b/Networking/CryptoPlayer.h @@ -20,7 +20,6 @@ */ class CryptoPlayer : public MultiPlayer { - PlainPlayer plaintext_player, other_player; ssl_ctx ctx; boost::asio::io_service io_service; diff --git a/Networking/Player.h b/Networking/Player.h index 668c097a7..033aa3bd1 100644 --- a/Networking/Player.h +++ b/Networking/Player.h @@ -373,6 +373,7 @@ class MultiPlayer : public Player T send_to_self_socket; T socket_to_send(int player) const { return player == player_no ? send_to_self_socket : sockets[player]; } + T socket(int i) const { return sockets[i]; } friend class CryptoPlayer; @@ -381,8 +382,6 @@ class MultiPlayer : public Player virtual ~MultiPlayer(); - T socket(int i) const { return sockets[i]; } - // Send/Receive data to/from player i void send_long(int i, long a) const; long receive_long(int i) const; diff --git a/Networking/sockets.cpp b/Networking/sockets.cpp index a1fe34c84..fd064cd2e 100644 --- a/Networking/sockets.cpp +++ b/Networking/sockets.cpp @@ -109,7 +109,9 @@ void set_up_client_socket(int& mysocket,const char* hostname,int Portnum) throw runtime_error( string() + "cannot connect from " + my_name + " to " + hostname + ":" + to_string(Portnum) + " after " + to_string(attempts) - + " attempts in one minute because " + strerror(connect_errno)); + + " attempts in one minute because " + strerror(connect_errno) + ". " + "https://mp-spdz.readthedocs.io/en/latest/troubleshooting.html#" + "connection-failures has more information on port requirements."); } freeaddrinfo(ai); diff --git a/Networking/ssl_sockets.h b/Networking/ssl_sockets.h index 20f5594b6..8989a0a10 100644 --- a/Networking/ssl_sockets.h +++ b/Networking/ssl_sockets.h @@ -16,7 +16,7 @@ typedef boost::asio::io_service ssl_service; void check_ssl_file(string filename); -void ssl_error(string side, string pronoun, string other, string server); +void ssl_error(string side, string other, string server); class ssl_ctx : public boost::asio::ssl::context { @@ -55,7 +55,7 @@ class ssl_socket : public boost::asio::ssl::stream handshake(ssl_socket::client); } catch (...) { - ssl_error("Client", "we", other, other); + ssl_error("Client", other, me); throw; } else @@ -65,7 +65,7 @@ class ssl_socket : public boost::asio::ssl::stream handshake(ssl_socket::server); } catch (...) { - ssl_error("Server", "they", other, me); + ssl_error("Server", other, me); throw; } diff --git a/OT/NPartyTripleGenerator.hpp b/OT/NPartyTripleGenerator.hpp index bc799e4a0..732850bc4 100644 --- a/OT/NPartyTripleGenerator.hpp +++ b/OT/NPartyTripleGenerator.hpp @@ -187,7 +187,13 @@ void NPartyTripleGenerator::generate() if (thread_num != 0) ss << "-" << thread_num; if (machine.output) + { outputFile.open(ss.str().c_str()); + if (machine.generateMACs or not T::clear::invertible) + file_signature().output(outputFile); + else + file_signature().output(outputFile); + } if (machine.generateBits) generateBits(); diff --git a/Processor/DataPositions.cpp b/Processor/DataPositions.cpp index 9eaa81e56..c32eb019f 100644 --- a/Processor/DataPositions.cpp +++ b/Processor/DataPositions.cpp @@ -89,6 +89,13 @@ DataPositions DataPositions::operator-(const DataPositions& other) const return res; } +DataPositions DataPositions::operator+(const DataPositions& other) const +{ + DataPositions res = *this; + res.increase(other); + return res; +} + void DataPositions::print_cost() const { ifstream file("cost"); diff --git a/Processor/Data_Files.h b/Processor/Data_Files.h index 069a36223..8f44ed253 100644 --- a/Processor/Data_Files.h +++ b/Processor/Data_Files.h @@ -19,6 +19,11 @@ using namespace std; template class dabit; +namespace GC +{ +template class ShareThread; +} + class DataTag { int t[4]; @@ -74,6 +79,7 @@ class DataPositions void increase(const DataPositions& delta); DataPositions& operator-=(const DataPositions& delta); DataPositions operator-(const DataPositions& delta) const; + DataPositions operator+(const DataPositions& delta) const; void print_cost() const; bool empty() const; bool any_more(const DataPositions& other) const; @@ -84,10 +90,15 @@ template class Data_Files; template class Machine; template class SubProcessor; +/** + * Abstract base class for preprocessing + */ template class Preprocessing : public PrepBase { protected: + static const bool use_part = false; + DataPositions& usage; map, vector>> edabits; @@ -114,6 +125,8 @@ class Preprocessing : public PrepBase template static Preprocessing* get_new(Machine& machine, DataPositions& usage, SubProcessor* proc); + static Preprocessing* get_new(bool live_prep, const Names& N, + DataPositions& usage); static Preprocessing* get_live_prep(SubProcessor* proc, DataPositions& usage); @@ -144,11 +157,15 @@ class Preprocessing : public PrepBase void get_input(T& a, typename T::open_type& x, int i); void get(vector& S, DataTag tag, const vector& regs, int vector_size); + /// Get fresh random multiplication triple virtual array get_triple(int n_bits); virtual array get_triple_no_count(int n_bits); + /// Get fresh random bit virtual T get_bit(); + /// Get fresh random value in domain virtual T get_random(); - virtual void get_dabit(T&, typename T::bit_type&); + /// Store fresh daBit in ``a`` (arithmetic part) and ``b`` (binary part) + virtual void get_dabit(T& a, typename T::bit_type& b); virtual void get_dabit_no_count(T&, typename T::bit_type&) { throw runtime_error("no daBit"); } virtual void get_edabits(bool strict, size_t size, T* a, vector& Sb, const vector& regs) @@ -156,6 +173,7 @@ class Preprocessing : public PrepBase template void get_edabit_no_count(bool, int n_bits, edabit& eb); template + /// Get fresh edaBit chunk edabitvec get_edabitvec(bool strict, int n_bits); virtual void buffer_edabits_with_queues(bool, int) { throw runtime_error("no edaBits"); } @@ -270,13 +288,14 @@ class Data_Files Preprocessing& DataFp; Preprocessing& DataF2; + Preprocessing& DataFb; Data_Files(Machine& machine, SubProcessor* procp = 0, SubProcessor* proc2 = 0); Data_Files(const Names& N); ~Data_Files(); - DataPositions tellg(); + DataPositions tellg() { return usage; } void seekg(DataPositions& pos); void skip(const DataPositions& pos); void prune(); @@ -289,7 +308,7 @@ class Data_Files void reset_usage() { usage.reset(); skipped.reset(); } - NamedCommStats comm_stats() { return DataFp.comm_stats() + DataF2.comm_stats(); } + NamedCommStats comm_stats(); }; template inline @@ -407,6 +426,13 @@ inline void Data_Files::purge() { DataFp.purge(); DataF2.purge(); + DataFb.purge(); +} + +template +NamedCommStats Data_Files::comm_stats() +{ + return DataFp.comm_stats() + DataF2.comm_stats() + DataFb.comm_stats(); } #endif diff --git a/Processor/Data_Files.hpp b/Processor/Data_Files.hpp index 702937951..6951ed2cc 100644 --- a/Processor/Data_Files.hpp +++ b/Processor/Data_Files.hpp @@ -5,6 +5,7 @@ #include "Processor/Processor.h" #include "Protocols/dabit.h" #include "Math/Setup.h" +#include "GC/BitPrepFiles.h" #include "Protocols/MascotPrep.hpp" @@ -28,6 +29,19 @@ Preprocessing* Preprocessing::get_new( machine.template prep_dir_prefix(), usage); } +template +Preprocessing* Preprocessing::get_new( + bool live_prep, const Names& N, + DataPositions& usage) +{ + if (live_prep) + return new typename T::LivePrep(usage); + else + return new GC::BitPrepFiles(N, + get_prep_sub_dir(PREP_DIR, N.num_players()), usage, + BaseMachine::thread_num); +} + template Sub_Data_Files::Sub_Data_Files(const Names& N, DataPositions& usage, int thread_num) : @@ -96,7 +110,7 @@ Sub_Data_Files::Sub_Data_Files(int my_num, int num_players, dabit_buffer.setup( PrepBase::get_filename(prep_data_dir, DATA_DABIT, - type_short, my_num, thread_num), 1, type_string, + type_short, my_num, thread_num), dabit::size(), type_string, DataPositions::dtype_names[DATA_DABIT]); input_buffers.resize(num_players); @@ -106,7 +120,7 @@ Sub_Data_Files::Sub_Data_Files(int my_num, int num_players, type_short, i, my_num, thread_num); if (i == my_num) my_input_buffers.setup(filename, - T::size() * 3 / 2, type_string); + T::size() + T::clear::size(), type_string); else input_buffers[i].setup(filename, T::size(), type_string); @@ -122,7 +136,10 @@ Data_Files::Data_Files(Machine& machine, SubProcessor< SubProcessor* proc2) : usage(machine.get_N().num_players()), DataFp(*Preprocessing::get_new(machine, usage, procp)), - DataF2(*Preprocessing::get_new(machine, usage, proc2)) + DataF2(*Preprocessing::get_new(machine, usage, proc2)), + DataFb( + *Preprocessing::get_new(machine.live_prep, + machine.get_N(), usage)) { } @@ -130,7 +147,8 @@ template Data_Files::Data_Files(const Names& N) : usage(N.num_players()), DataFp(*new Sub_Data_Files(N, usage)), - DataF2(*new Sub_Data_Files(N, usage)) + DataF2(*new Sub_Data_Files(N, usage)), + DataFb(*new Sub_Data_Files(N, usage)) { } @@ -150,6 +168,7 @@ Data_Files::~Data_Files() DataF2.data_sent() * 1e-6 << " MB" << endl; #endif delete &DataF2; + delete &DataFb; } template @@ -166,6 +185,12 @@ Sub_Data_Files::~Sub_Data_Files() template void Sub_Data_Files::seekg(DataPositions& pos) { + if (T::LivePrep::use_part) + { + get_part().seekg(pos); + return; + } + DataFieldType field_type = T::clear::field_type(); for (int dtype = 0; dtype < N_DTYPE; dtype++) if (T::clear::allows(Dtype(dtype))) @@ -181,6 +206,7 @@ void Sub_Data_Files::seekg(DataPositions& pos) setup_extended(it->first); extended[it->first].seekg(it->second); } + dabit_buffer.seekg(pos.files[field_type][DATA_DABIT]); } template @@ -188,6 +214,7 @@ void Data_Files::seekg(DataPositions& pos) { DataFp.seekg(pos); DataF2.seekg(pos); + DataFb.seekg(pos); usage = pos; } @@ -210,6 +237,9 @@ void Sub_Data_Files::prune() input_buffers[j].prune(); for (auto it : extended) it.second.prune(); + dabit_buffer.prune(); + if (part != 0) + part->prune(); } template @@ -217,6 +247,7 @@ void Data_Files::prune() { DataFp.prune(); DataF2.prune(); + DataFb.prune(); } template @@ -229,6 +260,7 @@ void Sub_Data_Files::purge() input_buffers[j].purge(); for (auto it : extended) it.second.purge(); + dabit_buffer.purge(); } template @@ -280,11 +312,12 @@ void Sub_Data_Files::buffer_edabits_with_queues(bool strict, int n_bits, ifstream* f = new ifstream(filename); if (f->fail()) throw runtime_error("cannot open " + filename); + check_file_signature(*f, filename); edabit_buffers[n_bits] = f; } auto& buffer = *edabit_buffers[n_bits]; if (buffer.peek() == EOF) - buffer.seekg(0); + buffer.seekg(file_signature().get_length()); edabitvec eb; eb.input(n_bits, buffer); this->edabits[{strict, n_bits}].push_back(eb); diff --git a/Processor/Input.h b/Processor/Input.h index 1e5aa1035..9816c3578 100644 --- a/Processor/Input.h +++ b/Processor/Input.h @@ -15,6 +15,9 @@ using namespace std; class ArithmeticProcessor; +/** + * Abstract base for input protocols + */ template class InputBase { @@ -45,18 +48,28 @@ class InputBase InputBase(SubProcessor* proc); virtual ~InputBase(); + /// Initialize input round for ``player`` virtual void reset(int player) = 0; + /// Initialize input round for all players void reset_all(Player& P); + /// Schedule input from me virtual void add_mine(const typename T::open_type& input, int n_bits = -1) = 0; + /// Schedule input from other player virtual void add_other(int player, int n_bits = -1) = 0; + /// Schedule input from all players void add_from_all(const clear& input); + /// Send my inputs virtual void send_mine() = 0; + /// Run input protocol for all players virtual void exchange(); + /// Get share for next input of mine virtual T finalize_mine() = 0; + /// Store share for next input from ``player`` from buffer ``o`` in ``target`` virtual void finalize_other(int player, T& target, octetStream& o, int n_bits = -1) = 0; + /// Get share for next input from ``player` virtual T finalize(int player, int n_bits = -1); void raw_input(SubProcessor& proc, const vector& args, int size); diff --git a/Processor/InputTuple.h b/Processor/InputTuple.h index e7a1c9cef..af38b94b0 100644 --- a/Processor/InputTuple.h +++ b/Processor/InputTuple.h @@ -19,6 +19,11 @@ struct InputTuple static string type_string() { return T::type_string(); } + static void specification(octetStream& os) + { + T::specification(os); + } + InputTuple() {} InputTuple(const T& share, const typename T::open_type& value) : share(share), value(value) {} diff --git a/Processor/Instruction.h b/Processor/Instruction.h index ad04cefc2..ca062cbcb 100644 --- a/Processor/Instruction.h +++ b/Processor/Instruction.h @@ -14,6 +14,7 @@ using namespace std; template class Machine; template class Processor; class ArithmeticProcessor; +class SwitchableOutput; /* * Opcode constants @@ -306,12 +307,6 @@ enum RegType { MAX_REG_TYPE, }; -enum SecrecyType { - SECRET, - CLEAR, - MAX_SECRECY_TYPE -}; - template struct TempVars { typename sgf2n::clear ans2; @@ -387,6 +382,10 @@ class Instruction : public BaseInstruction void shuffle(ArithmeticProcessor& Proc) const; void bitdecint(ArithmeticProcessor& Proc) const; + + template + void print(SwitchableOutput& out, T* v, T* p = 0, T* s = 0, T* z = 0, + T* nan = 0) const; }; #endif diff --git a/Processor/Instruction.hpp b/Processor/Instruction.hpp index 3d3db1fcf..72184d9e3 100644 --- a/Processor/Instruction.hpp +++ b/Processor/Instruction.hpp @@ -328,6 +328,7 @@ void BaseInstruction::parse_operands(istream& s, int pos, int file_pos) // write to external client, input is : opcode num_args, client_id, message_type, var1, var2 ... case WRITESOCKETC: + case WRITESOCKETS: case WRITESOCKETSHARE: case WRITESOCKETINT: num_var_args = get_int(s) - 3; @@ -336,8 +337,6 @@ void BaseInstruction::parse_operands(istream& s, int pos, int file_pos) n = get_int(s); get_vector(num_var_args, start, s); break; - case WRITESOCKETS: - throw runtime_error("sending MACs to client not supported any more"); case READCLIENTPUBLICKEY: case INITSECURESOCKET: case RESPSECURESOCKET: @@ -1070,31 +1069,19 @@ inline void Instruction::execute(Processor& Proc) const } break; case PRINTREGPLAIN: - { - Proc.out << Proc.read_Cp(r[0]) << flush; - } - break; + print(Proc.out, &Proc.read_Cp(r[0])); + return; case CONDPRINTPLAIN: if (not Proc.read_Cp(r[0]).is_zero()) { - auto v = Proc.read_Cp(r[1]); - auto p = Proc.read_Cp(r[2]); - if (p.is_zero()) - Proc.out << v << flush; - else - Proc.out << bigint::get_float(v, p, {}, {}) << flush; + print(Proc.out, &Proc.read_Cp(r[1]), &Proc.read_Cp(r[2])); } - break; + return; case PRINTFLOATPLAIN: - { - auto nan = Proc.read_Cp(start[4]); - typename sint::clear v = Proc.read_Cp(start[0]); - typename sint::clear p = Proc.read_Cp(start[1]); - typename sint::clear z = Proc.read_Cp(start[2]); - typename sint::clear s = Proc.read_Cp(start[3]); - bigint::output_float(Proc.out, bigint::get_float(v, p, z, s), nan); - } - break; + print(Proc.out, &Proc.read_Cp(start[0]), &Proc.read_Cp(start[1]), + &Proc.read_Cp(start[2]), &Proc.read_Cp(start[3]), + &Proc.read_Cp(start[4])); + return; case CONDPRINTSTR: if (not Proc.read_Cp(r[0]).is_zero()) { @@ -1124,9 +1111,7 @@ inline void Instruction::execute(Processor& Proc) const Proc.machine.stop(n); break; case RUN_TAPE: - Proc.DataF.skip( - Proc.machine.run_tapes(start, &Proc.DataF.DataFp, - &Proc.share_thread.DataF)); + Proc.machine.run_tapes(start, Proc.DataF); break; case JOIN_TAPE: Proc.machine.join_tape(r[0]); @@ -1186,15 +1171,19 @@ inline void Instruction::execute(Processor& Proc) const Proc.read_socket_private(Proc.read_Ci(r[0]), start, n, true); break; case WRITESOCKETINT: - Proc.write_socket(INT, Proc.read_Ci(r[0]), r[1], start, n); + Proc.write_socket(INT, false, Proc.read_Ci(r[0]), r[1], start, n); break; case WRITESOCKETC: - Proc.write_socket(CINT, Proc.read_Ci(r[0]), r[1], start, n); + Proc.write_socket(CINT, false, Proc.read_Ci(r[0]), r[1], start, n); + break; + case WRITESOCKETS: + // Send shares + MACs + Proc.write_socket(SINT, true, Proc.read_Ci(r[0]), r[1], start, n); break; case WRITESOCKETSHARE: // Send only shares, no MACs // N.B. doesn't make sense to have a corresponding read instruction for this - Proc.write_socket(SINT, Proc.read_Ci(r[0]), r[1], start, n); + Proc.write_socket(SINT, false, Proc.read_Ci(r[0]), r[1], start, n); break; case WRITEFILESHARE: // Write shares to file system @@ -1323,4 +1312,29 @@ void Program::execute(Processor& Proc) const } } +template +void Instruction::print(SwitchableOutput& out, T* v, T* p, T* s, T* z, T* nan) const +{ + if (size > 1) + out << "["; + for (int i = 0; i < size; i++) + { + if (p == 0) + out << v[i]; + else if (s == 0) + out << bigint::get_float(v[i], p[i], {}, {}); + else + { + assert(z != 0); + assert(nan != 0); + bigint::output_float(out, bigint::get_float(v[i], p[i], s[i], z[i]), + nan[i]); + } + if (i < size - 1) + out << ", "; + } + if (size > 1) + out << "]"; +} + #endif diff --git a/Processor/Machine.h b/Processor/Machine.h index d6ab84848..3f23dc9f9 100644 --- a/Processor/Machine.h +++ b/Processor/Machine.h @@ -42,9 +42,6 @@ class Machine : public BaseMachine typename sgf2n::mac_key_type alpha2i; typename sint::bit_type::mac_key_type alphabi; - // Keep record of used offline data - DataPositions pos; - Player* P; void load_program(const string& threadname, const string& filename); @@ -83,8 +80,8 @@ class Machine : public BaseMachine const Names& get_N() { return N; } - DataPositions run_tapes(const vector &args, Preprocessing *prep, - Preprocessing *bit_prep); + DataPositions run_tapes(const vector &args, + Data_Files& DataF); void fill_buffers(int thread_number, int tape_number, Preprocessing *prep, Preprocessing *bit_prep); @@ -93,7 +90,8 @@ class Machine : public BaseMachine Preprocessing *prep, true_type); template void fill_matmul(int, int, Preprocessing*, false_type) {} - DataPositions run_tape(int thread_number, int tape_number, int arg); + DataPositions run_tape(int thread_number, int tape_number, int arg, + const DataPositions& pos); DataPositions join_tape(int thread_number); void run(); diff --git a/Processor/Machine.hpp b/Processor/Machine.hpp index bd08aa39e..804dc51aa 100644 --- a/Processor/Machine.hpp +++ b/Processor/Machine.hpp @@ -92,9 +92,6 @@ Machine::Machine(int my_number, Names& playerNames, exit(1); } - // Keep record of used offline data - pos.set_num_players(N.num_players()); - load_schedule(progname_str); // remove persistence if necessary @@ -161,14 +158,16 @@ void Machine::load_program(const string& threadname, template DataPositions Machine::run_tapes(const vector& args, - Preprocessing* prep, Preprocessing* bit_prep) + Data_Files& DataF) { assert(args.size() % 3 == 0); for (unsigned i = 0; i < args.size(); i += 3) - fill_buffers(args[i], args[i + 1], prep, bit_prep); + fill_buffers(args[i], args[i + 1], &DataF.DataFp, &DataF.DataFb); DataPositions res(N.num_players()); for (unsigned i = 0; i < args.size(); i += 3) - res.increase(run_tape(args[i], args[i + 1], args[i + 2])); + res.increase( + run_tape(args[i], args[i + 1], args[i + 2], DataF.tellg() + res)); + DataF.skip(res); return res; } @@ -281,7 +280,7 @@ void Machine::fill_matmul(int thread_number, int tape_number, template DataPositions Machine::run_tape(int thread_number, int tape_number, - int arg) + int arg, const DataPositions& pos) { if (size_t(thread_number) >= tinfo.size()) throw overflow("invalid thread number", thread_number, tinfo.size()); @@ -294,7 +293,7 @@ DataPositions Machine::run_tape(int thread_number, int tape_number, if (progs[tape_number].usage_unknown()) { #ifndef INSECURE - if (not opts.live_prep) + if (not opts.live_prep and thread_number != 0) { cerr << "Internally called tape " << tape_number << " has unknown offline data usage" << endl; @@ -328,7 +327,7 @@ void Machine::run() timer[0].start(); // run main tape - pos.increase(run_tape(0, 0, 0)); + run_tape(0, 0, 0, N.num_players()); join_tape(0); print_compiler(); @@ -341,8 +340,8 @@ void Machine::run() queues[i]->schedule(-1); } - // reset to sum actual usage - pos.reset(); + // sum actual usage + DataPositions pos(N.num_players()); #ifdef DEBUG_THREADS cerr << "Waiting for all clients to finish" << endl; diff --git a/Processor/Memory.h b/Processor/Memory.h index 3c5093952..2c4a3d2e3 100644 --- a/Processor/Memory.h +++ b/Processor/Memory.h @@ -15,22 +15,29 @@ template istream& operator>>(istream& s,Memory& M); #include "Processor/Program.h" #include "Tools/CheckVector.h" +template +class MemoryPart : public CheckVector +{ +public: + void minimum_size(size_t size); +}; + template class Memory { public: - CheckVector MS; - CheckVector MC; + MemoryPart MS; + MemoryPart MC; - void resize_s(int sz) + void resize_s(size_t sz) { MS.resize(sz); } - void resize_c(int sz) + void resize_c(size_t sz) { MC.resize(sz); } - unsigned size_s() + size_t size_s() { return MS.size(); } - unsigned size_c() + size_t size_c() { return MC.size(); } template @@ -40,23 +47,23 @@ class Memory throw overflow("memory", i, M.size()); } - const typename T::clear& read_C(int i) const + const typename T::clear& read_C(size_t i) const { check_index(MC, i); return MC[i]; } - const T& read_S(int i) const + const T& read_S(size_t i) const { check_index(MS, i); return MS[i]; } - void write_C(unsigned int i,const typename T::clear& x) + void write_C(size_t i,const typename T::clear& x) { check_index(MC, i); MC[i]=x; } - void write_S(unsigned int i,const T& x) + void write_S(size_t i,const T& x) { check_index(MS, i); MS[i]=x; diff --git a/Processor/Memory.hpp b/Processor/Memory.hpp index 44e7d3432..c3c3e01bf 100644 --- a/Processor/Memory.hpp +++ b/Processor/Memory.hpp @@ -8,27 +8,23 @@ void Memory::minimum_size(RegType secret_type, RegType clear_type, const Program &program, const string& threadname) { (void) threadname; - unsigned sizes[MAX_SECRECY_TYPE]; - sizes[SECRET]= program.direct_mem(secret_type); - sizes[CLEAR] = program.direct_mem(clear_type); - if (sizes[SECRET] > size_s()) - { -#ifdef DEBUG_MEMORY - cerr << threadname << " needs more secret " << T::type_string() << " memory, resizing to " - << sizes[SECRET] << endl; -#endif - resize_s(sizes[SECRET]); - } - if (sizes[CLEAR] > size_c()) - { -#ifdef DEBUG_MEMORY - cerr << threadname << " needs more clear " << T::type_string() << " memory, resizing to " - << sizes[CLEAR] << endl; -#endif - resize_c(sizes[CLEAR]); - } + MS.minimum_size(program.direct_mem(secret_type)); + MC.minimum_size(program.direct_mem(clear_type)); } +template +void MemoryPart::minimum_size(size_t size) +{ + try + { + if (size > this->size()) + this->resize(size); + } + catch (bad_alloc&) + { + throw insufficient_memory(size, T::type_string()); + } +} template ostream& operator<<(ostream& s,const Memory& M) diff --git a/Processor/OfflineMachine.hpp b/Processor/OfflineMachine.hpp index b9901a0c6..cffaded40 100644 --- a/Processor/OfflineMachine.hpp +++ b/Processor/OfflineMachine.hpp @@ -8,6 +8,7 @@ #include "OfflineMachine.h" #include "Protocols/mac_key.hpp" +#include "Tools/Buffer.h" template template @@ -39,8 +40,8 @@ int OfflineMachine::run() T::bit_type::mac_key_type::init_field(); auto binary_mac_key = read_generate_write_mac_key< typename T::bit_type::part_type>(P); - GC::ShareThread thread(playerNames, - OnlineOptions::singleton, P, binary_mac_key, usage); + typename T::bit_type::LivePrep bit_prep(usage); + GC::ShareThread thread(bit_prep, P, binary_mac_key); generate(); generate(); @@ -74,6 +75,7 @@ void OfflineMachine::generate() if (my_usage > 0) { ofstream out(filename, iostream::out | iostream::binary); + file_signature().output(out); if (i == DATA_DABIT) { for (long long j = 0; @@ -108,6 +110,7 @@ void OfflineMachine::generate() if (n_inputs > 0) { ofstream out(filename, iostream::out | iostream::binary); + file_signature().output(out); InputTuple tuple; for (long long j = 0; j < DIV_CEIL(n_inputs, BUFFER_SIZE) * BUFFER_SIZE; j++) @@ -138,6 +141,7 @@ void OfflineMachine::generate() if (total > 0) { ofstream out(filename, ios::binary); + file_signature().output(out); for (int i = 0; i < DIV_CEIL(total, batch) * batch; i++) preprocessing.template get_edabitvec<0>(true, n_bits).output(n_bits, out); diff --git a/Processor/Online-Thread.h b/Processor/Online-Thread.h index b0965ae0d..577ab9f44 100644 --- a/Processor/Online-Thread.h +++ b/Processor/Online-Thread.h @@ -26,7 +26,7 @@ class thread_info static void* Main_Func(void *ptr); - static void purge_preprocessing(const Names& N); + static void purge_preprocessing(const Names& N, int thread_num); template static void print_usage(ostream& o, const vector& regs, diff --git a/Processor/Online-Thread.hpp b/Processor/Online-Thread.hpp index 1ef7da055..cb25b4261 100644 --- a/Processor/Online-Thread.hpp +++ b/Processor/Online-Thread.hpp @@ -352,7 +352,7 @@ void* thread_info::Main_Func(void* ptr) catch (...) { thread_info* ti = (thread_info*)ptr; - ti->purge_preprocessing(ti->machine->get_N()); + ti->purge_preprocessing(ti->machine->get_N(), ti->thread_num); throw; } #endif @@ -361,13 +361,17 @@ void* thread_info::Main_Func(void* ptr) template -void thread_info::purge_preprocessing(const Names& N) +void thread_info::purge_preprocessing(const Names& N, int thread_num) { cerr << "Purging preprocessed data because something is wrong" << endl; try { Data_Files df(N); df.purge(); + DataPositions pos; + Sub_Data_Files bit_df(N, pos, thread_num); + bit_df.get_part(); + bit_df.purge(); } catch(...) { diff --git a/Processor/OnlineMachine.hpp b/Processor/OnlineMachine.hpp index f728288ff..4e944d624 100644 --- a/Processor/OnlineMachine.hpp +++ b/Processor/OnlineMachine.hpp @@ -249,7 +249,7 @@ int OnlineMachine::run() catch(...) { if (not online_opts.live_prep) - thread_info::purge_preprocessing(playerNames); + thread_info::purge_preprocessing(playerNames, 0); throw; } #endif diff --git a/Processor/OnlineOptions.cpp b/Processor/OnlineOptions.cpp index df0ff7b49..03fa23793 100644 --- a/Processor/OnlineOptions.cpp +++ b/Processor/OnlineOptions.cpp @@ -36,13 +36,9 @@ OnlineOptions::OnlineOptions() : playerno(-1) } OnlineOptions::OnlineOptions(ez::ezOptionParser& opt, int argc, - const char** argv, int default_batch_size, bool default_live_prep, - bool variable_prime_length) : + const char** argv, false_type) : OnlineOptions() { - if (default_batch_size <= 0) - default_batch_size = batch_size; - opt.syntax = std::string(argv[0]) + " [OPTIONS] [] "; opt.add( @@ -78,6 +74,58 @@ OnlineOptions::OnlineOptions(ez::ezOptionParser& opt, int argc, "--output-file" // Flag token. ); + opt.add( + "", // Default. + 0, // Required? + 1, // Number of args expected. + 0, // Delimiter if expecting multiple args. + "This player's number (required if not given before program name)", // Help description. + "-p", // Flag token. + "--player" // Flag token. + ); + opt.add( + "", // Default. + 0, // Required? + 0, // Number of args expected. + 0, // Delimiter if expecting multiple args. + "Verbose output", // Help description. + "-v", // Flag token. + "--verbose" // Flag token. + ); + opt.add( + "4", // Default. + 0, // Required? + 1, // Number of args expected. + 0, // Delimiter if expecting multiple args. + "Batch size for sacrifice (3-5, default: 4)", // Help description. + "-B", // Flag token. + "--bucket-size" // Flag token. + ); + + opt.parse(argc, argv); + + interactive = opt.isSet("-I"); + + opt.get("-IF")->getString(cmd_private_input_file); + opt.get("-OF")->getString(cmd_private_output_file); + + opt.get("--bucket-size")->getInt(bucket_size); + +#ifndef VERBOSE + verbose = opt.isSet("--verbose"); +#endif + + opt.resetArgs(); +} + +OnlineOptions::OnlineOptions(ez::ezOptionParser& opt, int argc, + const char** argv, int default_batch_size, bool default_live_prep, + bool variable_prime_length) : + OnlineOptions(opt, argc, argv, false_type()) +{ + if (default_batch_size <= 0) + default_batch_size = batch_size; + string default_lgp = to_string(lgp); if (variable_prime_length) { @@ -121,15 +169,6 @@ OnlineOptions::OnlineOptions(ez::ezOptionParser& opt, int argc, "-L", // Flag token. "--live-preprocessing" // Flag token. ); - opt.add( - "", // Default. - 0, // Required? - 1, // Number of args expected. - 0, // Delimiter if expecting multiple args. - "This player's number (required if not given before program name)", // Help description. - "-p", // Flag token. - "--player" // Flag token. - ); opt.add( to_string(default_batch_size).c_str(), // Default. @@ -170,28 +209,9 @@ OnlineOptions::OnlineOptions(ez::ezOptionParser& opt, int argc, "-d", // Flag token. "--direct" // Flag token. ); - opt.add( - "4", // Default. - 0, // Required? - 1, // Number of args expected. - 0, // Delimiter if expecting multiple args. - "Batch size for sacrifice (3-5, default: 4)", // Help description. - "-B", // Flag token. - "--bucket-size" // Flag token. - ); - opt.add( - "", // Default. - 0, // Required? - 0, // Number of args expected. - 0, // Delimiter if expecting multiple args. - "Verbose output", // Help description. - "-v", // Flag token. - "--verbose" // Flag token. - ); opt.parse(argc, argv); - interactive = opt.isSet("-I"); if (variable_prime_length) { opt.get("--lgp")->getInt(lgp); @@ -208,17 +228,8 @@ OnlineOptions::OnlineOptions(ez::ezOptionParser& opt, int argc, opt.get("--memory")->getString(memtype); bits_from_squares = opt.isSet("-Q"); - opt.get("-IF")->getString(cmd_private_input_file); - opt.get("-OF")->getString(cmd_private_output_file); - direct = opt.isSet("--direct"); - opt.get("--bucket-size")->getInt(bucket_size); - -#ifndef VERBOSE - verbose = opt.isSet("--verbose"); -#endif - opt.resetArgs(); } diff --git a/Processor/OnlineOptions.h b/Processor/OnlineOptions.h index 615afc4c1..32c80fc2b 100644 --- a/Processor/OnlineOptions.h +++ b/Processor/OnlineOptions.h @@ -31,6 +31,8 @@ class OnlineOptions bool verbose; OnlineOptions(); + OnlineOptions(ez::ezOptionParser& opt, int argc, const char** argv, + false_type); OnlineOptions(ez::ezOptionParser& opt, int argc, const char** argv, int default_batch_size = 0, bool default_live_prep = true, bool variable_prime_length = false); diff --git a/Processor/PrepBase.cpp b/Processor/PrepBase.cpp index b4fd58a99..b99d091e6 100644 --- a/Processor/PrepBase.cpp +++ b/Processor/PrepBase.cpp @@ -9,15 +9,8 @@ string PrepBase::get_suffix(int thread_num) { -#ifdef INSECURE (void) thread_num; return ""; -#else - if (thread_num >= 0) - return "-T" + to_string(thread_num); - else - return ""; -#endif } string PrepBase::get_filename(const string& prep_data_dir, diff --git a/Processor/Processor.h b/Processor/Processor.h index b62c64c24..d9141855c 100644 --- a/Processor/Processor.h +++ b/Processor/Processor.h @@ -31,7 +31,7 @@ class SubProcessor DataPositions bit_usage; - void resize(int size) { C.resize(size); S.resize(size); } + void resize(size_t size) { C.resize(size); S.resize(size); } template friend class Processor; template friend class SPDZ; @@ -64,10 +64,10 @@ class SubProcessor void muls(const vector& reg, int size); void mulrs(const vector& reg); void dotprods(const vector& reg, int size); - void matmuls(const vector& source, const Instruction& instruction, int a, - int b); - void matmulsm(const CheckVector& source, const Instruction& instruction, int a, - int b); + void matmuls(const vector& source, const Instruction& instruction, size_t a, + size_t b); + void matmulsm(const CheckVector& source, const Instruction& instruction, size_t a, + size_t b); void conv2ds(const Instruction& instruction); void input_personal(const vector& args); @@ -82,12 +82,12 @@ class SubProcessor return C; } - T& get_S_ref(int i) + T& get_S_ref(size_t i) { return S[i]; } - typename T::clear& get_C_ref(int i) + typename T::clear& get_C_ref(size_t i) { return C[i]; } @@ -136,11 +136,11 @@ class ArithmeticProcessor : public ProcessorBase return thread_num; } - const long& read_Ci(int i) const + const long& read_Ci(size_t i) const { return Ci[i]; } - long& get_Ci_ref(int i) + long& get_Ci_ref(size_t i) { return Ci[i]; } - void write_Ci(int i,const long& x) + void write_Ci(size_t i, const long& x) { Ci[i]=x; } CheckVector& get_Ci() { return Ci; } @@ -190,30 +190,30 @@ class Processor : public ArithmeticProcessor const Program& program); ~Processor(); - const typename sgf2n::clear& read_C2(int i) const + const typename sgf2n::clear& read_C2(size_t i) const { return Proc2.C[i]; } - const sgf2n& read_S2(int i) const + const sgf2n& read_S2(size_t i) const { return Proc2.S[i]; } - typename sgf2n::clear& get_C2_ref(int i) + typename sgf2n::clear& get_C2_ref(size_t i) { return Proc2.C[i]; } - sgf2n& get_S2_ref(int i) + sgf2n& get_S2_ref(size_t i) { return Proc2.S[i]; } - void write_C2(int i,const typename sgf2n::clear& x) + void write_C2(size_t i,const typename sgf2n::clear& x) { Proc2.C[i]=x; } - void write_S2(int i,const sgf2n& x) + void write_S2(size_t i,const sgf2n& x) { Proc2.S[i]=x; } - const typename sint::clear& read_Cp(int i) const + const typename sint::clear& read_Cp(size_t i) const { return Procp.C[i]; } - const sint & read_Sp(int i) const + const sint & read_Sp(size_t i) const { return Procp.S[i]; } - typename sint::clear& get_Cp_ref(int i) + typename sint::clear& get_Cp_ref(size_t i) { return Procp.C[i]; } - sint & get_Sp_ref(int i) + sint & get_Sp_ref(size_t i) { return Procp.S[i]; } - void write_Cp(int i,const typename sint::clear& x) + void write_Cp(size_t i,const typename sint::clear& x) { Procp.C[i]=x; } - void write_Sp(int i,const sint & x) + void write_Sp(size_t i,const sint & x) { Procp.S[i]=x; } void check(); @@ -229,8 +229,8 @@ class Processor : public ArithmeticProcessor // Access to external client sockets for reading clear/shared data void read_socket_ints(int client_id, const vector& registers, int size); - void write_socket(const RegType reg_type, int socket_id, int message_type, - const vector& registers, int size); + void write_socket(const RegType reg_type, bool send_macs, int socket_id, + int message_type, const vector& registers, int size); void read_socket_vector(int client_id, const vector& registers, int size); diff --git a/Processor/Processor.hpp b/Processor/Processor.hpp index dd1e82382..ebbc1c8cc 100644 --- a/Processor/Processor.hpp +++ b/Processor/Processor.hpp @@ -70,7 +70,7 @@ Processor::Processor(int thread_num,Player& P, const Program& program) : ArithmeticProcessor(machine.opts, thread_num),DataF(machine, &Procp, &Proc2),P(P), MC2(MC2),MCp(MCp),machine(machine), - share_thread(machine.get_N(), machine.opts, P, machine.get_bit_mac_key(), DataF.usage), + share_thread(DataF.DataFb, P, machine.get_bit_mac_key()), Procb(machine.bit_memories), Proc2(*this,MC2,DataF.DataF2,P),Procp(*this,MCp,DataF.DataFp,P), privateOutput2(Proc2),privateOutputp(Procp), @@ -94,21 +94,8 @@ Processor::Processor(int thread_num,Player& P, secure_prng.ReSeed(); shared_prng.SeedGlobally(P, false); - // only output on party 0 if not interactive - bool always_stdout = machine.opts.cmd_private_output_file == "."; - bool output = P.my_num() == 0 or machine.opts.interactive or always_stdout; - out.activate(output); - Procb.out.activate(output); - - if (not always_stdout) - setup_redirection(P.my_num(), thread_num, opts); - - if (stdout_redirect_file.is_open()) - { - out.redirect_to_file(stdout_redirect_file); - Procb.out.redirect_to_file(stdout_redirect_file); - } - + setup_redirection(P.my_num(), thread_num, opts, out); + Procb.out = out; } @@ -266,8 +253,9 @@ void Processor::split(const Instruction& instruction) // If message_type is > 0, send message_type in bytes 0 - 3, to allow an external client to // determine the data structure being sent in a message. template -void Processor::write_socket(const RegType reg_type, int socket_id, - int message_type, const vector& registers, int size) +void Processor::write_socket(const RegType reg_type, + bool send_macs, int socket_id, int message_type, + const vector& registers, int size) { int m = registers.size(); socket_stream.reset_write_head(); @@ -283,9 +271,12 @@ void Processor::write_socket(const RegType reg_type, int socket_id, { if (reg_type == SINT) { - // Send vector of secret shares - get_Sp_ref(registers[i] + j).pack(socket_stream, - sint::get_rec_factor(P.my_num(), P.num_players())); + // Send vector of secret shares and optionally macs + if (send_macs) + get_Sp_ref(registers[i] + j).pack(socket_stream); + else + get_Sp_ref(registers[i] + j).pack(socket_stream, + sint::get_rec_factor(P.my_num(), P.num_players())); } else if (reg_type == CINT) { @@ -522,7 +513,7 @@ void SubProcessor::dotprods(const vector& reg, int size) template void SubProcessor::matmuls(const vector& source, - const Instruction& instruction, int a, int b) + const Instruction& instruction, size_t a, size_t b) { auto& dim = instruction.get_start(); auto A = source.begin() + a; @@ -549,7 +540,7 @@ void SubProcessor::matmuls(const vector& source, template void SubProcessor::matmulsm(const CheckVector& source, - const Instruction& instruction, int a, int b) + const Instruction& instruction, size_t a, size_t b) { auto& dim = instruction.get_start(); auto C = S.begin() + (instruction.get_r(0)); diff --git a/Processor/ProcessorBase.cpp b/Processor/ProcessorBase.cpp index f2d34bb97..0fa1ab529 100644 --- a/Processor/ProcessorBase.cpp +++ b/Processor/ProcessorBase.cpp @@ -5,6 +5,11 @@ #include "ProcessorBase.hpp" +ProcessorBase::ProcessorBase() : + input_counter(0), arg(0) +{ +} + string ProcessorBase::get_parameterized_filename(int my_num, int thread_num, const string& prefix) { string filename = prefix + "-P" + to_string(my_num) + "-" + to_string(thread_num); @@ -22,12 +27,18 @@ void ProcessorBase::open_input_file(int my_num, int thread_num, } void ProcessorBase::setup_redirection(int my_num, int thread_num, - OnlineOptions& opts) + OnlineOptions& opts, SwitchableOutput& out) { - if (not opts.cmd_private_output_file.empty()) + // only output on party 0 if not interactive + bool always_stdout = opts.cmd_private_output_file == "."; + bool output = my_num == 0 or opts.interactive or always_stdout; + out.activate(output); + + if (not (opts.cmd_private_output_file.empty() or always_stdout)) { const string stdout_filename = get_parameterized_filename(my_num, thread_num, opts.cmd_private_output_file); stdout_redirect_file.open(stdout_filename.c_str(), ios_base::out); + out.redirect_to_file(stdout_redirect_file); } } diff --git a/Processor/ProcessorBase.h b/Processor/ProcessorBase.h index 3c7d71166..d30de5d30 100644 --- a/Processor/ProcessorBase.h +++ b/Processor/ProcessorBase.h @@ -12,6 +12,7 @@ using namespace std; #include "Tools/ExecutionStats.h" +#include "Tools/SwitchableOutput.h" #include "OnlineOptions.h" class ProcessorBase @@ -21,6 +22,7 @@ class ProcessorBase ifstream input_file; string input_filename; + size_t input_counter; protected: // Optional argument to tape @@ -34,6 +36,8 @@ class ProcessorBase ofstream stdout_redirect_file; + ProcessorBase(); + void pushi(long x) { stacki.push(x); } void popi(long& x) { x = stacki.top(); stacki.pop(); } @@ -55,7 +59,8 @@ class ProcessorBase template T get_input(istream& is, const string& input_filename, const int* params); - void setup_redirection(int my_nu, int thread_num, OnlineOptions& opts); + void setup_redirection(int my_nu, int thread_num, OnlineOptions& opts, + SwitchableOutput& out); }; #endif /* PROCESSOR_PROCESSORBASE_H_ */ diff --git a/Processor/ProcessorBase.hpp b/Processor/ProcessorBase.hpp index 06b26a996..9af3e9928 100644 --- a/Processor/ProcessorBase.hpp +++ b/Processor/ProcessorBase.hpp @@ -42,8 +42,9 @@ T ProcessorBase::get_input(istream& input_file, const string& input_filename, co res.read(input_file, params); if (input_file.fail()) { - throw input_error(T::NAME, input_filename, input_file); + throw input_error(T::NAME, input_filename, input_file, input_counter); } + input_counter++; return res; } diff --git a/Processor/RingMachine.hpp b/Processor/RingMachine.hpp index dfeb02bfd..add3f43cc 100644 --- a/Processor/RingMachine.hpp +++ b/Processor/RingMachine.hpp @@ -42,7 +42,7 @@ RingMachine::RingMachine(int argc, const char** argv, case L: \ machine.template run, V>(); \ break; - X(64) X(72) X(128) + X(64) X(72) X(128) X(192) #ifdef RING_SIZE X(RING_SIZE) #endif diff --git a/Programs/Source/mnist_49.mpc b/Programs/Source/mnist_49.mpc index 05218130a..da5b1de9b 100644 --- a/Programs/Source/mnist_49.mpc +++ b/Programs/Source/mnist_49.mpc @@ -8,6 +8,7 @@ import util program.options_from_args() sfix.set_precision_from_args(program) +MultiArray.disable_index_checks() n_examples = 11791 n_test = 1991 diff --git a/Programs/Source/mnist_full_A.mpc b/Programs/Source/mnist_full_A.mpc index a1250b5df..9dc8a6851 100644 --- a/Programs/Source/mnist_full_A.mpc +++ b/Programs/Source/mnist_full_A.mpc @@ -10,6 +10,7 @@ import util program.options_from_args() sfix.set_precision_from_args(program, adapt_ring=True) +MultiArray.disable_index_checks() if 'profile' in program.args: print('Compiling for profiling') diff --git a/Programs/Source/mnist_full_B.mpc b/Programs/Source/mnist_full_B.mpc index 84cfe615b..a7cdb3688 100644 --- a/Programs/Source/mnist_full_B.mpc +++ b/Programs/Source/mnist_full_B.mpc @@ -8,6 +8,7 @@ import util program.options_from_args() sfix.set_precision_from_args(program, adapt_ring=True) +MultiArray.disable_index_checks() if 'profile' in program.args: print('Compiling for profiling') diff --git a/Programs/Source/mnist_full_C.mpc b/Programs/Source/mnist_full_C.mpc index cd6603ea2..6ea76b260 100644 --- a/Programs/Source/mnist_full_C.mpc +++ b/Programs/Source/mnist_full_C.mpc @@ -8,6 +8,7 @@ import util program.options_from_args() sfix.set_precision_from_args(program, adapt_ring=True) +MultiArray.disable_index_checks() if 'profile' in program.args: print('Compiling for profiling') diff --git a/Programs/Source/mnist_full_D.mpc b/Programs/Source/mnist_full_D.mpc index 7ebe1904e..68d12f977 100644 --- a/Programs/Source/mnist_full_D.mpc +++ b/Programs/Source/mnist_full_D.mpc @@ -8,6 +8,7 @@ import util program.options_from_args() sfix.set_precision_from_args(program, True) +MultiArray.disable_index_checks() if 'profile' in program.args: print('Compiling for profiling') diff --git a/Programs/Source/tf.mpc b/Programs/Source/tf.mpc index e285dd917..0c51cf581 100644 --- a/Programs/Source/tf.mpc +++ b/Programs/Source/tf.mpc @@ -30,6 +30,8 @@ layers[0].X.input_from(0) for layer in layers: layer.input_from(0, raw='raw' in program.args) +sint(0).reveal().store_in_mem(0) + start_timer(1) opt.forward(1, keep_intermediate=False) stop_timer(1) diff --git a/Protocols/Atlas.h b/Protocols/Atlas.h index 1a6d66d4f..3dd34d173 100644 --- a/Protocols/Atlas.h +++ b/Protocols/Atlas.h @@ -8,6 +8,10 @@ #include "Replicated.h" +/** + * ATLAS protocol (simple version). + * Uses double sharings to reduce degree of Shamir secret sharing. + */ template class Atlas : public ProtocolBase { diff --git a/Protocols/AtlasPrep.h b/Protocols/AtlasPrep.h index 489f535af..666952d37 100644 --- a/Protocols/AtlasPrep.h +++ b/Protocols/AtlasPrep.h @@ -8,6 +8,9 @@ #include "ReplicatedPrep.h" +/** + * ATLAS preprocessing. + */ template class AtlasPrep : public ReplicatedPrep { @@ -21,6 +24,7 @@ class AtlasPrep : public ReplicatedPrep { } + /// Input tuples from random sharings void buffer_inputs(int player) { assert(this->protocol and this->proc); diff --git a/Protocols/Beaver.h b/Protocols/Beaver.h index 71bc96fce..e0c24e49e 100644 --- a/Protocols/Beaver.h +++ b/Protocols/Beaver.h @@ -17,6 +17,9 @@ template class SubProcessor; template class MAC_Check_Base; class Player; +/** + * Beaver multiplication + */ template class Beaver : public ProtocolBase { diff --git a/Protocols/ChaiGearPrep.h b/Protocols/ChaiGearPrep.h index 21e18eeb6..fab6e21fe 100644 --- a/Protocols/ChaiGearPrep.h +++ b/Protocols/ChaiGearPrep.h @@ -8,6 +8,9 @@ #include "FHEOffline/SimpleGenerator.h" +/** + * HighGear/ChaiGear preprocessing + */ template class ChaiGearPrep : public MaliciousRingPrep { diff --git a/Protocols/CowGearPrep.h b/Protocols/CowGearPrep.h index 93c973489..e15d3feab 100644 --- a/Protocols/CowGearPrep.h +++ b/Protocols/CowGearPrep.h @@ -11,6 +11,9 @@ class PairwiseMachine; template class PairwiseGenerator; +/** + * LowGear/CowGear preprocessing + */ template class CowGearPrep : public MaliciousRingPrep { diff --git a/Protocols/FakePrep.h b/Protocols/FakePrep.h index 8597ffc4b..4fd859e5b 100644 --- a/Protocols/FakePrep.h +++ b/Protocols/FakePrep.h @@ -69,6 +69,16 @@ class FakePrep : public BufferPrep } } + void buffer_inputs(int) + { + this->inputs.resize(1); + for (int i = 0; i < 1000; i++) + { + auto r = G.get(); + this->inputs[0].push_back({r, r}); + } + } + void get_dabit_no_count(T& a, typename T::bit_type& b) { auto bit = G.get_bit(); diff --git a/Protocols/FakeProtocol.h b/Protocols/FakeProtocol.h index 9e650a07d..853782459 100644 --- a/Protocols/FakeProtocol.h +++ b/Protocols/FakeProtocol.h @@ -26,6 +26,8 @@ class FakeProtocol : public ProtocolBase vector trunc_stats; + map cisc_stats; + public: Player& P; @@ -47,6 +49,10 @@ class FakeProtocol : public ProtocolBase } if (expected != 0) cerr << "Expected truncation failures: " << expected << endl; + for (auto& x : cisc_stats) + { + cerr << x.second << " " << x.first << endl; + } } template @@ -189,9 +195,22 @@ class FakeProtocol : public ProtocolBase } void cisc(SubProcessor& processor, const Instruction& instruction) + { + cisc(processor, instruction, T::characteristic_two); + } + + template + void cisc(SubProcessor&, const Instruction&, true_type) + { + throw not_implemented(); + } + + template + void cisc(SubProcessor& processor, const Instruction& instruction, false_type) { int r0 = instruction.get_r(0); string tag((char*)&r0, 4); + cisc_stats[tag.c_str()]++; auto& args = instruction.get_start(); if (tag == string("LTZ\0", 4)) { @@ -225,6 +244,56 @@ class FakeProtocol : public ProtocolBase } } } + else if (tag == "FPDi") + { + for (size_t i = 0; i < args.size(); i += args[i]) + { + assert(i + args[i] <= args.size()); + int f = args.at(i + 6); + for (int j = 0; j < args[i + 1]; j++) + { + auto& res = processor.get_S()[args[i + 2] + j]; + mpf_class a[2]; + for (int k = 0; k < 2; k++) + a[k] = bigint(typename T::clear( + processor.get_S()[args[i + 3 + k] + j])); + if (a[1] != 0) + res = bigint(a[0] / a[1] * exp2(f)); + else + res = 0; + } + } + } + else if (tag == "exp2") + { + for (size_t i = 0; i < args.size(); i += args[i]) + { + assert(i + args[i] <= args.size()); + int f = args.at(i + 5); + for (int j = 0; j < args[i + 1]; j++) + { + auto& res = processor.get_S()[args[i + 2] + j]; + auto a = bigint(typename T::clear( + processor.get_S()[args[i + 3] + j])); + res = bigint(round(exp2(mpf_class(a).get_d() / exp2(f) + f))); + } + } + } + else if (tag == "log2") + { + for (size_t i = 0; i < args.size(); i += args[i]) + { + assert(i + args[i] <= args.size()); + int f = args.at(i + 5); + for (int j = 0; j < args[i + 1]; j++) + { + auto& res = processor.get_S()[args[i + 2] + j]; + auto a = bigint(typename T::clear( + processor.get_S()[args[i + 3] + j])); + res = bigint(round((log2(mpf_class(a).get_d()) - f) * exp2(f))); + } + } + } else throw runtime_error("unknown CISC instruction: " + tag); } diff --git a/Protocols/Hemi.h b/Protocols/Hemi.h index bed380ac8..1e8021467 100644 --- a/Protocols/Hemi.h +++ b/Protocols/Hemi.h @@ -9,6 +9,9 @@ #include "SPDZ.h" #include "HemiMatrixPrep.h" +/** + * Matrix multiplication optimized with semi-homomorphic encryption + */ template class Hemi : public SPDZ { diff --git a/Protocols/Hemi.hpp b/Protocols/Hemi.hpp index d9bca4736..dc285c14c 100644 --- a/Protocols/Hemi.hpp +++ b/Protocols/Hemi.hpp @@ -104,6 +104,9 @@ ShareMatrix Hemi::matrix_multiply(const ShareMatrix& A, return C; } +/** + * Reduce convolution to matrix multiplication + */ template void Hemi::conv2ds(SubProcessor& processor, const Instruction& instruction) diff --git a/Protocols/HemiMatrixPrep.h b/Protocols/HemiMatrixPrep.h index 35db214f7..e48d92571 100644 --- a/Protocols/HemiMatrixPrep.h +++ b/Protocols/HemiMatrixPrep.h @@ -11,6 +11,9 @@ template class HemiPrep; +/** + * Semi-honest matrix triple generation using semi-homomorphic encryption + */ template class HemiMatrixPrep : public BufferPrep> { diff --git a/Protocols/HemiPrep.h b/Protocols/HemiPrep.h index b140e75ed..c43b43e95 100644 --- a/Protocols/HemiPrep.h +++ b/Protocols/HemiPrep.h @@ -11,6 +11,9 @@ template class HemiMatrixPrep; +/** + * Semi-honest triple generation with semi-homomorphic encryption (pairwise) + */ template class HemiPrep : public SemiHonestRingPrep { diff --git a/Protocols/HemiShare.h b/Protocols/HemiShare.h index 45dbb9949..d299fb18f 100644 --- a/Protocols/HemiShare.h +++ b/Protocols/HemiShare.h @@ -22,6 +22,7 @@ class HemiShare : public SemiShare typedef DirectSemiMC Direct_MC; typedef SemiInput Input; typedef ::PrivateOutput PrivateOutput; + // matrix multiplication only with prime order field typedef typename conditional, Beaver>::type Protocol; typedef HemiPrep LivePrep; diff --git a/Protocols/HighGearKeyGen.h b/Protocols/HighGearKeyGen.h index 7b9fb78e6..48789239d 100644 --- a/Protocols/HighGearKeyGen.h +++ b/Protocols/HighGearKeyGen.h @@ -33,6 +33,9 @@ class KeyGenBitFactory } }; +/** + * Somewhat homomorphic encryption key generation using MASCOT + */ template class HighGearKeyGen { diff --git a/Protocols/HighGearKeyGen.hpp b/Protocols/HighGearKeyGen.hpp index 41a452456..49fa6702b 100644 --- a/Protocols/HighGearKeyGen.hpp +++ b/Protocols/HighGearKeyGen.hpp @@ -14,6 +14,10 @@ HighGearKeyGen::HighGearKeyGen(Player& P, const FHE_Params& params) : { } +/** + * Generate maBits (authenticated random bits modulo two different primes) + * using daBits (authenticated random bits modulo a large prime and two) + */ template void HighGearKeyGen::buffer_mabits() { diff --git a/Protocols/LowGearKeyGen.h b/Protocols/LowGearKeyGen.h index 534cec856..2101ea6b1 100644 --- a/Protocols/LowGearKeyGen.h +++ b/Protocols/LowGearKeyGen.h @@ -14,6 +14,9 @@ #include "Math/gfp.h" #include "Math/gfpvar.h" +/** + * Homomorphic key component generation (modulo a prime) using MASCOT + */ template class KeyGenProtocol { @@ -55,6 +58,9 @@ class KeyGenProtocol vector& shares); }; +/** + * Semi-homomorphic key generation using MASCOT + */ template class LowGearKeyGen : public KeyGenProtocol<1, L> { diff --git a/Protocols/LowGearKeyGen.hpp b/Protocols/LowGearKeyGen.hpp index d0dd6f340..a59820404 100644 --- a/Protocols/LowGearKeyGen.hpp +++ b/Protocols/LowGearKeyGen.hpp @@ -79,6 +79,9 @@ void KeyGenProtocol::input(vector& shares, const Rq_Element& shares[j].push_back(inputter.finalize(j)); } +/** + * Binomial secret generation from random bits + */ template template void KeyGenProtocol::binomial(vector_type& shares, T& prep) diff --git a/Protocols/MAC_Check.h b/Protocols/MAC_Check.h index cf36c98c3..571f391ef 100644 --- a/Protocols/MAC_Check.h +++ b/Protocols/MAC_Check.h @@ -23,6 +23,9 @@ using namespace std; #define POPEN_MAX 1000000 +/** + * Sum and broadcast values via a tree of players + */ template class TreeSum { @@ -90,6 +93,9 @@ class Tree_MAC_Check : public TreeSum, public MAC_Check_B void set_random_element(const U& random_element) { (void) random_element; } }; +/** + * SPDZ opening protocol with MAC check (indirect communication) + */ template class MAC_Check_ : public Tree_MAC_Check { @@ -108,6 +114,9 @@ template class Spdz2kShare; template class Spdz2kPrep; template class MascotPrep; +/** + * SPDZ2k opening protocol with MAC check + */ template class MAC_Check_Z2k : public Tree_MAC_Check { @@ -141,6 +150,9 @@ template void add_openings(vector& values, const Player& P, int sum_players, int last_sum_players, int send_player, TreeSum& MC); +/** + * SPDZ opening protocol with MAC check (pairwise communication) + */ template class Direct_MAC_Check: public MAC_Check_ { @@ -257,12 +269,14 @@ void TreeSum::start(vector& values, const Player& P) int my_relative_num = positive_modulo(P.my_num() - base_player, P.num_players()); while (true) { + // summing phase int last_sum_players = sum_players; sum_players = (sum_players - 2 + opening_sum) / opening_sum; if (sum_players == 0) break; if (my_relative_num >= sum_players && my_relative_num < last_sum_players) { + // send to the player up the tree for (unsigned int i=0; i::start(vector& values, const Player& P) if (my_relative_num < sum_players) { + // if receiving, add the values timers[RECV_ADD].start(); add_openings(values, P, sum_players, last_sum_players, base_player, *this); timers[RECV_ADD].stop(); @@ -281,6 +296,7 @@ void TreeSum::start(vector& values, const Player& P) if (P.my_num() == base_player) { + // send from the root player os.reset_write_head(); for (unsigned int i=0; i::start(vector& values, const Player& P) } else if (my_relative_num * max_broadcast < P.num_players()) { + // send if there are children int sender = (base_player + my_relative_num / max_broadcast) % P.num_players(); ReceiveValues(values, P, sender); timers[BCAST].start(); @@ -316,6 +333,7 @@ void TreeSum::finish(vector& values, const Player& P) int my_relative_num = positive_modulo(P.my_num() - base_player, P.num_players()); if (my_relative_num * max_broadcast >= P.num_players()) { + // receiving at the leafs int sender = (base_player + my_relative_num / max_broadcast) % P.num_players(); ReceiveValues(values, P, sender); } diff --git a/Protocols/MAC_Check.hpp b/Protocols/MAC_Check.hpp index 10cc3b45a..db3f8dc71 100644 --- a/Protocols/MAC_Check.hpp +++ b/Protocols/MAC_Check.hpp @@ -83,12 +83,6 @@ void Tree_MAC_Check::exchange(const Player& P) popen_cnt += this->values.size(); CheckIfNeeded(P); - - /* not compatible with continuous communication - send_player++; - if (send_player==P.num_players()) - { send_player=0; } - */ } @@ -134,6 +128,7 @@ void MAC_Check_::Check(const Player& P) if (popen_cnt < 10) { + // no random combination with few values vector deltas; Bundle bundle(P); for (int i = 0; i < popen_cnt; i++) @@ -155,6 +150,7 @@ void MAC_Check_::Check(const Player& P) } else { + // check random combination octet seed[SEED_SIZE]; this->timers[SEED].start(); Create_Random_Seed(seed,P,SEED_SIZE); diff --git a/Protocols/MAC_Check_Base.h b/Protocols/MAC_Check_Base.h index ab0765ccb..c7d477ad4 100644 --- a/Protocols/MAC_Check_Base.h +++ b/Protocols/MAC_Check_Base.h @@ -12,6 +12,9 @@ using namespace std; #include "Networking/Player.h" #include "Tools/PointerVector.h" +/** + * Abstract base class for opening protocols + */ template class MAC_Check_Base { @@ -29,24 +32,32 @@ class MAC_Check_Base alphai(mac_key), values_opened(0) {} virtual ~MAC_Check_Base() {} + /// Run checking protocol virtual void Check(const Player& P) { (void)P; } int number() const { return values_opened; } + /// Get MAC key const typename T::mac_key_type::Scalar& get_alphai() const { return alphai; } virtual void POpen_Begin(vector& values,const vector& S,const Player& P); virtual void POpen_End(vector& values,const vector& S,const Player& P); + /// Open values in ``S`` and store results in ``values`` virtual void POpen(vector& values,const vector& S,const Player& P); typename T::open_type POpen(const T& secret, const Player& P); - // alternative name to avoid conflict + /// Open single value typename T::open_type open(const T& secret, const Player& P) { return POpen(secret, P); } + /// Initialize opening round virtual void init_open(const Player& P, int n = 0); + /// Add value to be opened virtual void prepare_open(const T& secret); + /// Run opening protocol virtual void exchange(const Player& P) = 0; + /// Get next opened value virtual typename T::open_type finalize_open(); + /// Check whether all ``shares`` are ``value`` virtual void CheckFor(const typename T::open_type& value, const vector& shares, const Player& P); virtual const Player& get_check_player(const Player& P) const { return P; } diff --git a/Protocols/MalRepRingPrep.h b/Protocols/MalRepRingPrep.h index 2ccb32211..ea857a5a4 100644 --- a/Protocols/MalRepRingPrep.h +++ b/Protocols/MalRepRingPrep.h @@ -8,6 +8,10 @@ #include "Protocols/ReplicatedPrep.h" +/** + * Generate random triples with malicious security modulo a power two, + * either via larger modulo or shuffling + */ template class MalRepRingPrep : public virtual BufferPrep { @@ -27,6 +31,9 @@ class MalRepRingPrep : public virtual BufferPrep void buffer_inputs(int player); }; +/** + * Generate random bits from squares modulo a power of two + */ template class RingOnlyBitsFromSquaresPrep : public virtual BufferPrep { diff --git a/Protocols/MaliciousRepMC.h b/Protocols/MaliciousRepMC.h index 2c9d9321c..87deaaa3b 100644 --- a/Protocols/MaliciousRepMC.h +++ b/Protocols/MaliciousRepMC.h @@ -30,6 +30,9 @@ class MaliciousRepMC : public ReplicatedMC } }; +/** + * 3-party replicated opening with checking via hash + */ template class HashMaliciousRepMC : public MaliciousRepMC { diff --git a/Protocols/MaliciousRepPrep.h b/Protocols/MaliciousRepPrep.h index 3e2c8d1c6..be005182a 100644 --- a/Protocols/MaliciousRepPrep.h +++ b/Protocols/MaliciousRepPrep.h @@ -19,6 +19,9 @@ template class PostSacriRepRingShare; template void sacrifice(const vector>& check_triples, Player& P); +/** + * Random bit generation from semi-honest protocol with sacrifice against square + */ template class MaliciousBitOnlyRepPrep : public virtual BufferPrep { @@ -39,6 +42,9 @@ class MaliciousBitOnlyRepPrep : public virtual BufferPrep void init_honest(Player& P); }; +/** + * Random triple/square from semi-honest protocol with sacrifice + */ template class MaliciousRepPrep : public MaliciousBitOnlyRepPrep { diff --git a/Protocols/MaliciousShamirMC.h b/Protocols/MaliciousShamirMC.h index a6b59fae2..a72c36b03 100644 --- a/Protocols/MaliciousShamirMC.h +++ b/Protocols/MaliciousShamirMC.h @@ -8,6 +8,9 @@ #include "ShamirMC.h" +/** + * Shamir share opening with correctness check + */ template class MaliciousShamirMC : public ShamirMC { diff --git a/Protocols/MamaPrep.h b/Protocols/MamaPrep.h index 9c142edc7..6a6bd9634 100644 --- a/Protocols/MamaPrep.h +++ b/Protocols/MamaPrep.h @@ -8,6 +8,9 @@ #include "MascotPrep.h" +/** + * MASCOT triple generation with multiple MACs + */ template class MamaPrep : public OTPrep, public MaliciousRingPrep { diff --git a/Protocols/MascotPrep.h b/Protocols/MascotPrep.h index 4737f39e2..734453d31 100644 --- a/Protocols/MascotPrep.h +++ b/Protocols/MascotPrep.h @@ -25,6 +25,9 @@ class OTPrep : public virtual BitPrep NamedCommStats comm_stats(); }; +/** + * MASCOT input tuple generation + */ template class MascotInputPrep : public OTPrep { @@ -38,6 +41,9 @@ class MascotInputPrep : public OTPrep } }; +/** + * MASCOT triple generation + */ template class MascotTriplePrep : public MascotInputPrep { @@ -51,6 +57,9 @@ class MascotTriplePrep : public MascotInputPrep void buffer_triples(); }; +/** + * MASCOT random bit generation + */ template class MascotDabitOnlyPrep : public virtual MaliciousDabitOnlyPrep, public virtual MascotTriplePrep @@ -75,6 +84,9 @@ class MascotDabitOnlyPrep : public virtual MaliciousDabitOnlyPrep, virtual void buffer_bits(); }; +/** + * MASCOT preprocessing with edaBits + */ template class MascotPrep : public virtual MaliciousRingPrep, public virtual MascotDabitOnlyPrep diff --git a/Protocols/NoShare.h b/Protocols/NoShare.h index e44006400..d966f5867 100644 --- a/Protocols/NoShare.h +++ b/Protocols/NoShare.h @@ -10,6 +10,7 @@ #include "Math/bigint.h" #include "Math/gfp.h" #include "GC/NoShare.h" +#include "BMR/Register.h" #include "NoLivePrep.h" #include "NoProtocol.h" diff --git a/Protocols/PostSacrifice.h b/Protocols/PostSacrifice.h index c9ed65b6f..73ec766e4 100644 --- a/Protocols/PostSacrifice.h +++ b/Protocols/PostSacrifice.h @@ -8,6 +8,9 @@ #include "Protocols/Replicated.h" +/** + * Protocol with optimistic multiplication and postponed sacrifice + */ template class PostSacrifice : public ProtocolBase { diff --git a/Protocols/Rep4.h b/Protocols/Rep4.h index f2dbaf7a6..aa0fc7bce 100644 --- a/Protocols/Rep4.h +++ b/Protocols/Rep4.h @@ -8,6 +8,9 @@ #include "Replicated.h" +/** + * Four-party protocol with malicious security via replication + */ template class Rep4 : public ProtocolBase { diff --git a/Protocols/RepRingOnlyEdabitPrep.h b/Protocols/RepRingOnlyEdabitPrep.h index cd324b5a8..205e7d342 100644 --- a/Protocols/RepRingOnlyEdabitPrep.h +++ b/Protocols/RepRingOnlyEdabitPrep.h @@ -8,6 +8,9 @@ #include "ReplicatedPrep.h" +/** + * edaBit generation for replicated secret sharing modulo a power of two + */ template class RepRingOnlyEdabitPrep : public virtual BufferPrep { diff --git a/Protocols/Replicated.h b/Protocols/Replicated.h index 74d0f0f3b..3de9bfabc 100644 --- a/Protocols/Replicated.h +++ b/Protocols/Replicated.h @@ -26,6 +26,9 @@ template class MAC_Check_Base; template class Preprocessing; class Instruction; +/** + * Base class for replicated three-party protocols + */ class ReplicatedBase { public: @@ -41,6 +44,9 @@ class ReplicatedBase int get_n_relevant_players() { return P.num_players() - 1; } }; +/** + * Abstract base class for multiplication protocols + */ template class ProtocolBase { @@ -67,17 +73,27 @@ class ProtocolBase void multiply(vector& products, vector>& multiplicands, int begin, int end, SubProcessor& proc); + /// Single multiplication T mul(const T& x, const T& y); + /// Initialize multiplication round virtual void init_mul(SubProcessor* proc) = 0; + /// Schedule multiplication of operand pair virtual typename T::clear prepare_mul(const T& x, const T& y, int n = -1) = 0; + /// Run multiplication protocol virtual void exchange() = 0; + /// Get next multiplication result virtual T finalize_mul(int n = -1) = 0; + /// Store next multiplication result in ``res`` virtual void finalize_mult(T& res, int n = -1); + /// Initialize dot product round void init_dotprod(SubProcessor* proc) { init_mul(proc); } + /// Add operand pair to current dot product void prepare_dotprod(const T& x, const T& y) { prepare_mul(x, y); } + /// Finish dot product void next_dotprod() {} + /// Get next dot product result T finalize_dotprod(int length); virtual T get_random(); @@ -106,6 +122,9 @@ class ProtocolBase { throw runtime_error("CISC instructions not implemented"); } }; +/** + * Semi-honest replicated three-party protocol + */ template class Replicated : public ReplicatedBase, public ProtocolBase { diff --git a/Protocols/ReplicatedInput.h b/Protocols/ReplicatedInput.h index 29dbbf142..7d62838a3 100644 --- a/Protocols/ReplicatedInput.h +++ b/Protocols/ReplicatedInput.h @@ -10,6 +10,9 @@ #include "Processor/Processor.h" #include "Replicated.h" +/** + * Base class for input protocols without preprocessing + */ template class PrepLessInput : public InputBase { @@ -33,6 +36,9 @@ class PrepLessInput : public InputBase T finalize_mine(); }; +/** + * Replicated three-party input protocol + */ template class ReplicatedInput : public PrepLessInput { diff --git a/Protocols/ReplicatedMC.h b/Protocols/ReplicatedMC.h index cfcd749ce..bb6f36a20 100644 --- a/Protocols/ReplicatedMC.h +++ b/Protocols/ReplicatedMC.h @@ -8,6 +8,9 @@ #include "MAC_Check_Base.h" +/** + * Replicated semi-honest three-party opening protocol + */ template class ReplicatedMC : public MAC_Check_Base { diff --git a/Protocols/ReplicatedPrep.h b/Protocols/ReplicatedPrep.h index a8c8266af..8c3ed3f13 100644 --- a/Protocols/ReplicatedPrep.h +++ b/Protocols/ReplicatedPrep.h @@ -25,6 +25,9 @@ namespace GC template class ShareThread; } +/** + * Abstract base class for live preprocessing + */ template class BufferPrep : public Preprocessing { @@ -78,8 +81,11 @@ class BufferPrep : public Preprocessing int buffer_size; + /// Key-independent setup if necessary (cryptosystem parameters) static void basic_setup(Player& P) { (void) P; } + /// Generate keys if necessary static void setup(Player& P, typename T::mac_key_type alphai) { (void) P, (void) alphai; } + /// Free memory of global cryptosystem parameters static void teardown() {} static void edabit_sacrifice_buckets(vector>&, size_t, bool, int, @@ -102,6 +108,7 @@ class BufferPrep : public Preprocessing virtual void get_dabit_no_count(T& a, typename T::bit_type& b); + /// Get fresh random value virtual T get_random(); void push_triples(const vector>& triples) @@ -118,6 +125,9 @@ class BufferPrep : public Preprocessing void set_proc(SubProcessor* proc) { this->proc = proc; } }; +/** + * Generic preprocessing protocols + */ template class BitPrep : public virtual BufferPrep { @@ -135,16 +145,23 @@ class BitPrep : public virtual BufferPrep void set_protocol(typename T::Protocol& protocol); + /// Generate squares from triples void buffer_squares(); + /// Generate random bits from inputs without semi-honest security void buffer_bits_without_check(); }; +/** + * Generate (e)daBit protocols + */ template class RingPrep : public virtual BitPrep { typedef typename T::bit_type::part_type BT; + SubProcessor* bit_part_proc; + protected: void buffer_dabits_without_check(vector>& dabits, int buffer_size = -1, ThreadQueues* queues = 0); @@ -169,10 +186,11 @@ class RingPrep : public virtual BitPrep public: RingPrep(SubProcessor* proc, DataPositions& usage); - virtual ~RingPrep() {} + virtual ~RingPrep(); vector& get_bits() { return this->bits; } + /// Generate strict edabits from loose ones template void sanitize(vector>& edabits, int n_bits, int player = -1, ThreadQueues* queues = 0); @@ -180,6 +198,7 @@ class RingPrep : public virtual BitPrep void sanitize(vector>& edabits, int n_bits, int player, int begin, int end); + /// Generic daBit generation with semi-honest security void buffer_dabits_without_check(vector>& dabits, size_t begin, size_t end); template @@ -187,6 +206,7 @@ class RingPrep : public virtual BitPrep size_t begin, size_t end, Preprocessing& bit_prep); + /// Generic edaBit generation with semi-honest security template void buffer_edabits_without_check(int n_bits, vector& sums, vector>& bits, int begin, @@ -198,6 +218,9 @@ class RingPrep : public virtual BitPrep int begin, int end); }; +/** + * Semi-honest *bit preprocessing + */ template class SemiHonestRingPrep : public virtual RingPrep { @@ -229,6 +252,9 @@ class SemiHonestRingPrep : public virtual RingPrep { this->buffer_sedabits_from_edabits(n_bits); } }; +/** + * daBit preprocessing with malicious security + */ template class MaliciousDabitOnlyPrep : public virtual RingPrep { @@ -250,6 +276,9 @@ class MaliciousDabitOnlyPrep : public virtual RingPrep virtual void buffer_dabits(ThreadQueues* queues); }; +/** + * Random bit and edaBit preprocessing with malicious security + */ template class MaliciousRingPrep : public virtual MaliciousDabitOnlyPrep { @@ -301,6 +330,9 @@ class MaliciousRingPrep : public virtual MaliciousDabitOnlyPrep virtual void buffer_edabits(bool strict, int n_bits, ThreadQueues* queues); }; +/** + * Semi-honest preprocessing with honest majority (no (e)daBits) + */ template class ReplicatedRingPrep : public virtual BitPrep { @@ -319,6 +351,9 @@ class ReplicatedRingPrep : public virtual BitPrep virtual void buffer_bits() { this->buffer_bits_without_check(); } }; +/** + * Semi-honest preprocessing with honest majority (including (e)daBits) + */ template class ReplicatedPrep : public virtual ReplicatedRingPrep, public virtual SemiHonestRingPrep diff --git a/Protocols/ReplicatedPrep.hpp b/Protocols/ReplicatedPrep.hpp index 27c96c19b..2b8aa1604 100644 --- a/Protocols/ReplicatedPrep.hpp +++ b/Protocols/ReplicatedPrep.hpp @@ -48,26 +48,33 @@ BufferPrep::BufferPrep(DataPositions& usage) : template BufferPrep::~BufferPrep() { -#ifdef VERBOSE string type_string = T::type_string(); + +#ifdef VERBOSE if (n_bit_rounds > 0) cerr << n_bit_rounds << " rounds of random " << type_string << " bit generation" << endl; +#endif - this->print_left("triples", triples.size() * T::default_length, - type_string); + if (OnlineOptions::singleton.verbose) + { + this->print_left("triples", triples.size() * T::default_length, + type_string); #define X(KIND) \ this->print_left(#KIND, KIND.size(), type_string); - X(squares) X(inverses) X(bits) X(dabits) + X(squares) + X(inverses) + X(bits) + X(dabits) #undef X - for (auto& x : this->edabits) - { - this->print_left_edabits(x.second.size(), x.second[0].size(), - x.first.first, x.first.second); + for (auto& x : this->edabits) + { + this->print_left_edabits(x.second.size(), x.second[0].size(), + x.first.first, x.first.second); + } } -#endif } template @@ -79,8 +86,15 @@ BitPrep::BitPrep(SubProcessor* proc, DataPositions& usage) : template RingPrep::RingPrep(SubProcessor* proc, DataPositions& usage) : - BufferPrep(usage), BitPrep(proc, usage) + BufferPrep(usage), BitPrep(proc, usage), bit_part_proc(0) +{ +} + +template +RingPrep::~RingPrep() { + if (bit_part_proc) + delete bit_part_proc; } template @@ -708,8 +722,10 @@ void RingPrep::buffer_edabits_without_check(int n_bits, vector& sums, assert(this->protocol != 0); assert(proc != 0); auto &party = GC::ShareThread::s(); - SubProcessor bit_proc(party.MC->get_part_MC(), proc->bit_prep, - proc->P); + if (bit_part_proc == 0) + bit_part_proc = new SubProcessor(party.MC->get_part_MC(), + proc->bit_prep, proc->P); + auto& bit_proc = *bit_part_proc; int n_relevant = this->protocol->get_n_relevant_players(); vector> player_ints(n_relevant, vector(buffer_size)); vector>> parts(n_relevant, @@ -1070,8 +1086,7 @@ void Preprocessing::get_edabits(bool strict, size_t size, T* a, { if (i % unit == 0) Sb[regs[j] + i / unit] = {}; - Sb[regs[j] + i / unit] ^= - (typename T::bit_type(eb.second[j]) << (i % unit)); + Sb[regs[j] + i / unit].xor_bit(i % unit, eb.second[j]); } } } diff --git a/Protocols/ReplicatedPrep2k.h b/Protocols/ReplicatedPrep2k.h index 0c2e9510e..da35865e4 100644 --- a/Protocols/ReplicatedPrep2k.h +++ b/Protocols/ReplicatedPrep2k.h @@ -8,6 +8,9 @@ #include "ReplicatedPrep.h" +/** + * Preprocessing for three-party replicated secret sharing modulo a power of two + */ template class ReplicatedPrep2k : public virtual SemiHonestRingPrep, public virtual ReplicatedRingPrep diff --git a/Protocols/RingOnlyPrep.h b/Protocols/RingOnlyPrep.h index 78fd3415a..2d2f1928f 100644 --- a/Protocols/RingOnlyPrep.h +++ b/Protocols/RingOnlyPrep.h @@ -8,6 +8,9 @@ #include "ReplicatedPrep.h" +/** + * Semi-honest daBit generation for computation modulo a power of two + */ template class RingOnlyPrep : public virtual RingPrep { diff --git a/Protocols/SPDZ.h b/Protocols/SPDZ.h index bc7b5f057..fb2888c05 100644 --- a/Protocols/SPDZ.h +++ b/Protocols/SPDZ.h @@ -15,6 +15,9 @@ template class SubProcessor; template class Share; class Player; +/** + * SPDZ protocol + */ template class SPDZ : public Beaver { diff --git a/Protocols/Semi2k.h b/Protocols/Semi2k.h index 646c955e3..69cf63aad 100644 --- a/Protocols/Semi2k.h +++ b/Protocols/Semi2k.h @@ -9,6 +9,9 @@ #include "SPDZ.h" #include "Processor/TruncPrTuple.h" +/** + * Dishonest-majority protocol for computation modulo a power of two + */ template class Semi2k : public SPDZ { diff --git a/Protocols/SemiInput.h b/Protocols/SemiInput.h index 0cc348d95..87a1e08e5 100644 --- a/Protocols/SemiInput.h +++ b/Protocols/SemiInput.h @@ -10,6 +10,9 @@ template class SemiMC; +/** + * Additive secret sharing input protocol + */ template class SemiInput : public IndividualInput { diff --git a/Protocols/SemiMC.h b/Protocols/SemiMC.h index 67f3b284b..fe4d9db6c 100644 --- a/Protocols/SemiMC.h +++ b/Protocols/SemiMC.h @@ -9,6 +9,9 @@ #include "MAC_Check.h" #include "Tools/Bundle.h" +/** + * Additive secret sharing opening protocol (indirect communication) + */ template class SemiMC : public TreeSum, public MAC_Check_Base { @@ -26,6 +29,9 @@ class SemiMC : public TreeSum, public MAC_Check_Base SemiMC& get_part_MC() { return *this; } }; +/** + * Additive secret sharing opening protocol (direct communication) + */ template class DirectSemiMC : public SemiMC { diff --git a/Protocols/SemiPrep.h b/Protocols/SemiPrep.h index 7148c8a9b..12e17203f 100644 --- a/Protocols/SemiPrep.h +++ b/Protocols/SemiPrep.h @@ -8,6 +8,9 @@ #include "MascotPrep.h" +/** + * Semi-honest triple generation based on oblivious transfer + */ template class SemiPrep : public virtual OTPrep, public virtual SemiHonestRingPrep { diff --git a/Protocols/SemiPrep2k.h b/Protocols/SemiPrep2k.h index 33ce580c6..50311c594 100644 --- a/Protocols/SemiPrep2k.h +++ b/Protocols/SemiPrep2k.h @@ -9,6 +9,9 @@ #include "SemiPrep.h" #include "RepRingOnlyEdabitPrep.h" +/** + * Preprocessing for additive secret sharing modulo a power of two + */ template class SemiPrep2k : public SemiPrep, public RepRingOnlyEdabitPrep { diff --git a/Protocols/Shamir.h b/Protocols/Shamir.h index e9336c753..3d2bf469b 100644 --- a/Protocols/Shamir.h +++ b/Protocols/Shamir.h @@ -19,6 +19,9 @@ template class IndirectShamirMC; class Player; +/** + * Shamir secret sharing-based protocol with resharing + */ template class Shamir : public ProtocolBase { diff --git a/Protocols/Shamir.hpp b/Protocols/Shamir.hpp index 100107469..d387f3b47 100644 --- a/Protocols/Shamir.hpp +++ b/Protocols/Shamir.hpp @@ -218,21 +218,21 @@ void Shamir::get_hyper(vector >& hyper, octetStream os; string filename = hyper_filename(t, n); ifstream in(filename); -#ifdef VERBOSE +#ifdef VERBOSE_HYPER cerr << "Trying to load hyper-invertable matrix from " << filename << endl; #endif os.input(in); os.get(hyper); if (int(hyper.size()) != n - t) throw exception(); -#ifdef VERBOSE +#ifdef VERBOSE_HYPER cerr << "Loaded hyper-invertable matrix from " << filename << endl; #endif return; } catch (...) { -#ifdef VERBOSE +#ifdef VERBOSE_HYPER cerr << "Failed to load hyper-invertable" << endl; #endif } diff --git a/Protocols/ShamirInput.h b/Protocols/ShamirInput.h index 5958efc61..023467077 100644 --- a/Protocols/ShamirInput.h +++ b/Protocols/ShamirInput.h @@ -11,6 +11,10 @@ #include "ReplicatedInput.h" #include "Machines/ShamirMachine.h" +/** + * Base class for input protocols where the inputting player sends a share + * to every other player + */ template class IndividualInput : public PrepLessInput { @@ -36,6 +40,9 @@ class IndividualInput : public PrepLessInput void finalize_other(int player, T& target, octetStream& o, int n_bits = -1); }; +/** + * Shamir secret sharing input protocol + */ template class ShamirInput : public IndividualInput { diff --git a/Protocols/ShamirMC.h b/Protocols/ShamirMC.h index ccd370f21..8f76d6a79 100644 --- a/Protocols/ShamirMC.h +++ b/Protocols/ShamirMC.h @@ -11,6 +11,9 @@ #include "Machines/ShamirMachine.h" #include "Tools/Bundle.h" +/** + * Shamir secret sharing opening protocol (indirect communication) + */ template class IndirectShamirMC : public MAC_Check_Base { @@ -24,6 +27,9 @@ class IndirectShamirMC : public MAC_Check_Base virtual void exchange(const Player& P); }; +/** + * Shamir secret sharing opening protocol (direct communication) + */ template class ShamirMC : public IndirectShamirMC { diff --git a/Protocols/ShuffleSacrifice.h b/Protocols/ShuffleSacrifice.h index faaf86875..b8ffd0aaf 100644 --- a/Protocols/ShuffleSacrifice.h +++ b/Protocols/ShuffleSacrifice.h @@ -18,6 +18,9 @@ class Player; template class LimitedPrep; +/** + * Base class for shuffle sacrificing + */ class ShuffleSacrifice { protected: diff --git a/Protocols/SohoPrep.h b/Protocols/SohoPrep.h index 07bc7b9c4..5e28381be 100644 --- a/Protocols/SohoPrep.h +++ b/Protocols/SohoPrep.h @@ -6,6 +6,9 @@ #ifndef PROTOCOLS_SOHOPREP_H_ #define PROTOCOLS_SOHOPREP_H_ +/** + * Semi-honest preprocessing with somewhat homomorphic encryption + */ template class SohoPrep : public SemiHonestRingPrep { diff --git a/Protocols/Spdz2kPrep.h b/Protocols/Spdz2kPrep.h index ab0cc33ea..33883c66f 100644 --- a/Protocols/Spdz2kPrep.h +++ b/Protocols/Spdz2kPrep.h @@ -13,6 +13,9 @@ template void bits_from_square_in_ring(vector& bits, int buffer_size, U* bit_prep); +/** + * SPDZ2k preprocessing + */ template class Spdz2kPrep : public virtual MaliciousRingPrep, public virtual MascotTriplePrep, diff --git a/Protocols/SpdzWise.h b/Protocols/SpdzWise.h index cb049fceb..afbf2c850 100644 --- a/Protocols/SpdzWise.h +++ b/Protocols/SpdzWise.h @@ -10,6 +10,9 @@ template class SpdzWiseInput; +/** + * Honest-majority protocol with MAC check + */ template class SpdzWise : public ProtocolBase { diff --git a/Protocols/SpdzWiseInput.h b/Protocols/SpdzWiseInput.h index 458fe02a1..e9597527d 100644 --- a/Protocols/SpdzWiseInput.h +++ b/Protocols/SpdzWiseInput.h @@ -8,6 +8,9 @@ #include "ReplicatedInput.h" +/** + * Honest-majority input protocol with MAC + */ template class SpdzWiseInput : public InputBase { diff --git a/Protocols/SpdzWisePrep.h b/Protocols/SpdzWisePrep.h index 35be8cb94..6b4df251f 100644 --- a/Protocols/SpdzWisePrep.h +++ b/Protocols/SpdzWisePrep.h @@ -10,6 +10,9 @@ template class MaliciousShamirShare; +/** + * Preprocessing for honest-majority protocol with MAC + */ template class SpdzWisePrep : public MaliciousRingPrep { diff --git a/Protocols/SpdzWiseRing.h b/Protocols/SpdzWiseRing.h index 9cc6c12c4..c1c04c192 100644 --- a/Protocols/SpdzWiseRing.h +++ b/Protocols/SpdzWiseRing.h @@ -10,6 +10,9 @@ #include "PostSacrifice.h" #include "PostSacriRepRingShare.h" +/** + * Three-party replicated secret sharing protocol with MAC modulo a power of two + */ template class SpdzWiseRing : public SpdzWise { diff --git a/Protocols/SpdzWiseRingPrep.h b/Protocols/SpdzWiseRingPrep.h index c201c7a6b..4a16b92ee 100644 --- a/Protocols/SpdzWiseRingPrep.h +++ b/Protocols/SpdzWiseRingPrep.h @@ -9,6 +9,10 @@ #include "SpdzWisePrep.h" #include "RepRingOnlyEdabitPrep.h" +/** + * Preprocessing for three-party replicated secret sharing protocol with MAC + * modulo a power of two + */ template class SpdzWiseRingPrep : public virtual SpdzWisePrep, public virtual RepRingOnlyEdabitPrep diff --git a/Protocols/SpdzWiseShare.h b/Protocols/SpdzWiseShare.h index 101965cad..55a19dedc 100644 --- a/Protocols/SpdzWiseShare.h +++ b/Protocols/SpdzWiseShare.h @@ -80,6 +80,7 @@ class SpdzWiseShare : public Share_ { } + void pack(octetStream& os, bool full = true) const; void pack(octetStream& os, open_type factor) const; }; diff --git a/Protocols/SpdzWiseShare.hpp b/Protocols/SpdzWiseShare.hpp index 038556936..6401c083a 100644 --- a/Protocols/SpdzWiseShare.hpp +++ b/Protocols/SpdzWiseShare.hpp @@ -40,6 +40,12 @@ void SpdzWiseShare::read_or_generate_mac_key(string directory, Player& P, T& } } +template +void SpdzWiseShare::pack(octetStream& os, bool full) const +{ + super::pack(os, full); +} + template void SpdzWiseShare::pack(octetStream& os, open_type factor) const { diff --git a/Protocols/dabit.h b/Protocols/dabit.h index c6a61fe00..9f7741f0a 100644 --- a/Protocols/dabit.h +++ b/Protocols/dabit.h @@ -27,6 +27,11 @@ class dabit : public pair return T::type_string(); } + static void specification(octetStream& os) + { + T::specification(os); + } + dabit() { } diff --git a/Protocols/fake-stuff.h b/Protocols/fake-stuff.h index 9add273fa..0c209869b 100644 --- a/Protocols/fake-stuff.h +++ b/Protocols/fake-stuff.h @@ -6,6 +6,8 @@ using namespace std; #include "Networking/Player.h" +#include "Processor/Data_Files.h" +#include "Math/Setup.h" template void check_share(vector& Sa, typename T::clear& value, @@ -43,15 +45,27 @@ class Files int N; typename T::mac_type key; PRNG G; - Files(int N, const typename T::mac_type& key, const string& prefix) : N(N), key(key) + Files(int N, const typename T::mac_type& key, const string& prep_data_prefix, + Dtype type, int thread_num = -1) : + Files(N, key, + get_prep_sub_dir(prep_data_prefix, N) + + DataPositions::dtype_names[type] + "-" + T::type_short(), + thread_num) + { + } + Files(int N, const typename T::mac_type& key, const string& prefix, + int thread_num = -1) : + N(N), key(key) { outf = new ofstream[N]; for (int i=0; i().output(outf[i]); if (outf[i].fail()) throw file_error(filename.str().c_str()); } diff --git a/Protocols/fake-stuff.hpp b/Protocols/fake-stuff.hpp index 89b029b71..951cbfe74 100644 --- a/Protocols/fake-stuff.hpp +++ b/Protocols/fake-stuff.hpp @@ -485,7 +485,6 @@ inline void check_files(ofstream* outf, int N) /* N = Number players * ntrip = Number triples needed - * str = "2" or "p" */ template void make_mult_triples(const typename T::mac_type& key, int N, int ntrip, @@ -496,44 +495,25 @@ void make_mult_triples(const typename T::mac_type& key, int N, int ntrip, PRNG G; G.ReSeed(); - ofstream* outf=new ofstream[N]; + Files files(N, key, prep_data_prefix, DATA_TRIPLE, thread_num); typename T::clear a,b,c; - vector Sa(N),Sb(N),Sc(N); /* Generate Triples */ - for (int i=0; i(prep_data_prefix, N), DATA_TRIPLE, - T::type_short(), i, thread_num); - cout << "Opening " << filename << endl; - outf[i].open(filename,ios::out | ios::binary); - if (outf[i].fail()) { throw file_error(filename); } - } for (int i=0; i void make_inverse(const typename T::mac_type& key, int N, int ntrip, bool zero, @@ -542,17 +522,8 @@ void make_inverse(const typename T::mac_type& key, int N, int ntrip, bool zero, PRNG G; G.ReSeed(); - ofstream* outf=new ofstream[N]; + Files files(N, key, prep_data_prefix, DATA_INVERSE); typename T::clear a,b; - vector Sa(N),Sb(N); - /* Generate Triples */ - for (int i=0; i(prep_data_prefix, N) << "Inverses-" << T::type_short() << "-P" << i; - cout << "Opening " << filename.str() << endl; - outf[i].open(filename.str().c_str(),ios::out | ios::binary); - if (outf[i].fail()) { throw file_error(filename.str().c_str()); } - } for (int i=0; i&1 | tee logs/$log & true -done - -wait || exit 1 +run_player yao-party.x $* || exit 1 diff --git a/Tools/Buffer.cpp b/Tools/Buffer.cpp index 33dd3d6be..75cb8b6ed 100644 --- a/Tools/Buffer.cpp +++ b/Tools/Buffer.cpp @@ -4,6 +4,7 @@ */ #include "Tools/Buffer.h" +#include "Processor/BaseMachine.h" #include @@ -22,15 +23,30 @@ void BufferBase::setup(ifstream* f, int length, const string& filename, void BufferBase::seekg(int pos) { +#ifdef DEBUG_BUFFER + if (pos != 0) + printf("seek %d %s thread %d\n", pos, filename.c_str(), + BaseMachine::thread_num); +#endif if (not file) - file = open(); - file->seekg(pos * tuple_length); + { + if (pos == 0) + return; + else + file = open(); + } + + file->seekg(header_length + pos * tuple_length); if (file->eof() || file->fail()) { // let it go in case we don't need it anyway if (pos != 0) try_rewind(); } +#ifdef DEBUG_BUFFER + printf("seek %d %d thread %d\n", pos, int(file->tellg()), + BaseMachine::thread_num); +#endif next = BUFFER_SIZE; } @@ -40,10 +56,10 @@ void BufferBase::try_rewind() string type; if (field_type.size() and data_type.size()) type = (string)" of " + field_type + " " + data_type; - throw not_enough_to_buffer(type); + throw not_enough_to_buffer(type, filename); #endif file->clear(); // unset EOF flag - file->seekg(0); + file->seekg(header_length); if (file->peek() == ifstream::traits_type::eof()) throw runtime_error("empty file: " + filename); if (!rewind) @@ -54,18 +70,26 @@ void BufferBase::try_rewind() void BufferBase::prune() { - if (file and not file->good()) + if (file and (not file->good() or file->peek() == EOF)) purge(); - else if (file and file->tellg() != 0) + else if (file and file->tellg() != header_length) { #ifdef VERBOSE cerr << "Pruning " << filename << endl; #endif string tmp_name = filename + ".new"; ofstream tmp(tmp_name.c_str()); + size_t start = file->tellg(); + char buf[header_length]; + file->seekg(0); + file->read(buf, header_length); + tmp.write(buf, header_length); + file->seekg(start); tmp << file->rdbuf(); if (tmp.fail()) - throw runtime_error("problem writing to " + tmp_name); + throw runtime_error( + "problem writing to " + tmp_name + " from " + + to_string(start) + " of " + filename); tmp.close(); file->close(); rename(tmp_name.c_str(), filename.c_str()); diff --git a/Tools/Buffer.h b/Tools/Buffer.h index 84fbdaca9..a95dee0d9 100644 --- a/Tools/Buffer.h +++ b/Tools/Buffer.h @@ -13,6 +13,7 @@ using namespace std; #include "Math/field_types.h" #include "Tools/time-func.h" +#include "Tools/octetStream.h" #ifndef BUFFER_SIZE #define BUFFER_SIZE 101 @@ -30,12 +31,13 @@ class BufferBase Timer timer; int tuple_length; string filename; + int header_length; public: bool eof; BufferBase() : file(0), next(BUFFER_SIZE), - tuple_length(-1), eof(false) {} + tuple_length(-1), header_length(0), eof(false) {} ~BufferBase() {} virtual ifstream* open() = 0; void setup(ifstream* f, int length, const string& filename, @@ -63,6 +65,31 @@ class Buffer : public BufferBase void fill_buffer(); }; +template +octetStream file_signature() +{ + octetStream res(T::type_string()); + T::specification(res); + return res; +} + +template +octetStream check_file_signature(ifstream& file, const string& filename) +{ + octetStream file_spec; + try + { + file_spec.input(file); + } + catch (bad_alloc&) + { + throw signature_mismatch(filename); + } + if (file_signature() != file_spec) + throw signature_mismatch(filename); + return file_spec; +} + template class BufferOwner : public Buffer { @@ -88,6 +115,12 @@ class BufferOwner : public Buffer ifstream* open() { file = new ifstream(this->filename, ios::in | ios::binary); + if (file->good()) + { + auto file_spec = check_file_signature(*file, this->filename); + this->header_length = file_spec.get_length() + + sizeof(file_spec.get_length()); + } return file; } @@ -159,6 +192,9 @@ inline void Buffer::read(char* read_buffer) { file->read(read_buffer + n_read, size_in_bytes - n_read); n_read += file->gcount(); +#ifdef DEBUG_BUFFER + fprintf(stderr, "read %d\n", n_read); +#endif if (file->eof()) { try_rewind(); @@ -180,6 +216,9 @@ inline void Buffer::read(char* read_buffer) template inline void Buffer::input(U& a) { +#ifdef DEBUG_BUFFER + fprintf(stderr, "next is %d\n", next); +#endif if (next == BUFFER_SIZE) { fill_buffer(); diff --git a/Tools/Exceptions.cpp b/Tools/Exceptions.cpp index ee6722e28..96f69b0c5 100644 --- a/Tools/Exceptions.cpp +++ b/Tools/Exceptions.cpp @@ -51,11 +51,35 @@ invalid_opcode::invalid_opcode(int opcode) : } input_error::input_error(const char* name, const string& filename, - istream& input_file) + istream& input_file, size_t input_counter) { input_file.clear(); string token; input_file >> token; msg += string() + "cannot read " + name + " from " + filename - + ", problem with '" + token + "'"; + + ", problem with '" + token + "' after " + + to_string(input_counter); +} + +signature_mismatch::signature_mismatch(const string& filename) : + runtime_error("Signature in " + filename + " doesn't match protocol. " + "Re-run preprocessing") +{ +} + +insufficient_memory::insufficient_memory(size_t size, const string& type) : + runtime_error( + "program requires too much " + type + " memory: " + + to_string(size)) +{ +} + +not_enough_to_buffer::not_enough_to_buffer(const string& type, const string& filename) : + runtime_error( + "Not enough data available for buffer" + + (filename.empty() ? "" : (" in " + filename)) + ". " + "Maybe insufficient preprocessing" + type + + ".\nFor benchmarking, you can activate reusing data by " + "adding -DINSECURE to the compiler options.") +{ } diff --git a/Tools/Exceptions.h b/Tools/Exceptions.h index fd9820c26..18406cf6c 100644 --- a/Tools/Exceptions.h +++ b/Tools/Exceptions.h @@ -187,14 +187,7 @@ class how_would_that_work : public exception {}; class not_enough_to_buffer : public runtime_error { public: - not_enough_to_buffer(string type) : - runtime_error( - "Not enough data available for buffer. " - "Maybe insufficient preprocessing" + type - + ".\nFor benchmarking, you can activate reusing data by " - "adding -DINSECURE to the compiler options.") - { - } + not_enough_to_buffer(const string& type, const string& filename); }; class needs_cleaning : public exception {}; @@ -265,7 +258,7 @@ class input_error : public exception public: input_error(const char* name, const string& filename, - istream& input_file); + istream& input_file, size_t input_counter); const char* what() const throw() { @@ -273,4 +266,16 @@ class input_error : public exception } }; +class signature_mismatch : public runtime_error +{ +public: + signature_mismatch(const string& filename); +}; + +class insufficient_memory : public runtime_error +{ +public: + insufficient_memory(size_t size, const string& type); +}; + #endif diff --git a/Tools/aes-arm.h b/Tools/aes-arm.h index 0eacbe00a..33f24e883 100644 --- a/Tools/aes-arm.h +++ b/Tools/aes-arm.h @@ -246,22 +246,22 @@ FORCE_INLINE __m128i _mm_aesenclast_si128(__m128i a, __m128i RoundKey) { /* FIXME: optimized for NEON */ uint8_t v[4][4] = { - [0] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 0)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 5)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 10)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 15)]}, - [1] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 4)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 9)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 14)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 3)]}, - [2] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 8)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 13)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 2)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 7)]}, - [3] = {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 12)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 1)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 6)], - SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 11)]}, + {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 0)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 5)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 10)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 15)]}, + {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 4)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 9)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 14)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 3)]}, + {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 8)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 13)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 2)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 7)]}, + {SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 12)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 1)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 6)], + SSE2NEON_sbox[vreinterpretq_nth_u8_m128i(a, 11)]}, }; for (int i = 0; i < 16; i++) vreinterpretq_nth_u8_m128i(a, i) = diff --git a/Tools/cpu_support.h b/Tools/cpu_support.h index 755c302d9..aec7d2b3e 100644 --- a/Tools/cpu_support.h +++ b/Tools/cpu_support.h @@ -6,12 +6,19 @@ #ifndef TOOLS_CPU_SUPPORT_H_ #define TOOLS_CPU_SUPPORT_H_ +#include + inline bool check_cpu(int func, bool ecx, int feature) { +#ifdef __aarch64__ + (void) func, (void) ecx, (void) feature; + throw std::runtime_error("only for x86"); +#else int ax = func, bx, cx = 0, dx; __asm__ __volatile__ ("cpuid": "+a" (ax), "=b" (bx), "+c" (cx), "=d" (dx)); return ((ecx ? cx : bx) >> feature) & 1; +#endif } inline bool cpu_has_adx() diff --git a/Utils/Check-Offline-Z2k.cpp b/Utils/Check-Offline-Z2k.cpp index 7994b08b6..f00f6de4e 100644 --- a/Utils/Check-Offline-Z2k.cpp +++ b/Utils/Check-Offline-Z2k.cpp @@ -33,6 +33,9 @@ void check_triples_Z2k(int n_players, string type_char = "") ss << "-P" << i; inputFiles[i].open(ss.str().c_str()); cout << "Opening file " << ss.str() << endl; + octetStream tmp; + tmp.input(inputFiles[i]); + assert(tmp == file_signature()); } int j = 0; diff --git a/Utils/Check-Offline.cpp b/Utils/Check-Offline.cpp index 738a58916..3a3644144 100644 --- a/Utils/Check-Offline.cpp +++ b/Utils/Check-Offline.cpp @@ -59,13 +59,9 @@ void check_mult_triples(const typename T::mac_key_type& key,int N,vector void make_square_tuples(const typename T::mac_type& key,int N,int ntrip,const string& str,bool zero) @@ -88,34 +87,18 @@ void make_square_tuples(const typename T::mac_type& key,int N,int ntrip,const st PRNG G; G.ReSeed(); - ofstream* outf=new ofstream[N]; + Files files(N, key, prep_data_prefix, DATA_SQUARE); typename T::clear a,c; - vector Sa(N),Sc(N); /* Generate Squares */ - for (int i=0; i(prep_data_prefix, N) << "Squares-" - << T::type_short() << "-P" << i; - cout << "Opening " << filename.str() << endl; - outf[i].open(filename.str().c_str(),ios::out | ios::binary); - if (outf[i].fail()) { throw file_error(filename.str().c_str()); } - } for (int i=0; i files(N, key, prep_data_prefix, DATA_BIT, thread_num); typename T::clear a; - vector Sa(N); /* Generate Bits */ - for (int i=0; i(prep_data_prefix, N) << "Bits-" - << T::type_short() << "-P" << i - << Sub_Data_Files::get_suffix(thread_num); - cout << "Opening " << filename.str() << endl; - outf[i].open(filename.str().c_str(),ios::out | ios::binary); - if (outf[i].fail()) { throw file_error(filename.str().c_str()); } - } for (int i=0; i @@ -206,8 +174,6 @@ void FakeParams::make_edabits(const typename T::mac_type& key, int N, int ntrip, /* N = Number players * ntrip = Number inputs needed - * str = "2" or "p" - * */ template void make_inputs(const typename T::mac_type& key,int N,int ntrip,const string& str,bool zero) @@ -228,6 +194,7 @@ void make_inputs(const typename T::mac_type& key,int N,int ntrip,const string& s << T::type_short() << "-P" << i << "-" << player; cout << "Opening " << filename.str() << endl; outf[i].open(filename.str().c_str(),ios::out | ios::binary); + file_signature().output(outf[i]); if (outf[i].fail()) { throw file_error(filename.str().c_str()); } } for (int i=0; i>(keytt, nplayers, prep_data_prefix); - make_minimal>(keytt, nplayers, default_num / 64, zero); + make_minimal>(keytt, nplayers, default_num, zero); make_dabits(keyp, nplayers, default_num, zero, keytt); make_edabits(keyp, nplayers, default_num, zero, false_type(), keytt); @@ -804,6 +771,8 @@ int FakeParams::generate() { make_mult_triples>({}, nplayers, default_num, zero, prep_data_prefix); + make_bits>({}, nplayers, + default_num, zero); } generate_field(T::clear::prime_field); diff --git a/Utils/check-passive.cpp b/Utils/check-passive.cpp index dd20bdc86..86923be52 100644 --- a/Utils/check-passive.cpp +++ b/Utils/check-passive.cpp @@ -25,6 +25,9 @@ void check_triples(int n_players, string type_char = "") ss << "-P" << i; inputFiles[i].open(ss.str().c_str()); cout << "Opening file " << ss.str() << endl; + octetStream tmp, tmp2 = file_signature(); + tmp.input(inputFiles[i]); + assert(tmp == tmp2); } int j = 0; @@ -78,6 +81,7 @@ int main(int argc, char** argv) n_players = atoi(argv[1]); read_setup(get_prep_sub_dir>(PREP_DIR, n_players, 128)); gfp::init_field(gfp::pr(), false); + gf2n::init_field(); check_triples(n_players); check_triples(n_players); } diff --git a/Yao/YaoEvalWire.cpp b/Yao/YaoEvalWire.cpp index 2379d42d8..b3240e086 100644 --- a/Yao/YaoEvalWire.cpp +++ b/Yao/YaoEvalWire.cpp @@ -139,7 +139,7 @@ void YaoEvalWire::my_input(T& inputter, bool value, int n_bits) assert(n_bits == 1); auto& inputs = inputter.inputs; size_t start = inputs.size(); - inputs.resize(start + 1); + inputs.resize_zero(start + 1); inputs.set_bit(start, value); } @@ -215,10 +215,32 @@ void YaoEvalWire::set(Key key, bool external) void YaoEvalWire::convcbit(Integer& dest, const GC::Clear& source, GC::Processor>&) { - auto& evaluator = YaoEvaluator::s(); dest = source; - evaluator.P->send_long(0, source.get()); - throw needs_cleaning(); + auto &evaluator = YaoEvaluator::s(); + if (not evaluator.continuous()) + { + evaluator.P->send_long(0, source.get()); + throw needs_cleaning(); + } +} + +void YaoEvalWire::reveal_inst(Processor& processor, const vector& args) +{ + processor.reveal(args); + auto &evaluator = YaoEvaluator::s(); + if (evaluator.continuous()) + { + octetStream buffer; + for (size_t j = 0; j < args.size(); j += 3) + { + int n = args[j]; + int r0 = args[j + 1]; + for (int i = 0; i < DIV_CEIL(n, GC::Clear::N_BITS); i++) + processor.C[r0 + i].pack(buffer); + } + YaoEvaluator::s().P->send_to(0, buffer); + throw needs_cleaning(); + } } template void YaoEvalWire::and_( diff --git a/Yao/YaoEvalWire.h b/Yao/YaoEvalWire.h index 18b1e4caf..dc5d45a91 100644 --- a/Yao/YaoEvalWire.h +++ b/Yao/YaoEvalWire.h @@ -59,6 +59,7 @@ class YaoEvalWire : public YaoWire static void convcbit(Integer& dest, const GC::Clear& source, GC::Processor>&); + static void reveal_inst(Processor& processor, const vector& args); void set(const Key& key); void set(Key key, bool external); diff --git a/Yao/YaoEvaluator.cpp b/Yao/YaoEvaluator.cpp index 0126c8b15..7b1b60154 100644 --- a/Yao/YaoEvaluator.cpp +++ b/Yao/YaoEvaluator.cpp @@ -29,7 +29,8 @@ YaoEvaluator::YaoEvaluator(int thread_num, YaoEvalMaster& master) : void YaoEvaluator::pre_run() { - processor.out.activate(true); + if (master.opts.cmd_private_output_file.empty()) + processor.out.activate(not continuous()); if (not continuous()) receive_to_store(*P); } diff --git a/Yao/YaoGarbleWire.cpp b/Yao/YaoGarbleWire.cpp index 637ce4b40..7e52602ec 100644 --- a/Yao/YaoGarbleWire.cpp +++ b/Yao/YaoGarbleWire.cpp @@ -8,6 +8,7 @@ #include "YaoGarbler.h" #include "YaoGarbleInput.h" #include "GC/ArgTuples.h" +#include "Tools/pprint.h" #include "GC/Processor.hpp" #include "GC/Secret.hpp" @@ -197,8 +198,35 @@ char YaoGarbleWire::get_output() void YaoGarbleWire::convcbit(Integer& dest, const GC::Clear& source, GC::Processor>&) { - (void) source; - auto& garbler = YaoGarbler::s(); - garbler.untaint(); - dest = garbler.P->receive_long(1); + auto &garbler = YaoGarbler::s(); + if (garbler.continuous()) + dest = source; + else + { + garbler.untaint(); + dest = garbler.P->receive_long(1); + } +} + +void YaoGarbleWire::reveal_inst(Processor& processor, const vector& args) +{ + auto &garbler = YaoGarbler::s(); + if (garbler.continuous()) + { + if (garbler.is_tainted()) + processor.reveal(args); + garbler.untaint(); + octetStream buffer; + garbler.P->receive_player(1, buffer); + for (size_t j = 0; j < args.size(); j += 3) + { + int n = args[j]; + int r0 = args[j + 1]; + for (int i = 0; i < DIV_CEIL(n, GC::Clear::N_BITS); i++) + processor.C[r0 + i].unpack(buffer); + } + garbler.taint(); + } + else + processor.reveal(args); } diff --git a/Yao/YaoGarbleWire.h b/Yao/YaoGarbleWire.h index 885bde7c2..47ebe8e51 100644 --- a/Yao/YaoGarbleWire.h +++ b/Yao/YaoGarbleWire.h @@ -23,6 +23,7 @@ class YaoGarbleWire : public YaoWire typedef YaoGarbler Party; typedef YaoGarbleInput Input; typedef GC::Processor> Processor; + typedef SwitchableOutput out_type; static string name() { return "YaoGarbleWire"; } @@ -59,6 +60,7 @@ class YaoGarbleWire : public YaoWire static void convcbit(Integer& dest, const GC::Clear& source, GC::Processor>&); + static void reveal_inst(Processor& processor, const vector& args); void randomize(PRNG& prng); void set(Key key, bool mask); diff --git a/Yao/YaoGarbler.cpp b/Yao/YaoGarbler.cpp index 53b0401f4..e6ae6cda1 100644 --- a/Yao/YaoGarbler.cpp +++ b/Yao/YaoGarbler.cpp @@ -30,6 +30,15 @@ YaoGarbler::YaoGarbler(int thread_num, YaoGarbleMaster& master) : prng.ReSeed(); set_n_program_threads(master.machine.nthreads); this->init(*this); + if (continuous()) + taint(); + else + { + processor.out.activate(false); + if (not master.opts.cmd_private_output_file.empty()) + cerr << "Garbling party cannot output with one-shot computation" + << endl; + } } YaoGarbler::~YaoGarbler() diff --git a/Yao/YaoPlayer.cpp b/Yao/YaoPlayer.cpp index fcebe2875..a947b1f51 100644 --- a/Yao/YaoPlayer.cpp +++ b/Yao/YaoPlayer.cpp @@ -7,39 +7,13 @@ #include "YaoGarbler.h" #include "YaoEvaluator.h" #include "Tools/ezOptionParser.h" +#include "Tools/NetworkOptions.h" #include "GC/Machine.hpp" YaoPlayer::YaoPlayer(int argc, const char** argv) { ez::ezOptionParser opt; - opt.add( - "", // Default. - 1, // Required? - 1, // Number of args expected. - 0, // Delimiter if expecting multiple args. - "This player's number, 0 for garbling, 1 for evaluating.", // Help description. - "-p", // Flag token. - "--player" // Flag token. - ); - opt.add( - "localhost", // Default. - 0, // Required? - 1, // Number of args expected. - 0, // Delimiter if expecting multiple args. - "Host where party 0 is running (default: localhost)", // Help description. - "-h", // Flag token. - "--hostname" // Flag token. - ); - opt.add( - "5000", // Default. - 0, // Required? - 1, // Number of args expected. - 0, // Delimiter if expecting multiple args. - "Base port number (default: 5000).", // Help description. - "-pn", // Flag token. - "--portnum" // Flag token. - ); opt.add( "", // Default. 0, // Required? @@ -59,33 +33,15 @@ YaoPlayer::YaoPlayer(int argc, const char** argv) "--threshold" // Flag token. ); auto& online_opts = OnlineOptions::singleton; - online_opts = {opt, argc, argv}; - opt.parse(argc, argv); - opt.syntax = "./yao-player.x [OPTIONS] "; - vector free_args = opt.firstArgs; - free_args.insert(free_args.end(), opt.unknownArgs.begin(), opt.unknownArgs.end()); - free_args.insert(free_args.end(), opt.lastArgs.begin(), opt.lastArgs.end()); - if (free_args.size() == 2) - { - progname = *free_args[1]; - } - else - { - string usage; - opt.getUsage(usage); - cerr << usage; - exit(1); - } + online_opts = {opt, argc, argv, false_type()}; + NetworkOptionsWithNumber network_opts(opt, argc, argv, 2, false); + online_opts.finalize(opt, argc, argv); - int my_num; - int pnb; - string hostname; + int my_num = online_opts.playerno; int threshold; - opt.get("-p")->getInt(my_num); - opt.get("-pn")->getInt(pnb); - opt.get("-h")->getString(hostname); bool continuous = not opt.get("-O")->isSet; opt.get("-t")->getInt(threshold); + progname = online_opts.progname; GC::ThreadMasterBase* master; if (my_num == 0) @@ -93,7 +49,7 @@ YaoPlayer::YaoPlayer(int argc, const char** argv) else master = new YaoEvalMaster(continuous, online_opts); - Server::start_networking(master->N, my_num, 2, hostname, pnb); + network_opts.start_networking(master->N, my_num); master->run(progname); if (my_num == 1) diff --git a/compile.py b/compile.py index eea78ec8d..da1b69ee3 100755 --- a/compile.py +++ b/compile.py @@ -78,7 +78,7 @@ def main(): "(number of parties as argument)") parser.add_option("-C", "--CISC", action="store_true", dest="cisc", help="faster CISC compilation mode") - parser.add_option("-K", "--keep-cisc", action="store_true", dest="keep_cisc", + parser.add_option("-K", "--keep-cisc", dest="keep_cisc", help="don't translate CISC instructions") parser.add_option("-l", "--flow-optimization", action="store_true", dest="flow_optimization", help="optimize control flow") diff --git a/doc/Doxyfile b/doc/Doxyfile index 7fa2bafe7..771f8cf13 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -829,7 +829,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = ../Networking ../Tools/octetStream.h +INPUT = ../Networking ../Tools/octetStream.h ../Processor/Data_Files.h ../Protocols/Replicated.h ../Protocols/ReplicatedPrep.h ../Protocols/MAC_Check_Base.h ../Processor/Input.h # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/doc/_static/custom.css b/doc/_static/custom.css new file mode 100644 index 000000000..d756b5ce6 --- /dev/null +++ b/doc/_static/custom.css @@ -0,0 +1,3 @@ +.wy-table-responsive table td { +white-space: normal; +} diff --git a/doc/add-protocol.rst b/doc/add-protocol.rst index e9cad665b..ff6a05081 100644 --- a/doc/add-protocol.rst +++ b/doc/add-protocol.rst @@ -40,11 +40,13 @@ found in ``Protocols/Replicated.h``. 1. Fill in the :c:func:`constant` static member function of :c:type:`NoShare` as well as the :c:func:`exchange` member function - of c:type:`NoOutput`. Check out + of :c:type:`NoOutput`. Check out :c:func:`DirectSemiMC::exchange_` in ``Protocols/SemiMC.hpp`` for a simple example. It opens an additive secret sharing by sending all shares to all other parties and then summing up the - received. Constant sharing and public output allows to execute the + received. See :ref:`this reference ` for + documentation on the necessary infrastructure. + Constant sharing and public output allows to execute the following program:: print_ln('%s', sint(123).reveal()) diff --git a/doc/conf.py b/doc/conf.py index bf13bf574..a57f08fa0 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -186,3 +186,6 @@ breathe_default_project = 'mp-spdz' import subprocess subprocess.call('doxygen', shell=True) + +def setup(app): + app.add_stylesheet('custom.css') diff --git a/doc/gen-instructions.py b/doc/gen-instructions.py index db0c5a2d8..561f25c63 100755 --- a/doc/gen-instructions.py +++ b/doc/gen-instructions.py @@ -24,7 +24,7 @@ for name, opcode in sorted(items, key=lambda x: x[1]): d, n = desc.get(opcode, (None, None)) if d and '$' not in d and '|' not in d and opcode not in \ - (0x64, 0x65, 0x66, 0x6a) : + (0x65, 0x6a) : m = re.split(r'\.\s', d) if m: d = m[0] diff --git a/doc/instructions.rst b/doc/instructions.rst index 795077707..1a833994e 100644 --- a/doc/instructions.rst +++ b/doc/instructions.rst @@ -89,7 +89,6 @@ Compiler.instructions module print_char_regint, protectmemc, sqrs, start_grind, startprivateoutput, stop_grind, stopprivateoutput, writesocketc, writesocketint, - writesockets, readsockets, protectmemint, protectmems, print_mem, matmul_base, g2muls, inputmixed_base, raw_output diff --git a/doc/low-level.rst b/doc/low-level.rst index 5325fd623..0aaf3708e 100644 --- a/doc/low-level.rst +++ b/doc/low-level.rst @@ -254,3 +254,151 @@ necessary to call the checking in order to verify the outputs. This frees the memory used for global key material when using homomorphic encryption. Otherwise, this does not do anything. + + +Domain Types +------------ + +.. list-table:: + :widths: 20 80 + + * + - ``gfp_`` + - Computation modulo a prime. ``L`` is the number of 64-bit + limbs, that is, it covers primes of bit length + :math:`64(L-1)+1` to :math:`64L`. The type has to be + initialized using :cpp:func:`init_field` or + :cpp:func:`init_default`. The latter picks a prime given a bit length. + * + - ``SignedZ2`` / ``Z2`` + - Computation modulo :math:`2^K`. This is not a field. + * + - ``gf2n_short`` / ``gf2n_long`` / ``gf2n_`` + - :math:`GF(2^n)`. ``T`` denotes a type that is used to store the + values. It must support a variety of integer + operations. The type has to be initialized using + :cpp:func:`init_field`. The choice of degrees is limited. At + the time of writing, 4, 8, 28, 40, 63, and 128 are supported if the + storage type is large enough. + +Share Types +------------ + +.. list-table:: + :widths: 20 80 + :header-rows: 1 + + * + - Type + - Protocol + * + - ``AtlasShare`` + - Semi-honest version of `ATLAS + `_ (Section 4.2). ``T`` must + represent a field. + * + - ``ChaiGearShare`` + - `HighGear `_ with covert key + setup. ``T`` must be ``gfp_`` or ``gf2n_short``. + * + - ``CowGearShare`` + - `LowGear `_ with covert key + setup. ``T`` must be ``gfp_`` or ``gf2n_short``. + * + - ``HemiShare`` + - Semi-honest protocol with Beaver multiplication based on + semi-homomorphic encryption. ``T`` must be ``gfp_`` or + ``gf2n_short``. + * + - ``HighGearShare`` + - `HighGear `_. ``T`` must be + ``gfp_`` or ``gf2n_short``. + * + - ``LowGearShare`` + - `LowGear `_. ``T`` must be + ``gfp_`` or ``gf2n_short``. + * + - ``MaliciousShamirShare`` + - Shamir secret sharing with Beaver multiplication and sacrifice. + ``T`` must represent a field. + * + - ``MamaShare`` + - `MASCOT `_ with multiple + MACs. ``T`` must represent a field, ``N`` is the number of MACs. + * + - ``PostSacriRepFieldShare`` + - `Post-sacrifice `_ protocol + using three-party replicated secret sharing with ``T`` + representing a field. + * + - ``PostSacriRepRingShare`` + - `Post-sacrifice protocol `_ + using replicated three-party secret sharing modulo :math:`2^K` + with security parameter ``S``. + * + - ``Rep3Share2`` + - `Three-party semi-honest protocol + `_ using replicated secret + sharing modulo :math:`2^K`. + * + - ``Rep4Share`` + - `Four-party malicious protocol + `_ using replicated secret + sharing over a field. + * + - ``Rep4Share2`` + - `Four-party malicious protocol + `_ using replicated secret + sharing modulo :math:`2^K`. + * + - ``SemiShare2`` + - Semi-honest dishonest-majority protocol using Beaver + multiplication based on oblivious transfer modulo :math:`2^K`. + * + - ``SemiShare`` + - Semi-honest dishonest-majority protocol using Beaver + multiplication based on oblivious transfer in a field. + * + - ``ShamirShare`` + - `Semi-honest protocol `_ + based on Shamir's secret sharing. ``T`` must represent a field. + * + - ``Share`` + - `MASCOT `_. ``T`` must + represent a field. + * + - ``SohoShare`` + - Semi-honest protocol with Beaver multiplication based on + somewhat homomorphic encryption. ``T`` must be ``gfp_`` + or ``gf2n_short``. + * + - ``Spdz2kShare`` + - `SPDZ2k `_ computing modulo + :math:`2^K` with security parameter ``S``. + * + - ``SpdzWiseShare`` + - `SPDZ-wise `_ computing + modulo :math:`2^K` with security parameter ``S``. + * + - ``SpdzWiseShare`` + - `SPDZ-wise `_. ``T`` must be + ``MaliciousShamirShare`` or ``MaliciousRep3Share``. + + +Protocol Interfaces +------------------- + +.. doxygenclass:: ProtocolBase + :members: + +.. doxygenclass:: InputBase + :members: + +.. doxygenclass:: MAC_Check_Base + :members: + +.. doxygenclass:: Preprocessing + :members: + +.. doxygenclass:: BufferPrep + :members: diff --git a/doc/networking.rst b/doc/networking.rst index 896a4bf5b..16908681a 100644 --- a/doc/networking.rst +++ b/doc/networking.rst @@ -43,6 +43,8 @@ the same on all hosts, and you have to run ``c_rehash Player-Data`` on all of them. +.. _network-reference: + Internal Infrastructure ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/non-linear.rst b/doc/non-linear.rst index e85f2e24d..5fe8df1f6 100644 --- a/doc/non-linear.rst +++ b/doc/non-linear.rst @@ -65,8 +65,46 @@ computation for parts of the computation. MP-SPDZ implements protocols proposed for particular security models by a number of works: `Demmler et al. `_, `Mohassel and Rindal `_, and `Dalskov et -al. `_. MP-SPDZ also implements +al. `_ MP-SPDZ also implements more general methods such as `daBits `_ and `edaBits -`_ +`_. + +Protocol Pairs +============== + +The following table lists the matching arithmetic and binary protocols. + +.. list-table:: + :header-rows: 1 + + * + - Arithmetic + - Binary + * + - MASCOT, SPDZ2k, LowGear, HighGear, CowGear, ChaiGear + - `Tinier `_ with improved + cut-and-choose analysis by `Furukawa et + al. `_ + * + - Semi, Hemi, Soho, Semi2k + - SemiBin (Beaver triples modulo 2 using OT) + * + - `Malicious Shamir `_ + - Malicious Shamir over :math:`GF(2^{40})` for secure sacrificing + * + - Malicious Rep3, Post-Sacrifice, SPDZ-wise replicated + - `Malicious Rep3 modulo 2 `_ + * + - `Rep4 `_ + - Rep4 modulo 2 + * + - `Shamir `_ + - Shamir over :math:`GF(2^8)` + * + - `ATLAS `_ + - ATLAS over :math:`GF(2^8)` + * + - `Rep3 `_ + - Rep3 diff --git a/doc/troubleshooting.rst b/doc/troubleshooting.rst index 09b877542..1c096d985 100644 --- a/doc/troubleshooting.rst +++ b/doc/troubleshooting.rst @@ -53,17 +53,30 @@ that computation can seem oddly slow or fast. For example, one multiplication has a similar cost then some thousand multiplications when using homomorphic encryption because one batch contains information for more than than 10,000 multiplications. Only when a -second batch is necessary the cost shoots up. +second batch is necessary the cost shoots up. Other preprocessing +methods allow for a variable batch size, which can be changed using +``-b``. Smaller batch sizes generally reduce the communication cost +while potentially increasing the number of communication rounds. Try +adding ``-b 10`` to the virtal machine (or script) arguments for very +short computations. Handshake failures ~~~~~~~~~~~~~~~~~~ If you run on different hosts, the certificates -(``Player-Data/*.pem``) must be the same on all of them. Also make -sure to run ``c_rehash Player-Data`` on all hosts. Finally, the -certificates generated by ``Scripts/setup-ssl.sh`` expire after a -month, so you might to regenerate them. +(``Player-Data/*.pem``) must be the same on all of them. Furthermore, +party ```` requires ``Player-Data/P.key`` that must match +``Player-Data/P.pem``, that is, they have to be generated to +together. The easiest way of setting this up is to run +``Scripts/setup-ssl.sh`` on one host and then copy all +``Player-Data/*.{pem,key}`` to all other hosts. This is *not* secure +but it suffices for experiments. A secure setup would generate every +key pair locally and then distributed only the public keys. Finally, +run ``c_rehash Player-Data`` on all hosts. The certificates generated +by ``Scripts/setup-ssl.sh`` expire after a month, so you need to +regenerate them. The same holds for ``Scripts/setup-client.sh`` if you +use the client facility. Connection failures