From bd60197886922bf039f4844f8f90d327be9e414c Mon Sep 17 00:00:00 2001 From: Marcel Keller Date: Tue, 6 Aug 2019 16:45:52 +1000 Subject: [PATCH] ECDSA, more replicated secret sharing. --- CHANGELOG.md | 11 +- CONFIG | 12 ++- Check-Offline.cpp | 2 +- Compiler/allocator.py | 21 +++- Compiler/instructions.py | 2 + Compiler/instructions_base.py | 2 +- Compiler/library.py | 95 +++++++++++++---- Compiler/program.py | 13 ++- Compiler/types.py | 11 +- ECDSA/Fake-ECDSA.cpp | 25 +++++ ECDSA/P256Element.cpp | 120 +++++++++++++++++++++ ECDSA/P256Element.h | 74 +++++++++++++ ECDSA/README.md | 44 ++++++++ ECDSA/fake-spdz-ecdsa-party.cpp | 52 ++++++++++ ECDSA/hm-ecdsa-party.hpp | 71 +++++++++++++ ECDSA/mal-rep-ecdsa-party.cpp | 13 +++ ECDSA/mal-shamir-ecdsa-party.cpp | 20 ++++ ECDSA/mascot-ecdsa-party.cpp | 15 +++ ECDSA/ot-ecdsa-party.hpp | 80 ++++++++++++++ ECDSA/preprocessing.hpp | 101 ++++++++++++++++++ ECDSA/rep-ecdsa-party.cpp | 20 ++++ ECDSA/semi-ecdsa-party.cpp | 17 +++ ECDSA/shamir-ecdsa-party.cpp | 19 ++++ ECDSA/sign.hpp | 148 ++++++++++++++++++++++++++ FHE/Matrix.h | 2 +- FHE/NTL-Subs.cpp | 2 +- FHEOffline/SimpleEncCommit.cpp | 2 + Fake-Offline.cpp | 142 ++----------------------- GC/FakeSecret.h | 4 + GC/Machine.cpp | 2 +- GC/MaliciousRepPrep.cpp | 53 ++++++++++ GC/MaliciousRepPrep.h | 34 ++++++ GC/MaliciousRepSecret.h | 22 ++++ GC/MaliciousRepThread.cpp | 40 ++----- GC/MaliciousRepThread.h | 9 +- GC/ReplicatedSecret.cpp | 91 +++++----------- GC/ReplicatedSecret.h | 14 ++- GC/Secret.h | 3 + GC/Thread.h | 2 +- Machines/Semi.hpp | 1 + Machines/ShamirMachine.cpp | 28 ++--- Machines/ShamirMachine.h | 19 ++-- Machines/mal-shamir-bmr-party.cpp | 3 +- Machines/shamir-bmr-party.cpp | 3 +- Makefile | 38 +++++-- Math/BitVec.h | 6 ++ Math/FixedVec.h | 9 ++ Math/Setup.cpp | 4 +- Math/Setup.h | 2 +- Math/Square.cpp | 36 +++++++ Math/Square.h | 42 ++++++++ Math/Square.hpp | 59 +++++++++++ Math/Z2k.h | 16 +-- Math/Zp_Data.cpp | 17 ++- Math/Zp_Data.h | 10 ++ Math/gf2n.cpp | 3 +- Math/gf2n.h | 23 +++-- Math/gf2nlong.cpp | 3 +- Math/gf2nlong.h | 23 +++-- Math/gf2nshortsquare.cpp | 53 ---------- Math/gf2nshortsquare.h | 42 -------- Math/gfp.cpp | 15 ++- Math/gfp.h | 32 ++++-- Math/modp.hpp | 2 +- Networking/Player.cpp | 65 +++++++++++- Networking/Player.h | 12 ++- Networking/Server.cpp | 1 + OT/BaseOT.h | 2 +- OT/BitMatrix.cpp | 148 +++----------------------- OT/BitMatrix.h | 11 +- OT/OTExtensionWithMatrix.cpp | 16 +-- OT/OTMultiplier.cpp | 7 +- OT/Rectangle.h | 2 +- Processor/Data_Files.h | 2 + Processor/Input.h | 2 +- Processor/Input.hpp | 30 +++--- Processor/Instruction.hpp | 20 ++-- Processor/Machine.hpp | 4 + Processor/OnlineOptions.cpp | 8 +- Processor/Processor.hpp | 1 + Processor/ProcessorBase.cpp | 2 +- Programs/Source/tutorial.mpc | 6 +- Protocols/Beaver.h | 11 +- Protocols/Beaver.hpp | 22 ++-- Protocols/BrainPrep.hpp | 3 +- Protocols/CowGearPrep.h | 2 + Protocols/CowGearPrep.hpp | 33 +++++- Protocols/MAC_Check.h | 5 +- Protocols/MAC_Check.hpp | 105 ++++++++++++------- Protocols/MAC_Check_Base.h | 6 +- Protocols/MalRepRingPrep.hpp | 17 ++- Protocols/MalRepRingShare.h | 1 + Protocols/MaliciousRep3Share.h | 2 + Protocols/MaliciousRepMC.hpp | 1 + Protocols/MaliciousRepPrep.h | 2 +- Protocols/MaliciousRepPrep.hpp | 12 +-- Protocols/MaliciousShamirMC.h | 6 +- Protocols/MaliciousShamirMC.hpp | 3 +- Protocols/MaliciousShamirShare.h | 1 + Protocols/PostSacriRepRingShare.h | 10 +- Protocols/PostSacrifice.h | 13 ++- Protocols/PostSacrifice.hpp | 23 +++-- Protocols/Rep3Share.h | 1 + Protocols/Replicated.h | 10 +- Protocols/Replicated.hpp | 15 +-- Protocols/ReplicatedPrep.h | 7 +- Protocols/ReplicatedPrep.hpp | 20 +++- Protocols/Semi2kShare.h | 2 +- Protocols/SemiMC.h | 13 ++- Protocols/SemiMC.hpp | 22 ++++ Protocols/SemiShare.h | 8 +- Protocols/Shamir.h | 4 +- Protocols/Shamir.hpp | 7 +- Protocols/ShamirInput.h | 2 +- Protocols/ShamirMC.h | 6 +- Protocols/ShamirMC.hpp | 2 +- Protocols/ShamirShare.h | 1 + Protocols/Share.h | 10 +- Protocols/fake-stuff.hpp | 140 +++++++++++++++++++++++++ README.md | 22 ++-- Scripts/mal-rep-bin.sh | 21 ++-- Scripts/mal-shamir.sh | 2 +- Scripts/mascot.sh | 6 +- Scripts/rep-field.sh | 2 +- Scripts/replicated.sh | 21 ++-- Scripts/run-online.sh | 6 +- Scripts/semi.sh | 6 +- Scripts/test_ecdsa.sh | 29 ++++++ Scripts/test_tutorial.sh | 2 +- SimpleOT | 2 +- {OT => Tools}/BitVector.cpp | 3 +- {OT => Tools}/BitVector.h | 5 +- Tools/Bundle.h | 2 +- Tools/MMO.cpp | 71 ++++++------- Tools/MMO.h | 3 + Tools/octetStream.h | 11 +- Tools/random.cpp | 28 ++++- Tools/random.h | 2 + Tools/time-func.cpp | 10 ++ Tools/time-func.h | 2 + compile.py | 3 + default-prime-length.cpp | 11 ++ tutorial.md | 166 ------------------------------ 143 files changed, 2186 insertions(+), 1036 deletions(-) create mode 100644 ECDSA/Fake-ECDSA.cpp create mode 100644 ECDSA/P256Element.cpp create mode 100644 ECDSA/P256Element.h create mode 100644 ECDSA/README.md create mode 100644 ECDSA/fake-spdz-ecdsa-party.cpp create mode 100644 ECDSA/hm-ecdsa-party.hpp create mode 100644 ECDSA/mal-rep-ecdsa-party.cpp create mode 100644 ECDSA/mal-shamir-ecdsa-party.cpp create mode 100644 ECDSA/mascot-ecdsa-party.cpp create mode 100644 ECDSA/ot-ecdsa-party.hpp create mode 100644 ECDSA/preprocessing.hpp create mode 100644 ECDSA/rep-ecdsa-party.cpp create mode 100644 ECDSA/semi-ecdsa-party.cpp create mode 100644 ECDSA/shamir-ecdsa-party.cpp create mode 100644 ECDSA/sign.hpp create mode 100644 GC/MaliciousRepPrep.cpp create mode 100644 GC/MaliciousRepPrep.h create mode 100644 Math/Square.cpp create mode 100644 Math/Square.h create mode 100644 Math/Square.hpp delete mode 100644 Math/gf2nshortsquare.cpp delete mode 100644 Math/gf2nshortsquare.h create mode 100755 Scripts/test_ecdsa.sh rename {OT => Tools}/BitVector.cpp (98%) rename {OT => Tools}/BitVector.h (98%) create mode 100644 default-prime-length.cpp delete mode 100644 tutorial.md diff --git a/CHANGELOG.md b/CHANGELOG.md index cc20e8358..5d08a074e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,13 @@ -The changelog explains changes pulled through from the private development repository. Bug fixes and small enchancements are committed between releases and not documented here. +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.1.1 (Aug 6, 2019) + +- ECDSA +- Loop unrolling with budget as in [HyCC](https://thomaschneider.de/papers/BDKKS18.pdf) +- Malicious replicated secret sharing for binary circuits +- New variants of malicious replicated secret over rings in [Use your Brain!](https://eprint.iacr.org/2019/164) +- MASCOT for any prime larger than 2^64 +- Private fixed- and floating-point inputs ## 0.1.0 (Jun 7, 2019) diff --git a/CONFIG b/CONFIG index 7007773e4..329bfbf0f 100644 --- a/CONFIG +++ b/CONFIG @@ -18,8 +18,8 @@ USE_GF2N_LONG = 1 # set to -march= for optimization # SSE4.2 is required homomorphic encryption in GF(2^n) when compiling with clang -# AES-NI is required for BMR -# PCLMUL is required for GF(2^128) computation +# AES-NI and PCLMUL are not required +# AVX is required for oblivious transfer (OT) # AVX2 support (Haswell or later) is used to optimize OT # AVX/AVX2 is required for replicated binary secret sharing # BMI2 is used to optimize multiplication modulo a prime @@ -63,3 +63,11 @@ endif CFLAGS += $(ARCH) $(MY_CFLAGS) $(GDEBUG) -Wextra -Wall $(OPTIM) -I$(ROOT) -pthread $(PROF) $(DEBUG) $(MOD) $(MEMPROTECT) $(GF2N_LONG) $(PREP_DIR) -std=c++11 -Werror CPPFLAGS = $(CFLAGS) LD = $(CXX) + +ECLIB = -lcryptopp + +ifeq ($(OS), Darwin) +ifeq ($(USE_NTL),1) +CFLAGS += -Wno-error=unused-parameter +endif +endif diff --git a/Check-Offline.cpp b/Check-Offline.cpp index 271f12292..c7645a44a 100644 --- a/Check-Offline.cpp +++ b/Check-Offline.cpp @@ -146,7 +146,7 @@ void check_bits(const typename T::mac_key_type& key,int N,vector 0: - print 'Eliminated %d dead instructions, among which %d opens' % (count, open_count) + print 'Eliminated %d dead instructions, among which %d opens: %s' \ + % (count, open_count, dict(stats)) def print_graph(self, filename): f = open(filename, 'w') diff --git a/Compiler/instructions.py b/Compiler/instructions.py index fd5e1a16e..568091abc 100644 --- a/Compiler/instructions.py +++ b/Compiler/instructions.py @@ -870,6 +870,7 @@ def add_usage(self, req_node): def execute(self): self.args[0].value = _python_input("Enter player %d's input:" % self.args[1]) % program.P +@base.vectorize class inputfix(base.TextInputInstruction): __slots__ = [] code = base.opcodes['INPUTFIX'] @@ -881,6 +882,7 @@ def add_usage(self, req_node): req_node.increment((self.field_type, 'input', player), \ self.get_size()) +@base.vectorize class inputfloat(base.TextInputInstruction): __slots__ = [] code = base.opcodes['INPUTFLOAT'] diff --git a/Compiler/instructions_base.py b/Compiler/instructions_base.py index 2f598e7a1..a4f7a2900 100644 --- a/Compiler/instructions_base.py +++ b/Compiler/instructions_base.py @@ -726,7 +726,7 @@ class IntegerInstruction(Instruction): __slots__ = [] arg_format = ['ciw', 'ci', 'ci'] -class StackInstruction(Instruction): +class StackInstruction(DoNotEliminateInstruction): """ Base class for thread-local stack instructions. """ __slots__ = [] diff --git a/Compiler/library.py b/Compiler/library.py index d5d354cbd..8f42f3207 100644 --- a/Compiler/library.py +++ b/Compiler/library.py @@ -804,14 +804,17 @@ def decorator(loop_body): return decorator def for_range_parallel(n_parallel, n_loops): - return map_reduce_single(n_parallel, n_loops, \ - lambda *x: [], lambda *x: []) + return map_reduce_single(n_parallel, n_loops) -def map_reduce_single(n_parallel, n_loops, initializer, reducer, mem_state=None): - if not isinstance(n_parallel, int): +def for_range_opt(n_loops): + return map_reduce_single(None, n_loops) + +def map_reduce_single(n_parallel, n_loops, initializer=lambda *x: [], + reducer=lambda *x: [], mem_state=None): + if not (isinstance(n_parallel, int) or n_parallel is None): raise CompilerException('Number of parallel executions' \ 'must be constant') - n_parallel = n_parallel or 1 + n_parallel = 1 if n_parallel is 0 else n_parallel if mem_state is None: # default to list of MemValues to allow varying types mem_state = [MemValue(x) for x in initializer()] @@ -820,11 +823,13 @@ def map_reduce_single(n_parallel, n_loops, initializer, reducer, mem_state=None) # use Arrays for multithread version use_array = True def decorator(loop_body): - if isinstance(n_loops, int): - loop_rounds = n_loops / n_parallel \ - if n_parallel < n_loops else 0 - else: - loop_rounds = n_loops / n_parallel + my_n_parallel = n_parallel + if isinstance(n_parallel, int): + if isinstance(n_loops, int): + loop_rounds = n_loops / n_parallel \ + if n_parallel < n_loops else 0 + else: + loop_rounds = n_loops / n_parallel def write_state_to_memory(r): if use_array: mem_state.assign(r) @@ -832,21 +837,69 @@ def write_state_to_memory(r): # cannot do mem_state = [...] due to scope issue for j,x in enumerate(r): mem_state[j].write(x) - # will be optimized out if n_loops <= n_parallel - @for_range(loop_rounds) - def f(i): - state = tuplify(initializer()) - for k in range(n_parallel): - j = i * n_parallel + k - state = reducer(tuplify(loop_body(j)), state) - r = reducer(mem_state, state) - write_state_to_memory(r) + if n_parallel is not None: + # will be optimized out if n_loops <= n_parallel + @for_range(loop_rounds) + def f(i): + state = tuplify(initializer()) + for k in range(n_parallel): + j = i * n_parallel + k + state = reducer(tuplify(loop_body(j)), state) + r = reducer(mem_state, state) + write_state_to_memory(r) + else: + n_parallel_reg = MemValue(regint(0)) + parent_block = get_block() + @while_do(lambda x: x + n_parallel_reg <= n_loops, regint(0)) + def _(i): + state = tuplify(initializer()) + k = 0 + block = get_block() + while k < n_loops and (len(get_block()) < get_program().budget \ + or k == 0) \ + and block is get_block(): + j = i + k + state = reducer(tuplify(loop_body(j)), state) + k += 1 + r = reducer(mem_state, state) + write_state_to_memory(r) + global n_opt_loops + n_opt_loops = k + n_parallel_reg.write(k) + return i + k + my_n_parallel = n_opt_loops + loop_rounds = n_loops / my_n_parallel + blocks = get_tape().basicblocks + n_to_merge = 5 + if loop_rounds == 1 and parent_block is blocks[-n_to_merge]: + # merge blocks started by if and do_while + def exit_elimination(block): + if block.exit_condition is not None: + for reg in block.exit_condition.get_used(): + reg.can_eliminate = True + exit_elimination(parent_block) + merged = parent_block + merged.exit_condition = blocks[-1].exit_condition + merged.exit_block = blocks[-1].exit_block + assert parent_block is blocks[-n_to_merge] + assert blocks[-n_to_merge + 1] is \ + get_tape().req_node.children[-1].nodes[0].blocks[0] + for block in blocks[-n_to_merge + 1:]: + merged.instructions += block.instructions + exit_elimination(block) + del blocks[-n_to_merge + 1:] + del get_tape().req_node.children[-1] + merged.children = [] + get_tape().active_basicblock = merged + else: + req_node = get_tape().req_node.children[-1].nodes[0] + req_node.children[0].aggregator = lambda x: loop_rounds * x[0] if isinstance(n_loops, int): state = mem_state - for j in range(loop_rounds * n_parallel, n_loops): + for j in range(loop_rounds * my_n_parallel, n_loops): state = reducer(tuplify(loop_body(j)), state) else: - @for_range(loop_rounds * n_parallel, n_loops) + @for_range(loop_rounds * my_n_parallel, n_loops) def f(j): r = reducer(tuplify(loop_body(j)), mem_state) write_state_to_memory(r) diff --git a/Compiler/program.py b/Compiler/program.py index a5438d255..1b09986ed 100644 --- a/Compiler/program.py +++ b/Compiler/program.py @@ -70,6 +70,7 @@ def __init__(self, args, options, param=-1, assemblymode=False): self.free_threads = set() self.public_input_file = open(self.programs_dir + '/Public-Input/%s' % self.name, 'w') self.types = {} + self.budget = int(self.options.budget) self.to_merge = [Compiler.instructions.asm_open_class, \ Compiler.instructions.gasm_open_class, \ Compiler.instructions.muls_class, \ @@ -80,8 +81,8 @@ def __init__(self, args, options, param=-1, assemblymode=False): Compiler.instructions.gdotprods_class, \ Compiler.instructions.asm_input_class, \ Compiler.instructions.gasm_input_class, - Compiler.instructions.inputfix, - Compiler.instructions.inputfloat] + Compiler.instructions.inputfix_class, + Compiler.instructions.inputfloat_class] import Compiler.GC.instructions as gc self.to_merge += [gc.ldmsdi, gc.stmsdi, gc.ldmsd, gc.stmsd, \ gc.stmsdci, gc.xors, gc.andrs, gc.ands, gc.inputb] @@ -423,6 +424,7 @@ def __init__(self, name, program): self.req_node = self.req_tree self.basicblocks = [] self.purged = False + self.block_counter = 0 self.active_basicblock = None self.start_new_basicblock() self._is_empty = False @@ -438,7 +440,6 @@ def __init__(self, parent, name, scope, exit_condition=None): self.parent = parent self.instructions = [] self.name = name - self.index = len(parent.basicblocks) self.open_queue = [] self.exit_condition = exit_condition self.exit_block = None @@ -452,6 +453,9 @@ def __init__(self, parent, name, scope, exit_condition=None): self.alloc_pool = defaultdict(set) self.purged = False + def __len__(self): + return len(self.instructions) + def new_reg(self, reg_type, size=None): return self.parent.new_reg(reg_type, size=size) @@ -520,7 +524,8 @@ def start_new_basicblock(self, scope=False, name=''): # use False because None means no scope if scope is False: scope = self.active_basicblock - suffix = '%s-%d' % (name, len(self.basicblocks)) + suffix = '%s-%d' % (name, self.block_counter) + self.block_counter += 1 sub = self.BasicBlock(self, self.name + '-' + suffix, scope) self.basicblocks.append(sub) self.active_basicblock = sub diff --git a/Compiler/types.py b/Compiler/types.py index ff4e3ed85..68e51e32e 100644 --- a/Compiler/types.py +++ b/Compiler/types.py @@ -707,6 +707,7 @@ def pop(cls): @vectorized_classmethod def get_random(cls, bit_length): + """ Public insecure randomness """ if isinstance(bit_length, int): bit_length = regint(bit_length) res = cls() @@ -914,6 +915,7 @@ def protect_memory(cls, start, end): @vectorized_classmethod @set_instruction_type def get_input_from(cls, player): + """ Secret input """ res = cls() asm_input(res, player) return res @@ -921,6 +923,7 @@ def get_input_from(cls, player): @vectorized_classmethod @set_instruction_type def get_random_triple(cls): + """ Secret random triple according to security model """ res = (cls(), cls(), cls()) triple(*res) return res @@ -928,6 +931,7 @@ def get_random_triple(cls): @vectorized_classmethod @set_instruction_type def get_random_bit(cls): + """ Secret random bit according to security model """ res = cls() bit(res) return res @@ -935,6 +939,7 @@ def get_random_bit(cls): @vectorized_classmethod @set_instruction_type def get_random_square(cls): + """ Secret random square according to security model """ res = (cls(), cls()) square(*res) return res @@ -942,6 +947,7 @@ def get_random_square(cls): @vectorized_classmethod @set_instruction_type def get_random_inverse(cls): + """ Secret random inverse according to security model """ res = (cls(), cls()) inverse(*res) return res @@ -1110,6 +1116,7 @@ class sint(_secret, _int): @vectorized_classmethod def get_random_int(cls, bits): + """ Secret random n-bit number according to security model """ res = sint() comparison.PRandInt(res, bits) return res @@ -2408,7 +2415,7 @@ class sfix(_fix): int_type = sint clear_type = cfix - @classmethod + @vectorized_classmethod def get_input_from(cls, player): v = cls.int_type() inputfix(v, cls.f, player) @@ -2734,7 +2741,7 @@ def convert_float(v, vlen, plen): 'with %d exponent bits' % (vv, plen)) return v, p, z, s - @classmethod + @vectorized_classmethod def get_input_from(cls, player): v = sint() p = sint() diff --git a/ECDSA/Fake-ECDSA.cpp b/ECDSA/Fake-ECDSA.cpp new file mode 100644 index 000000000..6ddc519c6 --- /dev/null +++ b/ECDSA/Fake-ECDSA.cpp @@ -0,0 +1,25 @@ +/* + * Fake-ECDSA.cpp + * + */ + +#include "ECDSA/P256Element.h" +#include "Tools/mkpath.h" + +#include "Protocols/fake-stuff.hpp" +#include "Protocols/Share.hpp" +#include "Processor/Data_Files.hpp" + +int main() +{ + P256Element::init(); + P256Element::Scalar key; + gf2n key2; + string prefix = PREP_DIR "ECDSA/"; + mkdir_p(prefix.c_str()); + ofstream outf; + write_online_setup(outf, prefix, P256Element::Scalar::pr(), 0, false); + generate_mac_keys>(key, key2, 2, prefix); + make_mult_triples>(key, 2, 1000, false, prefix); + make_inverse>(key, 2, 1000, false, prefix); +} diff --git a/ECDSA/P256Element.cpp b/ECDSA/P256Element.cpp new file mode 100644 index 000000000..0d58db435 --- /dev/null +++ b/ECDSA/P256Element.cpp @@ -0,0 +1,120 @@ +/* + * P256Element.cpp + * + */ + +#include "P256Element.h" + +#include +#include + +CryptoPP::DL_GroupParameters_EC P256Element::params; +CryptoPP::ECP P256Element::curve; + +void P256Element::init() +{ + params = CryptoPP::DL_GroupParameters_EC(CryptoPP::ASN1::secp256k1()); + curve = params.GetCurve(); + auto mod = params.GetSubgroupOrder(); + Scalar::init_field(CryptoPP::IntToString(mod).c_str(), false); +} + +CryptoPP::Integer P256Element::convert(const Scalar& other) +{ + return CryptoPP::Integer((unsigned char*) other.get_ptr(), other.size(), + CryptoPP::Integer::UNSIGNED, CryptoPP::LITTLE_ENDIAN_ORDER); +} + +P256Element::P256Element() +{ + point = curve.Identity(); +} + +P256Element::P256Element(const Scalar& other) +{ + point = params.ExponentiateBase(convert(other)); +} + +P256Element::P256Element(word other) +{ + point = params.ExponentiateBase(other); +} + +void P256Element::check() +{ + curve.VerifyPoint(point); +} + +P256Element::Scalar P256Element::x() const +{ + return bigint(IntToString(point.x)); +} + +P256Element P256Element::operator +(const P256Element& other) const +{ + P256Element res; + res.point = curve.Add(point, other.point); + return res; +} + +P256Element P256Element::operator -(const P256Element& other) const +{ + P256Element res; + res.point = curve.Add(point, curve.Inverse(other.point)); + return res; +} + +P256Element P256Element::operator *(const Scalar& other) const +{ + P256Element res; + res.point = curve.Multiply(convert(other), point); + return res; +} + +P256Element& P256Element::operator +=(const P256Element& other) +{ + *this = *this + other; + return *this; +} + +bool P256Element::operator ==(const P256Element& other) const +{ + return point == other.point; +} + +bool P256Element::operator !=(const P256Element& other) const +{ + return not (*this == other); +} + +void P256Element::pack(octetStream& os) const +{ + os.serialize(point.identity); + size_t l; + l = point.x.MinEncodedSize(); + os.serialize(l); + point.x.Encode(os.append(l), l); + l = point.y.MinEncodedSize(); + os.serialize(l); + point.y.Encode(os.append(l), l); +} + +void P256Element::unpack(octetStream& os) +{ + os.unserialize(point.identity); + size_t l; + os.unserialize(l); + point.x.Decode(os.consume(l), l); + os.unserialize(l); + point.y.Decode(os.consume(l), l); +} + +ostream& operator <<(ostream& s, const P256Element& x) +{ + auto& point = x.get(); + if (point.identity) + s << "ID" << endl; + else + s << point.x << "," << point.y; + return s; +} diff --git a/ECDSA/P256Element.h b/ECDSA/P256Element.h new file mode 100644 index 000000000..603a7e0d0 --- /dev/null +++ b/ECDSA/P256Element.h @@ -0,0 +1,74 @@ +/* + * Element.h + * + */ + +#ifndef ECDSA_P256ELEMENT_H_ +#define ECDSA_P256ELEMENT_H_ + +#include + +#include "Math/gfp.h" + +#if GFP_MOD_SZ != 4 +#error GFP_MOD_SZ must be 4 +#endif + +class P256Element : public ValueInterface +{ +public: + typedef gfp Scalar; + +private: + static CryptoPP::DL_GroupParameters_EC params; + static CryptoPP::ECP curve; + + CryptoPP::ECP::Point point; + + static CryptoPP::Integer convert(const Scalar& other); + +public: + typedef void next; + typedef void Square; + + static int size() { return 0; } + static string type_string() { return "P256"; } + + static void init(); + + P256Element(); + P256Element(const Scalar& other); + P256Element(word other); + + void check(); + + const CryptoPP::ECP::Point& get() const { return point; } +// const unsigned char* get() const { return a; } + + Scalar x() const; + + P256Element operator+(const P256Element& other) const; + P256Element operator-(const P256Element& other) const; + P256Element operator*(const Scalar& other) const; + + P256Element& operator+=(const P256Element& other); + + bool operator==(const P256Element& other) const; + bool operator!=(const P256Element& other) const; + + void assign_zero() { *this = 0; } + bool is_zero() { return *this == 0; } + void add(const P256Element& x, const P256Element& y) { *this = x + y; } + void sub(const P256Element& x, const P256Element& y) { *this = x - y; } + void mul(const P256Element& x, const Scalar& y) { *this = x * y; } + void mul(const Scalar& x, const P256Element& y) { *this = y * x; } + template + void add(octetStream& os) { *this += os.get(); } + + void pack(octetStream& os) const; + void unpack(octetStream& os); +}; + +ostream& operator<<(ostream& s, const P256Element& x); + +#endif /* ECDSA_P256ELEMENT_H_ */ diff --git a/ECDSA/README.md b/ECDSA/README.md new file mode 100644 index 000000000..d81699afb --- /dev/null +++ b/ECDSA/README.md @@ -0,0 +1,44 @@ +This directory contains the code used for the benchmarks by [Dalskov +et al.](https://eprint.iacr.org/2019/889) `*-ecdsa-party.cpp` +contains the high-level programs while the two phases are implemented +`preprocessing.hpp` and `sign.hpp`, respectively. + +#### Compilation + +- Add `MOD = -DGFP_MOD_SZ=4` to `CONFIG.mine` +- Also consider adding either `CXX = clang++` or `OPTIM = -O2` because GCC 8 or later with `-O3` will produce a segfault when using `mascot-ecdsa-party.x` +- For older hardware, also add `ARCH = -march=native` +- Install [Crypto++](https://www.cryptopp.com) (`libcrypto++-dev` on Ubuntu). We used version 5.6.4, which is the default on Ubuntu 18.04. +- Compile the binaries: `make -j8 ecdsa` +- Or compile the static binaries: `make -j8 ecdsa-static` + +#### Running + +The following binaries have been used for the paper: + +| Protocol | Binary | +| --- | --- | +| MASCOT | `mascot-ecdsa-party.x` | +| Semi-honest OT | `semi-ecdsa-party.x` | +| Malicious Shamir | `mal-shamir-ecdsa-party.x` | +| Semi-honest Shamir | `shamir-ecdsa-party.x` | +| Malicious replicated | `mal-rep-ecdsa-party.x` | +| Semi-honest replicated | `rep-ecdsa-party.x` | + +All binaries offer the same interface. With MASCOT for example, run +the following: +``` +./mascot-ecsda-party.x -p 0 [-N ] [-h ] [-D] [] +./mascot-ecsda-party.x -p 1 [-N ] [-h ] [-D] [] +... +``` + +`-D` activates delayed multiplication, deferring usage of the secret +key until signing. + +The number of parties defaults to 2 for OT-based protocols and to 3 +for honest-majority protocols. + +In addition, there is `fake-spdz-ecsda-party.x`, which runs only the +online phase of SPDZ. You will need to run `Fake-ECDSA.x` beforehands +and then distribute `Player-Data/ECSDA` to all parties. diff --git a/ECDSA/fake-spdz-ecdsa-party.cpp b/ECDSA/fake-spdz-ecdsa-party.cpp new file mode 100644 index 000000000..9a703f376 --- /dev/null +++ b/ECDSA/fake-spdz-ecdsa-party.cpp @@ -0,0 +1,52 @@ +/* + * fake-spdz-ecdsa-party.cpp + * + */ + +#include "Networking/Server.h" +#include "Networking/CryptoPlayer.h" +#include "Math/gfp.h" +#include "ECDSA/P256Element.h" + +#include "ECDSA/preprocessing.hpp" +#include "ECDSA/sign.hpp" +#include "Protocols/Beaver.hpp" +#include "Protocols/fake-stuff.hpp" +#include "Protocols/Share.hpp" +#include "Protocols/MAC_Check.hpp" +#include "Processor/Input.hpp" +#include "Processor/Processor.hpp" +#include "Processor/Data_Files.hpp" + +#include + +int main(int argc, const char** argv) +{ + ez::ezOptionParser opt; + Names N(opt, argc, argv, 2); + int n_tuples = 1000; + if (not opt.lastArgs.empty()) + n_tuples = atoi(opt.lastArgs[0]->c_str()); + PlainPlayer P(N); + P256Element::init(); + + P256Element::Scalar keyp; + gf2n key2; + string prefix = PREP_DIR "ECDSA/"; + read_mac_keys(prefix, N, keyp, key2); + + typedef Share pShare; + DataPositions usage; + Sub_Data_Files prep(N, prefix, usage); + typename pShare::MAC_Check MCp(keyp); + ArithmeticProcessor _({}, 0); + SubProcessor proc(_, MCp, prep, P); + + pShare sk, __; + proc.DataF.get_two(DATA_INVERSE, sk, __); + + vector> tuples; + preprocessing(tuples, n_tuples, sk, proc); + check(tuples, sk, keyp, P); + sign_benchmark(tuples, sk, MCp, P); +} diff --git a/ECDSA/hm-ecdsa-party.hpp b/ECDSA/hm-ecdsa-party.hpp new file mode 100644 index 000000000..174ec672d --- /dev/null +++ b/ECDSA/hm-ecdsa-party.hpp @@ -0,0 +1,71 @@ +/* + * mal-rep-ecdsa-party.cpp + * + */ + +#include "Networking/Server.h" +#include "Networking/CryptoPlayer.h" +#include "Protocols/Replicated.h" +#include "Protocols/MaliciousRep3Share.h" +#include "Protocols/ReplicatedInput.h" +#include "Math/gfp.h" +#include "ECDSA/P256Element.h" +#include "Tools/Bundle.h" + +#include "ECDSA/preprocessing.hpp" +#include "ECDSA/sign.hpp" +#include "Protocols/MaliciousRepMC.hpp" +#include "Protocols/MaliciousRepPrep.hpp" +#include "Protocols/Beaver.hpp" +#include "Protocols/fake-stuff.hpp" +#include "Processor/Input.hpp" +#include "Processor/Processor.hpp" +#include "Processor/Data_Files.hpp" + +#include + +template class T> +void run(int argc, const char** argv) +{ + bigint::init_thread(); + ez::ezOptionParser opt; + opt.add( + "", // Default. + 0, // Required? + 0, // Number of args expected. + 0, // Delimiter if expecting multiple args. + "Delay multiplication until signing", // Help description. + "-D", // Flag token. + "--delay-multiplication" // Flag token. + ); + Names N(opt, argc, argv, 3); + int n_tuples = 1000; + if (not opt.lastArgs.empty()) + n_tuples = atoi(opt.lastArgs[0]->c_str()); + CryptoPlayer P(N); + P256Element::init(); + typedef T pShare; + OnlineOptions::singleton.batch_size = 1; + // synchronize + Bundle bundle(P); + P.Broadcast_Receive(bundle, false); + Timer timer; + timer.start(); + pShare sk = typename T::Honest::Protocol(P).get_random(); + cout << "Secret key generation took " << timer.elapsed() * 1e3 << " ms" << endl; + + OnlineOptions::singleton.batch_size = n_tuples; + DataPositions usage; + auto& prep = *Preprocessing::get_live_prep(0, usage); + typename pShare::MAC_Check MCp; + ArithmeticProcessor _({}, 0); + SubProcessor proc(_, MCp, prep, P); + + bool prep_mul = not opt.isSet("-D"); + vector> tuples; + preprocessing(tuples, n_tuples, sk, proc, prep_mul); +// check(tuples, sk, {}, P); + sign_benchmark(tuples, sk, MCp, P, prep_mul ? 0 : &proc); + + delete &prep; +} diff --git a/ECDSA/mal-rep-ecdsa-party.cpp b/ECDSA/mal-rep-ecdsa-party.cpp new file mode 100644 index 000000000..16495f3d7 --- /dev/null +++ b/ECDSA/mal-rep-ecdsa-party.cpp @@ -0,0 +1,13 @@ +/* + * mal-rep-ecdsa-party.cpp + * + */ + +#include "Protocols/MaliciousRep3Share.h" + +#include "hm-ecdsa-party.hpp" + +int main(int argc, const char** argv) +{ + run(argc, argv); +} diff --git a/ECDSA/mal-shamir-ecdsa-party.cpp b/ECDSA/mal-shamir-ecdsa-party.cpp new file mode 100644 index 000000000..17f212ffd --- /dev/null +++ b/ECDSA/mal-shamir-ecdsa-party.cpp @@ -0,0 +1,20 @@ +/* + * mal-shamir-ecdsa-party.cpp + * + */ + +#include "Protocols/MaliciousShamirShare.h" + +#include "Protocols/Shamir.hpp" +#include "Protocols/ShamirInput.hpp" +#include "Protocols/ShamirMC.hpp" +#include "Protocols/MaliciousShamirMC.hpp" + +#include "hm-ecdsa-party.hpp" + +int main(int argc, const char** argv) +{ + ez::ezOptionParser opt; + ShamirOptions(opt, argc, argv); + run(argc, argv); +} diff --git a/ECDSA/mascot-ecdsa-party.cpp b/ECDSA/mascot-ecdsa-party.cpp new file mode 100644 index 000000000..6b2fa5650 --- /dev/null +++ b/ECDSA/mascot-ecdsa-party.cpp @@ -0,0 +1,15 @@ +/* + * fake-spdz-ecdsa-party.cpp + * + */ + +#include "Protocols/Share.hpp" +#include "Protocols/MAC_Check.hpp" +#include "ot-ecdsa-party.hpp" + +#include + +int main(int argc, const char** argv) +{ + run(argc, argv); +} diff --git a/ECDSA/ot-ecdsa-party.hpp b/ECDSA/ot-ecdsa-party.hpp new file mode 100644 index 000000000..998657dbc --- /dev/null +++ b/ECDSA/ot-ecdsa-party.hpp @@ -0,0 +1,80 @@ +/* + * fake-spdz-ecdsa-party.cpp + * + */ + +#include "Networking/Server.h" +#include "Networking/CryptoPlayer.h" +#include "Math/gfp.h" +#include "ECDSA/P256Element.h" +#include "Protocols/SemiShare.h" +#include "Processor/BaseMachine.h" + +#include "ECDSA/preprocessing.hpp" +#include "ECDSA/sign.hpp" +#include "Protocols/Beaver.hpp" +#include "Protocols/fake-stuff.hpp" +#include "Protocols/MascotPrep.hpp" +#include "Processor/Processor.hpp" +#include "Processor/Data_Files.hpp" +#include "Processor/Input.hpp" + +#include + +template class T> +void run(int argc, const char** argv) +{ + ez::ezOptionParser opt; + opt.add( + "", // Default. + 0, // Required? + 0, // Number of args expected. + 0, // Delimiter if expecting multiple args. + "Delay multiplication until signing", // Help description. + "-D", // Flag token. + "--delay-multiplication" // Flag token. + ); + Names N(opt, argc, argv, 2); + int n_tuples = 1000; + if (not opt.lastArgs.empty()) + n_tuples = atoi(opt.lastArgs[0]->c_str()); + PlainPlayer P(N); + P256Element::init(); + gfp1::init_field(P256Element::Scalar::pr(), false); + + BaseMachine machine; + machine.ot_setups.resize(1); + for (int i = 0; i < 2; i++) + machine.ot_setups[0].push_back({P, true}); + + P256Element::Scalar keyp; + SeededPRNG G; + keyp.randomize(G); + + typedef T pShare; + DataPositions usage; + + OnlineOptions::singleton.batch_size = 1; + typename pShare::Direct_MC MCp(keyp, N, 0); + ArithmeticProcessor _({}, 0); + typename pShare::LivePrep sk_prep(0, usage); + SubProcessor sk_proc(_, MCp, sk_prep, P); + pShare sk, __; + // synchronize + Bundle bundle(P); + P.Broadcast_Receive(bundle, false); + Timer timer; + timer.start(); + sk_prep.get_two(DATA_INVERSE, sk, __); + cout << "Secret key generation took " << timer.elapsed() * 1e3 << " ms" << endl; + + OnlineOptions::singleton.batch_size = n_tuples; + typename pShare::LivePrep prep(0, usage); + SubProcessor proc(_, MCp, prep, P); + + bool prep_mul = not opt.isSet("-D"); + vector> tuples; + preprocessing(tuples, n_tuples, sk, proc, prep_mul); + //check(tuples, sk, keyp, P); + sign_benchmark(tuples, sk, MCp, P, prep_mul ? 0 : &proc); +} diff --git a/ECDSA/preprocessing.hpp b/ECDSA/preprocessing.hpp new file mode 100644 index 000000000..10306dafb --- /dev/null +++ b/ECDSA/preprocessing.hpp @@ -0,0 +1,101 @@ +/* + * preprocessing.hpp + * + */ + +#ifndef ECDSA_PREPROCESSING_HPP_ +#define ECDSA_PREPROCESSING_HPP_ + +#include "P256Element.h" +#include "Processor/Data_Files.h" +#include "Protocols/ReplicatedPrep.h" +#include "Protocols/MaliciousShamirShare.h" + +template class T> +class EcTuple +{ +public: + T a; + T b; + P256Element R; +}; + +template class T> +void preprocessing(vector>& tuples, int buffer_size, + T& sk, + SubProcessor>& proc, bool prep_mul = true) +{ + Timer timer; + timer.start(); + Player& P = proc.P; + auto& prep = proc.DataF; + size_t start = P.sent + prep.data_sent(); + auto& protocol = proc.protocol; + auto& MCp = proc.MC; + typedef T pShare; + typedef T cShare; + vector inv_ks; + vector secret_Rs; + for (int i = 0; i < buffer_size; i++) + { + pShare a, a_inv; + prep.get_two(DATA_INVERSE, a, a_inv); + inv_ks.push_back(a_inv); + secret_Rs.push_back(a); + } + if (prep_mul) + { + protocol.init_mul(&proc); + for (int i = 0; i < buffer_size; i++) + protocol.prepare_mul(inv_ks[i], sk); + protocol.exchange(); + } + else + prep.buffer_triples(); + vector opened_Rs; + typename cShare::MAC_Check MCc(MCp.get_alphai()); + MCc.POpen(opened_Rs, secret_Rs, P); + MCc.Check(P); + MCp.Check(P); + for (int i = 0; i < buffer_size; i++) + { + tuples.push_back( + { inv_ks[i], prep_mul ? protocol.finalize_mul() : pShare(), + opened_Rs[i] }); + } + timer.stop(); + cout << "Generated " << buffer_size << " tuples in " << timer.elapsed() + << " seconds, throughput " << buffer_size / timer.elapsed() << ", " + << 1e-3 * (P.sent + prep.data_sent() - start) / buffer_size + << " kbytes per tuple" << endl; +} + +template class T> +void check(vector>& tuples, T sk, + P256Element::Scalar alphai, Player& P) +{ + typename T::MAC_Check MC(alphai); + auto open_sk = MC.POpen(sk, P); + for (auto& tuple : tuples) + { + auto inv_k = MC.POpen(tuple.a, P); + auto k = inv_k; + k.invert(); + assert(open_sk * inv_k == MC.POpen(tuple.b, P)); + assert(tuple.R == k); + } +} + +template<> +void ReplicatedPrep>::buffer_bits() +{ + throw not_implemented(); +} + +template<> +void ReplicatedPrep>::buffer_bits() +{ + throw not_implemented(); +} + +#endif /* ECDSA_PREPROCESSING_HPP_ */ diff --git a/ECDSA/rep-ecdsa-party.cpp b/ECDSA/rep-ecdsa-party.cpp new file mode 100644 index 000000000..1678f1de1 --- /dev/null +++ b/ECDSA/rep-ecdsa-party.cpp @@ -0,0 +1,20 @@ +/* + * mal-rep-ecdsa-party.cpp + * + */ + +#include "Protocols/Rep3Share.h" + +#include "hm-ecdsa-party.hpp" + +template<> +Preprocessing>* Preprocessing>::get_live_prep( + SubProcessor>* proc, DataPositions& usage) +{ + return new ReplicatedPrep>(proc, usage); +} + +int main(int argc, const char** argv) +{ + run(argc, argv); +} diff --git a/ECDSA/semi-ecdsa-party.cpp b/ECDSA/semi-ecdsa-party.cpp new file mode 100644 index 000000000..14b0a2925 --- /dev/null +++ b/ECDSA/semi-ecdsa-party.cpp @@ -0,0 +1,17 @@ +/* + * fake-spdz-ecdsa-party.cpp + * + */ + +#include "Protocols/SemiMC.hpp" +#include "Protocols/SemiPrep.hpp" +#include "Protocols/SemiInput.hpp" +#include "Protocols/MAC_Check_Base.hpp" +#include "ot-ecdsa-party.hpp" + +#include + +int main(int argc, const char** argv) +{ + run(argc, argv); +} diff --git a/ECDSA/shamir-ecdsa-party.cpp b/ECDSA/shamir-ecdsa-party.cpp new file mode 100644 index 000000000..419e4fde9 --- /dev/null +++ b/ECDSA/shamir-ecdsa-party.cpp @@ -0,0 +1,19 @@ +/* + * mal-shamir-ecdsa-party.cpp + * + */ + +#include "Protocols/ShamirShare.h" + +#include "Protocols/Shamir.hpp" +#include "Protocols/ShamirInput.hpp" +#include "Protocols/ShamirMC.hpp" + +#include "hm-ecdsa-party.hpp" + +int main(int argc, const char** argv) +{ + ez::ezOptionParser opt; + ShamirOptions(opt, argc, argv); + run(argc, argv); +} diff --git a/ECDSA/sign.hpp b/ECDSA/sign.hpp new file mode 100644 index 000000000..c0e8c338c --- /dev/null +++ b/ECDSA/sign.hpp @@ -0,0 +1,148 @@ +/* + * sign.hpp + * + */ + +#ifndef ECDSA_SIGN_HPP_ +#define ECDSA_SIGN_HPP_ + +//#include "CurveElement.h" +#include "P256Element.h" +#include "Tools/Bundle.h" + +#include "preprocessing.hpp" + +class EcSignature +{ +public: + P256Element R; + P256Element::Scalar s; +}; + +/* +inline +CurveElement::Scalar hash_to_scalar(const unsigned char* message, size_t length, CurveElement::Scalar rx, CurveElement pk) +{ + crypto_hash_sha512_state state; + crypto_hash_sha512_init(&state); + crypto_hash_sha512_update(&state, (unsigned char*) rx.get_ptr(), + crypto_core_ristretto255_SCALARBYTES); + crypto_hash_sha512_update(&state, pk.get(), crypto_core_ristretto255_BYTES); + crypto_hash_sha512_update(&state, message, length); + unsigned char hash[crypto_hash_sha512_BYTES]; + crypto_hash_sha512_final(&state, hash); + auto& tmp = bigint::tmp; + mpz_import(tmp.get_mpz_t(), crypto_hash_sha512_BYTES, -1, 1, 0, 0, hash); + return tmp; +} +*/ + +inline P256Element::Scalar hash_to_scalar(const unsigned char* message, size_t length) +{ + P256Element::Scalar res; + assert(res.size() == crypto_hash_sha256_BYTES); + crypto_hash_sha256((unsigned char*) res.get_ptr(), message, length); + res.zero_overhang(); + return res; +} + +template class T> +EcSignature sign(const unsigned char* message, size_t length, + EcTuple tuple, + typename T::MAC_Check& MC, Player& P, + P256Element pk, + T sk = {}, + SubProcessor>* proc = 0) +{ + (void) pk; + Timer timer; + timer.start(); + size_t start = P.sent; + auto stats = P.comm_stats; + EcSignature signature; + signature.R = tuple.R; + T prod = tuple.b; + if (proc) + { + auto& protocol = proc->protocol; + protocol.init_mul(proc); + protocol.prepare_mul(sk, tuple.a); + protocol.exchange(); + prod = protocol.finalize_mul(); + } + auto rx = tuple.R.x(); + signature.s = MC.POpen( + tuple.a * hash_to_scalar(message, length) + prod * rx, P); + cout << "Minimal signing took " << timer.elapsed() * 1e3 << " ms and sending " + << (P.sent - start) << " bytes" << endl; + auto diff = (P.comm_stats - stats); + diff.print(); + return signature; +} + +inline +EcSignature sign(const unsigned char* message, size_t length, P256Element::Scalar sk) +{ + EcSignature signature; + auto k = SeededPRNG().get(); + auto inv_k = k; + inv_k.invert(); + signature.R = k; + auto rx = signature.R.x(); + signature.s = inv_k * (hash_to_scalar(message, length) + rx * sk); + return signature; +} + +inline +void check(EcSignature signature, const unsigned char* message, size_t length, + P256Element pk) +{ + Timer timer; + timer.start(); + signature.s.check(); + signature.R.check(); + P256Element::Scalar w; + w.invert(signature.s); + auto u1 = hash_to_scalar(message, length) * w; + auto u2 = signature.R.x() * w; + assert(P256Element(u1) + pk * u2 == signature.R); + cout << "Offline checking took " << timer.elapsed() * 1e3 << " ms" << endl; +} + +template class T> +void sign_benchmark(vector>& tuples, T sk, + typename T::MAC_Check& MCp, Player& P, + SubProcessor>* proc = 0) +{ + unsigned char message[1024]; + GlobalPRNG(P).get_octets(message, 1024); + typename T::MAC_Check MCc(MCp.get_alphai()); + + // synchronize + Bundle bundle(P); + P.Broadcast_Receive(bundle, true); + Timer timer; + timer.start(); + P256Element pk = MCc.POpen(sk, P); + MCc.Check(P); + cout << "Public key generation took " << timer.elapsed() * 1e3 << " ms" << endl; + P.comm_stats.print(); + + for (size_t i = 0; i < min(10lu, tuples.size()); i++) + { + check(sign(message, 1 << i, tuples[i], MCp, P, pk, sk, proc), message, + 1 << i, pk); + Timer timer; + timer.start(); + auto& check_player = MCp.get_check_player(P); + auto stats = check_player.comm_stats; + auto start = check_player.sent; + MCp.Check(P); + cout << "Online checking took " << timer.elapsed() * 1e3 << " ms and sending " + << (check_player.sent - start) << " bytes" << endl; + auto diff = (check_player.comm_stats - stats); + diff.print(); + } +} + +#endif /* ECDSA_SIGN_HPP_ */ diff --git a/FHE/Matrix.h b/FHE/Matrix.h index a2e1e30f1..9eb2e99fa 100644 --- a/FHE/Matrix.h +++ b/FHE/Matrix.h @@ -7,7 +7,7 @@ using namespace std; #include "Math/bigint.h" #include "Math/modp.h" -#include "OT/BitVector.h" +#include "Tools/BitVector.h" typedef vector< vector > matrix; typedef vector< vector > modp_matrix; diff --git a/FHE/NTL-Subs.cpp b/FHE/NTL-Subs.cpp index cad67c6ab..93225300b 100644 --- a/FHE/NTL-Subs.cpp +++ b/FHE/NTL-Subs.cpp @@ -86,7 +86,7 @@ int generate_semi_setup(int plaintext_length, int sec, { p0 *= 2; } - if (phi_N(m) < nb.min_phi_m(numBits(p0 * (params.n_mults() > 0 ? p1 : 1)))) + if (phi_N(m) < nb.min_phi_m(2 + numBits(p0 * (params.n_mults() > 0 ? p1 : 1)))) { m *= 2; generate_prime(p, lgp, m); diff --git a/FHEOffline/SimpleEncCommit.cpp b/FHEOffline/SimpleEncCommit.cpp index 4df59a73a..64cc04e50 100644 --- a/FHEOffline/SimpleEncCommit.cpp +++ b/FHEOffline/SimpleEncCommit.cpp @@ -10,6 +10,8 @@ #include "Tools/Subroutines.h" #include "Protocols/MAC_Check.h" +#include "Protocols/MAC_Check.hpp" + template SimpleEncCommitBase::SimpleEncCommitBase(const MachineBase& machine) : sec(machine.sec), extra_slack(machine.extra_slack), n_rounds(0) diff --git a/Fake-Offline.cpp b/Fake-Offline.cpp index ab97c9905..2b61c9d03 100644 --- a/Fake-Offline.cpp +++ b/Fake-Offline.cpp @@ -28,50 +28,6 @@ using namespace std; string prep_data_prefix; -/* 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, - bool zero, int thread_num = -1) -{ - PRNG G; - G.ReSeed(); - - ofstream* outf=new ofstream[N]; - typename T::clear a,b,c; - vector Sa(N),Sb(N),Sc(N); - /* Generate Triples */ - for (int i=0; i::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 -void make_inverse(const typename T::mac_type& key,int N,int ntrip,bool zero) -{ - PRNG G; - G.ReSeed(); - - ofstream* outf=new ofstream[N]; - typename T::clear a,b; - vector Sa(N),Sb(N); - /* Generate Triples */ - for (int i=0; i void make_PreMulC(const typename T::mac_type& key, int N, int ntrip, bool zero) { @@ -307,13 +219,13 @@ void make_PreMulC(const typename T::mac_type& key, int N, int ntrip, bool zero) template void make_basic(const typename T::mac_type& key, int nplayers, int nitems, bool zero) { - make_mult_triples(key, nplayers, nitems, zero); + make_mult_triples(key, nplayers, nitems, zero, prep_data_prefix); make_bits(key, nplayers, nitems, zero); make_square_tuples(key, nplayers, nitems, T::type_short(), zero); make_inputs(key, nplayers, nitems, T::type_short(), zero); if (T::clear::invertible) { - make_inverse(key, nplayers, nitems, zero); + make_inverse(key, nplayers, nitems, zero, prep_data_prefix); make_PreMulC(key, nplayers, nitems, zero); } } @@ -567,12 +479,8 @@ int generate(ez::ezOptionParser& opt) generate_online_setup(outf, prep_data_prefix, p, lgp, lg2); /* Find number players and MAC keys etc*/ - typename T::mac_type keyp; - typename T::mac_key_type pp; - keyp.assign_zero(); - gf2n key2,p2; key2.assign_zero(); - int tmpN = 0; - ifstream inpf; + typename T::mac_key_type::Scalar keyp; + gf2n key2; // create PREP_DIR if not there if (mkdir_p(PREP_DIR) == -1) @@ -581,51 +489,21 @@ int generate(ez::ezOptionParser& opt) throw file_error(); } - for (i = 0; i < (unsigned int)nplayers; i++) - { - stringstream filename; - filename << prep_data_prefix << "Player-MAC-Keys-P" << i; - inpf.open(filename.str().c_str()); - if (inpf.fail()) - { - inpf.close(); - cout << "No MAC key share for player " << i << ", generating a fresh one\n"; - pp.randomize(G); - p2.randomize(G); - ofstream outf(filename.str().c_str()); - if (outf.fail()) - throw file_error(filename.str().c_str()); - outf << nplayers << " " << pp << " " << p2; - outf.close(); - cout << "Written new MAC key share to " << filename.str() << endl; - } - else - { - inpf >> tmpN; // not needed here - pp.input(inpf,true); - p2.input(inpf,true); - inpf.close(); - } - cout << " Key " << i << "\t p: " << pp << "\n\t 2: " << p2 << endl; - keyp.add(pp); - key2.add(p2); - } - cout << "--------------\n"; - cout << "Final Keys :\t p: " << keyp << "\n\t\t 2: " << key2 << endl; + generate_mac_keys(keyp, key2, nplayers, prep_data_prefix); typedef Share sgf2n; - make_mult_triples(key2,nplayers,ntrip2,zero); - make_mult_triples(keyp,nplayers,ntripp,zero); + make_mult_triples(key2,nplayers,ntrip2,zero,prep_data_prefix); + make_mult_triples(keyp,nplayers,ntripp,zero,prep_data_prefix); make_bits>(key2,nplayers,nbits2,zero); make_bits(keyp,nplayers,nbitsp,zero); make_square_tuples(key2,nplayers,nsqr2,"2",zero); make_square_tuples(keyp,nplayers,nsqrp,"p",zero); make_inputs(key2,nplayers,ninp2,"2",zero); make_inputs(keyp,nplayers,ninpp,"p",zero); - make_inverse(key2,nplayers,ninv,zero); + make_inverse(key2,nplayers,ninv,zero,prep_data_prefix); if (T::clear::invertible) - make_inverse(keyp,nplayers,ninv,zero); + make_inverse(keyp,nplayers,ninv,zero,prep_data_prefix); make_bit_triples(key2,nplayers,nbittrip,DATA_BITTRIPLE,zero); make_bit_triples(key2,nplayers,nbitgf2ntrip,DATA_BITGF2NTRIPLE,zero); make_PreMulC(key2,nplayers,ninv,zero); @@ -641,7 +519,7 @@ int generate(ez::ezOptionParser& opt) make_basic>({}, nplayers, default_num, zero); make_basic>({}, nplayers, default_num, zero); - make_mult_triples({}, nplayers, ntrip2, zero); + make_mult_triples({}, nplayers, ntrip2, zero, prep_data_prefix); make_bits({}, nplayers, nbits2, zero); } diff --git a/GC/FakeSecret.h b/GC/FakeSecret.h index face23440..a44cf62a7 100644 --- a/GC/FakeSecret.h +++ b/GC/FakeSecret.h @@ -23,6 +23,8 @@ namespace GC template class Processor; +template +class Machine; class FakeSecret { @@ -36,6 +38,8 @@ class FakeSecret typedef DummyMC MC; typedef DummyProtocol Protocol; + static MC* new_mc(Machine& _) { (void) _; return new MC; } + static string type_string() { return "fake secret"; } static string phase_name() { return "Faking"; } diff --git a/GC/Machine.cpp b/GC/Machine.cpp index 5329b21e5..eed1c9861 100644 --- a/GC/Machine.cpp +++ b/GC/Machine.cpp @@ -18,7 +18,7 @@ #include "Processor/Instruction.hpp" #include "Protocols/MaliciousRepMC.hpp" #include "Protocols/MAC_Check_Base.hpp" -#include "Protocols/Replicated.hpp" +#include "Protocols/Beaver.hpp" namespace GC { diff --git a/GC/MaliciousRepPrep.cpp b/GC/MaliciousRepPrep.cpp new file mode 100644 index 000000000..26d1ee46b --- /dev/null +++ b/GC/MaliciousRepPrep.cpp @@ -0,0 +1,53 @@ +/* + * MaliciousRepPrep.cpp + * + */ + +#include "MaliciousRepPrep.h" +#include "MaliciousRepThread.h" +#include "Processor/OnlineOptions.h" + +#include "Protocols/MalRepRingPrep.hpp" +#include "Protocols/ReplicatedPrep.hpp" +#include "Protocols/Replicated.hpp" +#include "Protocols/MAC_Check_Base.hpp" + +namespace GC +{ + +MaliciousRepPrep::MaliciousRepPrep(DataPositions& usage) : + BufferPrep(usage), protocol(0) +{ +} + +MaliciousRepPrep::~MaliciousRepPrep() +{ + if (protocol) + delete protocol; +} + +void MaliciousRepPrep::set_protocol(MaliciousRepSecret::Protocol& protocol) +{ + this->protocol = new ReplicatedBase(protocol.P); +} + +void MaliciousRepPrep::buffer_triples() +{ + assert(protocol != 0); + auto MC = MaliciousRepThread::s().new_mc(); + shuffle_triple_generation(triples, protocol->P, *MC, 64); + delete MC; +} + +void MaliciousRepPrep::buffer_bits() +{ + assert(this->protocol != 0); + for (int i = 0; i < OnlineOptions::singleton.batch_size; i++) + { + this->bits.push_back({}); + for (int j = 0; j < 2; j++) + this->bits.back()[j] = this->protocol->shared_prngs[j].get_bit(); + } +} + +} /* namespace GC */ diff --git a/GC/MaliciousRepPrep.h b/GC/MaliciousRepPrep.h new file mode 100644 index 000000000..28e801a5a --- /dev/null +++ b/GC/MaliciousRepPrep.h @@ -0,0 +1,34 @@ +/* + * MaliciousRepPrep.h + * + */ + +#ifndef GC_MALICIOUSREPPREP_H_ +#define GC_MALICIOUSREPPREP_H_ + +#include "MaliciousRepSecret.h" +#include "Protocols/ReplicatedPrep.h" + +namespace GC +{ + +class MaliciousRepPrep : public BufferPrep +{ + ReplicatedBase* protocol; + +public: + MaliciousRepPrep(DataPositions& usage); + ~MaliciousRepPrep(); + + void set_protocol(MaliciousRepSecret::Protocol& protocol); + + void buffer_triples(); + void buffer_bits(); + + void buffer_squares() { throw not_implemented(); } + void buffer_inverses() { throw not_implemented(); } +}; + +} /* namespace GC */ + +#endif /* GC_MALICIOUSREPPREP_H_ */ diff --git a/GC/MaliciousRepSecret.h b/GC/MaliciousRepSecret.h index 0ecca4d9b..f56de415e 100644 --- a/GC/MaliciousRepSecret.h +++ b/GC/MaliciousRepSecret.h @@ -7,6 +7,10 @@ #define GC_MALICIOUSREPSECRET_H_ #include "ReplicatedSecret.h" +#include "Machine.h" +#include "Protocols/Beaver.h" +#include "Protocols/MaliciousRepMC.h" +#include "Processor/DummyProtocol.h" template class MaliciousRepMC; @@ -23,6 +27,24 @@ class MaliciousRepSecret : public ReplicatedSecret typedef Memory DynamicMemory; typedef MaliciousRepMC MC; + typedef MC MAC_Check; + + typedef Beaver Protocol; + typedef NotImplementedInput Input; + + static MC* new_mc(Machine& machine) + { + if (machine.more_comm_less_comp) + return new CommMaliciousRepMC; + else + return new HashMaliciousRepMC; + } + + static MaliciousRepSecret constant(const BitVec& other, int my_num, const BitVec& alphai) + { + (void) my_num, (void) alphai; + return other; + } MaliciousRepSecret() {} template diff --git a/GC/MaliciousRepThread.cpp b/GC/MaliciousRepThread.cpp index c5d9d2191..7951b7397 100644 --- a/GC/MaliciousRepThread.cpp +++ b/GC/MaliciousRepThread.cpp @@ -8,6 +8,8 @@ #include "Math/Setup.h" #include "Protocols/MaliciousRepMC.hpp" +#include "Protocols/MAC_Check_Base.hpp" +#include "Protocols/Beaver.hpp" #include "Processor/Data_Files.hpp" namespace GC @@ -17,26 +19,16 @@ thread_local MaliciousRepThread* MaliciousRepThread::singleton = 0; MaliciousRepThread::MaliciousRepThread(int i, ThreadMaster& master) : - Thread(i, master), DataF(N.my_num(), - N.num_players(), - get_prep_dir(N.num_players(), 128, gf2n::default_degree()), - usage, i) + Thread(i, master), DataF(usage) { } -MaliciousRepMC* MaliciousRepThread::new_mc() -{ - if (machine.more_comm_less_comp) - return new CommMaliciousRepMC; - else - return new HashMaliciousRepMC; -} - void MaliciousRepThread::pre_run() { if (singleton) throw runtime_error("there can only be one"); singleton = this; + DataF.set_protocol(*protocol); } void MaliciousRepThread::post_run() @@ -51,44 +43,28 @@ void MaliciousRepThread::and_(Processor& processor, const vector& args, bool repeat) { assert(P->num_players() == 3); - os.resize(2); - for (auto& o : os) - o.reset_write_head(); processor.check_args(args, 4); - shares.clear(); - triples.clear(); + protocol->init_mul(DataF, *MC); for (size_t i = 0; i < args.size(); i += 4) { int n_bits = args[i]; int left = args[i + 2]; int right = args[i + 3]; - triples.push_back({{0}}); - DataF.get(DATA_TRIPLE, triples.back().data()); - shares.push_back((processor.S[left] - triples.back()[0]).mask(n_bits)); MaliciousRepSecret y_ext; if (repeat) y_ext = processor.S[right].extend_bit(); else y_ext = processor.S[right]; - shares.push_back((y_ext - triples.back()[1]).mask(n_bits)); + protocol->prepare_mul(processor.S[left].mask(n_bits), y_ext.mask(n_bits)); } - MC->POpen_Begin(opened, shares, *P); - MC->POpen_End(opened, shares, *P); - auto it = opened.begin(); + protocol->exchange(); for (size_t i = 0; i < args.size(); i += 4) { int n_bits = args[i]; int out = args[i + 1]; - MaliciousRepSecret tmp = triples[i / 4][2]; - BitVec masked[2]; - for (int k = 0; k < 2; k++) - { - masked[k] = *it++; - tmp += triples[i / 4][1 - k] & masked[k]; - } - processor.S[out] = (tmp + (masked[0] & masked[1])).mask(n_bits); + processor.S[out] = protocol->finalize_mul().mask(n_bits); } } diff --git a/GC/MaliciousRepThread.h b/GC/MaliciousRepThread.h index 1e46cebc9..69774b7ab 100644 --- a/GC/MaliciousRepThread.h +++ b/GC/MaliciousRepThread.h @@ -8,6 +8,7 @@ #include "Thread.h" #include "MaliciousRepSecret.h" +#include "MaliciousRepPrep.h" #include "Processor/Data_Files.h" #include @@ -19,21 +20,15 @@ class MaliciousRepThread : public Thread { static thread_local MaliciousRepThread* singleton; - vector shares; - vector opened; - vector> triples; - public: static MaliciousRepThread& s(); DataPositions usage; - Sub_Data_Files DataF; + MaliciousRepPrep DataF; MaliciousRepThread(int i, ThreadMaster& master); virtual ~MaliciousRepThread() {} - MaliciousRepSecret::MC* new_mc(); - void pre_run(); void post_run(); diff --git a/GC/ReplicatedSecret.cpp b/GC/ReplicatedSecret.cpp index 8c54c18dd..bae111626 100644 --- a/GC/ReplicatedSecret.cpp +++ b/GC/ReplicatedSecret.cpp @@ -14,6 +14,7 @@ #include "Protocols/Share.h" #include "Protocols/ReplicatedMC.hpp" +#include "Protocols/Replicated.hpp" namespace GC { @@ -150,66 +151,16 @@ void ReplicatedSecret::finalize_input(Thread& party, octetStream& o, int f (*this)[1 - j] = 0; } -template<> -inline void ReplicatedSecret::prepare_and(vector& os, int n, - const ReplicatedSecret& x, const ReplicatedSecret& y, - Thread& party, bool repeat) -{ - ReplicatedSecret y_ext; - if (repeat) - y_ext = y.extend_bit(); - else - y_ext = y; - auto add_share = x[0] * y_ext.sum() + x[1] * y_ext[0]; - BitVec tmp[2]; - for (int i = 0; i < 2; i++) - tmp[i].randomize(party.protocol->shared_prngs[i]); - add_share += tmp[0] - tmp[1]; - (*this)[0] = add_share; - BitVec mask = get_mask(n); - *this &= mask; - BitVec(mask & (*this)[0]).pack(os[0], n); -} - -template<> -inline void ReplicatedSecret::finalize_andrs( - vector& os, int n) -{ - (*this)[1].unpack(os[1], n); -} - -template<> -void ReplicatedSecret::andrs(int n, - const ReplicatedSecret& x, - const ReplicatedSecret& y) -{ - auto& party = Thread::s(); - assert(party.P->num_players() == 3); - vector& os = party.os; - os.resize(2); - for (auto& o : os) - o.reset_write_head(); - prepare_and(os, n, x, y, party, true); - party.P->send_relative(os); - party.P->receive_relative(os); - finalize_andrs(os, n); -} - -template<> -void ReplicatedSecret::and_(int n, - const ReplicatedSecret& x, - const ReplicatedSecret& y, bool repeat) +template +BitVec ReplicatedSecret::local_mul(const ReplicatedSecret& other) const { - if (repeat) - andrs(n, x, y); - else - throw runtime_error("call static ReplicatedSecret::ands()"); + return (*this)[0] * other.sum() + (*this)[1] * other[0]; } -template<> -void ReplicatedSecret::and_(int n, - const ReplicatedSecret& x, - const ReplicatedSecret& y, bool repeat) +template +void ReplicatedSecret::and_(int n, + const ReplicatedSecret& x, + const ReplicatedSecret& y, bool repeat) { (void)n, (void)x, (void)y, (void)repeat; throw runtime_error("use static method"); @@ -221,19 +172,25 @@ void ReplicatedSecret::and_(Processor& { auto& party = Thread::s(); assert(party.P->num_players() == 3); - vector& os = party.os; - os.resize(2); - for (auto& o : os) - o.reset_write_head(); processor.check_args(args, 4); + assert(party.protocol != 0); + auto& protocol = *party.protocol; + protocol.init_mul(); for (size_t i = 0; i < args.size(); i += 4) - processor.S[args[i + 1]].prepare_and(os, args[i], - processor.S[args[i + 2]], processor.S[args[i + 3]], - party, repeat); - party.P->send_relative(os); - party.P->receive_relative(os); + { + int n_bits = args[i]; + int left = args[i + 2]; + int right = args[i + 3]; + MaliciousRepSecret y_ext; + if (repeat) + y_ext = processor.S[right].extend_bit(); + else + y_ext = processor.S[right]; + protocol.prepare_mul(processor.S[left].mask(n_bits), y_ext.mask(n_bits), n_bits); + } + protocol.exchange(); for (size_t i = 0; i < args.size(); i += 4) - processor.S[args[i + 1]].finalize_andrs(os, args[i]); + processor.S[args[i + 1]] = protocol.finalize_mul(args[i]); } template<> diff --git a/GC/ReplicatedSecret.h b/GC/ReplicatedSecret.h index 1366ea39e..7af08e77b 100644 --- a/GC/ReplicatedSecret.h +++ b/GC/ReplicatedSecret.h @@ -17,6 +17,7 @@ using namespace std; #include "Math/BitVec.h" #include "Tools/SwitchableOutput.h" #include "Protocols/Replicated.h" +#include "Protocols/ReplicatedMC.h" namespace GC { @@ -27,6 +28,9 @@ class Processor; template class Thread; +template +class Machine; + template class ReplicatedSecret : public FixedVec { @@ -83,10 +87,8 @@ class ReplicatedSecret : public FixedVec { *this = x ^ y; (void)n; } void and_(int n, const ReplicatedSecret& x, const ReplicatedSecret& y, bool repeat); void andrs(int n, const ReplicatedSecret& x, const ReplicatedSecret& y); - void prepare_and(vector& os, int n, - const ReplicatedSecret& x, const ReplicatedSecret& y, - Thread& party, bool repeat); - void finalize_andrs(vector& os, int n); + + BitVec local_mul(const ReplicatedSecret& other) const; void reveal(size_t n_bits, Clear& x); @@ -102,6 +104,10 @@ class SemiHonestRepSecret : public ReplicatedSecret typedef Memory DynamicMemory; typedef ReplicatedMC MC; + typedef Replicated Protocol; + typedef MC MAC_Check; + + static MC* new_mc(Machine& _) { (void) _; return new MC; } SemiHonestRepSecret() {} template diff --git a/GC/Secret.h b/GC/Secret.h index f4c2843bf..024ecbd9d 100644 --- a/GC/Secret.h +++ b/GC/Secret.h @@ -58,6 +58,7 @@ class Mask }; template class Processor; +template class Machine; template class Secret @@ -73,6 +74,8 @@ class Secret typedef DummyMC MC; typedef DummyProtocol Protocol; + static MC* new_mc(Machine& _) { (void) _; return new MC; } + static string type_string() { return "evaluation secret"; } static string phase_name() { return T::name(); } diff --git a/GC/Thread.h b/GC/Thread.h index a10267d50..d0f35cd7a 100644 --- a/GC/Thread.h +++ b/GC/Thread.h @@ -51,7 +51,7 @@ class Thread Thread(int thread_num, ThreadMaster& master); virtual ~Thread(); - virtual typename T::MC* new_mc() { return new typename T::MC; } + virtual typename T::MC* new_mc() { return T::new_mc(machine); } void run(); virtual void pre_run() {} diff --git a/Machines/Semi.hpp b/Machines/Semi.hpp index ad484734a..41ca68680 100644 --- a/Machines/Semi.hpp +++ b/Machines/Semi.hpp @@ -17,6 +17,7 @@ #include "Protocols/SemiPrep.hpp" #include "Protocols/SemiInput.hpp" #include "Protocols/MAC_Check_Base.hpp" +#include "Protocols/MAC_Check.hpp" #include "Protocols/fake-stuff.hpp" #include "Protocols/SemiMC.hpp" #include "Protocols/Beaver.hpp" diff --git a/Machines/ShamirMachine.cpp b/Machines/ShamirMachine.cpp index 687413982..95fc39b01 100644 --- a/Machines/ShamirMachine.cpp +++ b/Machines/ShamirMachine.cpp @@ -23,23 +23,20 @@ #include "Protocols/fake-stuff.hpp" #include "Protocols/Beaver.hpp" -ShamirMachine* ShamirMachine::singleton = 0; +ShamirOptions ShamirOptions::singleton; -ShamirMachine& ShamirMachine::s() +ShamirOptions& ShamirOptions::s() { - if (singleton) - return *singleton; - else - throw runtime_error("no singleton"); + return singleton; } -ShamirMachine::ShamirMachine(int argc, const char** argv) +ShamirOptions::ShamirOptions() : + nparties(3), threshold(1) { - if (singleton) - throw runtime_error("there can only be one"); - else - singleton = this; +} +ShamirOptions::ShamirOptions(ez::ezOptionParser& opt, int argc, const char** argv) +{ opt.add( "3", // Default. 0, // Required? @@ -74,13 +71,16 @@ ShamirMachine::ShamirMachine(int argc, const char** argv) cerr << "Threshold has to be positive" << endl; exit(1); } + opt.resetArgs(); } template class T> -ShamirMachineSpec::ShamirMachineSpec(int argc, const char** argv) : - ShamirMachine(argc, argv) +ShamirMachineSpec::ShamirMachineSpec(int argc, const char** argv) { - ReplicatedMachine, T>(argc, argv, "shamir", opt, nparties); + auto& opts = ShamirOptions::singleton; + ez::ezOptionParser opt; + opts = {opt, argc, argv}; + ReplicatedMachine, T>(argc, argv, "shamir", opt, opts.nparties); } template class ShamirMachineSpec; diff --git a/Machines/ShamirMachine.h b/Machines/ShamirMachine.h index 108cfd00f..cc7161059 100644 --- a/Machines/ShamirMachine.h +++ b/Machines/ShamirMachine.h @@ -8,24 +8,25 @@ #include "Tools/ezOptionParser.h" -class ShamirMachine +class ShamirOptions { - static ShamirMachine* singleton; +public: + static ShamirOptions singleton; + static ShamirOptions& s(); -protected: - ez::ezOptionParser opt; int nparties; - -public: int threshold; - static ShamirMachine& s(); + ShamirOptions(); + ShamirOptions(ez::ezOptionParser& opt, int argc, const char** argv); +}; - ShamirMachine(int argc, const char** argv); +class ShamirMachine : public ShamirOptions +{ }; template class T> -class ShamirMachineSpec : ShamirMachine +class ShamirMachineSpec { public: ShamirMachineSpec(int argc, const char** argv); diff --git a/Machines/mal-shamir-bmr-party.cpp b/Machines/mal-shamir-bmr-party.cpp index 8bfa5dd0f..26da9440b 100644 --- a/Machines/mal-shamir-bmr-party.cpp +++ b/Machines/mal-shamir-bmr-party.cpp @@ -10,6 +10,7 @@ int main(int argc, const char** argv) { - ShamirMachine machine(argc, argv); + ez::ezOptionParser opt; + ShamirOptions::singleton = {opt, argc, argv}; RealProgramParty>(argc, argv); } diff --git a/Machines/shamir-bmr-party.cpp b/Machines/shamir-bmr-party.cpp index c6e677409..ad384356c 100644 --- a/Machines/shamir-bmr-party.cpp +++ b/Machines/shamir-bmr-party.cpp @@ -10,6 +10,7 @@ int main(int argc, const char** argv) { - ShamirMachine machine(argc, argv); + ez::ezOptionParser opt; + ShamirOptions::singleton = {opt, argc, argv}; RealProgramParty>(argc, argv); } diff --git a/Makefile b/Makefile index d880c62e4..b5aedf7f9 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ NETWORK = $(patsubst %.cpp,%.o,$(wildcard Networking/*.cpp)) PROCESSOR = $(patsubst %.cpp,%.o,$(wildcard Processor/*.cpp)) -FHEOFFLINE = $(patsubst %.cpp,%.o,$(wildcard FHEOffline/*.cpp FHE/*.cpp)) OT/BitVector.o +FHEOFFLINE = $(patsubst %.cpp,%.o,$(wildcard FHEOffline/*.cpp FHE/*.cpp)) GC = $(patsubst %.cpp,%.o,$(wildcard GC/*.cpp)) $(PROCESSOR) @@ -29,7 +29,10 @@ LIBSIMPLEOT = SimpleOT/libsimpleot.a # used for dependency generation OBJS = $(BMR) $(FHEOFFLINE) $(TINYOTOFFLINE) $(YAO) $(COMPLETE) $(patsubst %.cpp,%.o,$(wildcard Machines/*.cpp)) -DEPS := $(OBJS:.o=.d) +DEPS := $(wildcard */*.d) + +# never delete +.SECONDARY: $(OBJS) all: gen_input online offline externalIO bmr yao replicated shamir real-bmr spdz2k-party.x brain-party.x semi-party.x semi2k-party.x mascot-party.x @@ -84,20 +87,29 @@ endif shamir: shamir-party.x malicious-shamir-party.x galois-degree.x +ecdsa: $(patsubst ECDSA/%.cpp,%.x,$(wildcard ECDSA/*-ecdsa-party.cpp)) +ecdsa-static: static-dir $(patsubst ECDSA/%.cpp,static/%.x,$(wildcard ECDSA/*-ecdsa-party.cpp)) + $(LIBRELEASE): $(patsubst %.cpp,%.o,$(wildcard Machines/S*.cpp)) $(patsubst %.cpp,%.o,$(wildcard Protocols/*.cpp)) $(YAO) $(PROCESSOR) $(COMMON) $(BMR) $(FHEOFFLINE) $(AR) -csr $@ $^ static/%.x: Machines/%.o $(LIBRELEASE) $(LIBSIMPLEOT) - $(CXX) $(CFLAGS) -o $@ $< $(LIBRELEASE) $(LIBSIMPLEOT) -Wl,-Map=$<.map -Wl,-Bstatic -static-libgcc -static-libstdc++ $(BOOST) $(LDLIBS) -Wl,-Bdynamic -ldl + $(CXX) $(CFLAGS) -o $@ $^ -Wl,-Map=$<.map -Wl,-Bstatic -static-libgcc -static-libstdc++ $(BOOST) $(LDLIBS) -Wl,-Bdynamic -ldl + +static/%.x: ECDSA/%.o ECDSA/P256Element.o Machines/ShamirMachine.o $(VM) $(OT) $(LIBSIMPLEOT) + $(CXX) $(CFLAGS) -o $@ $^ -Wl,-Map=$<.map -Wl,-Bstatic -static-libgcc -static-libstdc++ $(BOOST) $(LDLIBS) $(ECLIB) -Wl,-Bdynamic -ldl static-dir: @ mkdir static 2> /dev/null; true -static-release: static-dir $(patsubst Machines/%.cpp, static/%.x, $(filter-out Machines/malicious-rep-bin-party.cpp,$(wildcard Machines/*-party.cpp))) +static-release: static-dir $(patsubst Machines/%.cpp, static/%.x, $(wildcard Machines/*-party.cpp)) Fake-Offline.x: Fake-Offline.cpp $(COMMON) $(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS) +Fake-ECDSA.x: ECDSA/Fake-ECDSA.cpp ECDSA/P256Element.o $(COMMON) + $(CXX) -o $@ $^ $(CFLAGS) $(LDLIBS) $(ECLIB) + Check-Offline.x: Check-Offline.o $(COMMON) $(PROCESSOR) $(CXX) $(CFLAGS) -o Check-Offline.x $^ $(LDLIBS) @@ -114,10 +126,10 @@ ot.x: $(OT) $(COMMON) OT/OText_main.cpp $(LIBSIMPLEOT) $(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS) ot-check.x: $(OT) $(COMMON) - $(CXX) $(CFLAGS) -o ot-check.x OT/BitVector.o OT/OutputCheck.cpp $(COMMON) $(LDLIBS) + $(CXX) $(CFLAGS) -o ot-check.x OT/OutputCheck.cpp $(COMMON) $(LDLIBS) ot-bitmatrix.x: $(OT) $(COMMON) OT/BitMatrixTest.cpp - $(CXX) $(CFLAGS) -o ot-bitmatrix.x OT/BitMatrixTest.cpp OT/BitMatrix.o OT/BitVector.o $(COMMON) $(LDLIBS) + $(CXX) $(CFLAGS) -o ot-bitmatrix.x OT/BitMatrixTest.cpp OT/BitMatrix.o $(COMMON) $(LDLIBS) ot-offline.x: $(OT) $(COMMON) ot-offline.cpp $(LIBSIMPLEOT) $(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS) @@ -174,9 +186,15 @@ yao-clean: galois-degree.x: galois-degree.cpp $(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS) -%.x: Machines/%.o $(VM) $(OT) $(LIBSIMPLEOT) +default-prime-length.x: default-prime-length.cpp + $(CXX) $(CFLAGS) -o $@ $^ $(LDLIBS) + +%.x: Machines/%.o $(VM) OT/OTTripleSetup.o OT/BaseOT.o $(LIBSIMPLEOT) $(CXX) -o $@ $(CFLAGS) $^ $(LDLIBS) +%-ecdsa-party.x: ECDSA/%-ecdsa-party.o ECDSA/P256Element.o $(VM) + $(CXX) -o $@ $(CFLAGS) $^ $(LDLIBS) $(ECLIB) + replicated-bin-party.x: $(GC) malicious-rep-bin-party.x: $(GC) shamir-party.x: Machines/ShamirMachine.o @@ -186,9 +204,13 @@ semi-party.x: $(OT) semi2k-party.x: $(OT) cowgear-party.x: $(FHEOFFLINE) Protocols/CowGearOptions.o mascot-party.x: Machines/SPDZ.o $(OT) -Player-Online.x: Machines/SPDZ.o +Player-Online.x: Machines/SPDZ.o $(OT) ps-rep-ring-party.x: Protocols/MalRepRingOptions.o malicious-rep-ring-party.x: Protocols/MalRepRingOptions.o +mal-shamir-ecdsa-party.x: Machines/ShamirMachine.o +shamir-ecdsa-party.x: Machines/ShamirMachine.o +semi-ecdsa-party.x: $(OT) $(LIBSIMPLEOT) +mascot-ecdsa-party.x: $(OT) $(LIBSIMPLEOT) $(LIBSIMPLEOT): SimpleOT/Makefile $(MAKE) -C SimpleOT diff --git a/Math/BitVec.h b/Math/BitVec.h index 5ab2f6636..1bfa8303d 100644 --- a/Math/BitVec.h +++ b/Math/BitVec.h @@ -12,6 +12,8 @@ class BitVec : public IntBase { public: + typedef BitVec Scalar; + static const int n_bits = sizeof(a) * 8; static char type_char() { return 'B'; } @@ -27,6 +29,8 @@ class BitVec : public IntBase BitVec operator-(const BitVec& other) const { return a ^ other.a; } BitVec operator*(const BitVec& other) const { return a & other.a; } + BitVec operator/(const BitVec& other) const { (void) other; throw not_implemented(); } + BitVec& operator+=(const BitVec& other) { *this ^= other; return *this; } BitVec extend_bit() const { return -(a & 1); } @@ -34,6 +38,8 @@ class BitVec : public IntBase void mul(const BitVec& a, const BitVec& b) { *this = a * b; } + void randomize(PRNG& G, int n = n_bits) { IntBase::randomize(G); *this = mask(n); } + void pack(octetStream& os, int n = n_bits) const { os.store_int(a, DIV_CEIL(n, 8)); } void unpack(octetStream& os, int n = n_bits) { a = os.get_int(DIV_CEIL(n, 8)); } diff --git a/Math/FixedVec.h b/Math/FixedVec.h index 7c0bf27eb..28d8eb90f 100644 --- a/Math/FixedVec.h +++ b/Math/FixedVec.h @@ -44,6 +44,15 @@ class FixedVec return T::field_type(); } + template + static FixedVec Mul(const FixedVec& a, const V& b) + { + FixedVec res; + for (int i = 0; i < L; i++) + res[i] = T::Mul(a[i], b); + return res; + } + FixedVec(const T& other = 0) { for (auto& x : v) diff --git a/Math/Setup.cpp b/Math/Setup.cpp index fc6a29bd3..ea9d1523a 100644 --- a/Math/Setup.cpp +++ b/Math/Setup.cpp @@ -109,7 +109,7 @@ void generate_online_setup(ofstream& outf, string dirname, bigint& p, int lgp, i write_online_setup(outf, dirname, p, lg2); } -void write_online_setup(ofstream& outf, string dirname, const bigint& p, int lg2) +void write_online_setup(ofstream& outf, string dirname, const bigint& p, int lg2, bool mont) { if (p == 0) throw runtime_error("prime cannot be 0"); @@ -133,7 +133,7 @@ void write_online_setup(ofstream& outf, string dirname, const bigint& p, int lg2 // LWE parameters outf << abs(lg2) << endl; - gfp::init_field(p, true); + gfp::init_field(p, mont); init_gf2n(lg2); } diff --git a/Math/Setup.h b/Math/Setup.h index fb44fa517..d9a196df6 100644 --- a/Math/Setup.h +++ b/Math/Setup.h @@ -21,7 +21,7 @@ using namespace std; // Create setup file for gfp and gf2n void generate_online_setup(ofstream& outf, string dirname, bigint& p, int lgp, int lg2); -void write_online_setup(ofstream& outf, string dirname, const bigint& p, int lg2); +void write_online_setup(ofstream& outf, string dirname, const bigint& p, int lg2, bool mont = true); // Setup primes only // Chooses a p of at least lgp bits diff --git a/Math/Square.cpp b/Math/Square.cpp new file mode 100644 index 000000000..31c760dfb --- /dev/null +++ b/Math/Square.cpp @@ -0,0 +1,36 @@ +/* + * Square.cpp + * + */ + +#include "Square.h" + +template<> +void Square::to(gf2n_short& result) +{ + int128 sum; + for (int i = 0; i < gf2n_short::degree(); i++) + sum ^= int128(rows[i].get()) << i; + result = sum; +} + +template <> +void Square::to(gfp1& result) +{ + const int L = gfp1::N_LIMBS; + mp_limb_t product[2 * L], sum[2 * L], tmp[L][2 * L]; + memset(tmp, 0, sizeof(tmp)); + memset(sum, 0, sizeof(sum)); + for (int i = 0; i < gfp1::length(); i++) + { + memcpy(&(tmp[i/64][i/64]), &(rows[i]), sizeof(rows[i])); + if (i % 64 == 0) + memcpy(product, tmp[i/64], sizeof(product)); + else + mpn_lshift(product, tmp[i/64], 2 * L, i % 64); + mpn_add_fixed_n<2 * L>(sum, product, sum); + } + mp_limb_t q[2 * L], ans[2 * L]; + mpn_tdiv_qr(q, ans, 0, sum, 2 * L, gfp1::get_ZpD().get_prA(), L); + result.assign((void*) ans); +} diff --git a/Math/Square.h b/Math/Square.h new file mode 100644 index 000000000..2fd144ceb --- /dev/null +++ b/Math/Square.h @@ -0,0 +1,42 @@ +/* + * gf2nSquare.h + * + */ + +#ifndef MATH_SQUARE_H_ +#define MATH_SQUARE_H_ + +#include "Tools/BitVector.h" + +template +class Square +{ +public: + static const int N_ROWS = U::MAX_N_BITS; + static const int N_ROWS_ALLOCATED = N_ROWS; + static const int N_COLUMNS = N_ROWS; + static const int N_ROW_BYTES = N_ROWS / 8; + + static size_t size() { return N_ROWS * U::size(); } + + U rows[N_ROWS]; + + template + Square& sub(const Square& other); + template + Square& rsub(const Square& other); + template + Square& sub(const void* other); + + template + void randomize(int row, PRNG& G) { rows[row].randomize(G); } + template + void conditional_add(BitVector& conditions, Square& other, + int offset); + void to(U& result); + + void pack(octetStream& os) const; + void unpack(octetStream& os); +}; + +#endif /* MATH_SQUARE_H_ */ diff --git a/Math/Square.hpp b/Math/Square.hpp new file mode 100644 index 000000000..8e4fdc138 --- /dev/null +++ b/Math/Square.hpp @@ -0,0 +1,59 @@ +/* + * gf2nSquare.cpp + * + */ + +#include "Math/Square.h" + +template +template +Square& Square::sub(const Square& other) +{ + for (int i = 0; i < U::length(); i++) + rows[i] -= other.rows[i]; + return *this; +} + +template +template +Square& Square::rsub(const Square& other) +{ + for (int i = 0; i < U::length(); i++) + rows[i] = other.rows[i] - rows[i]; + return *this; +} + +template +template +Square& Square::sub(const void* other) +{ + U value; + value.assign(other); + for (int i = 0; i < U::length(); i++) + rows[i] -= value; + return *this; +} + +template +template +void Square::conditional_add(BitVector& conditions, + Square& other, int offset) +{ + for (int i = 0; i < U::length(); i++) + if (conditions.get_bit(N_ROWS * offset + i)) + rows[i] += other.rows[i]; +} + +template +void Square::pack(octetStream& os) const +{ + for (int i = 0; i < U::length(); i++) + rows[i].pack(os); +} + +template +void Square::unpack(octetStream& os) +{ + for (int i = 0; i < U::length(); i++) + rows[i].unpack(os); +} diff --git a/Math/Z2k.h b/Math/Z2k.h index 2e4747b33..61d4229b6 100644 --- a/Math/Z2k.h +++ b/Math/Z2k.h @@ -69,6 +69,7 @@ class Z2 : public ValueInterface static bool allows(Dtype dtype); typedef Z2 next; + typedef Z2 Scalar; Z2() { assign_zero(); } Z2(uint64_t x) : Z2() { a[0] = x; } @@ -150,13 +151,13 @@ class Z2 : public ValueInterface void OR(const Z2& a, const Z2& b); void XOR(const Z2& a, const Z2& b); - void randomize(PRNG& G); + void randomize(PRNG& G, int n = -1); void almost_randomize(PRNG& G) { randomize(G); } void force_to_bit() { throw runtime_error("impossible"); } - void pack(octetStream& o) const; - void unpack(octetStream& o); + void pack(octetStream& o, int = -1) const; + void unpack(octetStream& o, int n = -1); void input(istream& s, bool human=true); void output(ostream& s, bool human=true) const; @@ -289,21 +290,24 @@ Z2 Z2::operator>>(int i) const } template -void Z2::randomize(PRNG& G) +void Z2::randomize(PRNG& G, int n) { + (void) n; G.get_octets((octet*)a); normalize(); } template -void Z2::pack(octetStream& o) const +void Z2::pack(octetStream& o, int n) const { + (void) n; o.append((octet*)a, N_BYTES); } template -void Z2::unpack(octetStream& o) +void Z2::unpack(octetStream& o, int n) { + (void) n; o.consume((octet*)a, N_BYTES); } diff --git a/Math/Zp_Data.cpp b/Math/Zp_Data.cpp index 104376f3f..098f766bd 100644 --- a/Math/Zp_Data.cpp +++ b/Math/Zp_Data.cpp @@ -5,10 +5,23 @@ void Zp_Data::init(const bigint& p,bool mont) -{ pr=p; - mask=(1<<((mpz_sizeinbase(pr.get_mpz_t(),2)-1)%(8*sizeof(mp_limb_t))))-1; +{ +#ifdef VERBOSE + if (pr != 0) + { + if (pr != p) + cerr << "Changing prime from " << p << " to " << pr << endl; + if (mont != montgomery) + cerr << "Changing Montgomery" << endl; + } +#endif + + pr=p; + mask=(1LL<<((mpz_sizeinbase(pr.get_mpz_t(),2)-1)%(8*sizeof(mp_limb_t))))-1; pr_byte_length = numBytes(pr); pr_bit_length = numBits(pr); + int k = pr_bit_length; + overhang = (uint64_t(-1LL) >> (63 - (k - 1) % 64)); montgomery=mont; t=mpz_size(pr.get_mpz_t()); diff --git a/Math/Zp_Data.h b/Math/Zp_Data.h index 3bc7ca243..989f9a873 100644 --- a/Math/Zp_Data.h +++ b/Math/Zp_Data.h @@ -35,6 +35,7 @@ class Zp_Data // extra limb needed for Montgomery multiplication mp_limb_t prA[MAX_MOD_SZ+1]; int t; // More Montgomery data + mp_limb_t overhang; template void Mont_Mult_(mp_limb_t* z,const mp_limb_t* x,const mp_limb_t* y) const; @@ -54,6 +55,8 @@ class Zp_Data void init(const bigint& p,bool mont=true); int get_t() const { return t; } const mp_limb_t* get_prA() const { return prA; } + bool get_mont() const { return montgomery; } + mp_limb_t overhang_mask() const; void pack(octetStream& o) const; void unpack(octetStream& o); @@ -63,6 +66,7 @@ class Zp_Data montgomery(0), pi(0), mask(0), pr_byte_length(0), pr_bit_length(0) { t = MAX_MOD_SZ; + overhang = 0; } // The main init funciton @@ -105,6 +109,12 @@ class Zp_Data friend istream& operator>>(istream& s,Zp_Data& ZpD); }; + +inline mp_limb_t Zp_Data::overhang_mask() const +{ + return overhang; +} + template<> inline void Zp_Data::Add<0>(mp_limb_t* ans,const mp_limb_t* x,const mp_limb_t* y) const { diff --git a/Math/gf2n.cpp b/Math/gf2n.cpp index b2f915dd9..ed98b9e0e 100644 --- a/Math/gf2n.cpp +++ b/Math/gf2n.cpp @@ -330,8 +330,9 @@ void gf2n_short::power(long i) } -void gf2n_short::randomize(PRNG& G) +void gf2n_short::randomize(PRNG& G, int n) { + (void) n; a=G.get_uint(); a=(a<<32)^G.get_uint(); a&=mask; diff --git a/Math/gf2n.h b/Math/gf2n.h index d5f49f4da..cd157d82f 100644 --- a/Math/gf2n.h +++ b/Math/gf2n.h @@ -13,8 +13,9 @@ using namespace std; #include "Math/field_types.h" class gf2n_short; -class gf2n_short_square; class P2Data; +template class Square; +typedef Square gf2n_short_square; void expand_byte(gf2n_short& a,int b); void collapse_byte(int& b,const gf2n_short& a); @@ -58,8 +59,11 @@ class gf2n_short typedef gf2n_short value_type; typedef word internal_type; typedef gf2n_short next; - typedef gf2n_short_square Square; + typedef ::Square Square; typedef P2Data FD; + typedef gf2n_short Scalar; + + static const int MAX_N_BITS = 64; static void init_field(int nn); static int degree() { return n; } @@ -88,6 +92,8 @@ class gf2n_short static gf2n_short cut(int128 x) { return x.get_lower(); } + static gf2n_short Mul(gf2n_short a, gf2n_short b) { return a * b; } + word get() const { return a; } word get_word() const { return a; } @@ -101,6 +107,7 @@ class gf2n_short void assign(word aa) { a=aa&mask; } void assign(long aa) { assign(word(aa)); } void assign(int aa) { a=static_cast(aa)&mask; } + void assign(const void* aa) { a = *(word*) aa & mask; } void normalize() { assign(a); } @@ -117,7 +124,7 @@ class gf2n_short gf2n_short(word a) { assign(a); } gf2n_short(long a) { assign(a); } gf2n_short(int a) { assign(a); } - gf2n_short(const char* a) { assign(*(word*)a); } + gf2n_short(const char* a) { assign(a); } gf2n_short(const int128& a) { reduce(a.get_upper(), a.get_lower()); } ~gf2n_short() { ; } @@ -184,7 +191,7 @@ class gf2n_short gf2n_short& operator>>=(int i) { SHR(*this, i); return *this; } /* Crap RNG */ - void randomize(PRNG& G); + void randomize(PRNG& G, int n = -1); // compatibility with gfp void almost_randomize(PRNG& G) { randomize(G); } @@ -205,10 +212,10 @@ class gf2n_short // Pack and unpack in native format // i.e. Dont care about conversion to human readable form - void pack(octetStream& o) const - { o.append((octet*) &a,sizeof(word)); } - void unpack(octetStream& o) - { o.consume((octet*) &a,sizeof(word)); } + void pack(octetStream& o, int n = -1) const + { (void) n; o.append((octet*) &a,sizeof(word)); } + void unpack(octetStream& o, int n = -1) + { (void) n; o.consume((octet*) &a,sizeof(word)); } }; #ifdef USE_GF2N_LONG diff --git a/Math/gf2nlong.cpp b/Math/gf2nlong.cpp index ca94ee3a7..f16d25769 100644 --- a/Math/gf2nlong.cpp +++ b/Math/gf2nlong.cpp @@ -236,8 +236,9 @@ void gf2n_long::invert() } -void gf2n_long::randomize(PRNG& G) +void gf2n_long::randomize(PRNG& G, int n) { + (void) n; a=G.get_doubleword(); a&=mask; } diff --git a/Math/gf2nlong.h b/Math/gf2nlong.h index 169956591..84131feb2 100644 --- a/Math/gf2nlong.h +++ b/Math/gf2nlong.h @@ -67,7 +67,7 @@ template class Input; template class PrivateOutput; template class SPDZ; template class Share; -union square128; +template class Square; /* This interface compatible with the gfp interface * which then allows us to template the Share @@ -97,7 +97,11 @@ class gf2n_long typedef int128 internal_type; typedef gf2n_long next; - typedef square128 Square; + typedef ::Square Square; + + const static int MAX_N_BITS = 128; + + typedef gf2n_long Scalar; void reduce(int128 xh,int128 xl) { @@ -109,6 +113,7 @@ class gf2n_long static void init_field(int nn); static int degree() { return n; } + static int length() { return n; } static int default_degree() { return 128; } static int get_nterms() { return nterms; } static int get_t(int i) @@ -133,6 +138,8 @@ class gf2n_long static gf2n_long cut(int128 x) { return x; } + static gf2n_long Mul(gf2n_long a, gf2n_long b) { return a * b; } + int128 get() const { return a; } __m128i to_m128i() const { return a.a; } word get_word() const { return _mm_cvtsi128_si64(a.a); } @@ -146,7 +153,7 @@ class gf2n_long void assign_x() { a=int128(0,2); } void assign(int128 aa) { a=aa&mask; } void assign(int aa) { a=int128(static_cast(aa))&mask; } - void assign(const char* buffer) { a = _mm_loadu_si128((__m128i*)buffer); } + void assign(const void* buffer) { a = _mm_loadu_si128((__m128i*)buffer); } void normalize() {} @@ -234,7 +241,7 @@ class gf2n_long gf2n_long& operator>>=(int i) { SHR(*this, i); return *this; } /* Crap RNG */ - void randomize(PRNG& G); + void randomize(PRNG& G, int n = -1); // compatibility with gfp void almost_randomize(PRNG& G) { randomize(G); } @@ -261,10 +268,10 @@ class gf2n_long // Pack and unpack in native format // i.e. Dont care about conversion to human readable form - void pack(octetStream& o) const - { o.append((octet*) &a,sizeof(__m128i)); } - void unpack(octetStream& o) - { o.consume((octet*) &a,sizeof(__m128i)); } + void pack(octetStream& o, int n = -1) const + { (void) n; o.append((octet*) &a,sizeof(__m128i)); } + void unpack(octetStream& o, int n = -1) + { (void) n; o.consume((octet*) &a,sizeof(__m128i)); } }; diff --git a/Math/gf2nshortsquare.cpp b/Math/gf2nshortsquare.cpp deleted file mode 100644 index af362f87f..000000000 --- a/Math/gf2nshortsquare.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - * gf2nSquare.cpp - * - */ - -#include "gf2nshortsquare.h" - - -template<> -gf2n_short_square& gf2n_short_square::sub(const gf2n_short_square& other) -{ - for (int i = 0; i < gf2n_short::degree(); i++) - rows[i] -= other.rows[i]; - return *this; -} - -template<> -gf2n_short_square& gf2n_short_square::sub(const void* other) -{ - gf2n_short value = *(word*)other; - for (int i = 0; i < gf2n_short::degree(); i++) - rows[i] -= value; - return *this; -} - -template<> -void gf2n_short_square::conditional_add(BitVector& conditions, - gf2n_short_square& other, int offset) -{ - for (int i = 0; i < gf2n_short::degree(); i++) - if (conditions.get_bit(N_ROWS * offset + i)) - rows[i] += other.rows[i]; -} - -void gf2n_short_square::to(gf2n_short& result) -{ - int128 sum; - for (int i = 0; i < gf2n_short::degree(); i++) - sum ^= int128(rows[i].get()) << i; - result = sum; -} - -void gf2n_short_square::pack(octetStream& os) const -{ - for (auto& x : rows) - x.pack(os); -} - -void gf2n_short_square::unpack(octetStream& os) -{ - for (auto& x : rows) - x.unpack(os); -} diff --git a/Math/gf2nshortsquare.h b/Math/gf2nshortsquare.h deleted file mode 100644 index 46a7e9369..000000000 --- a/Math/gf2nshortsquare.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * gf2nSquare.h - * - */ - -#ifndef MATH_GF2NSHORTSQUARE_H_ -#define MATH_GF2NSHORTSQUARE_H_ - -#include "Math/gf2n.h" -#include "OT/BitVector.h" - -class gf2n_short_square -{ -public: - static const int N_ROWS = 64; - static const int N_ROWS_ALLOCATED = 64; - static const int N_COLUMNS = 64; - static const int N_ROW_BYTES = sizeof(gf2n_short); - - static size_t size() { return N_ROWS * gf2n_short::size(); } - - gf2n_short rows[N_ROWS]; - - template - gf2n_short_square& sub(const gf2n_short_square& other); - template - gf2n_short_square& rsub(const gf2n_short_square& other) { return sub(other); } - template - gf2n_short_square& sub(const void* other); - - template - void randomize(int row, PRNG& G) { rows[row].randomize(G); } - template - void conditional_add(BitVector& conditions, gf2n_short_square& other, - int offset); - void to(gf2n_short& result); - - void pack(octetStream& os) const; - void unpack(octetStream& os); -}; - -#endif /* MATH_GF2NSHORTSQUARE_H_ */ diff --git a/Math/gfp.cpp b/Math/gfp.cpp index 15c867b2e..e2f53f5b0 100644 --- a/Math/gfp.cpp +++ b/Math/gfp.cpp @@ -18,7 +18,13 @@ void gfp_::init_field(const bigint& p, bool mont) "Maybe change GFP_MOD_SZ to " + to_string(ZpD.get_t())); } if (ZpD.get_t() < L) - cerr << name << " larger than necessary for modulus " << p << endl; + { + if (mont) + throw runtime_error(name + " too large for modulus. " + "Maybe change GFP_MOD_SZ to " + to_string(ZpD.get_t())); + else + cerr << name << " larger than necessary for modulus " << p << endl; + } } template @@ -27,6 +33,12 @@ void gfp_::init_default(int lgp, bool mont) init_field(SPDZ_Data_Setup_Primes(lgp), mont); } +template +void gfp_::check() +{ + assert(mpn_cmp(a.x, ZpD.get_prA(), t()) < 0); +} + template void gfp_::almost_randomize(PRNG& G) { @@ -205,5 +217,6 @@ void to_signed_bigint(bigint& ans, const gfp& x) template class gfp_<0, GFP_MOD_SZ>; template class gfp_<1, GFP_MOD_SZ>; template class gfp_<2, 4>; +template class gfp_<3, 4>; template mpf_class bigint::get_float(gfp, Integer, gfp, gfp); diff --git a/Math/gfp.h b/Math/gfp.h index 6b0ead4be..ca6f2645f 100644 --- a/Math/gfp.h +++ b/Math/gfp.h @@ -25,6 +25,7 @@ using namespace std; template class Input; template class SPDZ; +template class Square; class FFT_Data; #ifndef GFP_MOD_SZ @@ -46,12 +47,16 @@ class gfp_ public: typedef gfp_ value_type; + typedef gfp_ Scalar; typedef gfp_ next; - typedef square128 Square; + typedef ::Square Square; typedef FFT_Data FD; + static const int N_LIMBS = L; + static const int MAX_N_BITS = 64 * L; + template static void init(bool mont = true) { init_field(T::pr(), mont); } @@ -63,7 +68,7 @@ class gfp_ static bigint pr() { return ZpD.pr; } static int t() - { return ZpD.get_t(); } + { return L; } static Zp_Data& get_ZpD() { return ZpD; } @@ -80,6 +85,8 @@ class gfp_ static const bool invertible = true; + static gfp_ Mul(gfp_ a, gfp_ b) { return a * b; } + void assign(const gfp_& g) { a=g.a; } void assign_zero() { assignZero(a,ZpD); } void assign_one() { assignOne(a,ZpD); } @@ -99,6 +106,7 @@ class gfp_ unsigned long debug() const { return a.get_limb(0); } const void* get_ptr() const { return &a.x; } + void* get_ptr() { return &a.x; } // Assumes prD behind x is equal to ZpD void assign(modp_& x) { a=x; } @@ -133,6 +141,8 @@ class gfp_ return _mm_loadu_si128((__m128i*)a.x); } + void zero_overhang(); + void check(); bool is_zero() const { return isZero(a,ZpD); } bool is_one() const { return isOne(a,ZpD); } @@ -190,8 +200,8 @@ class gfp_ // deterministic square root gfp_ sqrRoot(); - void randomize(PRNG& G) - { a.randomize(G,ZpD); } + void randomize(PRNG& G, int n = -1) + { (void) n; a.randomize(G,ZpD); } // faster randomization, see implementation for explanation void almost_randomize(PRNG& G); @@ -233,10 +243,10 @@ class gfp_ // Pack and unpack in native format // i.e. Dont care about conversion to human readable form - void pack(octetStream& o) const - { a.pack(o,ZpD); } - void unpack(octetStream& o) - { a.unpack(o,ZpD); } + void pack(octetStream& o, int n = -1) const + { (void) n; a.pack(o,ZpD); } + void unpack(octetStream& o, int n = -1) + { (void) n; a.unpack(o,ZpD); } void convert_destroy(bigint& x) { a.convert_destroy(x, ZpD); } @@ -275,4 +285,10 @@ gfp_::gfp_(const SignedZ2& other) a.convert(abs(other).get(), other.size_in_limbs(), ZpD, other.negative()); } +template +inline void gfp_::zero_overhang() +{ + a.x[t() - 1] &= ZpD.overhang_mask(); +} + #endif diff --git a/Math/modp.hpp b/Math/modp.hpp index ccb9c4d54..4da616783 100644 --- a/Math/modp.hpp +++ b/Math/modp.hpp @@ -10,7 +10,7 @@ template void modp_::randomize(PRNG& G, const Zp_Data& ZpD) { - G.randomBnd(x, ZpD.get_prA(), ZpD.pr_byte_length); + G.randomBnd(x, ZpD.get_prA(), ZpD.pr_byte_length, ZpD.overhang_mask()); } template diff --git a/Networking/Player.cpp b/Networking/Player.cpp index 07da138e7..d73bd8231 100644 --- a/Networking/Player.cpp +++ b/Networking/Player.cpp @@ -4,6 +4,8 @@ #include "Exceptions/Exceptions.h" #include "Networking/STS.h" #include "Tools/int.h" +#include "Tools/NetworkOptions.h" +#include "Networking/Server.h" #include #include @@ -74,6 +76,36 @@ void Names::init(int player, int pnb, const string& filename, int nplayers_wante setup_server(); } +Names::Names(ez::ezOptionParser& opt, int argc, const char** argv, + int default_nplayers) : + Names() +{ + NetworkOptions network_opts(opt, argc, argv); + opt.add( + to_string(default_nplayers).c_str(), // Default. + 0, // Required? + 1, // Number of args expected. + 0, // Delimiter if expecting multiple args. + "Number of players", // Help description. + "-N", // Flag token. + "--nparties" // Flag token. + ); + opt.add( + "", // Default. + 1, // Required? + 1, // Number of args expected. + 0, // Delimiter if expecting multiple args. + "This player's number", // Help description. + "-p", // Flag token. + "--player" // Flag token. + ); + opt.parse(argc, argv); + opt.get("-p")->getInt(player_no); + opt.get("-N")->getInt(nplayers); + global_server = Server::start_networking(*this, player_no, nplayers, + network_opts.hostname, network_opts.portnum_base); +} + void Names::setup_ports() { ports.resize(nplayers); @@ -151,6 +183,7 @@ Names::Names(const Names& other) names = other.names; ports = other.ports; server = 0; + global_server = 0; } @@ -158,6 +191,8 @@ Names::~Names() { if (server != 0) delete server; + if (global_server != 0) + delete global_server; } @@ -199,10 +234,7 @@ Player::~Player() PlayerBase::~PlayerBase() { #ifdef VERBOSE - for (auto it = comm_stats.begin(); it != comm_stats.end(); it++) - cerr << it->first << " " << 1e-6 * it->second.data << " MB in " - << it->second.rounds << " rounds, taking " << it->second.timer.elapsed() - << " seconds" << endl; + comm_stats.print(); if (timer.elapsed() > 0) cerr << "Receiving took " << timer.elapsed() << " seconds" << endl; #endif @@ -653,6 +685,22 @@ NamedCommStats& NamedCommStats::operator +=(const NamedCommStats& other) return *this; } +CommStats& CommStats::operator -=(const CommStats& other) +{ + data -= other.data; + rounds -= other.rounds; + timer -= other.timer; + return *this; +} + +NamedCommStats NamedCommStats::operator -(const NamedCommStats& other) const +{ + NamedCommStats res = *this; + for (auto it = other.begin(); it != other.end(); it++) + res[it->first] -= it->second; + return res; +} + size_t NamedCommStats::total_data() { size_t res = 0; @@ -661,5 +709,14 @@ size_t NamedCommStats::total_data() return res; } +void NamedCommStats::print() +{ + for (auto it = begin(); it != end(); it++) + if (it->second.data) + cerr << it->first << " " << 1e-6 * it->second.data << " MB in " + << it->second.rounds << " rounds, taking " << it->second.timer.elapsed() + << " seconds" << endl; +} + template class MultiPlayer; template class MultiPlayer; diff --git a/Networking/Player.h b/Networking/Player.h index e5ca38fc2..cfadfef30 100644 --- a/Networking/Player.h +++ b/Networking/Player.h @@ -22,8 +22,10 @@ using namespace std; #include "Tools/int.h" #include "Networking/Receiver.h" #include "Networking/Sender.h" +#include "Tools/ezOptionParser.h" template class MultiPlayer; +class Server; /* Class to get the names off the server */ class Names @@ -33,6 +35,7 @@ class Names int nplayers; int portnum_base; int player_no; + Server* global_server; int default_port(int playerno) { return portnum_base + playerno; } void setup_ports(); @@ -62,7 +65,11 @@ class Names Names(int player, int pnb, const string& hostsfile) { init(player, pnb, hostsfile); } - Names() : nplayers(-1), portnum_base(-1), player_no(-1), server(0) { ; } + // initialize from command-line options + Names(ez::ezOptionParser& opt, int argc, const char** argv, + int default_nplayers = 2); + + Names() : nplayers(-1), portnum_base(-1), player_no(-1), global_server(0), server(0) { ; } Names(const Names& other); ~Names(); @@ -85,13 +92,16 @@ struct CommStats CommStats() : data(0), rounds(0) {} Timer& add(const octetStream& os) { data += os.get_length(); rounds++; return timer; } CommStats& operator+=(const CommStats& other); + CommStats& operator-=(const CommStats& other); }; class NamedCommStats : public map { public: NamedCommStats& operator+=(const NamedCommStats& other); + NamedCommStats operator-(const NamedCommStats& other) const; size_t total_data(); + void print(); #ifdef VERBOSE_COMM CommStats& operator[](const string& name) { diff --git a/Networking/Server.cpp b/Networking/Server.cpp index 6189eba63..89c54c204 100644 --- a/Networking/Server.cpp +++ b/Networking/Server.cpp @@ -168,6 +168,7 @@ Server* Server::start_networking(Names& N, int my_num, int nplayers, << " with server on " << hostname << ":" << (portnum - 1) << endl; #endif assert(my_num >= 0); + assert(my_num < nplayers); Server* server = 0; if (my_num == 0) { diff --git a/OT/BaseOT.h b/OT/BaseOT.h index eba353c80..54be8a1da 100644 --- a/OT/BaseOT.h +++ b/OT/BaseOT.h @@ -10,7 +10,7 @@ #include "Networking/Player.h" #include "Tools/random.h" -#include "OT/BitVector.h" +#include "Tools/BitVector.h" // currently always assumes BOTH, i.e. do 2 sets of OT symmetrically, // use bitwise & to check for role diff --git a/OT/BitMatrix.cpp b/OT/BitMatrix.cpp index 80422e414..4ba949c15 100644 --- a/OT/BitMatrix.cpp +++ b/OT/BitMatrix.cpp @@ -15,6 +15,7 @@ #include "OT/Rectangle.hpp" #include "Math/Z2k.hpp" +#include "Math/Square.hpp" union matrix16x8 { @@ -273,27 +274,6 @@ void square128::randomize(int row, PRNG& G) rows[row] = G.get_doubleword(); } -template <> -void square128::randomize(int row, PRNG& G) -{ - rows[row] = gfp1::get_ZpD().get_random128(G); -} - - -void gfp_iadd(__m128i& a, __m128i& b) -{ - gfp1::get_ZpD().Add((mp_limb_t*)&a, (mp_limb_t*)&a, (mp_limb_t*)&b); -} - -void gfp_isub(__m128i& a, __m128i& b) -{ - gfp1::get_ZpD().Sub((mp_limb_t*)&a, (mp_limb_t*)&a, (mp_limb_t*)&b); -} - -void gfp_irsub(__m128i& a, __m128i& b) -{ - gfp1::get_ZpD().Sub((mp_limb_t*)&a, (mp_limb_t*)&b, (mp_limb_t*)&a); -} template<> void square128::conditional_add(BitVector& conditions, square128& other, int offset) @@ -303,14 +283,6 @@ void square128::conditional_add(BitVector& conditions, square128& oth rows[i] ^= other.rows[i]; } -template<> -void square128::conditional_add(BitVector& conditions, square128& other, int offset) -{ - for (int i = 0; i < 128; i++) - if (conditions.get_bit(128 * offset + i)) - gfp_iadd(rows[i], other.rows[i]); -} - template void square128::hash_row_wise(MMO& mmo, square128& input) { @@ -318,37 +290,17 @@ void square128::hash_row_wise(MMO& mmo, square128& input) } template <> -void square128::to(gf2n_long& result) +void Square::to(gf2n_long& result) { int128 high, low; for (int i = 0; i < 128; i++) { - low ^= int128(rows[i]) << i; - high ^= int128(rows[i]) >> (128 - i); + low ^= rows[i].get() << i; + high ^= rows[i].get() >> (128 - i); } result.reduce(high, low); } -template <> -void square128::to(gfp1& result) -{ - mp_limb_t product[4], sum[4], tmp[2][4]; - memset(tmp, 0, sizeof(tmp)); - memset(sum, 0, sizeof(sum)); - for (int i = 0; i < 128; i++) - { - memcpy(&(tmp[i/64][i/64]), &(rows[i]), sizeof(rows[i])); - if (i % 64 == 0) - memcpy(product, tmp[i/64], sizeof(product)); - else - mpn_lshift(product, tmp[i/64], 4, i % 64); - mpn_add_fixed_n<4>(sum, product, sum); - } - mp_limb_t q[4], ans[4]; - mpn_tdiv_qr(q, ans, 0, sum, 4, gfp1::get_ZpD().get_prA(), 2); - result = *(__m128i*)ans; -} - void square128::check_transpose(square128& dual, int i, int k) { for (int j = 0; j < 16; j++) @@ -449,42 +401,18 @@ square128& square128::add(square128& other) return *this ^= other; } -template<> -square128& square128::add(square128& other) -{ - for (int i = 0; i < 128; i++) - gfp_iadd(rows[i], other.rows[i]); - return *this; -} - template<> square128& square128::sub(square128& other) { return *this ^= other; } -template<> -square128& square128::sub(square128& other) -{ - for (int i = 0; i < 128; i++) - gfp_isub(rows[i], other.rows[i]); - return *this; -} - template<> square128& square128::rsub(square128& other) { return *this ^= other; } -template<> -square128& square128::rsub(square128& other) -{ - for (int i = 0; i < 128; i++) - gfp_irsub(rows[i], other.rows[i]); - return *this; -} - square128& square128::operator^=(const __m128i* other) { __m128i value = _mm_loadu_si128(other); @@ -499,15 +427,6 @@ square128& square128::sub(const __m128i* other) return *this ^= other; } -template <> -square128& square128::sub(const __m128i* other) -{ - __m128i value = _mm_loadu_si128(other); - for (int i = 0; i < 128; i++) - gfp_isub(rows[i], value); - return *this; -} - square128& square128::operator^=(BitVector& other) { return *this ^= (__m128i*)other.get_ptr(); @@ -553,31 +472,6 @@ int BitMatrix::size() return squares.size() * 128; } -template -template -Matrix& Matrix::operator=(const Matrix& other) -{ - int n = other.squares.size() * V::N_ROWS; - squares.resize(DIV_CEIL(n, U::N_ROWS)); - for (int i = 0; i < n; i++) - { - auto& dest = squares[i / U::N_ROWS].rows[i % U::N_ROWS]; - auto& source = other.squares[i / V::N_ROWS].rows[i % V::N_ROWS]; - if (U::N_COLUMNS < V::N_COLUMNS) - dest = source; - else - { - PRNG prng; - octet seed[SEED_SIZE]; - avx_memcpy(seed, &source, min(SEED_SIZE, (int)sizeof(source))); - prng.SetSeed(seed); - dest = 0; - prng.get_octets((octet*)dest.get_ptr()); - } - } - return *this; -} - template bool Matrix::operator==(Matrix& other) { @@ -678,28 +572,14 @@ void Matrix::unpack(octetStream& os) squares[i].unpack(os); } -template <> -void Matrix::to(vector& output) +void BitMatrix::vertical_to(vector& output) { - output.resize(128); - for (int i = 0; i < 128; i++) - { - output[i].resize(128 * squares.size()); - for (size_t j = 0; j < squares.size(); j++) - output[i].set_int128(j, squares[j].rows[i]); - } -} - -template -void Matrix::to(vector& output) -{ - int n = U::N_ROWS; + int n = 128 * squares.size(); output.resize(n); for (int i = 0; i < n; i++) { - output[i].resize(U::N_COLUMNS * squares.size()); - for (size_t j = 0; j < squares.size(); j++) - output[i].set_portion(j, squares[j].rows[i]); + output[i].resize(128); + output[i].set_int128(0, squares[i / 128].rows[i % 128]); } } @@ -808,7 +688,6 @@ template void Slice, Z2 > > >::conditional_add< \ #undef X #define X(N,L) \ -template M(N,L)& M(N,L)::operator=(const Matrix& other); \ template void Slice, Z2 > > >::randomize >(int row, PRNG& G); \ XXX(Z2, N, L) @@ -824,11 +703,11 @@ Y(32, 32) template class Matrix; -#define BMS X(BitMatrix) X(Matrix) +#define BMS X(BitMatrix) #undef X #define X(BM) \ template class Slice; \ -XX(BM, gfp1) XX(BM, gf2n_long) +XX(BM, gf2n_long) #define XX(BM, GF) \ template void Slice::conditional_add(BitVector& conditions, BM& other, bool useOffset); \ @@ -842,5 +721,8 @@ BMS template class Slice>; XX(Matrix, gf2n_short) -template void square128::hash_row_wise(MMO& mmo, square128& input); -template void square128::hash_row_wise(MMO& mmo, square128& input); +template class Slice>>; +XX(Matrix>, gf2n_long) + +template class Slice>>; +XX(Matrix>, gfp1) diff --git a/OT/BitMatrix.h b/OT/BitMatrix.h index c4a2bed61..6f4c7eda5 100644 --- a/OT/BitMatrix.h +++ b/OT/BitMatrix.h @@ -10,11 +10,11 @@ #include #include -#include "BitVector.h" +#include "Tools/BitVector.h" #include "Tools/random.h" #include "Tools/MMO.h" #include "Math/gf2nlong.h" -#include "Math/gf2nshortsquare.h" +#include "Math/Square.h" using namespace std; @@ -131,9 +131,6 @@ class Matrix void resize_vertical(int length) { squares.resize(DIV_CEIL(length, U::N_ROWS)); } - template - Matrix& operator=(const Matrix& other); - bool operator==(Matrix& other); bool operator!=(Matrix& other); @@ -146,8 +143,6 @@ class Matrix // i.e. Dont care about conversion to human readable form void pack(octetStream& o) const; void unpack(octetStream& o); - - void to(vector& output); }; class BitMatrix : public Matrix @@ -163,6 +158,8 @@ class BitMatrix : public Matrix void transpose(); void check_transpose(BitMatrix& dual); + + void vertical_to(vector& output); }; template diff --git a/OT/OTExtensionWithMatrix.cpp b/OT/OTExtensionWithMatrix.cpp index 07b0b238c..b4fd9113d 100644 --- a/OT/OTExtensionWithMatrix.cpp +++ b/OT/OTExtensionWithMatrix.cpp @@ -7,9 +7,11 @@ #include "Rectangle.h" #include "Math/gfp.h" #include "Math/Z2k.h" +#include "Math/gf2nlong.h" #include "OT/Rectangle.hpp" #include "Math/Z2k.hpp" +#include "Math/Square.hpp" OTExtensionWithMatrix OTExtensionWithMatrix::setup(TwoPartyPlayer& player, int128 delta, OT_ROLE role, bool passive) @@ -514,7 +516,8 @@ void OTExtensionWithMatrix::print_pre_expand() } template class OTCorrelator; -template class OTCorrelator >; +template void OTCorrelator::correlate(int start, int slice, + BitVector& newReceiverInput, bool useConstantBase, int repeat); #define Z(BM,GF) \ template void OTCorrelator::correlate(int start, int slice, \ @@ -526,18 +529,17 @@ template void OTCorrelator::reduce_squares(unsigned int nTriples, \ template class OTCorrelator>; Z(Matrix, gf2n_short) -#define ZZ(BM) Z(BM, gfp1) Z(BM, gf2n_long) +template class OTCorrelator>>; +Z(Matrix>, gf2n_long) -ZZ(BitMatrix) -ZZ(Matrix ) +template class OTCorrelator>>; +Z(Matrix>, gfp1) #define ZZZZ(GF) \ -ZZZ(GF, Matrix) \ template void OTExtensionWithMatrix::print_post_correlate( \ BitVector& newReceiverInput, int j, int offset, int sender); \ template void OTExtensionWithMatrix::extend(int nOTs_requested, \ BitVector& newReceiverInput); \ -template void OTExtensionWithMatrix::expand_transposed(); #define ZZZ(GF, M) \ template void OTExtensionWithMatrix::hash_outputs(int, vector&, M&); @@ -547,6 +549,8 @@ ZZZZ(gfp1) ZZZZ(gf2n_long) ZZZ(Z2<160>, MM) ZZZ(gf2n_short, Matrix) +ZZZ(gf2n_long, Matrix>) +ZZZ(gfp1, Matrix>) #undef XX #define XX(T,U,N,L) \ diff --git a/OT/OTMultiplier.cpp b/OT/OTMultiplier.cpp index f1dc099c3..cdcbe5db5 100644 --- a/OT/OTMultiplier.cpp +++ b/OT/OTMultiplier.cpp @@ -17,6 +17,7 @@ #include "OT/Row.hpp" #include "OT/Rectangle.hpp" #include "Math/Z2k.hpp" +#include "Math/Square.hpp" #include @@ -86,7 +87,8 @@ void OTMultiplier::multiply() senderOutput[j][i].set_int128(0, rot_ext.senderOutputMatrices[i].squares[0].rows[j]); } } - rot_ext.receiverOutputMatrix.to(receiverOutput); + rot_ext.receiverOutputMatrix.vertical_to(receiverOutput); + assert(receiverOutput.size() >= keyBits.size()); receiverOutput.resize(keyBits.size()); init_authenticator(keyBits, senderOutput, receiverOutput); @@ -189,7 +191,8 @@ void SemiMultiplier::after_correlation() template void MascotMultiplier::after_correlation() { - this->auth_ot_ext.resize(this->generator.nPreampTriplesPerLoop * square128::N_COLUMNS); + this->auth_ot_ext.resize( + this->generator.nPreampTriplesPerLoop * T::Square::N_COLUMNS); this->auth_ot_ext.set_role(BOTH); this->otCorrelator.reduce_squares(this->generator.nPreampTriplesPerLoop, diff --git a/OT/Rectangle.h b/OT/Rectangle.h index 96374b49e..03bf0a7c3 100644 --- a/OT/Rectangle.h +++ b/OT/Rectangle.h @@ -7,7 +7,7 @@ #define OT_RECTANGLE_H_ #include "Tools/random.h" -#include "OT/BitVector.h" +#include "Tools/BitVector.h" #include "Math/Z2k.h" #define TAU(K, S) 2 * K + 4 * S diff --git a/Processor/Data_Files.h b/Processor/Data_Files.h index c8e8c481e..f33cd8806 100644 --- a/Processor/Data_Files.h +++ b/Processor/Data_Files.h @@ -108,6 +108,8 @@ class Preprocessing void get_one(Dtype dtype, T& a); void get_input(T& a, typename T::open_type& x, int i); void get(vector& S, DataTag tag, const vector& regs, int vector_size); + + virtual void buffer_triples() {} }; template diff --git a/Processor/Input.h b/Processor/Input.h index cffd81c1a..17b2f348c 100644 --- a/Processor/Input.h +++ b/Processor/Input.h @@ -32,7 +32,7 @@ class InputBase int values_input; template - static void input(SubProcessor& Proc, const vector& args); + static void input(SubProcessor& Proc, const vector& args, int size); InputBase(ArithmeticProcessor* proc); virtual ~InputBase(); diff --git a/Processor/Input.hpp b/Processor/Input.hpp index cb356a9ca..4d8d0d65a 100644 --- a/Processor/Input.hpp +++ b/Processor/Input.hpp @@ -186,11 +186,10 @@ T InputBase::finalize(int player) template template void InputBase::input(SubProcessor& Proc, - const vector& args) + const vector& args, int size) { auto& input = Proc.input; - for (int i = 0; i < Proc.P.num_players(); i++) - input.reset(i); + input.reset_all(Proc.P); int n_arg_tuple = U::N_DEST + U::N_PARAM + 1; assert(args.size() % n_arg_tuple == 0); @@ -199,7 +198,7 @@ void InputBase::input(SubProcessor& Proc, if (Proc.Proc.opts.interactive and Proc.Proc.thread_num == 0) { for (size_t i = n_arg_tuple - 1; i < args.size(); i += n_arg_tuple) - n_from_me += (args[i] == Proc.P.my_num()); + n_from_me += (args[i] == Proc.P.my_num()) * size; if (n_from_me > 0) cout << "Please input " << n_from_me << " " << U::NAME << "(s):" << endl; } @@ -209,13 +208,17 @@ void InputBase::input(SubProcessor& Proc, int n = args[i + U::N_PARAM]; if (n == Proc.P.my_num()) { - U tuple = Proc.Proc.template get_input(n_from_me > 0, &args[i]); - for (auto x : tuple.items) - input.add_mine(x); + for (int j = 0; j < size; j++) + { + U tuple = Proc.Proc.template get_input(n_from_me > 0, + &args[i]); + for (auto x : tuple.items) + input.add_mine(x); + } } else { - for (int j = 0; j < U::N_DEST; j++) + for (int j = 0; j < U::N_DEST * size; j++) input.add_other(n); } } @@ -223,14 +226,13 @@ void InputBase::input(SubProcessor& Proc, if (n_from_me > 0) cout << "Thank you" << endl; - input.send_mine(); + input.exchange(); - vector> regs(Proc.P.num_players()); for (size_t i = 0; i < args.size(); i += n_arg_tuple) { - for (int j = 0; j < U::N_DEST; j++) - regs[args[i + n_arg_tuple - 1]].push_back(args[i + j]); + int player = args[i + n_arg_tuple - 1]; + for (int k = 0; k < size; k++) + for (int j = 0; j < U::N_DEST; j++) + Proc.get_S_ref(args[i + j] + k) = input.finalize(player); } - for (int i = 0; i < Proc.P.num_players(); i++) - input.stop(i, regs[i]); } diff --git a/Processor/Instruction.hpp b/Processor/Instruction.hpp index f25e9b5c2..e08818f0d 100644 --- a/Processor/Instruction.hpp +++ b/Processor/Instruction.hpp @@ -992,17 +992,17 @@ inline void Instruction::execute(Processor& Proc) const Proc.temp.ans2.output(Proc.private_output, false); break; case INPUT: - sint::Input::template input(Proc.Procp, start); - break; + sint::Input::template input(Proc.Procp, start, size); + return; case GINPUT: - sgf2n::Input::template input(Proc.Proc2, start); - break; + sgf2n::Input::template input(Proc.Proc2, start, size); + return; case INPUTFIX: - sint::Input::template input(Proc.Procp, start); - break; + sint::Input::template input(Proc.Procp, start, size); + return; case INPUTFLOAT: - sint::Input::template input(Proc.Procp, start); - break; + sint::Input::template input(Proc.Procp, start, size); + return; case STARTINPUT: Proc.Procp.input.start(r[0],n); break; @@ -1133,13 +1133,13 @@ inline void Instruction::execute(Processor& Proc) const Proc.Proc2.POpen(start, Proc.P, size); return; case MULS: - Proc.Procp.protocol.muls(start, Proc.Procp, Proc.MCp, size); + Proc.Procp.muls(start, size); return; case GMULS: Proc.Proc2.protocol.muls(start, Proc.Proc2, Proc.MC2, size); return; case MULRS: - Proc.Procp.protocol.mulrs(start, Proc.Procp); + Proc.Procp.mulrs(start); return; case GMULRS: Proc.Proc2.protocol.mulrs(start, Proc.Proc2); diff --git a/Processor/Machine.hpp b/Processor/Machine.hpp index 7da4abf7a..6caf26c5d 100644 --- a/Processor/Machine.hpp +++ b/Processor/Machine.hpp @@ -61,6 +61,10 @@ Machine::Machine(int my_number, Names& playerNames, cerr << "End of file reading MAC key but maybe we don't need it" << endl; } + auto P = new PlainPlayer(N, 0xF00); + sint::LivePrep::basic_setup(*P); + delete P; + if (not read_mac_keys) { #ifdef VERBOSE diff --git a/Processor/OnlineOptions.cpp b/Processor/OnlineOptions.cpp index 2aef0765d..0b4bc11f4 100644 --- a/Processor/OnlineOptions.cpp +++ b/Processor/OnlineOptions.cpp @@ -4,6 +4,7 @@ */ #include "OnlineOptions.h" +#include "Math/gfp.h" using namespace std; @@ -12,7 +13,7 @@ OnlineOptions OnlineOptions::singleton; OnlineOptions::OnlineOptions() : playerno(-1) { interactive = false; - lgp = 128; + lgp = gfp::MAX_N_BITS; live_prep = true; batch_size = 10000; } @@ -32,12 +33,13 @@ OnlineOptions::OnlineOptions(ez::ezOptionParser& opt, int argc, "-I", // Flag token. "--interactive" // Flag token. ); + string default_lgp = to_string(lgp); opt.add( - "128", // Default. + default_lgp.c_str(), // Default. 0, // Required? 1, // Number of args expected. 0, // Delimiter if expecting multiple args. - "Bit length of GF(p) field (default: 128)", // Help description. + ("Bit length of GF(p) field (default: " + default_lgp + ")").c_str(), // Help description. "-lgp", // Flag token. "--lgp" // Flag token. ); diff --git a/Processor/Processor.hpp b/Processor/Processor.hpp index c10b0e767..5b8138732 100644 --- a/Processor/Processor.hpp +++ b/Processor/Processor.hpp @@ -1,5 +1,6 @@ #include "Processor/Processor.h" +#include "Processor/Program.h" #include "Networking/STS.h" #include "Protocols/fake-stuff.h" diff --git a/Processor/ProcessorBase.cpp b/Processor/ProcessorBase.cpp index 24503ec01..9b0dc38ce 100644 --- a/Processor/ProcessorBase.cpp +++ b/Processor/ProcessorBase.cpp @@ -43,7 +43,7 @@ T ProcessorBase::get_input(istream& input_file, const string& input_filename, co if (input_file.eof()) throw IO_Error("not enough inputs in " + input_filename); if (input_file.fail()) - throw IO_Error("cannot read from " + input_filename); + throw IO_Error(string() + "cannot read " + T::NAME + " from " + input_filename); return res; } diff --git a/Programs/Source/tutorial.mpc b/Programs/Source/tutorial.mpc index a24a9f2a9..c18a63a18 100644 --- a/Programs/Source/tutorial.mpc +++ b/Programs/Source/tutorial.mpc @@ -98,9 +98,11 @@ print_ln('Party 1: please input any three numbers') data = Matrix(3, 2, sfix) -# use Python loops for compile-time optimization +# use @for_range_opt for balanced optimization +# but use Python loops if compile-time numbers are need (e.g., for players) -for i in range(3): +@for_range_opt(3) +def _(i): for j in range(2): data[i][j] = sfix.get_input_from(j) diff --git a/Protocols/Beaver.h b/Protocols/Beaver.h index 3b27cd0e4..9d2346283 100644 --- a/Protocols/Beaver.h +++ b/Protocols/Beaver.h @@ -11,6 +11,7 @@ using namespace std; #include "Replicated.h" +#include "Processor/Data_Files.h" template class SubProcessor; template class MAC_Check_Base; @@ -24,17 +25,19 @@ class Beaver : public ProtocolBase vector> triples; typename vector::iterator it; typename vector>::iterator triple; - SubProcessor* proc; + Preprocessing* prep; + typename T::MAC_Check* MC; public: Player& P; - Beaver(Player& P) : proc(0), P(P) {} + Beaver(Player& P) : prep(0), MC(0), P(P) {} void init_mul(SubProcessor* proc); - typename T::clear prepare_mul(const T& x, const T& y); + void init_mul(Preprocessing& prep, typename T::MAC_Check& MC); + typename T::clear prepare_mul(const T& x, const T& y, int n = -1); void exchange(); - T finalize_mul(); + T finalize_mul(int n = -1); int get_n_relevant_players() { return P.num_players(); } }; diff --git a/Protocols/Beaver.hpp b/Protocols/Beaver.hpp index cf54a09f0..80bf1c4e6 100644 --- a/Protocols/Beaver.hpp +++ b/Protocols/Beaver.hpp @@ -13,18 +13,27 @@ template void Beaver::init_mul(SubProcessor* proc) { - this->proc = proc; + assert(proc != 0); + init_mul(proc->DataF, proc->MC); +} + +template +void Beaver::init_mul(Preprocessing& prep, typename T::MAC_Check& MC) +{ + this->prep = &prep; + this->MC = &MC; shares.clear(); opened.clear(); triples.clear(); } template -typename T::clear Beaver::prepare_mul(const T& x, const T& y) +typename T::clear Beaver::prepare_mul(const T& x, const T& y, int n) { + (void) n; triples.push_back({{}}); auto& triple = triples.back(); - proc->DataF.get(DATA_TRIPLE, triple.data()); + prep->get(DATA_TRIPLE, triple.data()); shares.push_back(x - triple[0]); shares.push_back(y - triple[1]); return 0; @@ -33,14 +42,15 @@ typename T::clear Beaver::prepare_mul(const T& x, const T& y) template void Beaver::exchange() { - proc->MC.POpen(opened, shares, P); + MC->POpen(opened, shares, P); it = opened.begin(); triple = triples.begin(); } template -T Beaver::finalize_mul() +T Beaver::finalize_mul(int n) { + (void) n; typename T::clear masked[2]; T& tmp = (*triple)[2]; for (int k = 0; k < 2; k++) @@ -48,7 +58,7 @@ T Beaver::finalize_mul() masked[k] = *it++; tmp += (masked[k] * (*triple)[1 - k]); } - tmp.add(tmp, masked[0] * masked[1], P.my_num(), proc->MC.get_alphai()); + tmp += T::constant(masked[0] * masked[1], P.my_num(), MC->get_alphai()); triple++; return tmp; } diff --git a/Protocols/BrainPrep.hpp b/Protocols/BrainPrep.hpp index 5fc080e86..c2820b76e 100644 --- a/Protocols/BrainPrep.hpp +++ b/Protocols/BrainPrep.hpp @@ -30,8 +30,9 @@ class Zint : public SignedZ2 { } - void randomize(PRNG& G) + void randomize(PRNG& G, int n = -1) { + (void) n; *this = G.get>(); } }; diff --git a/Protocols/CowGearPrep.h b/Protocols/CowGearPrep.h index 6ac415654..2f7c129ec 100644 --- a/Protocols/CowGearPrep.h +++ b/Protocols/CowGearPrep.h @@ -25,6 +25,8 @@ class CowGearPrep : public RingPrep PairwiseGenerator& get_generator(); public: + static void basic_setup(Player& P); + static void key_setup(Player& P, mac_key_type alphai); static void setup(Player& P, mac_key_type alphai); static void teardown(); diff --git a/Protocols/CowGearPrep.hpp b/Protocols/CowGearPrep.hpp index 9ecd3bc7e..577680c45 100644 --- a/Protocols/CowGearPrep.hpp +++ b/Protocols/CowGearPrep.hpp @@ -27,7 +27,7 @@ void CowGearPrep::teardown() } template -void CowGearPrep::setup(Player& P, mac_key_type alphai) +void CowGearPrep::basic_setup(Player& P) { Timer timer; timer.start(); @@ -42,6 +42,27 @@ void CowGearPrep::setup(Player& P, mac_key_type alphai) cerr << "LowGear security parameter: " << options.lowgear_security << endl; #endif setup.secure_init(P, machine, T::clear::length(), options.lowgear_security); +#ifdef VERBOSE + cerr << T::type_string() << " parameter setup took " << timer.elapsed() + << " seconds" << endl; +#endif +} + +template +void CowGearPrep::setup(Player& P, mac_key_type alphai) +{ + basic_setup(P); + key_setup(P, alphai); +} + +template +void CowGearPrep::key_setup(Player& P, mac_key_type alphai) +{ + Timer timer; + timer.start(); + auto& machine = *pairwise_machine; + auto& setup = machine.setup(); + auto& options = CowGearOptions::singleton; setup.covert_key_generation(P, machine, options.covert_security); setup.covert_mac_generation(P, machine, options.covert_security); @@ -61,7 +82,8 @@ void CowGearPrep::setup(Player& P, mac_key_type alphai) // generate minimal number of items machine.nTriplesPerThread = 1; #ifdef VERBOSE - cerr << T::type_string() << " setup took " << timer.elapsed() << " seconds" << endl; + cerr << T::type_string() << " key setup took " << timer.elapsed() + << " seconds" << endl; #endif } @@ -71,10 +93,13 @@ PairwiseGenerator& CowGearPrep::get_generator() auto& proc = this->proc; assert(proc != 0); lock.lock(); - if (pairwise_machine == 0) + if (pairwise_machine == 0 or pairwise_machine->enc_alphas.empty()) { PlainPlayer P(proc->P.N, T::clear::type_char()); - setup(P, proc->MC.get_alphai()); + if (pairwise_machine == 0) + setup(P, proc->MC.get_alphai()); + else + key_setup(P, proc->MC.get_alphai()); } lock.unlock(); if (pairwise_generator == 0) diff --git a/Protocols/MAC_Check.h b/Protocols/MAC_Check.h index f96ba4c38..04ef6f8c5 100644 --- a/Protocols/MAC_Check.h +++ b/Protocols/MAC_Check.h @@ -86,7 +86,8 @@ class MAC_Check_ : public TreeSum, public MAC_Check_Base< public: - MAC_Check_(const T& ai, int opening_sum=10, int max_broadcast=10, int send_player=0); + MAC_Check_(const typename T::Scalar& ai, int opening_sum = 10, + int max_broadcast = 10, int send_player = 0); virtual ~MAC_Check_(); /* Run protocols to partially open data and check the MACs are @@ -155,6 +156,8 @@ class Separate_MAC_Check: public MAC_Check_ public: virtual void Check(const Player& P); + + const Player& get_check_player(const Player& P) const { (void) P; return check_player; } }; diff --git a/Protocols/MAC_Check.hpp b/Protocols/MAC_Check.hpp index 45a8c10ed..04e52faad 100644 --- a/Protocols/MAC_Check.hpp +++ b/Protocols/MAC_Check.hpp @@ -1,3 +1,5 @@ +#ifndef PROTOCOLS_MAC_CHECK_HPP_ +#define PROTOCOLS_MAC_CHECK_HPP_ #include "Protocols/MAC_Check.h" #include "Tools/Subroutines.h" @@ -7,6 +9,7 @@ #include "Tools/time-func.h" #include "Tools/int.h" #include "Tools/benchmarking.h" +#include "Tools/Bundle.h" #include @@ -27,7 +30,8 @@ const char* TreeSum::mc_timer_names[] = { }; template -MAC_Check_::MAC_Check_(const T& ai, int opening_sum, int max_broadcast, int send_player) : +MAC_Check_::MAC_Check_(const typename T::Scalar& ai, int opening_sum, + int max_broadcast, int send_player) : TreeSum(opening_sum, max_broadcast, send_player) { popen_cnt=0; @@ -140,43 +144,72 @@ void MAC_Check_::Check(const Player& P) return; //cerr << "In MAC Check : " << popen_cnt << endl; - octet seed[SEED_SIZE]; - this->timers[SEED].start(); - Create_Random_Seed(seed,P,SEED_SIZE); - this->timers[SEED].stop(); - PRNG G; - G.SetSeed(seed); - U sj; - T a,gami,h,temp; - a.assign_zero(); - gami.assign_zero(); - vector tau(P.num_players()); - for (int i=0; i deltas; + Bundle bundle(P); + for (int i = 0; i < popen_cnt; i++) + { + deltas.push_back(vals[i] * this->alphai - macs[i]); + deltas.back().pack(bundle.mine); + } + this->timers[COMMIT].start(); + Commit_And_Open_(bundle, P); + this->timers[COMMIT].stop(); + for (auto& delta : deltas) + { + for (auto& os : bundle) + if (&os != &bundle.mine) + delta += os.get(); + if (not delta.is_zero()) + throw mac_fail(); + } + } + else + { + octet seed[SEED_SIZE]; + this->timers[SEED].start(); + Create_Random_Seed(seed,P,SEED_SIZE); + this->timers[SEED].stop(); + PRNG G; + G.SetSeed(seed); + + U sj; + T a,gami,temp; + typename T::Scalar h; + vector tau(P.num_players()); + a.assign_zero(); + gami.assign_zero(); + for (int i=0; ialphai,a); + tau[P.my_num()].sub(gami,temp); + + //cerr << "\tCommit and Open" << endl; + this->timers[COMMIT].start(); + Commit_And_Open(tau,P); + this->timers[COMMIT].stop(); + + //cerr << "\tFinal Check" << endl; + + T t; + t.assign_zero(); + for (int i=0; ialphai,a); - tau[P.my_num()].sub(gami,temp); - - //cerr << "\tCommit and Open" << endl; - this->timers[COMMIT].start(); - Commit_And_Open(tau,P); - this->timers[COMMIT].stop(); - - //cerr << "\tFinal Check" << endl; - - T t; - t.assign_zero(); - for (int i=0; i& values, const Player& P, vector for (unsigned int i=0; i(os[j].consume(T::size())); + values[i].template add(os[j]); } template @@ -574,3 +607,5 @@ void Passing_MAC_Check::POpen_End(vector& values,const vector >& this->popen_cnt += values.size(); this->CheckIfNeeded(P); } + +#endif diff --git a/Protocols/MAC_Check_Base.h b/Protocols/MAC_Check_Base.h index 87729580e..d231cfac7 100644 --- a/Protocols/MAC_Check_Base.h +++ b/Protocols/MAC_Check_Base.h @@ -16,7 +16,7 @@ class MAC_Check_Base { protected: /* MAC Share */ - typename T::mac_key_type alphai; + typename T::mac_key_type::Scalar alphai; public: int values_opened; @@ -28,7 +28,7 @@ class MAC_Check_Base int number() const { return values_opened; } - const typename T::mac_key_type& get_alphai() const { return alphai; } + const typename T::mac_key_type::Scalar& get_alphai() const { return alphai; } virtual void POpen_Begin(vector& values,const vector& S,const Player& P) = 0; virtual void POpen_End(vector& values,const vector& S,const Player& P) = 0; @@ -36,6 +36,8 @@ class MAC_Check_Base typename T::open_type POpen(const T& secret, const Player& P); 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; } }; #endif /* PROTOCOLS_MAC_CHECK_BASE_H_ */ diff --git a/Protocols/MalRepRingPrep.hpp b/Protocols/MalRepRingPrep.hpp index 2c94cb6a6..babdb2d46 100644 --- a/Protocols/MalRepRingPrep.hpp +++ b/Protocols/MalRepRingPrep.hpp @@ -6,6 +6,7 @@ #include "MalRepRingPrep.h" #include "MaliciousRepPrep.h" #include "MalRepRingOptions.h" +#include "Processor/OnlineOptions.h" template MalRepRingPrep::MalRepRingPrep(SubProcessor* proc, @@ -58,17 +59,24 @@ template void MalRepRingPrep::shuffle_buffer_triples() { assert(T::SECURITY <= 40); + assert(this->proc != 0); + typename T::MAC_Check MC; + shuffle_triple_generation(this->triples, this->proc->P, MC); +} + +template +void shuffle_triple_generation(vector>& triples, Player& P, + typename T::MAC_Check& MC, int n_bits = -1) +{ int N = max(1 << 20, OnlineOptions::singleton.batch_size); int B = 3; int C = 3; int buffer_size = B * N + C; vector> check_triples; - assert(this->proc != 0); - Player& P = this->proc->P; // optimistic triple generation Replicated protocol(P); - generate_triples(check_triples, buffer_size, &protocol); + generate_triples(check_triples, buffer_size, &protocol, n_bits); // shuffle GlobalPRNG G(P); @@ -88,7 +96,6 @@ void MalRepRingPrep::shuffle_buffer_triples() check_triples.pop_back(); } vector opened; - typename T::MAC_Check MC; MC.POpen(opened, shares, P); for (int i = 0; i < C; i++) if (typename T::open_type(opened[3 * i] * opened[3 * i + 1]) != opened[3 * i + 2]) @@ -128,7 +135,7 @@ void MalRepRingPrep::shuffle_buffer_triples() } MC.CheckFor(0, checks, P); check_triples.resize(N); - this->triples = check_triples; + triples = check_triples; } template diff --git a/Protocols/MalRepRingShare.h b/Protocols/MalRepRingShare.h index cb1877eb2..b1dedc52b 100644 --- a/Protocols/MalRepRingShare.h +++ b/Protocols/MalRepRingShare.h @@ -28,6 +28,7 @@ class MalRepRingShare : public MaliciousRep3Share> typedef ReplicatedPrivateOutput PrivateOutput; typedef MalRepRingPrepWithBits LivePrep; typedef MaliciousRep3Share> prep_type; + typedef Z2 random_type; static string type_short() { diff --git a/Protocols/MaliciousRep3Share.h b/Protocols/MaliciousRep3Share.h index 1f3958124..3766f7a87 100644 --- a/Protocols/MaliciousRep3Share.h +++ b/Protocols/MaliciousRep3Share.h @@ -25,6 +25,8 @@ class MaliciousRep3Share : public Rep3Share typedef ReplicatedPrivateOutput> PrivateOutput; typedef Rep3Share Honest; typedef MaliciousRepPrep LivePrep; + typedef MaliciousRep3Share prep_type; + typedef T random_type; static string type_short() { diff --git a/Protocols/MaliciousRepMC.hpp b/Protocols/MaliciousRepMC.hpp index 0409f8716..122c2179a 100644 --- a/Protocols/MaliciousRepMC.hpp +++ b/Protocols/MaliciousRepMC.hpp @@ -8,6 +8,7 @@ #include "Math/BitVec.h" #include "ReplicatedMC.hpp" +#include "MAC_Check_Base.hpp" #include diff --git a/Protocols/MaliciousRepPrep.h b/Protocols/MaliciousRepPrep.h index b0574676e..6e51cf8a8 100644 --- a/Protocols/MaliciousRepPrep.h +++ b/Protocols/MaliciousRepPrep.h @@ -16,7 +16,7 @@ template class MalRepRingPrep; template class MalRepRingShare; template class PostSacriRepRingShare; -template +template void sacrifice(const vector& check_triples, Player& P); template diff --git a/Protocols/MaliciousRepPrep.hpp b/Protocols/MaliciousRepPrep.hpp index 7447e1034..a36ca3981 100644 --- a/Protocols/MaliciousRepPrep.hpp +++ b/Protocols/MaliciousRepPrep.hpp @@ -5,7 +5,7 @@ #include "MaliciousRepPrep.h" #include "Tools/Subroutines.h" -//#include "Protocols/MaliciousRepMC.hpp" +#include "Processor/OnlineOptions.h" template MaliciousRepPrep::MaliciousRepPrep(SubProcessor* proc, DataPositions& usage) : @@ -75,25 +75,25 @@ void MaliciousRepPrep::buffer_triples() for (int i = 0; i < buffer_size; i++) for (int j = 3; j < 5; j++) check_triples[i][j] = honest_prot.finalize_mul(); - sacrifice(check_triples, P); + sacrifice(check_triples, P); for (auto& tuple : check_triples) triples.push_back({{tuple[0], tuple[2], tuple[3]}}); } -template +template void sacrifice(const vector>& check_triples, Player& P) { vector masked, checks; vector opened; typename T::MAC_Check MC; int buffer_size = check_triples.size(); - auto t = Create_Random(P); + auto t = Create_Random(P); masked.reserve(buffer_size); for (int i = 0; i < buffer_size; i++) { const T& a = check_triples[i][0]; const T& a_prime = check_triples[i][1]; - masked.push_back(a * t - a_prime); + masked.push_back(T::Mul(a, t) - a_prime); } MC.POpen(opened, masked, P); checks.reserve(buffer_size); @@ -103,7 +103,7 @@ void sacrifice(const vector>& check_triples, Player& P) const T& c = check_triples[i][3]; const T& c_prime = check_triples[i][4]; typename T::open_type& rho = opened[i]; - checks.push_back(t * c - c_prime - rho * b); + checks.push_back(T::Mul(c, t) - c_prime - rho * b); } MC.CheckFor(0, checks, P); MC.Check(P); diff --git a/Protocols/MaliciousShamirMC.h b/Protocols/MaliciousShamirMC.h index 47741a48a..999e77b3f 100644 --- a/Protocols/MaliciousShamirMC.h +++ b/Protocols/MaliciousShamirMC.h @@ -11,18 +11,18 @@ template class MaliciousShamirMC : public ShamirMC { - vector> reconstructions; + vector> reconstructions; public: MaliciousShamirMC(); // emulate MAC_Check - MaliciousShamirMC(const typename T::value_type& _, int __ = 0, int ___ = 0) : + MaliciousShamirMC(const typename T::mac_key_type& _, int __ = 0, int ___ = 0) : MaliciousShamirMC() { (void)_; (void)__; (void)___; } // emulate Direct_MAC_Check - MaliciousShamirMC(const typename T::value_type& _, Names& ____, int __ = 0, + MaliciousShamirMC(const typename T::mac_key_type& _, Names& ____, int __ = 0, int ___ = 0) : MaliciousShamirMC() { (void)_; (void)__; (void)___; (void)____; } diff --git a/Protocols/MaliciousShamirMC.hpp b/Protocols/MaliciousShamirMC.hpp index 98691b9c2..c2bc0bf79 100644 --- a/Protocols/MaliciousShamirMC.hpp +++ b/Protocols/MaliciousShamirMC.hpp @@ -25,7 +25,8 @@ void MaliciousShamirMC::POpen_End(vector& values, { reconstructions[i].resize(i); for (int j = 0; j < i; j++) - reconstructions[i][j] = Shamir::get_rec_factor(j, i); + reconstructions[i][j] = + Shamir::get_rec_factor(j, i); } } diff --git a/Protocols/MaliciousShamirShare.h b/Protocols/MaliciousShamirShare.h index 91fad0ef4..fb64a21b0 100644 --- a/Protocols/MaliciousShamirShare.h +++ b/Protocols/MaliciousShamirShare.h @@ -25,6 +25,7 @@ class MaliciousShamirShare : public ShamirShare typedef ReplicatedPrivateOutput PrivateOutput; typedef ShamirShare Honest; typedef MaliciousRepPrep LivePrep; + typedef T random_type; static string type_short() { diff --git a/Protocols/PostSacriRepRingShare.h b/Protocols/PostSacriRepRingShare.h index caaf5c661..ec10c20cc 100644 --- a/Protocols/PostSacriRepRingShare.h +++ b/Protocols/PostSacriRepRingShare.h @@ -12,9 +12,9 @@ template class MalRepRingPrepWithBits; template class PostSacrifice; template -class PostSacriRepRingShare : public MaliciousRep3Share> +class PostSacriRepRingShare : public MaliciousRep3Share> { - typedef MaliciousRep3Share> super; + typedef MaliciousRep3Share> super; public: static const int BIT_LENGTH = K; @@ -22,6 +22,7 @@ class PostSacriRepRingShare : public MaliciousRep3Share> typedef SignedZ2 clear; typedef MaliciousRep3Share> prep_type; + typedef Z2 random_type; typedef PostSacrifice Protocol; typedef HashMaliciousRepMC MAC_Check; @@ -46,11 +47,6 @@ class PostSacriRepRingShare : public MaliciousRep3Share> PostSacriRepRingShare(const U& other) : super(other) { } - - void mul(const PostSacriRepRingShare& x, const clear& y) - { - super::mul(x, Z2(y)); - } }; #endif /* PROTOCOLS_POSTSACRIREPRINGSHARE_H_ */ diff --git a/Protocols/PostSacrifice.h b/Protocols/PostSacrifice.h index c76d63b0f..cb17a821e 100644 --- a/Protocols/PostSacrifice.h +++ b/Protocols/PostSacrifice.h @@ -11,10 +11,13 @@ template class PostSacrifice : public ProtocolBase { - typename T::Honest::Protocol internal; + typedef typename T::prep_type prep_type; - vector> operands; - vector results; + typename prep_type::Honest::Protocol internal; + typename T::Honest::Protocol randomizer; + + vector> operands; + vector results; void check(); @@ -25,9 +28,9 @@ class PostSacrifice : public ProtocolBase ~PostSacrifice(); void init_mul(SubProcessor* proc); - typename T::clear prepare_mul(const T& x, const T& y); + typename T::clear prepare_mul(const T& x, const T& y, int n = -1); void exchange() { internal.exchange(); } - T finalize_mul(); + T finalize_mul(int n = -1); int get_n_relevant_players() { return internal.get_n_relevant_players(); } }; diff --git a/Protocols/PostSacrifice.hpp b/Protocols/PostSacrifice.hpp index f01e095ae..c141ef185 100644 --- a/Protocols/PostSacrifice.hpp +++ b/Protocols/PostSacrifice.hpp @@ -7,7 +7,7 @@ template PostSacrifice::PostSacrifice(Player& P) : - internal(P), P(P) + internal(P), randomizer(P), P(P) { results.reserve(OnlineOptions::singleton.batch_size); } @@ -22,24 +22,26 @@ template void PostSacrifice::init_mul(SubProcessor* proc) { (void) proc; - internal.init_mul(); // throw away unused operands operands.resize(results.size()); if ((int) results.size() >= OnlineOptions::singleton.batch_size) check(); + internal.init_mul(); } template -typename T::clear PostSacrifice::prepare_mul(const T& x, const T& y) +typename T::clear PostSacrifice::prepare_mul(const T& x, const T& y, int n) { + (void) n; operands.push_back({{x, y}}); return internal.prepare_mul(x, y); } template -T PostSacrifice::finalize_mul() +T PostSacrifice::finalize_mul(int n) { - T res = internal.finalize_mul(); + (void) n; + auto res = internal.finalize_mul(); results.push_back(res); return res; } @@ -48,9 +50,12 @@ template void PostSacrifice::check() { int buffer_size = results.size(); - vector> tuples; + if (buffer_size == 0) + return; + + vector> tuples; tuples.reserve(buffer_size); - typename T::Honest::Protocol honest_prot(P); + auto& honest_prot = internal; honest_prot.init_mul(); for (int i = 0; i < buffer_size; i++) { @@ -59,7 +64,7 @@ void PostSacrifice::check() tuple[0] = operands[i][0]; tuple[2] = operands[i][1]; tuple[3] = results[i]; - tuple[1] = internal.get_random(); + tuple[1] = randomizer.get_random(); honest_prot.prepare_mul(tuple[1], tuple[2]); } honest_prot.exchange(); @@ -67,7 +72,7 @@ void PostSacrifice::check() { tuples[i][4] = honest_prot.finalize_mul(); } - sacrifice(tuples, P); + sacrifice(tuples, P); operands.erase(operands.begin(), operands.begin() + buffer_size); results.clear(); } diff --git a/Protocols/Rep3Share.h b/Protocols/Rep3Share.h index 6920944dc..140bac4e7 100644 --- a/Protocols/Rep3Share.h +++ b/Protocols/Rep3Share.h @@ -27,6 +27,7 @@ class Rep3Share : public FixedVec typedef ReplicatedInput Input; typedef ReplicatedPrivateOutput PrivateOutput; typedef ReplicatedRingPrep LivePrep; + typedef Rep3Share Honest; const static bool needs_ot = false; const static bool dishonest_majority = false; diff --git a/Protocols/Replicated.h b/Protocols/Replicated.h index de63676e3..ddf18300b 100644 --- a/Protocols/Replicated.h +++ b/Protocols/Replicated.h @@ -50,9 +50,9 @@ class ProtocolBase void mulrs(const vector& reg, SubProcessor& proc); virtual void init_mul(SubProcessor* proc) = 0; - virtual typename T::clear prepare_mul(const T& x, const T& y) = 0; + virtual typename T::clear prepare_mul(const T& x, const T& y, int n = -1) = 0; virtual void exchange() = 0; - virtual T finalize_mul() = 0; + virtual T finalize_mul(int n = -1) = 0; void init_dotprod(SubProcessor* proc) { init_mul(proc); } void prepare_dotprod(const T& x, const T& y) { prepare_mul(x, y); } @@ -84,11 +84,11 @@ class Replicated : public ReplicatedBase, public ProtocolBase void init_mul(SubProcessor* proc); void init_mul(); - typename T::clear prepare_mul(const T& x, const T& y); + typename T::clear prepare_mul(const T& x, const T& y, int n = -1); void exchange(); - T finalize_mul(); + T finalize_mul(int n = -1); - void prepare_reshare(const typename T::clear& share); + void prepare_reshare(const typename T::clear& share, int n = -1); void init_dotprod(SubProcessor* proc); void prepare_dotprod(const T& x, const T& y); diff --git a/Protocols/Replicated.hpp b/Protocols/Replicated.hpp index 930c60170..d532ac917 100644 --- a/Protocols/Replicated.hpp +++ b/Protocols/Replicated.hpp @@ -84,22 +84,23 @@ void Replicated::init_mul() template inline typename T::clear Replicated::prepare_mul(const T& x, - const T& y) + const T& y, int n) { typename T::value_type add_share = x.local_mul(y); - prepare_reshare(add_share); + prepare_reshare(add_share, n); return add_share; } template -inline void Replicated::prepare_reshare(const typename T::clear& share) +inline void Replicated::prepare_reshare(const typename T::clear& share, + int n) { auto add_share = share; typename T::value_type tmp[2]; for (int i = 0; i < 2; i++) - tmp[i].randomize(shared_prngs[i]); + tmp[i].randomize(shared_prngs[i], n); add_share += tmp[0] - tmp[1]; - add_share.pack(os[0]); + add_share.pack(os[0], n); add_shares.push_back(add_share); } @@ -110,12 +111,12 @@ void Replicated::exchange() } template -inline T Replicated::finalize_mul() +inline T Replicated::finalize_mul(int n) { T result; result[0] = add_shares.front(); add_shares.pop_front(); - result[1].unpack(os[1]); + result[1].unpack(os[1], n); return result; } diff --git a/Protocols/ReplicatedPrep.h b/Protocols/ReplicatedPrep.h index abc8f90ce..f7915292d 100644 --- a/Protocols/ReplicatedPrep.h +++ b/Protocols/ReplicatedPrep.h @@ -38,12 +38,15 @@ class BufferPrep : public Preprocessing int buffer_size; + static void basic_setup(Player& P) { (void) P; } static void setup(Player& P, typename T::mac_key_type alphai) { (void) P, (void) alphai; } static void teardown() {} BufferPrep(DataPositions& usage); virtual ~BufferPrep(); + void clear(); + void get_three_no_count(Dtype dtype, T& a, T& b, T& c); void get_two_no_count(Dtype dtype, T& a, T& b); void get_one_no_count(Dtype dtype, T& a); @@ -101,10 +104,6 @@ class MaliciousRingPrep : public RingPrep virtual void buffer_bits(); }; -template -void generate_triples(vector>& triples, int n_triples, - U* protocol); - template class ReplicatedRingPrep : public SemiHonestRingPrep { diff --git a/Protocols/ReplicatedPrep.hpp b/Protocols/ReplicatedPrep.hpp index 1f6c668c0..7e8e8a93f 100644 --- a/Protocols/ReplicatedPrep.hpp +++ b/Protocols/ReplicatedPrep.hpp @@ -36,16 +36,28 @@ void RingPrep::set_protocol(typename T::Protocol& protocol) base_player = proc->Proc.thread_num; } +template +void BufferPrep::clear() +{ + triples.clear(); + inverses.clear(); + bits.clear(); + squares.clear(); + inputs.clear(); +} + template void ReplicatedRingPrep::buffer_triples() { assert(this->protocol != 0); - generate_triples(this->triples, OnlineOptions::singleton.batch_size, this->protocol); + typename T::Protocol protocol(this->protocol->P); + generate_triples(this->triples, OnlineOptions::singleton.batch_size, + &protocol); } template void generate_triples(vector>& triples, int n_triples, - U* protocol) + U* protocol, int n_bits = -1) { triples.resize(n_triples); protocol->init_mul(); @@ -54,11 +66,11 @@ void generate_triples(vector>& triples, int n_triples, auto& triple = triples[i]; triple[0] = protocol->get_random(); triple[1] = protocol->get_random(); - protocol->prepare_mul(triple[0], triple[1]); + protocol->prepare_mul(triple[0], triple[1], n_bits); } protocol->exchange(); for (size_t i = 0; i < triples.size(); i++) - triples[i][2] = protocol->finalize_mul(); + triples[i][2] = protocol->finalize_mul(n_bits); } template diff --git a/Protocols/Semi2kShare.h b/Protocols/Semi2kShare.h index d6c240d8b..8889d3433 100644 --- a/Protocols/Semi2kShare.h +++ b/Protocols/Semi2kShare.h @@ -18,7 +18,7 @@ class Semi2kShare : public SemiShare> typedef Z2<64> mac_key_type; typedef SemiMC MAC_Check; - typedef MAC_Check Direct_MC; + typedef DirectSemiMC Direct_MC; typedef SemiInput Input; typedef ::PrivateOutput PrivateOutput; typedef SPDZ Protocol; diff --git a/Protocols/SemiMC.h b/Protocols/SemiMC.h index 3f8cd0109..130dea35d 100644 --- a/Protocols/SemiMC.h +++ b/Protocols/SemiMC.h @@ -7,6 +7,7 @@ #define PROTOCOLS_SEMIMC_H_ #include "MAC_Check.h" +#include "Tools/Bundle.h" template class SemiMC : public TreeSum, public MAC_Check_Base @@ -16,8 +17,18 @@ class SemiMC : public TreeSum, public MAC_Check_Base SemiMC(const typename T::mac_key_type& _ = {}, int __ = 0, int ___ = 0) { (void)_; (void)__; (void)___; } + void POpen_Begin(vector& values,const vector& S,const Player& P); + void POpen_End(vector& values,const vector& S,const Player& P); + + void Check(const Player& P) { (void)P; } +}; + +template +class DirectSemiMC : public SemiMC +{ +public: // emulate Direct_MAC_Check - SemiMC(const typename T::mac_key_type& _, Names& ____, int __ = 0, int ___ = 0) + DirectSemiMC(const typename T::mac_key_type& _, Names& ____, int __ = 0, int ___ = 0) { (void)_; (void)__; (void)___; (void)____; } void POpen_Begin(vector& values,const vector& S,const Player& P); diff --git a/Protocols/SemiMC.hpp b/Protocols/SemiMC.hpp index 928da99e3..e7f87a961 100644 --- a/Protocols/SemiMC.hpp +++ b/Protocols/SemiMC.hpp @@ -5,6 +5,8 @@ #include "SemiMC.h" +#include "MAC_Check.hpp" + template void SemiMC::POpen_Begin(vector& values, const vector& S, const Player& P) @@ -22,3 +24,23 @@ void SemiMC::POpen_End(vector& values, (void) S; this->finish(values, P); } + +template +void DirectSemiMC::POpen_Begin(vector& values, + const vector& S, const Player& P) +{ + values.clear(); + values.insert(values.begin(), S.begin(), S.end()); + Bundle oss(P); + for (auto& x : values) + x.pack(oss.mine); + P.Broadcast_Receive(oss, true); + direct_add_openings(values, P, oss); +} + +template +void DirectSemiMC::POpen_End(vector& values, + const vector& S, const Player& P) +{ + (void) values, (void) S, (void) P; +} diff --git a/Protocols/SemiShare.h b/Protocols/SemiShare.h index 9745f191f..a61ae1fc2 100644 --- a/Protocols/SemiShare.h +++ b/Protocols/SemiShare.h @@ -15,6 +15,7 @@ using namespace std; template class Input; template class SemiMC; +template class DirectSemiMC; template class SPDZ; template class SemiPrep; template class SemiInput; @@ -34,7 +35,7 @@ class SemiShare : public T typedef T clear; typedef SemiMC MAC_Check; - typedef MAC_Check Direct_MC; + typedef DirectSemiMC Direct_MC; typedef SemiInput Input; typedef ::PrivateOutput PrivateOutput; typedef SPDZ Protocol; @@ -51,6 +52,11 @@ class SemiShare : public T static string type_short() { return "D" + string(1, T::type_char()); } + static SemiShare constant(const clear& other, int my_num, const T& alphai) + { + return SemiShare(other, my_num, alphai); + } + SemiShare() { } diff --git a/Protocols/Shamir.h b/Protocols/Shamir.h index 403b5d820..83341f641 100644 --- a/Protocols/Shamir.h +++ b/Protocols/Shamir.h @@ -51,9 +51,9 @@ class Shamir : public ProtocolBase> void init_mul(); void init_mul(SubProcessor* proc); - U prepare_mul(const T& x, const T& y); + U prepare_mul(const T& x, const T& y, int n = -1); void exchange(); - T finalize_mul(); + T finalize_mul(int n = -1); T finalize(int n_input_players); diff --git a/Protocols/Shamir.hpp b/Protocols/Shamir.hpp index a06ee8832..d361db1ae 100644 --- a/Protocols/Shamir.hpp +++ b/Protocols/Shamir.hpp @@ -6,6 +6,7 @@ #include "Shamir.h" #include "ShamirInput.h" #include "Machines/ShamirMachine.h" +#include "Tools/benchmarking.h" template U Shamir::get_rec_factor(int i, int n) @@ -70,8 +71,9 @@ void Shamir::init_mul() } template -U Shamir::prepare_mul(const T& x, const T& y) +U Shamir::prepare_mul(const T& x, const T& y, int n) { + (void) n; auto add_share = x * y * rec_factor; if (P.my_num() < n_mul_players) resharing->add_mine(add_share); @@ -99,8 +101,9 @@ void Shamir::exchange() } template -ShamirShare Shamir::finalize_mul() +ShamirShare Shamir::finalize_mul(int n) { + (void) n; return finalize(n_mul_players); } diff --git a/Protocols/ShamirInput.h b/Protocols/ShamirInput.h index 2d7ed9c4c..1726d2adb 100644 --- a/Protocols/ShamirInput.h +++ b/Protocols/ShamirInput.h @@ -41,7 +41,7 @@ class ShamirInput : public IndividualInput vector> vandermonde; SeededPRNG secure_prng; - vector randomness; + vector randomness; public: ShamirInput(SubProcessor& proc, ShamirMC& MC) : diff --git a/Protocols/ShamirMC.h b/Protocols/ShamirMC.h index 4d83eca7f..fd98fe001 100644 --- a/Protocols/ShamirMC.h +++ b/Protocols/ShamirMC.h @@ -13,7 +13,7 @@ template class ShamirMC : public MAC_Check_Base { - vector reconstruction; + vector reconstruction; protected: vector os; @@ -23,11 +23,11 @@ class ShamirMC : public MAC_Check_Base ShamirMC() : threshold(ShamirMachine::s().threshold) {} // emulate MAC_Check - ShamirMC(const typename T::value_type& _, int __ = 0, int ___ = 0) : ShamirMC() + ShamirMC(const typename T::mac_key_type& _, int __ = 0, int ___ = 0) : ShamirMC() { (void)_; (void)__; (void)___; } // emulate Direct_MAC_Check - ShamirMC(const typename T::value_type& _, Names& ____, int __ = 0, int ___ = 0) : + ShamirMC(const typename T::mac_key_type& _, Names& ____, int __ = 0, int ___ = 0) : ShamirMC() { (void)_; (void)__; (void)___; (void)____; } diff --git a/Protocols/ShamirMC.hpp b/Protocols/ShamirMC.hpp index f2cd6f52d..6d3627570 100644 --- a/Protocols/ShamirMC.hpp +++ b/Protocols/ShamirMC.hpp @@ -43,7 +43,7 @@ void ShamirMC::POpen_End(vector& values, { reconstruction.resize(n_relevant_players, 1); for (int i = 0; i < n_relevant_players; i++) - reconstruction[i] = Shamir::get_rec_factor(i, + reconstruction[i] = Shamir::get_rec_factor(i, n_relevant_players); } diff --git a/Protocols/ShamirShare.h b/Protocols/ShamirShare.h index 344b74def..f82324c40 100644 --- a/Protocols/ShamirShare.h +++ b/Protocols/ShamirShare.h @@ -25,6 +25,7 @@ class ShamirShare : public T typedef ShamirInput Input; typedef ReplicatedPrivateOutput PrivateOutput; typedef ReplicatedPrep LivePrep; + typedef ShamirShare Honest; const static bool needs_ot = false; const static bool dishonest_majority = false; diff --git a/Protocols/Share.h b/Protocols/Share.h index 9948c7f00..ffe41727d 100644 --- a/Protocols/Share.h +++ b/Protocols/Share.h @@ -68,7 +68,7 @@ class Share static DataFieldType field_type() { return T::field_type(); } - static Share constant(const clear& aa, int my_num, const T& alphai) + static Share constant(const clear& aa, int my_num, const typename T::Scalar& alphai) { return Share(aa, my_num, alphai); } template @@ -80,12 +80,13 @@ class Share { a.assign_zero(); mac.assign_zero(); } - void assign(const clear& aa, int my_num, const T& alphai); + void assign(const clear& aa, int my_num, const typename T::Scalar& alphai); Share() { assign_zero(); } template Share(const Share& S) { assign(S); } - Share(const clear& aa, int my_num, const T& alphai) { assign(aa, my_num, alphai); } + Share(const clear& aa, int my_num, const typename T::Scalar& alphai) + { assign(aa, my_num, alphai); } Share(const T& share, const T& mac) : a(share), mac(mac) {} ~Share() { ; } @@ -210,7 +211,8 @@ inline void Share::sub(const clear& aa,const Share& S,int my_num,const T& } template -inline void Share::assign(const clear& aa, int my_num, const T& alphai) +inline void Share::assign(const clear& aa, int my_num, + const typename T::Scalar& alphai) { Protocol::assign(a, aa, my_num); mac.mul(aa, alphai); diff --git a/Protocols/fake-stuff.hpp b/Protocols/fake-stuff.hpp index c07fd5f40..30659d939 100644 --- a/Protocols/fake-stuff.hpp +++ b/Protocols/fake-stuff.hpp @@ -1,5 +1,6 @@ #include "Protocols/fake-stuff.h" +#include "Processor/Data_Files.h" #include "Tools/benchmarking.h" #include "Math/gfp.h" #include "Math/gf2n.h" @@ -170,6 +171,12 @@ void write_mac_keys(const string& directory, int i, int nplayers, U macp, T mac2 outf.close(); } +template +void read_mac_keys(const string& directory, const Names& N, U& keyp, T& key2) +{ + read_mac_keys(directory, N.my_num(), N.num_players(), keyp, key2); +} + template void read_mac_keys(const string& directory, int player_num, int nplayers, U& keyp, T& key2) { @@ -196,3 +203,136 @@ void read_mac_keys(const string& directory, int player_num, int nplayers, U& key key2.input(inpf,true); inpf.close(); } + +template +void generate_mac_keys(typename T::mac_key_type::Scalar& keyp, gf2n& key2, + int nplayers, string prep_data_prefix) +{ + keyp.assign_zero(); + gf2n p2; + key2.assign_zero(); + int tmpN = 0; + ifstream inpf; + SeededPRNG G; + for (int i = 0; i < nplayers; i++) + { + stringstream filename; + filename << prep_data_prefix << "Player-MAC-Keys-P" << i; + inpf.open(filename.str().c_str()); + typename T::mac_key_type::Scalar pp; + gf2n p2; + if (inpf.fail()) + { + inpf.close(); + cout << "No MAC key share for player " << i << ", generating a fresh one\n"; + pp.randomize(G); + p2.randomize(G); + ofstream outf(filename.str().c_str()); + if (outf.fail()) + throw file_error(filename.str().c_str()); + outf << nplayers << " " << pp << " " << p2; + outf.close(); + cout << "Written new MAC key share to " << filename.str() << endl; + } + else + { + inpf >> tmpN; // not needed here + pp.input(inpf,true); + p2.input(inpf,true); + inpf.close(); + } + cout << " Key " << i << "\t p: " << pp << "\n\t 2: " << p2 << endl; + keyp.add(pp); + key2.add(p2); + } + cout << "--------------\n"; + cout << "Final Keys :\t p: " << keyp << "\n\t\t 2: " << key2 << endl; +} + +/* 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, + bool zero, string prep_data_prefix, int thread_num = -1) +{ + PRNG G; + G.ReSeed(); + + ofstream* outf=new ofstream[N]; + typename T::clear a,b,c; + vector Sa(N),Sb(N),Sc(N); + /* Generate Triples */ + for (int i=0; i::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 +void make_inverse(const typename T::mac_type& key, int N, int ntrip, bool zero, + string prep_data_prefix) +{ + PRNG G; + G.ReSeed(); + + ofstream* outf=new ofstream[N]; + typename T::clear a,b; + vector Sa(N),Sb(N); + /* Generate Triples */ + for (int i=0; i` to set the computation domain to Z_{2^k}, and time of writing, the following combinations are available: 32/32, 64/64, 64/48, and 66/48. -Running './ot-offline.x' without parameters give the full menu of +Running `./ot-offline.x` without parameters give the full menu of options such as how many items to generate in how many threads and loops. diff --git a/Scripts/mal-rep-bin.sh b/Scripts/mal-rep-bin.sh index 5b79d3592..7beb385bf 100755 --- a/Scripts/mal-rep-bin.sh +++ b/Scripts/mal-rep-bin.sh @@ -1,19 +1,10 @@ #!/bin/bash -port=$[RANDOM+1024] +HERE=$(cd `dirname $0`; pwd) +SPDZROOT=$HERE/.. -for i in 0 1 2; do - IFS="" - log="mal-rep-bin-$*-$i" - IFS=" " - $prefix ./malicious-rep-bin-party.x -p $i -pn $port $* 2>&1 | - { - if test $i = 0; then - tee -a logs/$log - else - cat >> logs/$log - fi - } & true -done +export PLAYERS=3 -wait || exit 1 +. $HERE/run-common.sh + +run_player malicious-rep-bin-party.x $* || exit 1 diff --git a/Scripts/mal-shamir.sh b/Scripts/mal-shamir.sh index 33678d7b5..7b902fb96 100755 --- a/Scripts/mal-shamir.sh +++ b/Scripts/mal-shamir.sh @@ -11,4 +11,4 @@ fi . $HERE/run-common.sh -run_player malicious-shamir-party.x ${1:-test_all} $t || exit 1 +run_player malicious-shamir-party.x $* $t || exit 1 diff --git a/Scripts/mascot.sh b/Scripts/mascot.sh index 6ecc967fa..5564dbe8c 100755 --- a/Scripts/mascot.sh +++ b/Scripts/mascot.sh @@ -3,10 +3,6 @@ HERE=$(cd `dirname $0`; pwd) SPDZROOT=$HERE/.. -bits=${2:-128} -g=${3:-0} -mem=${4:-empty} - . $HERE/run-common.sh -run_player mascot-party.x ${1:-test_all} -lgp ${bits} -lg2 ${g} -m ${mem} || exit 1 +run_player mascot-party.x $* || exit 1 diff --git a/Scripts/rep-field.sh b/Scripts/rep-field.sh index f5fea2d96..fd3eb6ef2 100755 --- a/Scripts/rep-field.sh +++ b/Scripts/rep-field.sh @@ -7,4 +7,4 @@ export PLAYERS=3 . $HERE/run-common.sh -run_player replicated-field-party.x ${1:-test_all} -lgp ${2:-128} || exit 1 +run_player replicated-field-party.x $* || exit 1 diff --git a/Scripts/replicated.sh b/Scripts/replicated.sh index e35f3522c..03f45a035 100755 --- a/Scripts/replicated.sh +++ b/Scripts/replicated.sh @@ -1,19 +1,10 @@ #!/bin/bash -port=$[RANDOM+1024] +HERE=$(cd `dirname $0`; pwd) +SPDZROOT=$HERE/.. -for i in 0 1 2; do - IFS="" - log="replicated-$*-$i" - IFS=" " - $prefix ./replicated-bin-party.x -p $i -pn $port $* 2>&1 | - { - if test $i = 0; then - tee -a logs/$log - else - cat >> logs/$log - fi - } & true -done +export PLAYERS=3 -wait || exit 1 +. $HERE/run-common.sh + +run_player replicated-bin-party.x $* || exit 1 diff --git a/Scripts/run-online.sh b/Scripts/run-online.sh index ca66ebe3d..6af69d4be 100755 --- a/Scripts/run-online.sh +++ b/Scripts/run-online.sh @@ -3,10 +3,6 @@ HERE=$(cd `dirname $0`; pwd) SPDZROOT=$HERE/.. -bits=${2:-128} -g=${3:-0} -mem=${4:-empty} - . $HERE/run-common.sh -run_player Player-Online.x ${1:-test_all} -lgp ${bits} -lg2 ${g} -m ${mem} || exit 1 +run_player Player-Online.x $* || exit 1 diff --git a/Scripts/semi.sh b/Scripts/semi.sh index dd71bbf3c..0a663d097 100755 --- a/Scripts/semi.sh +++ b/Scripts/semi.sh @@ -3,10 +3,6 @@ HERE=$(cd `dirname $0`; pwd) SPDZROOT=$HERE/.. -bits=${2:-128} -g=${3:-0} -mem=${4:-empty} - . $HERE/run-common.sh -run_player semi-party.x ${1:-test_all} -lgp ${bits} -lg2 ${g} -m ${mem} || exit 1 +run_player semi-party.x $* || exit 1 diff --git a/Scripts/test_ecdsa.sh b/Scripts/test_ecdsa.sh new file mode 100755 index 000000000..78194c6bf --- /dev/null +++ b/Scripts/test_ecdsa.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +echo 'MOD = -DGFP_MOD_SZ=4' >> CONFIG.mine + +make clean +make -j4 ecdsa Fake-ECDSA.x + +run() +{ + port=$[RANDOM+1024] + if ! { + for j in $(seq 0 $2); do + ./$1-ecdsa-party.x -p $j 1 2>/dev/null & true + done + wait + } | grep "Online checking"; then + exit 1 + fi +} + +for i in rep mal-rep shamir mal-shamir; do + run $i 2 +done + +./Fake-ECDSA.x + +for i in semi mascot fake-spdz; do + run $i 1 +done diff --git a/Scripts/test_tutorial.sh b/Scripts/test_tutorial.sh index b37b4763a..86abc8b6a 100755 --- a/Scripts/test_tutorial.sh +++ b/Scripts/test_tutorial.sh @@ -26,6 +26,6 @@ done ./compile.py -B 16 tutorial -for i in replicated yao rep-bmr mal-rep-bmr shamir-bmr mal-shamir-bmr; do +for i in replicated mal-rep-bin yao rep-bmr mal-rep-bmr shamir-bmr mal-shamir-bmr; do test $i done diff --git a/SimpleOT b/SimpleOT index 66a9d3923..96f8a97e6 160000 --- a/SimpleOT +++ b/SimpleOT @@ -1 +1 @@ -Subproject commit 66a9d392362ca6d8e1cdd78e9e4ed85a76df284d +Subproject commit 96f8a97e6c049e11059337fd33457d84cb730f4c diff --git a/OT/BitVector.cpp b/Tools/BitVector.cpp similarity index 98% rename from OT/BitVector.cpp rename to Tools/BitVector.cpp index 7d3b72f4e..0d13b62e4 100644 --- a/OT/BitVector.cpp +++ b/Tools/BitVector.cpp @@ -1,6 +1,5 @@ -#include "OT/BitVector.h" -#include "OT/Rectangle.h" +#include "BitVector.h" #include "Tools/random.h" #include "Tools/octetStream.h" #include "Math/gf2n.h" diff --git a/OT/BitVector.h b/Tools/BitVector.h similarity index 98% rename from OT/BitVector.h rename to Tools/BitVector.h index 665e1ace1..54e319b31 100644 --- a/OT/BitVector.h +++ b/Tools/BitVector.h @@ -286,11 +286,10 @@ template<> inline void BitVector::randomize_blocks(PRNG& G) { gfp1 tmp; - for (size_t i = 0; i < (nbits / 128); i++) + for (size_t i = 0; i < (nbytes / gfp1::size()); i++) { tmp.randomize(G); - for (int j = 0; j < 2; j++) - ((mp_limb_t*)bytes)[2*i+j] = tmp.get().get_limb(j); + memcpy(bytes + i * gfp1::size(), tmp.get_ptr(), gfp1::size()); } } diff --git a/Tools/Bundle.h b/Tools/Bundle.h index 3ae528d93..011768618 100644 --- a/Tools/Bundle.h +++ b/Tools/Bundle.h @@ -15,7 +15,7 @@ class Bundle : public vector public: T& mine; - Bundle(Player& P) : + Bundle(const Player& P) : vector(P.num_players()), mine(this->at(P.my_num())) { } diff --git a/Tools/MMO.cpp b/Tools/MMO.cpp index 8a3a4996f..27990d572 100644 --- a/Tools/MMO.cpp +++ b/Tools/MMO.cpp @@ -44,21 +44,28 @@ void MMO::encrypt_and_xor(void* output, const void* input, const octet* key, _mm_storeu_si128(((__m128i*)output) + indices[i], out[i]); } -template -void MMO::hashBlocks(void* output, const void* input) +template +void MMO::hashBlocks(void* output, const void* input, size_t alloc_size, + size_t used_size) { - int n_blocks = DIV_CEIL(T::size(), 16); + int n_blocks = DIV_CEIL(used_size, 16); if (n_blocks > N_KEYS) throw runtime_error("not enough MMO keys"); __m128i tmp[N]; - int block_size = sizeof(tmp[0]); + size_t block_size = sizeof(tmp[0]); for (int i = 0; i < n_blocks; i++) { encrypt_and_xor(tmp, input, IV[i]); for (int j = 0; j < N; j++) - memcpy((char*)output + j * sizeof(T) + i * block_size, &tmp[j], - min(T::size() - i * block_size, block_size)); + memcpy((char*)output + j * alloc_size + i * block_size, &tmp[j], + min(used_size - i * block_size, block_size)); } +} + +template +void MMO::hashBlocks(void* output, const void* input) +{ + hashBlocks(output, input, sizeof(T), T::size()); for (int j = 0; j < N; j++) ((T*)output + j)->normalize(); } @@ -83,53 +90,37 @@ void MMO::hashBlockWise(octet* output, octet* input) template <> void MMO::hashBlocks(void* output, const void* input) { - if (gfp1::get_ZpD().get_t() != 2) + if (gfp1::get_ZpD().get_t() < 2) throw not_implemented(); - __m128i* in = (__m128i*)input; - __m128i* out = (__m128i*)output; - encrypt_and_xor<8>(out, in, IV[0]); + gfp1* out = (gfp1*)output; + hashBlocks<8>(output, input, sizeof(gfp1), gfp1::size()); + for (int i = 0; i < 8; i++) + out[i].zero_overhang(); int left = 8; int indices[8] = {0, 1, 2, 3, 4, 5, 6, 7}; while (left) { int now_left = 0; for (int j = 0; j < left; j++) - if (mpn_cmp((mp_limb_t*)&out[indices[j]], gfp1::get_ZpD().get_prA(), gfp1::t()) >= 0) + if (mpn_cmp((mp_limb_t*) out[indices[j]].get_ptr(), + gfp1::get_ZpD().get_prA(), gfp1::t()) >= 0) { indices[now_left] = indices[j]; now_left++; } left = now_left; - // and now my favorite hack - switch (left) { - case 8: - ecb_aes_128_encrypt<8>(out, out, IV[0], indices); - break; - case 7: - ecb_aes_128_encrypt<7>(out, out, IV[0], indices); - break; - case 6: - ecb_aes_128_encrypt<6>(out, out, IV[0], indices); - break; - case 5: - ecb_aes_128_encrypt<5>(out, out, IV[0], indices); - break; - case 4: - ecb_aes_128_encrypt<4>(out, out, IV[0], indices); - break; - case 3: - ecb_aes_128_encrypt<3>(out, out, IV[0], indices); - break; - case 2: - ecb_aes_128_encrypt<2>(out, out, IV[0], indices); - break; - case 1: - ecb_aes_128_encrypt<1>(out, out, IV[0], indices); - break; - default: - break; - } + int block_size = sizeof(__m128i); + int n_blocks = DIV_CEIL(gfp1::size(), block_size); + for (int i = 0; i < n_blocks; i++) + for (int j = 0; j < left; j++) + { + __m128i* addr = (__m128i*) out[indices[j]].get_ptr() + i; + __m128i* in = (__m128i*) out[indices[j]].get_ptr(); + auto tmp = aes_128_encrypt(_mm_loadu_si128(in), IV[i]); + memcpy(addr, &tmp, min(block_size, gfp1::size() - i * block_size)); + out[indices[j]].zero_overhang(); + } } } diff --git a/Tools/MMO.h b/Tools/MMO.h index b7821a354..a6646dc77 100644 --- a/Tools/MMO.h +++ b/Tools/MMO.h @@ -28,6 +28,9 @@ class MMO void setIV(int i, octet key[AES_BLK_SIZE]); template void hashOneBlock(void* output, const void* input) { hashBlocks((T*)output, input); } + template + void hashBlocks(void* output, const void* input, size_t alloc_size, + size_t used_size); template void hashBlocks(void* output, const void* input); template diff --git a/Tools/octetStream.h b/Tools/octetStream.h index 61cd5c4b0..8c41a3d00 100644 --- a/Tools/octetStream.h +++ b/Tools/octetStream.h @@ -96,6 +96,7 @@ class octetStream // Append with no padding for decoding void append(const octet* x,const size_t l); + octet* append(const size_t l); void append_no_resize(const octet* x,const size_t l); // Read l octets, with no padding for decoding void consume(octet* x,const size_t l); @@ -206,12 +207,18 @@ inline void octetStream::reserve(size_t l) resize_precise(len + l); } -inline void octetStream::append(const octet* x, const size_t l) +inline octet* octetStream::append(const size_t l) { if (len+l>mxlen) resize(len+l); - avx_memcpy(data+len,x,l*sizeof(octet)); + octet* res = data + len; len+=l; + return res; +} + +inline void octetStream::append(const octet* x, const size_t l) +{ + avx_memcpy(append(l), x, l*sizeof(octet)); } inline void octetStream::append_no_resize(const octet* x, const size_t l) diff --git a/Tools/random.cpp b/Tools/random.cpp index df20aa76d..8ccaedd13 100644 --- a/Tools/random.cpp +++ b/Tools/random.cpp @@ -183,13 +183,29 @@ void PRNG::get_octetStream(octetStream& ans,int len) } +template +void PRNG::randomBnd(mp_limb_t* res, const mp_limb_t* B, mp_limb_t mask) +{ + size_t n_limbs = (N_BYTES + sizeof(mp_limb_t) - 1) / sizeof(mp_limb_t); + do + { + get_octets((octet*) res); + res[n_limbs - 1] &= mask; + } + while (mpn_cmp(res, B, n_limbs) >= 0); +} + void PRNG::randomBnd(mp_limb_t* res, const mp_limb_t* B, size_t n_bytes, mp_limb_t mask) { - if (n_bytes == 16) - do - get_octets<16>((octet*) res); - while (mpn_cmp(res, B, 2) >= 0); - else + switch (n_bytes) + { + case 16: + randomBnd<16>(res, B, mask); + return; + case 32: + randomBnd<32>(res, B, mask); + return; + default: { size_t n_limbs = (n_bytes + sizeof(mp_limb_t) - 1) / sizeof(mp_limb_t); do @@ -199,6 +215,7 @@ void PRNG::randomBnd(mp_limb_t* res, const mp_limb_t* B, size_t n_bytes, mp_limb } while (mpn_cmp(res, B, n_limbs) >= 0); } + } } bigint PRNG::randomBnd(const bigint& B, bool positive) @@ -233,6 +250,7 @@ void PRNG::randomBnd(bigint& x, const bigint& B, bool positive) void PRNG::get_bigint(bigint& res, int n_bits, bool positive) { + assert(n_bits > 0); int n_bytes = (n_bits + 7) / 8; if (n_bytes > 1000) throw not_implemented(); diff --git a/Tools/random.h b/Tools/random.h index 26dc9208b..a0dc9e3d9 100644 --- a/Tools/random.h +++ b/Tools/random.h @@ -90,6 +90,8 @@ class PRNG void get(int& res, int n_bits, bool positive = true); void randomBnd(bigint& res, const bigint& B, bool positive=true); bigint randomBnd(const bigint& B, bool positive=true); + template + void randomBnd(mp_limb_t* res, const mp_limb_t* B, mp_limb_t mask = -1); void randomBnd(mp_limb_t* res, const mp_limb_t* B, size_t n_bytes, mp_limb_t mask = -1); word get_word() { diff --git a/Tools/time-func.cpp b/Tools/time-func.cpp index 4e2c84481..9dc0b8006 100644 --- a/Tools/time-func.cpp +++ b/Tools/time-func.cpp @@ -2,6 +2,7 @@ #include "Tools/time-func.h" #include "Exceptions/Exceptions.h" +#include long long timeval_diff(struct timeval *start_time, struct timeval *end_time) { struct timeval temp_diff; @@ -62,3 +63,12 @@ double Timer::idle() else return convert_ns_to_seconds(elapsed_since_last_start()); } + +Timer& Timer::operator -=(const Timer& other) +{ + assert(clock_id == other.clock_id); + assert(not running); + assert(not other.running); + elapsed_time -= other.elapsed_time; + return *this; +} diff --git a/Tools/time-func.h b/Tools/time-func.h index c78c07fab..144f11ff6 100644 --- a/Tools/time-func.h +++ b/Tools/time-func.h @@ -25,6 +25,8 @@ class Timer double elapsed_then_reset(); double idle(); + Timer& operator-=(const Timer& other); + private: timespec startv; bool running; diff --git a/compile.py b/compile.py index 125281ed0..48586cf3f 100755 --- a/compile.py +++ b/compile.py @@ -65,6 +65,9 @@ def main(): help="bit length of sint modulo prime (default: 64)") parser.add_option("-I", "--insecure", action="store_true", dest="insecure", help="activate insecure functionality for benchmarking") + parser.add_option("-b", "--budget", dest="budget", default=100000, + help="set budget for optimized loop unrolling " + "(default: 100000)") options,args = parser.parse_args() if len(args) < 1: parser.print_help() diff --git a/default-prime-length.cpp b/default-prime-length.cpp new file mode 100644 index 000000000..4a3128bac --- /dev/null +++ b/default-prime-length.cpp @@ -0,0 +1,11 @@ +/* + * default-prime-length.cpp + * + */ + +#include "Math/gfp.h" + +int main() +{ + std::cout << gfp::MAX_N_BITS << endl; +} diff --git a/tutorial.md b/tutorial.md deleted file mode 100644 index db81e0bc2..000000000 --- a/tutorial.md +++ /dev/null @@ -1,166 +0,0 @@ -Suppose we want to add 2 integers mod p in clear, where p has 128 bits and compute over 2 parties inputs: P0, P1. - -First create a file named "addition.mpc" in Programs/Source/ folder containing the following: - - -Computation on Clear Data -================== - -``` -a = cint(2) -b = cint(10) - -c = a + b -print_ln('Result is %s', c) -``` - -Next step is to transform the file into bytecode which will be run later on the VM between different parties. -For that, type in terminal: - -``` -./compile -p 128 addition - -``` - -The command will output to stderr the number of registers, rounds and other parameters used for measuring the requirements from the offline phase. - -To run the program, you first need to set up the parameters of the different players. This can be done with the following command. - -``` -Scripts/setup-online.sh -``` - -To simply run the program between 2 parties simulated locally, type in terminal: - -``` -Scripts/run-online.sh addition - -``` - -The output will be a summary for the online phase including the result of the computation. - -```` - Result is 12 - -```` - - -Computation on Secret Shared data -================================= - -``` -a = sint(2) -b = sint(10) - -c = a + b -print_ln('Result is %s', c.reveal()) - -``` - -This means that a = a_0 + a_1, b = b_0 + b_1 where a_i belongs to party P_i. - -It's that simple! When we reveal a secret register, the MAC-checking - according -to SPDZ online phase - is done automatically. If there are multiple calls to -reveal() then the rounds of communication are merged automatically by the -compiler. - -Remember that a and b are hard-coded constants so the data is shared by one -party having the actualy inputs (a_0=2, b_0=10) where the other one has (a_1 = -0, b_1 = 0). Usually it's easier to debug when things are written in this way. - -If we want to run a real MPC computation - P1 shares a and P2 shares b - and -reveal the sum of the values then we can write the following. - -``` -a = sint.get_raw_input_from(0) -b = sint.get_raw_input_from(1) - -c = a + b -print_ln('Result is %s', c.reveal()) - -``` - -SPDZ also supports multiplication, division (in a prime field) as well as -GF(2^n) data types. All types can be seen in types.py file. - - -Array Lookup -============= - -Suppose party P0 inputs an array of fixed length n: A[1]...A[n] and party P1 -inputs a SS index [index]. - -``` -A = [sint.get_raw_input_from(0) for _ in range(100)] -index = sint.get_raw_input_from(1) -``` - -Let's see how can we obtain [A[i]]. - -The standard way to solve this task in a non-MPC way is the following: - -``` -clear_index = index.reveal() -print_ln('%s', A[clear_index].reveal()) - -``` - -But this solution reveals party P1's input which isn't secure! - -Another way of doing this is:inary form. There is - -``` -accumulator = 0 -for i in range(len(A)): - accumulator = accumulator + (i == index) * A[i] - -print_ln('%s', accumulator.reveal()) - -``` - -In this case the only revealed value is A[index]. The main trick was that -comparison between sint() and clear data returns a sint(). In conclusion, all -data is masked except the last step. - -Providing input to SPDZ -======================== - -Looking back at the addition example, in Player-Data/Private-Input-{i} for i in -{0,1} we have to provide one integer in each file. Because the conversion -between human readable form to SPDZ data types is time expensive, we have to -feed the numbers in binary form. There is a script for that: gen_input_fp.cpp -and gen_input_f2n.cpp in the Scripts directory designed for generating gfp -inputs. The executables can be found after compiling SPDZ. Customizing those -should be straightforward. Make sure you copy the output files to Player-Data -/Private-Input-{i} files. - -There is a sockets interface to provide input and output from external client processes. See the [ExternalIO directory](./ExternalIO/README.md). - -Other examples -============== - -aes.mpc has the AES evaluation in MPC where the key belongs to party 0 -and the message to party 1. - -For example, say that we have a key equal to - -``` -2b7e151628aed2a6abf7158809cf4f3c -``` - -We have to convert this into SPDZ datatypes so we use the scripts -gen_input_f2n.x which can be found in the main directory after compiling -SPDZ. Next, the file 'gf2n_vals.in' should contain the following: - -``` -16 -0x2b 0x7e 0x15 0x16 0x28 0xae 0xd2 0xa6 0xab 0xf7 0x15 0x88 0x9 0xcf 0x4f 0x3c -``` - -Now execute the gen_input_f2n.x script and copy the output file to -Player-Data/Private-Input-0 - -The same method applies to generate the message as an input to SPDZ. - -Since all items are in place we can run the online phase and see the -revealed encryption result: