Skip to content

Commit 9ef15cc

Browse files
committed
Protocol in dealer model.
1 parent eee8865 commit 9ef15cc

File tree

186 files changed

+2008
-618
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

186 files changed

+2008
-618
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
The changelog explains changes pulled through from the private development repository. Bug fixes and small enhancements are committed between releases and not documented here.
22

3+
## 0.3.1 (Apr 19, 2022)
4+
5+
- Protocol in dealer model
6+
- Command-line option for security parameter
7+
- Fixed security bug in SPDZ2k (see Section 3.4 of [the updated paper](https://eprint.iacr.org/2018/482))
8+
- Ability to run high-level (Python) code from C++
9+
- More memory capacity due to 64-bit addressing
10+
- Homomorphic encryption for more fields of characteristic two
11+
- Docker container
12+
313
## 0.3.0 (Feb 17, 2022)
414

515
- Semi-honest computation based on threshold semi-homomorphic encryption

Compiler/GC/instructions.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ class ldmsb(base.DirectMemoryInstruction, base.ReadMemoryInstruction,
305305
:param: memory address (int)
306306
"""
307307
code = opcodes['LDMSB']
308-
arg_format = ['sbw','int']
308+
arg_format = ['sbw','long']
309309

310310
class stmsb(base.DirectMemoryWriteInstruction, base.VectorInstruction):
311311
""" Copy secret bit register to secret bit memory cell with compile-time
@@ -315,7 +315,7 @@ class stmsb(base.DirectMemoryWriteInstruction, base.VectorInstruction):
315315
:param: memory address (int)
316316
"""
317317
code = opcodes['STMSB']
318-
arg_format = ['sb','int']
318+
arg_format = ['sb','long']
319319
# def __init__(self, *args, **kwargs):
320320
# super(type(self), self).__init__(*args, **kwargs)
321321
# import inspect
@@ -330,7 +330,7 @@ class ldmcb(base.DirectMemoryInstruction, base.ReadMemoryInstruction,
330330
:param: memory address (int)
331331
"""
332332
code = opcodes['LDMCB']
333-
arg_format = ['cbw','int']
333+
arg_format = ['cbw','long']
334334

335335
class stmcb(base.DirectMemoryWriteInstruction, base.VectorInstruction):
336336
""" Copy clear bit register to clear bit memory cell with compile-time
@@ -340,7 +340,7 @@ class stmcb(base.DirectMemoryWriteInstruction, base.VectorInstruction):
340340
:param: memory address (int)
341341
"""
342342
code = opcodes['STMCB']
343-
arg_format = ['cb','int']
343+
arg_format = ['cb','long']
344344

345345
class ldmsbi(base.ReadMemoryInstruction, base.VectorInstruction):
346346
""" Copy secret bit memory cell with run-time address to secret bit

Compiler/GC/types.py

+14-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
fixed-length types obtained by :py:obj:`get_type(n)` are the preferred
44
way of using them, and in some cases required in connection with
55
container types.
6+
7+
Computation using these types will always be executed as a binary
8+
circuit. See :ref:`protocol-pairs` for the exact protocols.
69
"""
710

811
from Compiler.types import MemValue, read_mem_value, regint, Array, cint
@@ -17,7 +20,6 @@
1720
from functools import reduce
1821

1922
class bits(Tape.Register, _structure, _bit):
20-
""" Base class for binary registers. """
2123
n = 40
2224
unit = 64
2325
PreOp = staticmethod(floatingpoint.PreOpN)
@@ -400,12 +402,18 @@ def get_random_bit():
400402
res = sbit()
401403
inst.bitb(res)
402404
return res
405+
@staticmethod
406+
def _check_input_player(player):
407+
if not util.is_constant(player):
408+
raise CompilerError('player must be known at compile time '
409+
'for binary circuit inputs')
403410
@classmethod
404411
def get_input_from(cls, player, n_bits=None):
405412
""" Secret input from :py:obj:`player`.
406413
407414
:param: player (int)
408415
"""
416+
cls._check_input_player(player)
409417
if n_bits is None:
410418
n_bits = cls.n
411419
res = cls()
@@ -653,6 +661,7 @@ def get_input_from(cls, player):
653661
654662
:param: player (int)
655663
"""
664+
sbits._check_input_player(player)
656665
res = cls.from_vec(sbit() for i in range(n))
657666
inst.inputbvec(n + 3, 0, player, *res.v)
658667
return res
@@ -780,6 +789,8 @@ def coerce(self, other):
780789
size = other.size
781790
return (other.get_vector(base, min(64, size - base)) \
782791
for base in range(0, size, 64))
792+
if not isinstance(other, type(self)):
793+
return type(self)(other)
783794
return other
784795
def __xor__(self, other):
785796
other = self.coerce(other)
@@ -1222,6 +1233,7 @@ def get_input_from(cls, player):
12221233
12231234
:param: player (int)
12241235
"""
1236+
sbits._check_input_player(player)
12251237
v = cls.int_type()
12261238
inst.inputb(player, cls.k, cls.f, v)
12271239
return cls._new(v)
@@ -1287,6 +1299,7 @@ def get_input_from(cls, player):
12871299
:param: player (int)
12881300
"""
12891301
v = [sbit() for i in range(sbitfix.k)]
1302+
sbits._check_input_player(player)
12901303
inst.inputbvec(len(v) + 3, sbitfix.f, player, *v)
12911304
return cls._new(cls.int_type.from_vec(v))
12921305
def __init__(self, value=None, *args, **kwargs):

Compiler/allocator.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@
1515
class BlockAllocator:
1616
""" Manages freed memory blocks. """
1717
def __init__(self):
18-
self.by_logsize = [defaultdict(set) for i in range(32)]
18+
self.by_logsize = [defaultdict(set) for i in range(64)]
1919
self.by_address = {}
2020

2121
def by_size(self, size):
22-
if size >= 2 ** 32:
22+
if size >= 2 ** 64:
2323
raise CompilerError('size exceeds addressing capability')
2424
return self.by_logsize[int(math.log(size, 2))][size]
2525

Compiler/instructions.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class ldmc(base.DirectMemoryInstruction, base.ReadMemoryInstruction):
6969
"""
7070
__slots__ = []
7171
code = base.opcodes['LDMC']
72-
arg_format = ['cw','int']
72+
arg_format = ['cw','long']
7373

7474
@base.gf2n
7575
@base.vectorize
@@ -84,7 +84,7 @@ class ldms(base.DirectMemoryInstruction, base.ReadMemoryInstruction):
8484
"""
8585
__slots__ = []
8686
code = base.opcodes['LDMS']
87-
arg_format = ['sw','int']
87+
arg_format = ['sw','long']
8888

8989
@base.gf2n
9090
@base.vectorize
@@ -99,7 +99,7 @@ class stmc(base.DirectMemoryWriteInstruction):
9999
"""
100100
__slots__ = []
101101
code = base.opcodes['STMC']
102-
arg_format = ['c','int']
102+
arg_format = ['c','long']
103103

104104
@base.gf2n
105105
@base.vectorize
@@ -114,7 +114,7 @@ class stms(base.DirectMemoryWriteInstruction):
114114
"""
115115
__slots__ = []
116116
code = base.opcodes['STMS']
117-
arg_format = ['s','int']
117+
arg_format = ['s','long']
118118

119119
@base.vectorize
120120
class ldmint(base.DirectMemoryInstruction, base.ReadMemoryInstruction):
@@ -128,7 +128,7 @@ class ldmint(base.DirectMemoryInstruction, base.ReadMemoryInstruction):
128128
"""
129129
__slots__ = []
130130
code = base.opcodes['LDMINT']
131-
arg_format = ['ciw','int']
131+
arg_format = ['ciw','long']
132132

133133
@base.vectorize
134134
class stmint(base.DirectMemoryWriteInstruction):
@@ -142,7 +142,7 @@ class stmint(base.DirectMemoryWriteInstruction):
142142
"""
143143
__slots__ = []
144144
code = base.opcodes['STMINT']
145-
arg_format = ['ci','int']
145+
arg_format = ['ci','long']
146146

147147
@base.vectorize
148148
class ldmci(base.ReadMemoryInstruction, base.IndirectMemoryInstruction):

Compiler/instructions_base.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ def reformat(arg_format):
337337
if isinstance(arg_format, list):
338338
__format = []
339339
for __f in arg_format:
340-
if __f in ('int', 'p', 'ci', 'str'):
340+
if __f in ('int', 'long', 'p', 'ci', 'str'):
341341
__format.append(__f)
342342
else:
343343
__format.append(__f[0] + 'g' + __f[1:])
@@ -360,7 +360,7 @@ class GF2N_Instruction(instruction_cls):
360360
arg_format = instruction_cls.gf2n_arg_format
361361
elif isinstance(instruction_cls.arg_format, itertools.repeat):
362362
__f = next(instruction_cls.arg_format)
363-
if __f != 'int' and __f != 'p':
363+
if __f not in ('int', 'long', 'p'):
364364
arg_format = itertools.repeat(__f[0] + 'g' + __f[1:])
365365
else:
366366
arg_format = copy.deepcopy(instruction_cls.arg_format)
@@ -711,6 +711,14 @@ def __init__(self, f):
711711
def __str__(self):
712712
return str(self.i)
713713

714+
class LongArgFormat(IntArgFormat):
715+
@classmethod
716+
def encode(cls, arg):
717+
return struct.pack('>Q', arg)
718+
719+
def __init__(self, f):
720+
self.i = struct.unpack('>Q', f.read(8))[0]
721+
714722
class ImmediateModpAF(IntArgFormat):
715723
@classmethod
716724
def check(cls, arg):
@@ -768,6 +776,7 @@ def __str__(self):
768776
'i': ImmediateModpAF,
769777
'ig': ImmediateGF2NAF,
770778
'int': IntArgFormat,
779+
'long': LongArgFormat,
771780
'p': PlayerNoAF,
772781
'str': String,
773782
}

Compiler/library.py

+13
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,7 @@ def multithread(n_threads, n_items=None, max_size=None):
11491149
11501150
:param n_threads: compile-time (int)
11511151
:param n_items: regint/cint/int (default: :py:obj:`n_threads`)
1152+
:param max_size: maximum size to be processed at once (default: no limit)
11521153
11531154
The following executes ``f(0, 8)``, ``f(8, 8)``, and
11541155
``f(16, 9)`` in three different threads:
@@ -1366,6 +1367,18 @@ def _(base, size):
13661367
left = (left + 1) // 2
13671368
return inputs[0]
13681369

1370+
def tree_reduce(function, sequence):
1371+
""" Round-efficient reduction. The following computes the maximum
1372+
of the list :py:obj:`l`::
1373+
1374+
m = tree_reduce(lambda x, y: x.max(y), l)
1375+
1376+
:param function: reduction function taking two arguments
1377+
:param sequence: list, vector, or array
1378+
1379+
"""
1380+
return util.tree_reduce(function, sequence)
1381+
13691382
def foreach_enumerate(a):
13701383
""" Run-time loop over public data. This uses
13711384
``Player-Data/Public-Input/<progname>``. Example:

Compiler/ml.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -1079,14 +1079,17 @@ def __repr__(self):
10791079
(type(self).__name__, self.X.sizes, self.strides,
10801080
self.ksize, self.padding)
10811081

1082-
def _forward(self, batch):
1082+
def forward(self, batch=None, training=False):
1083+
if batch is None:
1084+
batch = Array.create_from(regint(0))
10831085
def process(pool, bi, k, i, j):
10841086
def m(a, b):
10851087
c = a[0] > b[0]
10861088
l = [c * x for x in a[1]]
10871089
l += [(1 - c) * x for x in b[1]]
10881090
return c.if_else(a[0], b[0]), l
1089-
red = util.tree_reduce(m, [(x[0], [1]) for x in pool])
1091+
red = util.tree_reduce(m, [(x[0], [1] if training else [])
1092+
for x in pool])
10901093
self.Y[bi][i][j][k] = red[0]
10911094
for i, x in enumerate(red[1]):
10921095
self.comparisons[bi][k][i] = x

Compiler/program.py

+3
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,9 @@ def malloc(self, size, mem_type, reg_type=None, creator_tape=None):
400400
self.allocated_mem[mem_type] += size
401401
if len(str(addr)) != len(str(addr + size)) and self.verbose:
402402
print("Memory of type '%s' now of size %d" % (mem_type, addr + size))
403+
if addr + size >= 2 ** 32:
404+
raise CompilerError("allocation exceeded for type '%s'" %
405+
mem_type)
403406
self.allocated_mem_blocks[addr,mem_type] = size
404407
if single_size:
405408
from .library import get_thread_number, runtime_error_if

Compiler/types.py

+29-6
Original file line numberDiff line numberDiff line change
@@ -1710,7 +1710,12 @@ def reveal_to(self, player):
17101710
res = Array.create_from(res)
17111711
return personal(player, res)
17121712

1713-
def bit_decompose(self, length):
1713+
def bit_decompose(self, length=None):
1714+
""" Bit decomposition.
1715+
1716+
:param length: number of bits
1717+
1718+
"""
17141719
return [personal(self.player, x) for x in self._v.bit_decompose(length)]
17151720

17161721
def _san(self, other):
@@ -2144,14 +2149,17 @@ class sint(_secret, _int):
21442149
the bit length.
21452150
21462151
:param val: initialization (sint/cint/regint/int/cgf2n or list
2147-
thereof or sbits/sbitvec/sfix)
2152+
thereof, sbits/sbitvec/sfix, or :py:class:`personal`)
21482153
:param size: vector size (int), defaults to 1 or size of list
21492154
21502155
When converting :py:class:`~Compiler.GC.types.sbits`, the result is a
21512156
vector of bits, and when converting
21522157
:py:class:`~Compiler.GC.types.sbitvec`, the result is a vector of values
21532158
with bit length equal the length of the input.
21542159
2160+
Initializing from a :py:class:`personal` value implies the
2161+
relevant party inputting their value securely.
2162+
21552163
"""
21562164
__slots__ = []
21572165
instruction_type = 'modp'
@@ -4285,6 +4293,7 @@ class sfix(_fix):
42854293
""" Secret fixed-point number represented as secret integer, by
42864294
multiplying with ``2^f`` and then rounding. See :py:class:`sint`
42874295
for security considerations of the underlying integer operations.
4296+
The secret integer is stored as the :py:obj:`v` member.
42884297
42894298
It supports basic arithmetic (``+, -, *, /``), returning
42904299
:py:class:`sfix`, and comparisons (``==, !=, <, <=, >, >=``),
@@ -5121,7 +5130,8 @@ class Array(_vectorizable):
51215130
array ``a`` and ``i`` being a :py:class:`regint`,
51225131
:py:class:`cint`, or a Python integer.
51235132
5124-
:param length: compile-time integer (int) or :py:obj:`None` for unknown length
5133+
:param length: compile-time integer (int) or :py:obj:`None`
5134+
for unknown length (need to specify :py:obj:`address`)
51255135
:param value_type: basic type
51265136
:param address: if given (regint/int), the array will not be allocated
51275137
@@ -5178,6 +5188,8 @@ def delete(self):
51785188
self.address = None
51795189

51805190
def get_address(self, index):
5191+
if isinstance(index, (_secret, _single)):
5192+
raise CompilerError('need cleartext index')
51815193
key = str(index)
51825194
if self.length is not None:
51835195
from .GC.types import cbits
@@ -5211,6 +5223,7 @@ def get_slice(self, index):
52115223
if index.step == 0:
52125224
raise CompilerError('slice step cannot be zero')
52135225
return index.start or 0, \
5226+
index.stop if self.length is None else \
52145227
min(index.stop or self.length, self.length), index.step or 1
52155228

52165229
def __getitem__(self, index):
@@ -5517,7 +5530,15 @@ def print_reveal_nested(self, end='\n'):
55175530
55185531
:param end: string to print after (default: line break)
55195532
"""
5520-
library.print_str('%s' + end, self.get_vector().reveal())
5533+
if util.is_constant(self.length):
5534+
library.print_str('%s' + end, self.get_vector().reveal())
5535+
else:
5536+
library.print_str('[')
5537+
@library.for_range(self.length - 1)
5538+
def _(i):
5539+
library.print_str('%s, ', self[i].reveal())
5540+
library.print_str('%s', self[self.length - 1].reveal())
5541+
library.print_str(']' + end)
55215542

55225543
def reveal_to_binary_output(self, player=None):
55235544
""" Reveal to binary output if supported by type.
@@ -5893,7 +5914,8 @@ def dot(self, other, res_params=None, n_threads=None):
58935914
""" Matrix-matrix and matrix-vector multiplication.
58945915
58955916
:param self: two-dimensional
5896-
:param other: Matrix or Array of matching size and type """
5917+
:param other: Matrix or Array of matching size and type
5918+
:param n_threads: number of threads (default: all in same thread) """
58975919
assert len(self.sizes) == 2
58985920
if isinstance(other, Array):
58995921
assert len(other) == self.sizes[1]
@@ -5928,6 +5950,7 @@ def _(base, size):
59285950
res_matrix.assign_part_vector(
59295951
self.get_part(base, size).direct_mul(other), base)
59305952
except AttributeError:
5953+
assert n_threads is None
59315954
if max(res_matrix.sizes) > 1000:
59325955
raise AttributeError()
59335956
A = self.get_vector()
@@ -5937,7 +5960,7 @@ def _(base, size):
59375960
res_params))
59385961
except (AttributeError, AssertionError):
59395962
# fallback for sfloat etc.
5940-
@library.for_range_opt(self.sizes[0])
5963+
@library.for_range_opt_multithread(n_threads, self.sizes[0])
59415964
def _(i):
59425965
try:
59435966
res_matrix[i] = self.value_type.row_matrix_mul(

0 commit comments

Comments
 (0)