Skip to content

Commit 78fe3d8

Browse files
committed
Maintenance.
1 parent b0dc2b3 commit 78fe3d8

File tree

234 files changed

+4265
-1359
lines changed

Some content is hidden

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

234 files changed

+4265
-1359
lines changed

BMR/AndJob.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ int AndJob::run()
1515
#endif
1616
__m128i* prf_output = new __m128i[PAD_TO_8(ProgramParty::s().get_n_parties())];
1717
auto gate = gates.begin();
18-
vector< GC::Secret<EvalRegister> >& S = *this->S;
18+
auto& S = *this->S;
1919
const vector<int>& args = *this->args;
2020
int i_gate = 0;
2121
for (size_t i = start; i < end; i += 4)

BMR/AndJob.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ using namespace std;
1515

1616
class AndJob
1717
{
18-
vector< GC::Secret<EvalRegister> >* S;
18+
StackedVector< GC::Secret<EvalRegister> >* S;
1919
const vector<int>* args;
2020

2121
public:
@@ -25,7 +25,7 @@ class AndJob
2525

2626
AndJob() : S(0), args(0), start(0), end(0), gate_id(0) {}
2727

28-
void reset(vector<GC::Secret<EvalRegister> >& S, const vector<int>& args,
28+
void reset(StackedVector<GC::Secret<EvalRegister> >& S, const vector<int>& args,
2929
size_t start, gate_id_t gate_id, size_t n_gates, int n_parties)
3030
{
3131
this->S = &S;

CHANGELOG.md

+17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,22 @@
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.9 (July 9, 2024)
4+
5+
- Inference with non-sequential PyTorch networks
6+
- SHA-3 for any input length (@hiddely)
7+
- Improved client facilities
8+
- Shuffling with malicious security for SPDZ-wise protocols by [Asharov et al.](https://ia.cr/2022/1595)
9+
- More reusable bytecode via in-thread calling facility
10+
- Recursive functions without return values
11+
- Fewer rounds for parallel matrix multiplications (@vincent-ehrmanntraut)
12+
- Optimized usage of SoftSpokenOT in semi-honest protocols
13+
- More integrity checks on storage in MAC-based protocols
14+
- Use C++17
15+
- Use glibc 2.18 for the binaries
16+
- Fixed security bugs: remotely caused buffer overflows (#1382)
17+
- Fixed security bug: Missing randomization before revealing to client
18+
- Fixed security bug: Bias in Rep3 secure shuffling
19+
320
## 0.3.8 (December 14, 2023)
421

522
- Functionality for multiple nodes per party

CONFIG

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ else
106106
BOOST = -lboost_thread $(MY_BOOST)
107107
endif
108108

109-
CFLAGS += $(ARCH) $(MY_CFLAGS) $(GDEBUG) -Wextra -Wall $(OPTIM) -I$(ROOT) -I$(ROOT)/deps -pthread $(PROF) $(DEBUG) $(MOD) $(GF2N_LONG) $(PREP_DIR) $(SSL_DIR) $(SECURE) -std=c++11 -Werror
109+
CFLAGS += $(ARCH) $(MY_CFLAGS) $(GDEBUG) -Wextra -Wall $(OPTIM) -I$(ROOT) -I$(ROOT)/deps -pthread $(PROF) $(DEBUG) $(MOD) $(GF2N_LONG) $(PREP_DIR) $(SSL_DIR) $(SECURE) -std=c++17 -Werror
110110
CFLAGS += $(BREW_CFLAGS)
111111
CPPFLAGS = $(CFLAGS)
112112
LD = $(CXX)

Compiler/GC/instructions.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,10 @@ def dynamic_arg_format(cls, args):
203203
def add_usage(self, req_node):
204204
for i, n in self.bases(iter(self.args)):
205205
size = self.args[i + 1]
206-
req_node.increment(('bit', 'triple'), size * (n - 3) // 2)
207-
req_node.increment(('bit', 'mixed'), size)
206+
n = (n - 3) // 2
207+
req_node.increment(('bit', 'triple'), size * n)
208+
if n > 1:
209+
req_node.increment(('bit', 'mixed'), size * ((n + 63) // 64))
208210

209211
def copy(self, size, subs):
210212
return type(self)(*self.get_new_args(size, subs))

Compiler/GC/types.py

+55-50
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,19 @@
1313
from Compiler.types import vectorized_classmethod
1414
from Compiler.program import Tape, Program
1515
from Compiler.exceptions import *
16-
from Compiler import util, oram, floatingpoint, library
16+
from Compiler import util, oram, floatingpoint, library, comparison
1717
from Compiler import instructions_base
1818
import Compiler.GC.instructions as inst
1919
import operator
2020
import math
2121
import itertools
2222
from functools import reduce
2323

24+
class _binary:
25+
def reveal_to(self, *args, **kwargs):
26+
raise CompilerError(
27+
'%s does not support revealing to indivual players' % type(self))
28+
2429
class bits(Tape.Register, _structure, _bit):
2530
n = 40
2631
unit = 64
@@ -149,6 +154,12 @@ def set_length(self, n):
149154
self.n = n
150155
def set_size(self, size):
151156
pass
157+
def load_int(self, value):
158+
n_limbs = math.ceil(self.n / self.unit)
159+
for i in range(n_limbs):
160+
self.conv_regint(min(self.unit, self.n - i * self.unit),
161+
self[i], regint(value % 2 ** self.unit))
162+
value >>= self.unit
152163
def load_other(self, other):
153164
if isinstance(other, cint):
154165
assert(self.n == other.size)
@@ -236,12 +247,14 @@ def _new_by_number(self, i, size=1):
236247
return res
237248
def if_else(self, x, y):
238249
"""
239-
Vectorized oblivious selection::
250+
Bit-wise oblivious selection::
240251
241252
sb32 = sbits.get_type(32)
242253
print_ln('%s', sb32(3).if_else(sb32(5), sb32(2)).reveal())
243254
244-
This will output 1.
255+
This will output 1 because it selects the two least
256+
significant bits from 5 and the rest of the bits from 2.
257+
245258
"""
246259
return result_conv(x, y)(self & (x ^ y) ^ y)
247260
def zero_if_not(self, condition):
@@ -268,6 +281,9 @@ def copy_from_part(self, source, base, size):
268281
self.bit_compose(source.bit_decompose()[base:base + size]))
269282
def vector_size(self):
270283
return self.n
284+
@staticmethod
285+
def size_for_mem():
286+
return 1
271287

272288
class cbits(bits):
273289
""" Clear bits register. Helper type with limited functionality. """
@@ -302,13 +318,6 @@ def conv(cls, other):
302318
else:
303319
return super(cbits, cls).conv(other)
304320
types = {}
305-
def load_int(self, value):
306-
n_limbs = math.ceil(self.n / self.unit)
307-
tmp = regint(size=n_limbs)
308-
for i in range(n_limbs):
309-
tmp[i].load_int(value % 2 ** self.unit)
310-
value >>= self.unit
311-
self.load_other(tmp)
312321
def store_in_dynamic_mem(self, address):
313322
inst.stmsdci(self, cbits.conv(address))
314323
def clear_op(self, other, c_inst, ci_inst, op):
@@ -502,11 +511,7 @@ def load_int(self, value):
502511
if self.n <= 32:
503512
inst.ldbits(self, self.n, value)
504513
else:
505-
size = math.ceil(self.n / self.unit)
506-
tmp = regint(size=size)
507-
for i in range(size):
508-
tmp[i].load_int((value >> (i * 64)) % 2**64)
509-
self.load_other(tmp)
514+
bits.load_int(self, value)
510515
def load_other(self, other):
511516
if isinstance(other, cbits) and self.n == other.n:
512517
inst.convcbit2s(self.n, self, other)
@@ -675,7 +680,7 @@ def bit_adder(*args, **kwargs):
675680
def ripple_carry_adder(*args, **kwargs):
676681
return sbitint.ripple_carry_adder(*args, **kwargs)
677682

678-
class sbitvec(_vec, _bit):
683+
class sbitvec(_vec, _bit, _binary):
679684
""" Vector of registers of secret bits, effectively a matrix of secret bits.
680685
This facilitates parallel arithmetic operations in binary circuits.
681686
Container types are not supported, use :py:obj:`sbitvec.get_type` for that.
@@ -732,15 +737,16 @@ def get_type(cls, n):
732737
:py:obj:`v` and the columns by calling :py:obj:`elements`.
733738
"""
734739
class sbitvecn(cls, _structure):
735-
@staticmethod
736-
def malloc(size, creator_tape=None):
737-
return sbit.malloc(size * n, creator_tape=creator_tape)
740+
@classmethod
741+
def malloc(cls, size, creator_tape=None):
742+
return sbit.malloc(
743+
size * cls.mem_size(), creator_tape=creator_tape)
738744
@staticmethod
739745
def n_elements():
740746
return 1
741747
@staticmethod
742748
def mem_size():
743-
return n
749+
return sbits.get_type(n).mem_size()
744750
@classmethod
745751
def get_input_from(cls, player, size=1, f=0):
746752
""" Secret input from :py:obj:`player`. The input is decomposed
@@ -780,38 +786,28 @@ def __init__(self, other=None, size=None):
780786
self.v = sbits.get_type(n)(other).bit_decompose()
781787
assert len(self.v) == n
782788
assert size is None or size == self.v[0].n
783-
@vectorized_classmethod
784-
def load_mem(cls, address):
785-
size = instructions_base.get_global_vector_size()
786-
if size not in (None, 1):
787-
assert isinstance(address, int) or len(address) == 1
788-
sb = sbits.get_type(size)
789-
return cls.from_vec(sb.bit_compose(
790-
sbit.load_mem(address + i + j * n) for j in range(size))
791-
for i in range(n))
792-
if not isinstance(address, int):
793-
v = [sbit.load_mem(x, size=n).v[0] for x in address]
794-
return cls(v)
789+
@classmethod
790+
def load_mem(cls, address, size=None):
791+
if isinstance(address, int) or len(address) == 1:
792+
address = [address + i for i in range(size or 1)]
795793
else:
796-
return cls.from_vec(sbit.load_mem(address + i)
797-
for i in range(n))
794+
assert size == None
795+
return cls(
796+
[sbits.get_type(n).load_mem(x) for x in address])
798797
def store_in_mem(self, address):
799798
size = 1
800799
for x in self.v:
801800
if not util.is_constant(x):
802801
size = max(size, x.n)
803-
v = [sbits.get_type(size).conv(x) for x in self.v]
804-
if not isinstance(address, int) and len(address) != 1:
805-
v = self.elements()
806-
assert len(v) == len(address)
807-
for x, y in zip(v, address):
808-
for i, xx in enumerate(x.bit_decompose(n)):
809-
xx.store_in_mem(y + i)
802+
if isinstance(address, int):
803+
address = range(address, address + size)
804+
elif len(address) == 1:
805+
address = [address + i * self.mem_size()
806+
for i in range(size)]
810807
else:
811-
assert isinstance(address, int) or len(address) == 1
812-
for i in range(n):
813-
for j, x in enumerate(v[i].bit_decompose()):
814-
x.store_in_mem(address + i + j * n)
808+
assert size == len(address)
809+
for x, dest in zip(self.elements(), address):
810+
x.store_in_mem(dest)
815811
@classmethod
816812
def two_power(cls, nn, size=1):
817813
return cls.from_vec(
@@ -864,7 +860,7 @@ def __init__(self, elements=None, length=None, input_length=None):
864860
assert isinstance(elements, sint)
865861
if Program.prog.use_split():
866862
x = elements.split_to_two_summands(length)
867-
v = sbitint.carry_lookahead_adder(x[0], x[1], fewer_inv=True)
863+
v = sbitint.bit_adder(x[0], x[1])
868864
else:
869865
prog = Program.prog
870866
if not prog.options.ring:
@@ -877,6 +873,7 @@ def __init__(self, elements=None, length=None, input_length=None):
877873
length, prog.security)
878874
prog.use_edabit(backup)
879875
return
876+
comparison.require_ring_size(length, 'A2B conversion')
880877
l = int(Program.prog.options.ring)
881878
r, r_bits = sint.get_edabit(length, size=elements.size)
882879
c = ((elements - r) << (l - length)).reveal()
@@ -885,6 +882,8 @@ def __init__(self, elements=None, length=None, input_length=None):
885882
x = sbitintvec.from_vec(r_bits) + sbitintvec.from_vec(cb)
886883
v = x.v
887884
self.v = v[:length]
885+
elif isinstance(elements, sbitvec):
886+
self.v = elements.v
888887
elif elements is not None and not (util.is_constant(elements) and \
889888
elements == 0):
890889
self.v = sbits.trans(elements)
@@ -1347,13 +1346,19 @@ def elements(self):
13471346
def __add__(self, other):
13481347
if util.is_zero(other):
13491348
return self
1350-
a, b = self.expand(other)
1349+
try:
1350+
a, b = self.expand(other)
1351+
except:
1352+
return NotImplemented
13511353
v = sbitint.bit_adder(a, b)
13521354
return self.get_type(len(v)).from_vec(v)
13531355
__radd__ = __add__
13541356
__sub__ = _bitint.__sub__
13551357
def __rsub__(self, other):
1356-
a, b = self.expand(other)
1358+
try:
1359+
a, b = self.expand(other)
1360+
except:
1361+
return NotImplemented
13571362
return self.from_vec(b) - self.from_vec(a)
13581363
def __mul__(self, other):
13591364
if isinstance(other, sbits):
@@ -1447,7 +1452,7 @@ def output(self):
14471452
inst.print_float_plainb(v, cbits.get_type(32)(-self.f), cbits(0),
14481453
cbits(0), cbits(0))
14491454

1450-
class sbitfix(_fix):
1455+
class sbitfix(_fix, _binary):
14511456
""" Secret signed fixed-point number in one binary register.
14521457
Use :py:obj:`set_precision()` to change the precision.
14531458
@@ -1515,7 +1520,7 @@ class cls(_fix):
15151520
cls.set_precision(f, k)
15161521
return cls._new(cls.int_type(other), k, f)
15171522

1518-
class sbitfixvec(_fix, _vec):
1523+
class sbitfixvec(_fix, _vec, _binary):
15191524
""" Vector of fixed-point numbers for parallel binary computation.
15201525
15211526
Use :py:obj:`set_precision()` to change the precision.

Compiler/allocator.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def alloc(self, size):
7676
self.top += size
7777
self.limit = max(self.limit, self.top)
7878
if res >= REG_MAX:
79-
raise RegisterOverflowError()
79+
raise RegisterOverflowError(size)
8080
return res
8181

8282
def free(self, base, size):
@@ -209,7 +209,8 @@ def dealloc_reg(self, reg, inst, free):
209209
for x in itertools.chain(dup.duplicates, base.duplicates):
210210
to_check.add(x)
211211

212-
if reg not in self.program.base_addresses:
212+
if reg not in self.program.base_addresses \
213+
and not isinstance(inst, call_arg):
213214
free.free(base)
214215
if inst.is_vec() and base.vector:
215216
self.defined[base] = inst
@@ -608,7 +609,8 @@ def keep_text_order(inst, n):
608609
# so this threshold should lead to acceptable compile times even on slower processors.
609610
first_factor_total_number_of_values = instr.args[12 * matmul_idx + 3] * instr.args[12 * matmul_idx + 4]
610611
second_factor_total_number_of_values = instr.args[12 * matmul_idx + 4] * instr.args[12 * matmul_idx + 5]
611-
max_dependencies_per_matrix = 1500**2
612+
max_dependencies_per_matrix = \
613+
self.block.parent.program.budget
612614
if first_factor_total_number_of_values > max_dependencies_per_matrix or second_factor_total_number_of_values > max_dependencies_per_matrix:
613615
if block.warn_about_mem and not block.parent.warned_about_mem:
614616
print('WARNING: Order of memory instructions not preserved due to long vector, errors possible')

Compiler/circuit.py

+13-5
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
make Programs/Circuits
77
8-
.. _`Bristol Fashion`: https://homes.esat.kuleuven.be/~nsmart/MPC
8+
.. _`Bristol Fashion`: https://nigelsmart.github.io/MPC-Circuits
99
1010
"""
1111
import math
@@ -15,6 +15,7 @@
1515
from Compiler import util
1616
import itertools
1717
import struct
18+
import os
1819

1920
class Circuit:
2021
"""
@@ -47,7 +48,12 @@ class Circuit:
4748
"""
4849

4950
def __init__(self, name):
51+
self.name = name
5052
self.filename = 'Programs/Circuits/%s.txt' % name
53+
if not os.path.exists(self.filename):
54+
if os.system('make Programs/Circuits'):
55+
raise CompilerError('Cannot download circuit descriptions. '
56+
'Make sure make and git are installed.')
5157
f = open(self.filename)
5258
self.functions = {}
5359

@@ -57,8 +63,9 @@ def __call__(self, *inputs):
5763
def run(self, *inputs):
5864
n = inputs[0][0].n, get_tape()
5965
if n not in self.functions:
60-
self.functions[n] = function_block(lambda *args:
61-
self.compile(*args))
66+
self.functions[n] = function_block(
67+
lambda *args: self.compile(*args))
68+
self.functions[n].name = '%s(%d)' % (self.name, inputs[0][0].n)
6269
flat_res = self.functions[n](*itertools.chain(*inputs))
6370
res = []
6471
i = 0
@@ -124,7 +131,7 @@ def compile(self, *all_inputs):
124131

125132
def sha3_256(x):
126133
"""
127-
This function implements SHA3-256 for inputs of up to 1080 bits::
134+
This function implements SHA3-256 for inputs of any length::
128135
129136
from circuit import sha3_256
130137
a = sbitvec.from_vec([])
@@ -138,7 +145,8 @@ def sha3_256(x):
138145
for x in a, b, c, d, e, f, g, h:
139146
sha3_256(x).reveal_print_hex()
140147
141-
This should output the `test vectors
148+
This should output the hashes of the above inputs, beginning with
149+
the `test vectors
142150
<https://github.com/XKCP/XKCP/blob/master/tests/TestVectors/ShortMsgKAT_SHA3-256.txt>`_
143151
of SHA3-256 for 0, 8, 16, and 24 bits as well as the hash of the
144152
0 byte::

0 commit comments

Comments
 (0)