Distributed key generation for homomorphic encryption with active security.

This commit is contained in:
Marcel Keller
2021-02-23 17:40:05 +11:00
parent 08a80cfbda
commit c9b03d8b51
136 changed files with 2122 additions and 497 deletions

View File

@@ -1,6 +1,14 @@
The changelog explains changes pulled through from the private development repository. Bug fixes and small enhancements are committed between releases and not documented here.
## 0.2.2 (Jan 21, 2020)
## 0.2.3 (Feb 23, 2021)
- Distributed key generation for homomorphic encryption with active security similar to [Rotaru et al.](https://eprint.iacr.org/2019/1300)
- Homomorphic encryption parameters more similar to SCALE-MAMBA
- Fixed security bug: all-zero secret keys in homomorphic encryption
- Fixed security bug: missing check in binary Rep4
- Fixed security bug: insufficient "blaming" (covert security) in CowGear and HighGear due to low default security parameter
## 0.2.2 (Jan 21, 2021)
- Infrastructure for random element generation
- Programs generating as much preprocessing data as required by a particular high-level program

View File

@@ -490,6 +490,9 @@ class bitb(NonVectorInstruction):
code = opcodes['BITB']
arg_format = ['sbw']
def add_usage(self, req_node):
req_node.increment(('bit', 'bit'), 1)
class reveal(BinaryVectorInstruction, base.VarArgsInstruction, base.Mergeable):
""" Reveal secret bit register vectors and copy result to clear bit
register vectors.
@@ -519,6 +522,10 @@ class inputb(base.DoNotEliminateInstruction, base.VarArgsInstruction):
arg_format = tools.cycle(['p','int','int','sbw'])
is_vec = lambda self: True
def add_usage(self, req_node):
for i in range(0, len(self.args), 4):
req_node.increment(('bit', 'input', self.args[0]), self.args[1])
class inputbvec(base.DoNotEliminateInstruction, base.VarArgsInstruction,
base.Mergeable):
""" Copy private input to secret bit registers bit by bit. The input is
@@ -538,17 +545,26 @@ class inputbvec(base.DoNotEliminateInstruction, base.VarArgsInstruction,
def __init__(self, *args, **kwargs):
self.arg_format = []
for x in self.get_arg_tuples(args):
self.arg_format += ['int', 'int', 'p'] + ['sbw'] * (x[0] - 3)
super(inputbvec, self).__init__(*args, **kwargs)
@staticmethod
def get_arg_tuples(args):
i = 0
while i < len(args):
self.arg_format += ['int', 'int', 'p'] + ['sbw'] * (args[i] - 3)
yield args[i:i+args[i]]
i += args[i]
assert i == len(args)
super(inputbvec, self).__init__(*args, **kwargs)
def merge(self, other):
self.args += other.args
self.arg_format += other.arg_format
def add_usage(self, req_node):
for x in self.get_arg_tuples(self.args):
req_node.increment(('bit', 'input', x[2]), x[0] - 3)
class print_regb(base.VectorInstruction, base.IOInstruction):
""" Debug output of clear bit register.

View File

@@ -371,6 +371,14 @@ class Merger:
# hack
warned_about_mem.append(True)
def strict_mem_access(n, last_this_kind, last_other_kind):
if last_other_kind and last_this_kind and \
last_other_kind[-1] > last_this_kind[-1]:
last_this_kind[:] = []
last_this_kind.append(n)
for i in last_other_kind:
add_edge(i, n)
def keep_order(instr, n, t, arg_index=None):
if arg_index is None:
player = None
@@ -444,26 +452,17 @@ class Merger:
if isinstance(instr, ReadMemoryInstruction):
if options.preserve_mem_order:
if last_mem_write and last_mem_read and last_mem_write[-1] > last_mem_read[-1]:
last_mem_read[:] = []
last_mem_read.append(n)
for i in last_mem_write:
add_edge(i, n)
strict_mem_access(n, last_mem_read, last_mem_write)
else:
mem_access(n, instr, last_mem_read_of, last_mem_write_of)
elif isinstance(instr, WriteMemoryInstruction):
if options.preserve_mem_order:
if last_mem_write and last_mem_read and last_mem_write[-1] < last_mem_read[-1]:
last_mem_write[:] = []
last_mem_write.append(n)
for i in last_mem_read:
add_edge(i, n)
strict_mem_access(n, last_mem_write, last_mem_read)
else:
mem_access(n, instr, last_mem_write_of, last_mem_read_of)
elif isinstance(instr, matmulsm):
if options.preserve_mem_order:
for i in last_mem_write:
add_edge(i, n)
strict_mem_access(n, last_mem_read, last_mem_write)
else:
for i in last_mem_write_of.values():
for j in i:

View File

@@ -452,6 +452,11 @@ def CarryOutRaw(a, b, c=0):
assert len(a) == len(b)
k = len(a)
from . import types
if program.linear_rounds():
carry = 0
for (ai, bi) in zip(a, b):
carry = bi.carry_out(ai, carry)
return carry
d = [program.curr_block.new_reg('s') for i in range(k)]
s = [program.curr_block.new_reg('s') for i in range(3)]
for i in range(k):

View File

@@ -627,15 +627,14 @@ class Dense(DenseBase):
:param d_out: output dimension
"""
def __init__(self, N, d_in, d_out, d=1, activation='id', debug=False):
self.activation = activation
if activation == 'id':
self.f = lambda x: x
self.activation_layer = None
elif activation == 'relu':
self.f = relu
self.f_prime = relu_prime
elif activation == 'sigmoid':
self.f = sigmoid
self.f_prime = sigmoid_prime
self.activation_layer = Relu([N, d, d_out])
elif activation == 'square':
self.activation_layer = Square([N, d, d_out])
else:
raise CompilerError('activation not supported: %s', activation)
self.N = N
self.d_in = d_in
@@ -652,10 +651,16 @@ class Dense(DenseBase):
self.nabla_W = sfix.Matrix(d_in, d_out)
self.nabla_b = sfix.Array(d_out)
self.f_input = MultiArray([N, d, d_out], sfix)
self.debug = debug
l = self.activation_layer
if l:
self.f_input = l.X
l.Y = self.Y
l.nabla_Y = self.nabla_Y
else:
self.f_input = self.Y
def reset(self):
d_in = self.d_in
d_out = self.d_out
@@ -699,10 +704,8 @@ class Dense(DenseBase):
def forward(self, batch=None):
self.compute_f_input(batch=batch)
@multithread(self.n_threads, len(batch), 128)
def _(base, size):
self.Y.assign_part_vector(self.f(
self.f_input.get_part_vector(base, size)), base)
if self.activation_layer:
self.activation_layer.forward(batch)
if self.debug:
limit = self.debug
@for_range_opt(len(batch))
@@ -731,26 +734,11 @@ class Dense(DenseBase):
nabla_W = self.nabla_W
nabla_b = self.nabla_b
if self.activation == 'id':
f_schur_Y = nabla_Y
if self.activation_layer:
self.activation_layer.backward(batch)
f_schur_Y = self.activation_layer.nabla_X
else:
f_prime_bit = MultiArray([N, d, d_out], sint)
f_schur_Y = MultiArray([N, d, d_out], sfix)
@multithread(self.n_threads, f_prime_bit.total_size())
def _(base, size):
f_prime_bit.assign_vector(
self.f_prime(self.f_input.get_vector(base, size)), base)
progress('f prime')
@multithread(self.n_threads, f_prime_bit.total_size())
def _(base, size):
f_schur_Y.assign_vector(nabla_Y.get_vector(base, size) *
f_prime_bit.get_vector(base, size),
base)
progress('f prime schur Y')
f_schur_Y = nabla_Y
if compute_nabla_X:
@multithread(self.n_threads, N)
@@ -841,35 +829,55 @@ class Dropout:
def backward(self):
self.nabla_X = self.nabla_Y.schur(self.B)
class Relu(NoVariableLayer):
class ElementWiseLayer(NoVariableLayer):
def __init__(self, shape, inputs=None):
self.X = Tensor(shape, sfix)
self.Y = Tensor(shape, sfix)
self.nabla_X = Tensor(shape, sfix)
self.nabla_Y = Tensor(shape, sfix)
self.inputs = inputs
def forward(self, batch=[0]):
@multithread(self.n_threads, len(batch), 128)
def _(base, size):
self.Y.assign_part_vector(self.f(
self.X.get_part_vector(base, size)), base)
def backward(self, batch):
f_prime_bit = MultiArray(self.X.sizes, self.prime_type)
@multithread(self.n_threads, f_prime_bit.total_size())
def _(base, size):
f_prime_bit.assign_vector(
self.f_prime(self.X.get_vector(base, size)), base)
progress('f prime')
@multithread(self.n_threads, f_prime_bit.total_size())
def _(base, size):
self.nabla_X.assign_vector(self.nabla_Y.get_vector(base, size) *
f_prime_bit.get_vector(base, size),
base)
progress('f prime schur Y')
class Relu(ElementWiseLayer):
""" Fixed-point ReLU layer.
:param shape: input/output shape (tuple/list of int)
"""
def __init__(self, shape, inputs=None):
self.X = Tensor(shape, sfix)
self.Y = Tensor(shape, sfix)
self.inputs = inputs
f = staticmethod(relu)
f_prime = staticmethod(relu_prime)
prime_type = sint
def forward(self, batch=[0]):
assert len(batch) == 1
@multithread(self.n_threads, self.X[batch[0]].total_size())
def _(base, size):
tmp = relu(self.X[batch[0]].get_vector(base, size))
self.Y[batch[0]].assign_vector(tmp, base)
class Square(NoVariableLayer):
class Square(ElementWiseLayer):
""" Fixed-point square layer.
:param shape: input/output shape (tuple/list of int)
"""
def __init__(self, shape):
self.X = MultiArray(shape, sfix)
self.Y = MultiArray(shape, sfix)
def forward(self, batch=[0]):
assert len(batch) == 1
self.Y.assign_vector(self.X.get_part_vector(batch[0]) ** 2)
f = staticmethod(lambda x: x ** 2)
f_prime = staticmethod(lambda x: cfix(2, size=x.size) * x)
prime_type = sfix
class MaxPool(NoVariableLayer):
""" Fixed-point MaxPool layer.

View File

@@ -150,6 +150,7 @@ class Program(object):
self.use_split(int(options.split))
self._square = False
self._always_raw = False
self._linear_rounds = False
self.warn_about_mem = [True]
Program.prog = self
from . import instructions_base, instructions, types, comparison
@@ -461,6 +462,12 @@ class Program(object):
else:
self._always_raw = change
def linear_rounds(self, change=None):
if change is None:
return self._linear_rounds
else:
self._linear_rounds = change
def options_from_args(self):
""" Set a number of options from the command-line arguments. """
if 'trunc_pr' in self.args:
@@ -475,6 +482,8 @@ class Program(object):
self.always_raw(True)
if 'edabit' in self.args:
self.use_edabit(True)
if 'linear_rounds' in self.args:
self.linear_rounds(True)
def disable_memory_warnings(self):
self.warn_about_mem.append(False)
@@ -855,7 +864,9 @@ class Tape:
filename = self.program.programs_dir + '/Bytecode/' + filename
print('Writing to', filename)
f = open(filename, 'wb')
f.write(self.get_bytes())
for i in self._get_instructions():
if i is not None:
f.write(i.get_bytes())
f.close()
def new_reg(self, reg_type, size=None):

View File

@@ -267,7 +267,7 @@ class _number(object):
def __pow__(self, exp):
""" Exponentation through square-and-multiply.
:param exp: compile-time (int) """
:param exp: any type allowing bit decomposition """
if isinstance(exp, int) and exp >= 0:
if exp == 0:
return self.__class__(1)
@@ -425,6 +425,10 @@ class _bit(object):
:rtype: depending on inputs (secret if any of them is) """
return self ^ other, self & other
def carry_out(self, a, b):
s = a ^ b
return a ^ (s & (self ^ a))
class _gf2n(_bit):
""" :math:`\mathrm{GF}(2^n)` functionality. """
@@ -5247,6 +5251,7 @@ class MemValue(_mem):
bit_decompose = lambda self,*args,**kwargs: self.read().bit_decompose(*args, **kwargs)
if_else = lambda self,*args,**kwargs: self.read().if_else(*args, **kwargs)
bit_and = lambda self,other: self.read().bit_and(other)
def expand_to_vector(self, size=None):
if program.curr_block == self.last_write_block:

View File

@@ -35,13 +35,14 @@ int DiscreteGauss::sample(PRNG &G, int stretch) const
void RandomVectors::set(int nn,int hh,double R)
{
n=nn;
if (hh > 0)
h=hh;
h=hh;
DG.set(R);
assert(h > 0);
}
void RandomVectors::set_n(int nn)
{
n = nn;
}
vector<bigint> RandomVectors::sample_Gauss(PRNG& G, int stretch) const
{
@@ -54,8 +55,7 @@ vector<bigint> RandomVectors::sample_Gauss(PRNG& G, int stretch) const
vector<bigint> RandomVectors::sample_Hwt(PRNG& G) const
{
assert(h > 0);
if (h>n/2) { return sample_Gauss(G); }
if (h > n/2 or h <= 0) { return sample_Gauss(G); }
vector<bigint> ans(n);
for (int i=0; i<n; i++) { ans[i]=0; }
int cnt=0,j=0;

View File

@@ -48,10 +48,11 @@ class RandomVectors
public:
void set(int nn,int hh,double R); // R is input STANDARD DEVIATION
void set_n(int nn);
void pack(octetStream& o) const { o.store(n); o.store(h); DG.pack(o); }
void unpack(octetStream& o)
{ o.get(n); o.get(h); DG.unpack(o); if(h <= 0) throw exception(); }
{ o.get(n); o.get(h); DG.unpack(o); }
RandomVectors(int h, double R) : RandomVectors(0, h, R) {}
RandomVectors(int nn,int hh,double R) : DG(R) { set(nn,hh,R); }
@@ -61,6 +62,7 @@ class RandomVectors
double get_R() const { return DG.get_R(); }
DiscreteGauss get_DG() const { return DG; }
int get_h() const { return h; }
// Sample from Discrete Gauss distribution
vector<bigint> sample_Gauss(PRNG& G, int stretch = 1) const;

View File

@@ -191,6 +191,13 @@ void FFT2(vector<modp>& a, int N, const modp& alpha, const Zp_Data& PrD)
}
void FFT_non_power_of_two(vector<modp>& res, const vector<modp>& input, const FFT_Data& FFTD)
{
vector<modp> tmp(FFTD.m());
BFFT(tmp, input, FFTD);
for (int i = 0; i < (FFTD).phi_m(); i++)
res[i] = tmp[(FFTD).p(i)];
}
void BFFT(vector<modp>& ans,const vector<modp>& a,const FFT_Data& FFTD,bool forward)
{

View File

@@ -50,6 +50,8 @@ void FFT_Iter2(vector<modp>& a,int N,const modp& theta,const Zp_Data& PrD);
void BFFT(vector<modp>& ans,const vector<modp>& a,const FFT_Data& FFTD,bool forward=true);
void FFT_non_power_of_two(vector<modp>& res, const vector<modp>& input,
const FFT_Data& FFTD);
/* Computes the FFT via Horner's Rule
theta is assumed to be an Nth root of unity

View File

@@ -13,12 +13,16 @@ FHE_SK::FHE_SK(const FHE_PK& pk) : FHE_SK(pk.get_params(), pk.p())
}
void add(FHE_SK& a,const FHE_SK& b,const FHE_SK& c)
FHE_SK& FHE_SK::operator+=(const FHE_SK& c)
{
if (a.params!=b.params) { throw params_mismatch(); }
auto& a = *this;
auto& b = *this;
if (a.params!=c.params) { throw params_mismatch(); }
add(a.sk,b.sk,c.sk);
::add(a.sk,b.sk,c.sk);
return *this;
}
@@ -84,7 +88,7 @@ void FHE_PK::KeyGen(Rq_Element& sk, PRNG& G, int noise_boost)
}
}
void FHE_PK::check_noise(const FHE_SK& SK)
void FHE_PK::check_noise(const FHE_SK& SK) const
{
Rq_Element sk = SK.s();
if (params->n_mults() > 0)
@@ -92,7 +96,7 @@ void FHE_PK::check_noise(const FHE_SK& SK)
check_noise(b0 - a0 * sk);
}
void FHE_PK::check_noise(const Rq_Element& x, bool check_modulo)
void FHE_PK::check_noise(const Rq_Element& x, bool check_modulo) const
{
assert(pr != 0);
vector<bigint> noise = x.to_vec_bigint();
@@ -162,6 +166,7 @@ void FHE_PK::quasi_encrypt(Ciphertext& c,
{
if (&c.get_params()!=params) { throw params_mismatch(); }
if (&rc.get_params()!=params) { throw params_mismatch(); }
assert(pr != 0);
Rq_Element ed,edd,c0,c1,aa;
@@ -332,8 +337,11 @@ void FHE_PK::pack(octetStream& o) const
o.append((octet*) "PKPKPKPK", 8);
a0.pack(o);
b0.pack(o);
Sw_a.pack(o);
Sw_b.pack(o);
if (params->n_mults() > 0)
{
Sw_a.pack(o);
Sw_b.pack(o);
}
pr.pack(o);
}
@@ -345,8 +353,11 @@ void FHE_PK::unpack(octetStream& o)
throw runtime_error("invalid serialization of public key");
a0.unpack(o);
b0.unpack(o);
Sw_a.unpack(o);
Sw_b.unpack(o);
if (params->n_mults() > 0)
{
Sw_a.unpack(o);
Sw_b.unpack(o);
}
pr.unpack(o);
}
@@ -376,14 +387,30 @@ void FHE_SK::check(const FHE_Params& params, const FHE_PK& pk,
}
template<class FD>
void FHE_SK::check(const FHE_PK& pk, const FD& FieldD)
{
check(*params, pk, pr);
pk.check_noise(*this);
if (decrypt(pk.encrypt(Plaintext_<FD>(FieldD)), FieldD) !=
Plaintext_<FD>(FieldD))
throw runtime_error("incorrect key pair");
}
void FHE_PK::check(const FHE_Params& params, const bigint& pr) const
{
if (this->pr != pr)
throw pr_mismatch();
a0.check(params);
b0.check(params);
Sw_a.check(params);
Sw_b.check(params);
if (params.n_mults() > 0)
{
Sw_a.check(params);
Sw_b.check(params);
}
}
@@ -402,3 +429,6 @@ template void FHE_SK::decrypt_any(Plaintext_<FFT_Data>& res,
const Ciphertext& c);
template void FHE_SK::decrypt_any(Plaintext_<P2Data>& res,
const Ciphertext& c);
template void FHE_SK::check(const FHE_PK& pk, const FFT_Data&);
template void FHE_SK::check(const FHE_PK& pk, const P2Data&);

View File

@@ -20,6 +20,8 @@ class FHE_SK
public:
static int size() { return 0; }
const FHE_Params& get_params() const { return *params; }
bigint p() const { return pr; }
@@ -63,18 +65,24 @@ class FHE_SK
friend void KeyGen(FHE_PK& PK,FHE_SK& SK,PRNG& G);
/* Add secret key onto the existing one
/* Add secret keys
* Used for adding distributed keys together
* a,b,c must have same params otherwise an error
*/
friend void add(FHE_SK& a,const FHE_SK& b,const FHE_SK& c);
FHE_SK operator+(const FHE_SK& x) { FHE_SK res(*params, pr); add(res, *this, x); return res; }
FHE_SK& operator+=(const FHE_SK& x) { add(*this, *this, x); return *this; }
FHE_SK operator+(const FHE_SK& x) const { FHE_SK res = *this; res += x; return res; }
FHE_SK& operator+=(const FHE_SK& x);
bool operator!=(const FHE_SK& x) { return pr != x.pr or sk != x.sk; }
bool operator!=(const FHE_SK& x) const { return pr != x.pr or sk != x.sk; }
void add(octetStream& os) { FHE_SK tmp(*this); tmp.unpack(os); *this += tmp; }
void check(const FHE_Params& params, const FHE_PK& pk, const bigint& pr) const;
template<class FD>
void check(const FHE_PK& pk, const FD& FieldD);
friend ostream& operator<<(ostream& o, const FHE_SK&) { throw not_implemented(); return o; }
};
@@ -92,7 +100,7 @@ class FHE_PK
bigint p() const { return pr; }
void assign(const Rq_Element& a,const Rq_Element& b,
const Rq_Element& sa,const Rq_Element& sb
const Rq_Element& sa = {},const Rq_Element& sb = {}
)
{ a0=a; b0=b; Sw_a=sa; Sw_b=sb; }
@@ -143,8 +151,8 @@ class FHE_PK
Rq_Element sample_secret_key(PRNG& G);
void KeyGen(Rq_Element& sk, PRNG& G, int noise_boost = 1);
void check_noise(const FHE_SK& sk);
void check_noise(const Rq_Element& x, bool check_modulo = false);
void check_noise(const FHE_SK& sk) const;
void check_noise(const Rq_Element& x, bool check_modulo = false) const;
// params setting is done out of these IO/pack/unpack functions
void pack(octetStream& o) const;

View File

@@ -3,9 +3,16 @@
#include "FHE/Ring_Element.h"
#include "Tools/Exceptions.h"
void FHE_Params::set(const Ring& R,
const vector<bigint>& primes,double r,int hwt)
{
set(R, primes);
Chi.set(R.phi_m(),hwt,r);
}
void FHE_Params::set(const Ring& R,
const vector<bigint>& primes)
{
if (primes.size() != FFTData.size())
throw runtime_error("wrong number of primes");
@@ -13,8 +20,7 @@ void FHE_Params::set(const Ring& R,
for (size_t i = 0; i < FFTData.size(); i++)
FFTData[i].init(R,primes[i]);
Chi.set(R.phi_m(),hwt,r);
Chi.set_n(R.phi_m());
set_sec(40);
}

View File

@@ -29,14 +29,16 @@ class FHE_Params
public:
FHE_Params(int n_mults = 1) : FFTData(n_mults + 1), Chi(64, 0.7), sec_p(-1) {}
FHE_Params(int n_mults = 1) : FFTData(n_mults + 1), Chi(-1, 0.7), sec_p(-1) {}
int n_mults() const { return FFTData.size() - 1; }
// Rely on default copy assignment/constructor (not that they should
// ever be needed)
void set(const Ring& R,const vector<bigint>& primes,double r=-1,int hwt=-1);
void set(const Ring& R,const vector<bigint>& primes,double r,int hwt);
void set(const Ring& R,const vector<bigint>& primes);
void set(const vector<bigint>& primes);
void set_sec(int sec);
vector<bigint> sampleGaussian(PRNG& G, int noise_boost = 1) const
@@ -57,7 +59,9 @@ class FHE_Params
int secp() const { return sec_p; }
const bigint& B() const { return Bval; }
double get_R() const { return Chi.get_R(); }
void set_R(double R) const { return Chi.get_DG().set(R); }
DiscreteGauss get_DG() const { return Chi.get_DG(); }
int get_h() const { return Chi.get_h(); }
int phi_m() const { return FFTData[0].phi_m(); }
const Ring& get_ring() { return FFTData[0].get_R(); }

View File

@@ -55,13 +55,14 @@ int generate_semi_setup(int plaintext_length, int sec,
while (true)
{
SemiHomomorphicNoiseBounds nb(p, phi_N(m), 1, sec,
numBits(NonInteractiveProof::slack(sec, phi_N(m))), true);
numBits(NonInteractiveProof::slack(sec, phi_N(m))), true, params);
bigint p1 = 2 * p * m, p0 = p;
while (nb.min_p0(params.n_mults() > 0, p1) > p0)
{
p0 *= 2;
}
if (phi_N(m) < nb.min_phi_m(2 + 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)),
params.get_R()))
{
m *= 2;
generate_prime(p, lgp, m);
@@ -91,7 +92,7 @@ int generate_semi_setup(int plaintext_length, int sec,
int m;
char_2_dimension(m, plaintext_length);
SemiHomomorphicNoiseBounds nb(2, phi_N(m), 1, sec,
numBits(NonInteractiveProof::slack(sec, phi_N(m))), true);
numBits(NonInteractiveProof::slack(sec, phi_N(m))), true, params);
int lgp0 = numBits(nb.min_p0(false, 0));
int extra_slack = common_semi_setup(params, m, 2, lgp0, -1, round_up);
load_or_generate(P2D, params.get_ring());
@@ -111,7 +112,7 @@ int common_semi_setup(FHE_Params& params, int m, bigint p, int lgp0, int lgp1, b
int i;
for (i = 0; i <= 20; i++)
{
if (SemiHomomorphicNoiseBounds::min_phi_m(lgp0 + i) > phi_N(m))
if (SemiHomomorphicNoiseBounds::min_phi_m(lgp0 + i, params) > phi_N(m))
break;
if (not same_word_length(lgp0, lgp0 + i))
break;
@@ -138,7 +139,8 @@ int common_semi_setup(FHE_Params& params, int m, bigint p, int lgp0, int lgp1, b
return extra_slack;
}
int finalize_lengths(int& lg2p0, int& lg2p1, int n, int m, int* lg2pi, bool round_up)
int finalize_lengths(int& lg2p0, int& lg2p1, int n, int m, int* lg2pi,
bool round_up, FHE_Params& params)
{
if (n >= 2 and n <= 10)
cout << "Difference to suggestion for p0: " << lg2p0 - lg2pi[n - 2]
@@ -152,7 +154,7 @@ int finalize_lengths(int& lg2p0, int& lg2p1, int n, int m, int* lg2pi, bool roun
int i = 0;
for (i = 0; i < 10; i++)
{
if (phi_N(m) < NoiseBounds::min_phi_m(lg2p0 + lg2p1 + 2 * i))
if (phi_N(m) < NoiseBounds::min_phi_m(lg2p0 + lg2p1 + 2 * i, params))
break;
if (not same_word_length(lg2p0 + i, lg2p0))
break;
@@ -183,7 +185,8 @@ int finalize_lengths(int& lg2p0, int& lg2p1, int n, int m, int* lg2pi, bool roun
/*
* Subroutine for creating the FHE parameters
*/
int Parameters::SPDZ_Data_Setup_Char_p_Sub(int idx, int& m, bigint& p)
int Parameters::SPDZ_Data_Setup_Char_p_Sub(int idx, int& m, bigint& p,
FHE_Params& params)
{
int n = n_parties;
int lg2pi[5][2][9]
@@ -211,7 +214,7 @@ int Parameters::SPDZ_Data_Setup_Char_p_Sub(int idx, int& m, bigint& p)
while (sec != -1)
{
double phi_m_bound =
NoiseBounds(p, phi_N(m), n, sec, slack).optimize(lg2p0, lg2p1);
NoiseBounds(p, phi_N(m), n, sec, slack, params).optimize(lg2p0, lg2p1);
cout << "Trying primes of length " << lg2p0 << " and " << lg2p1 << endl;
if (phi_N(m) < phi_m_bound)
{
@@ -226,7 +229,7 @@ int Parameters::SPDZ_Data_Setup_Char_p_Sub(int idx, int& m, bigint& p)
init(R,m);
int extra_slack = finalize_lengths(lg2p0, lg2p1, n, m, lg2pi[idx][0],
round_up);
round_up, params);
generate_moduli(pr0, pr1, m, p, lg2p0, lg2p1);
return extra_slack;
}
@@ -241,8 +244,6 @@ void generate_moduli(bigint& pr0, bigint& pr1, const int m, const bigint p,
void generate_modulus(bigint& pr, const int m, const bigint p, const int lg2pr,
const string& i, const bigint& pr0)
{
int ex;
if (lg2pr==0) { throw invalid_params(); }
bigint step=m;
@@ -250,15 +251,20 @@ void generate_modulus(bigint& pr, const int m, const bigint p, const int lg2pr,
bigint gc=gcd(step,twop);
step=step*twop/gc;
ex=lg2pr-numBits(p)-numBits(step)+1;
if (ex<0) { cout << "Something wrong in lg2p" << i << " = " << lg2pr << endl; abort(); }
pr=1; pr=(pr<<ex)*p*step+1;
while (!probPrime(pr) || pr==pr0 || numBits(pr)<lg2pr) { pr=pr+p*step; }
step *= p;
pr = (bigint(1) << lg2pr) / step * step + 1;
while (pr == pr0 || !probPrime(pr))
{
pr -= step;
assert(numBits(pr) == lg2pr);
}
cout << "\t pr" << i << " = " << pr << " : " << numBits(pr) << endl;
cout << "\t\tFollowing should be both 1" << endl;
cout << "\t\tpr" << i << " mod m = " << pr%m << endl;
cout << "\t\tpr" << i << " mod p = " << pr%p << endl;
assert(pr % m == 1);
assert(pr % p == 1);
assert(numBits(pr) == lg2pr);
cout << "Minimal MAX_MOD_SZ = " << int(ceil(1. * lg2pr / 64)) << endl;
}
@@ -267,12 +273,12 @@ void generate_modulus(bigint& pr, const int m, const bigint p, const int lg2pr,
* Create the char p FHE parameters
*/
template <>
void Parameters::SPDZ_Data_Setup(FFT_Data& FTD)
void Parameters::SPDZ_Data_Setup(FHE_Params& params, FFT_Data& FTD)
{
bigint p;
int idx, m;
SPDZ_Data_Setup_Primes(p, plaintext_length, idx, m);
SPDZ_Data_Setup_Char_p_Sub(idx, m, p);
SPDZ_Data_Setup_Char_p_Sub(idx, m, p, params);
Zp_Data Zp(p);
gfp::init_field(p);
@@ -569,7 +575,7 @@ void char_2_dimension(int& m, int& lg2)
}
template <>
void Parameters::SPDZ_Data_Setup(P2Data& P2D)
void Parameters::SPDZ_Data_Setup(FHE_Params& params, P2Data& P2D)
{
int n = n_parties;
int lg2 = plaintext_length;
@@ -593,11 +599,11 @@ void Parameters::SPDZ_Data_Setup(P2Data& P2D)
}
else
{
NoiseBounds(2, phi_N(m), n, sec, slack).optimize(lg2p0, lg2p1);
finalize_lengths(lg2p0, lg2p1, n, m, lg2pi[0], round_up);
NoiseBounds(2, phi_N(m), n, sec, slack, params).optimize(lg2p0, lg2p1);
finalize_lengths(lg2p0, lg2p1, n, m, lg2pi[0], round_up, params);
}
if (NoiseBounds::min_phi_m(lg2p0 + lg2p1) > phi_N(m))
if (NoiseBounds::min_phi_m(lg2p0 + lg2p1, params) > phi_N(m))
throw runtime_error("number of slots too small");
cout << "m = " << m << endl;
@@ -651,7 +657,7 @@ void load_or_generate(P2Data& P2D, const Ring& R)
* Basically this is for general large primes only
*/
void SPDZ_Data_Setup_Char_p_General(Ring& R, PPData& PPD, bigint& pr0,
bigint& pr1, int n, int sec, bigint& p)
bigint& pr1, int n, int sec, bigint& p, FHE_Params& params)
{
cout << "Setting up parameters" << endl;
@@ -758,7 +764,7 @@ void SPDZ_Data_Setup_Char_p_General(Ring& R, PPData& PPD, bigint& pr0,
cout << "Chosen value of m=" << m << "\t\t phi(m)=" << bphi_m << " : " << min_hwt << " : " << bmx << endl;
Parameters parameters(n, lgp, sec);
parameters.SPDZ_Data_Setup_Char_p_Sub(idx,m,p);
parameters.SPDZ_Data_Setup_Char_p_Sub(idx,m,p,params);
int mx=0;
for (int i=0; i<R.phi_m(); i++)
{ if (mx<R.Phi()[i]) { mx=R.Phi()[i]; } }

View File

@@ -35,14 +35,15 @@ public:
template<class FD>
void generate_setup(FHE_Params& params, FD& FTD)
{
SPDZ_Data_Setup(FTD);
SPDZ_Data_Setup(params, FTD);
params.set(R, {pr0, pr1});
}
template<class FD>
void SPDZ_Data_Setup(FD& FTD);
void SPDZ_Data_Setup(FHE_Params& params, FD& FTD);
int SPDZ_Data_Setup_Char_p_Sub(int idx, int& m, bigint& p);
int SPDZ_Data_Setup_Char_p_Sub(int idx, int& m, bigint& p,
FHE_Params& params);
};
@@ -65,7 +66,7 @@ void init(P2Data& P2D,const Ring& Rg);
// For use when we want p to be a specific value
void SPDZ_Data_Setup_Char_p_General(Ring& R, PPData& PPD, bigint& pr0,
bigint& pr1, int n, int sec, bigint& p);
bigint& pr1, int n, int sec, bigint& p, FHE_Params& params);
// generate moduli according to lengths and other parameters
void generate_moduli(bigint& pr0, bigint& pr1, const int m,

View File

@@ -8,52 +8,51 @@
#include "Protocols/CowGearOptions.h"
#include <math.h>
SemiHomomorphicNoiseBounds::SemiHomomorphicNoiseBounds(const bigint& p,
int phi_m, int n, int sec, int slack_param, bool extra_h, double sigma, int h) :
int phi_m, int n, int sec, int slack_param, bool extra_h,
const FHE_Params& params) :
p(p), phi_m(phi_m), n(n), sec(sec),
slack(numBits(Proof::slack(slack_param, sec, phi_m))), sigma(sigma), h(h)
slack(numBits(Proof::slack(slack_param, sec, phi_m))),
sigma(params.get_R()), h(params.get_h())
{
if (sigma <= 0)
this->sigma = sigma = FHE_Params().get_R();
#ifdef VERBOSE
cerr << "Standard deviation: " << this->sigma << endl;
#endif
h += extra_h * sec;
if (h > 0)
h += extra_h * sec;
else if (extra_h)
{
sigma *= 1.4;
params.set_R(params.get_R() * 1.4);
}
produce_epsilon_constants();
if (CowGearOptions::singleton.top_gear())
{
// according to documentation of SCALE-MAMBA 1.7
// excluding a factor of n because we don't always add up n ciphertexts
B_clean = (bigint(phi_m) << (sec + 2)) * p
* (20.5 + c1 * sigma * sqrt(phi_m) + 20 * c1 * sqrt(h));
mpf_class V_s;
if (h > 0)
V_s = sqrt(h);
else
V_s = sigma * sqrt(phi_m);
B_scale = (c1 + c2 * V_s) * p * sqrt(phi_m / 12.0);
#ifdef NOISY
cout << "p * sqrt(phi(m) / 12): " << p * sqrt(phi_m / 12.0) << endl;
cout << "V_s: " << V_s << endl;
cout << "c1: " << c1 << endl;
cout << "c2: " << c2 << endl;
cout << "c1 + c2 * V_s: " << c1 + c2 * V_s << endl;
cout << "B_scale: " << B_scale << endl;
#endif
}
// according to documentation of SCALE-MAMBA 1.7
// excluding a factor of n because we don't always add up n ciphertexts
if (h > 0)
V_s = sqrt(h);
else
{
B_clean = (phi_m * p / 2
+ p * sigma
* (16 * phi_m * sqrt(n / 2) + 6 * sqrt(phi_m)
+ 16 * sqrt(n * h * phi_m))) << slack;
B_scale = p * sqrt(3 * phi_m) * (1 + 8 * sqrt(n * h) / 3);
#ifdef VERBOSE
cout << "log(slack): " << slack << endl;
V_s = sigma * sqrt(phi_m);
B_clean = (bigint(phi_m) << (sec + 1)) * p
* (20.5 + c1 * sigma * sqrt(phi_m) + 20 * c1 * V_s);
// unify parameters by taking maximum over TopGear or not
bigint B_clean_top_gear = B_clean * 2;
bigint B_clean_not_top_gear = B_clean << int(ceil(sec / 2.));
B_clean = max(B_clean_not_top_gear, B_clean_top_gear);
B_scale = (c1 + c2 * V_s) * p * sqrt(phi_m / 12.0);
#ifdef NOISY
cout << "p * sqrt(phi(m) / 12): " << p * sqrt(phi_m / 12.0) << endl;
cout << "V_s: " << V_s << endl;
cout << "c1: " << c1 << endl;
cout << "c2: " << c2 << endl;
cout << "c1 + c2 * V_s: " << c1 + c2 * V_s << endl;
cout << "log(slack): " << slack << endl;
cout << "B_clean: " << B_clean << endl;
cout << "B_scale: " << B_scale << endl;
#endif
}
drown = 1 + n * (bigint(1) << sec);
}
@@ -77,6 +76,11 @@ double SemiHomomorphicNoiseBounds::min_phi_m(int log_q, double sigma)
return 37.8 * (log_q - log2(sigma));
}
double SemiHomomorphicNoiseBounds::min_phi_m(int log_q, const FHE_Params& params)
{
return min_phi_m(log_q, params.get_R());
}
void SemiHomomorphicNoiseBounds::produce_epsilon_constants()
{
double C[3];
@@ -104,21 +108,10 @@ void SemiHomomorphicNoiseBounds::produce_epsilon_constants()
}
NoiseBounds::NoiseBounds(const bigint& p, int phi_m, int n, int sec, int slack,
double sigma, int h) :
SemiHomomorphicNoiseBounds(p, phi_m, n, sec, slack, false, sigma, h)
const FHE_Params& params) :
SemiHomomorphicNoiseBounds(p, phi_m, n, sec, slack, false, params)
{
if (CowGearOptions::singleton.top_gear())
{
B_KS = p * c2 * this->sigma * phi_m / sqrt(12);
}
else
{
B_KS = p * phi_m * mpf_class(this->sigma)
* (pow(n, 2.5) * (1.49 * sqrt(h * phi_m) + 2.11 * h)
+ 2.77 * n * n * sqrt(h)
+ pow(n, 1.5) * (1.96 * sqrt(phi_m) * 2.77 * sqrt(h))
+ 4.62 * n);
}
B_KS = p * c2 * this->sigma * phi_m / sqrt(12);
#ifdef NOISY
cout << "p size: " << numBits(p) << endl;
cout << "phi(m): " << phi_m << endl;
@@ -197,5 +190,5 @@ double NoiseBounds::optimize(int& lg2p0, int& lg2p1)
}
lg2p1 = numBits(min_p1);
lg2p0 = numBits(min_p0);
return min_phi_m(lg2p0 + lg2p1);
return min_phi_m(lg2p0 + lg2p1, sigma.get_d());
}

View File

@@ -9,6 +9,7 @@
#include "Math/bigint.h"
int phi_N(int N);
class FHE_Params;
class SemiHomomorphicNoiseBounds
{
@@ -21,25 +22,27 @@ protected:
const int sec;
int slack;
mpf_class sigma;
const int h;
int h;
bigint B_clean;
bigint B_scale;
bigint drown;
mpf_class c1, c2;
mpf_class V_s;
void produce_epsilon_constants();
public:
SemiHomomorphicNoiseBounds(const bigint& p, int phi_m, int n, int sec,
int slack, bool extra_h = false, double sigma = -1, int h = 64);
int slack, bool extra_h, const FHE_Params& params);
// with scaling
bigint min_p0(const bigint& p1);
// without scaling
bigint min_p0();
bigint min_p0(bool scale, const bigint& p1) { return scale ? min_p0(p1) : min_p0(); }
static double min_phi_m(int log_q, double sigma = -1);
static double min_phi_m(int log_q, double sigma);
static double min_phi_m(int log_q, const FHE_Params& params);
};
// as per ePrint 2012:642 for slack = 0
@@ -49,7 +52,7 @@ class NoiseBounds : public SemiHomomorphicNoiseBounds
public:
NoiseBounds(const bigint& p, int phi_m, int n, int sec, int slack,
double sigma = -1, int h = 64);
const FHE_Params& params);
bigint U1(const bigint& p0, const bigint& p1);
bigint U2(const bigint& p0, const bigint& p1);
bigint min_p0(const bigint& p0, const bigint& p1);

View File

@@ -286,15 +286,21 @@ void Plaintext_<FFT_Data>::randomize(PRNG& G, bigint B, bool Diag, bool binary,
template<class T,class FD,class S>
void Plaintext<T,FD,S>::randomize(PRNG& G, int n_bits, bool Diag, bool binary, PT_Type t)
{
if (Diag or binary)
if (binary)
throw not_implemented();
allocate(t);
switch(t)
{
case Polynomial:
for (int i = 0; i < n_slots; i++)
b[i].generateUniform(G, n_bits, false);
if (Diag)
{
assign_zero(t);
b[0].generateUniform(G, n_bits, false);
}
else
for (int i = 0; i < n_slots; i++)
b[i].generateUniform(G, n_bits, false);
break;
default:
throw not_implemented();
@@ -638,6 +644,41 @@ bool Plaintext<T,FD,S>::equals(const Plaintext& x) const
return true;
}
template<>
bool Plaintext<gfp, FFT_Data, bigint>::is_diagonal() const
{
if (type != Evaluation)
{
for (size_t i = 1; i < b.size(); i++)
if (b[i] != 0)
return false;
}
if (type != Polynomial)
{
auto first = a[0];
for (auto& x : a)
if (x != first)
return false;
}
return true;
}
template<>
bool Plaintext<gf2n_short, P2Data, int>::is_diagonal() const
{
if (type == Polynomial)
from_poly();
auto first = a[0];
for (auto& x : a)
if (x != first)
return false;
return true;
}
template <class T,class FD,class S>

View File

@@ -176,7 +176,7 @@ class Plaintext
bool equals(const Plaintext& x) const;
bool operator!=(const Plaintext& x) { return !equals(x); }
bool is_diagonal() const { throw not_implemented(); }
bool is_diagonal() const;
bool is_binary() const { throw not_implemented(); }
/* Pack and unpack into an octetStream

View File

@@ -222,10 +222,7 @@ void Ring_Element::change_rep(RepType r)
}
else
{ // Non m power of two variant and FFT enabled
vector<modp> fft((*FFTD).m());
BFFT(fft,element,*FFTD);
for (int i=0; i<(*FFTD).phi_m(); i++)
{ element[i]=fft[(*FFTD).p(i)]; }
FFT_non_power_of_two(element, element, *FFTD);
}
}
else

View File

@@ -70,6 +70,16 @@ class Ring_Element
Ring_Element(const FFT_Data& prd,RepType r=polynomial);
template<class T>
Ring_Element(const FFT_Data& prd, RepType r, const vector<T>& other)
{
assert(size_t(prd.num_slots()) == other.size());
FFTD = &prd;
rep = r;
for (auto& x : other)
element.push_back(x);
}
// Copy Constructor
Ring_Element(const Ring_Element& e)
{ assign(e); }

View File

@@ -66,6 +66,9 @@ protected:
Rq_Element(const Ring_Element& b0,const Ring_Element& b1) :
a({b0, b1}), lev(n_mults()) {}
Rq_Element(const Ring_Element& b0) :
a({b0}), lev(n_mults()) {}
template<class T, class FD, class S>
Rq_Element(const FHE_Params& params, const Plaintext<T, FD, S>& plaintext) :
Rq_Element(params)
@@ -73,6 +76,15 @@ protected:
from(plaintext.get_iterator());
}
template<class U, class V>
Rq_Element(const vector<FFT_Data>& prd, const vector<U>& b0,
const vector<V>& b1, RepType r = evaluation) :
Rq_Element(prd, r, r)
{
a[0] = Ring_Element(prd[0], r, b0);
a[1] = Ring_Element(prd[1], r, b1);
}
// Destructor
~Rq_Element()
{ ; }
@@ -107,6 +119,7 @@ protected:
void Scale(const bigint& p);
bool equals(const Rq_Element& a) const;
bool operator==(const Rq_Element& a) const { return equals(a); }
bool operator!=(const Rq_Element& a) const { return !equals(a); }
int level() const { return lev; }

View File

@@ -241,67 +241,12 @@ void PartSetup<FD>::covert_mac_generation(Player& P, MachineBase&, int num_runs)
}
template<class FD>
void PartSetup<FD>::covert_secrets_generation(Player& P, MachineBase& machine,
int num_runs)
void PartSetup<FD>::key_and_mac_generation(Player& P,
MachineBase& machine, int num_runs, true_type)
{
read_or_generate_covert_secrets(*this, P, machine, num_runs);
}
template<class T, class U>
void read_or_generate_covert_secrets(T& setup, Player& P, U& machine,
int num_runs)
{
octetStream os;
setup.params.pack(os);
setup.FieldD.pack(os);
string filename = PREP_DIR + setup.covert_name() + "-Secrets-"
+ to_string(num_runs) + "-"
+ os.check_sum(20).get_str(16) + "-P" + to_string(P.my_num()) + "-"
+ to_string(P.num_players());
string error;
try
{
ifstream input(filename);
os.input(input);
setup.unpack(os);
machine.unpack(os);
}
catch (exception& e)
{
error = e.what();
}
try
{
setup.check(P, machine);
machine.check(P);
}
catch (mismatch_among_parties& e)
{
error = e.what();
}
if (not error.empty())
{
cerr << "Running secrets generation because " << error << endl;
setup.covert_key_generation(P, machine, num_runs);
setup.covert_mac_generation(P, machine, num_runs);
ofstream output(filename);
octetStream os;
setup.pack(os);
machine.pack(os);
os.output(output);
}
covert_key_generation(P, machine, num_runs);
covert_mac_generation(P, machine, num_runs);
}
template class PartSetup<FFT_Data>;
template class PartSetup<P2Data>;
template void read_or_generate_covert_secrets<PairwiseSetup<FFT_Data>,
PairwiseMachine>(PairwiseSetup<FFT_Data>&, Player&, PairwiseMachine&,
int);
template void read_or_generate_covert_secrets<PairwiseSetup<P2Data>,
PairwiseMachine>(PairwiseSetup<P2Data>&, Player&, PairwiseMachine&,
int);

View File

@@ -16,10 +16,6 @@ class DataSetup;
class MachineBase;
class MultiplicativeMachine;
template<class T, class U>
void read_or_generate_covert_secrets(T& setup, Player& P, U& machine,
int num_runs);
template <class FD>
class PartSetup
{
@@ -38,9 +34,12 @@ public:
return "GlobalParams-" + T::type_string();
}
static string covert_name()
static string protocol_name(bool covert)
{
return "ChaiGear";
if (covert)
return "ChaiGear";
else
return "HighGear";
}
PartSetup();
@@ -69,7 +68,11 @@ public:
void covert_key_generation(Player& P, MachineBase&, int num_runs);
void covert_mac_generation(Player& P, MachineBase&, int num_runs);
void covert_secrets_generation(Player& P, MachineBase& machine, int num_runs);
void key_and_mac_generation(Player& P, MachineBase& machine, int num_runs,
false_type);
void key_and_mac_generation(Player& P, MachineBase& machine, int num_runs,
true_type);
void output(Names& N);
};

63
FHEOffline/DataSetup.hpp Normal file
View File

@@ -0,0 +1,63 @@
/*
* DataSetup.hpp
*
*/
#ifndef FHEOFFLINE_DATASETUP_HPP_
#define FHEOFFLINE_DATASETUP_HPP_
#include "Networking/Player.h"
#include "Tools/Bundle.h"
template<class T, class U, class V>
void read_or_generate_secrets(T& setup, Player& P, U& machine,
int num_runs, V)
{
octetStream os;
setup.params.pack(os);
setup.FieldD.pack(os);
bool covert = num_runs > 0;
assert(covert == V());
string filename = PREP_DIR + setup.protocol_name(covert) + "-Secrets-"
+ (covert ? to_string(num_runs) : to_string(machine.sec)) + "-"
+ os.check_sum(20).get_str(16) + "-P" + to_string(P.my_num()) + "-"
+ to_string(P.num_players());
string error;
try
{
ifstream input(filename);
os.input(input);
setup.unpack(os);
machine.unpack(os);
}
catch (exception& e)
{
error = e.what();
}
try
{
setup.check(P, machine);
machine.check(P);
}
catch (mismatch_among_parties& e)
{
error = e.what();
}
if (not error.empty())
{
cerr << "Running secrets generation because " << error << endl;
setup.key_and_mac_generation(P, machine, num_runs, V());
ofstream output(filename);
octetStream os;
setup.pack(os);
machine.pack(os);
os.output(output);
}
}
#endif /* FHEOFFLINE_DATASETUP_HPP_ */

View File

@@ -120,7 +120,7 @@ void PairwiseMachine::pack(octetStream& os) const
void PairwiseMachine::unpack(octetStream& os)
{
os.get(other_pks, {setup_p.params, 0});
os.get_no_resize(other_pks);
os.get(enc_alphas, {pk});
sk.unpack(os);
}

View File

@@ -12,6 +12,7 @@
#include "Tools/Commit.h"
#include "Tools/Bundle.h"
#include "Processor/OnlineOptions.h"
#include "Protocols/LowGearKeyGen.h"
#include "Protocols/Share.hpp"
#include "Protocols/mac_key.hpp"
@@ -189,6 +190,14 @@ void PairwiseSetup<FD>::covert_mac_generation(Player& P,
alphai = alpha.element(0);
}
template <class FD>
void PairwiseSetup<FD>::key_and_mac_generation(Player& P,
PairwiseMachine& machine, int num_runs, true_type)
{
covert_key_generation(P, machine, num_runs);
covert_mac_generation(P, machine, num_runs);
}
template <class FD>
void PairwiseSetup<FD>::set_alphai(T alphai)
{

View File

@@ -33,9 +33,12 @@ public:
return "PairwiseParams-" + FD::T::type_string();
}
static string covert_name()
static string protocol_name(bool covert)
{
return "CowGear";
if (covert)
return "CowGear";
else
return "LowGear";
}
PairwiseSetup() : params(0), alpha(FieldD) {}
@@ -48,6 +51,11 @@ public:
void covert_key_generation(Player& P, PairwiseMachine& machine, int num_runs);
void covert_mac_generation(Player& P, PairwiseMachine& machine, int num_runs);
void key_and_mac_generation(Player& P, PairwiseMachine& machine,
int num_runs, false_type);
void key_and_mac_generation(Player& P, PairwiseMachine& machine,
int num_runs, true_type);
void pack(octetStream& os) const;
void unpack(octetStream& os);

View File

@@ -588,8 +588,8 @@ void InputProducer<FD>::run(const Player& P, const FHE_PK& pk,
P.receive_player(j, ciphertexts);
P.receive_player(j, cleartexts);
C.resize(personal_EC.machine->sec, pk.get_params());
Verifier<FD>(personal_EC.proof).NIZKPoK(C, ciphertexts,
cleartexts, pk, false, false);
Verifier<FD>(personal_EC.proof, FieldD).NIZKPoK(C, ciphertexts,
cleartexts, pk, false);
}
inputs[j].clear();

View File

@@ -24,6 +24,8 @@ class Proof
{
unsigned int sec;
bool diagonal;
Proof(); // Private to avoid default
public:
@@ -72,7 +74,8 @@ class Proof
typedef AddableMatrix<typename Int_Random_Coins::rand_type> X;
Proof(int sc, const bigint& Tau, const bigint& Rho, const FHE_PK& pk,
int n_proofs = 1) :
int n_proofs = 1, bool diagonal = false) :
diagonal(diagonal),
B_plain_length(0), B_rand_length(0), pk(&pk), n_proofs(n_proofs)
{ sec=sc;
tau=Tau; rho=Rho;
@@ -95,19 +98,25 @@ class Proof
}
}
Proof(int sec, const FHE_PK& pk, int n_proofs = 1) :
Proof(int sec, const FHE_PK& pk, int n_proofs = 1, bool diagonal = false) :
Proof(sec, pk.p() / 2,
pk.get_params().get_DG().get_NewHopeB(), pk,
n_proofs) {}
n_proofs, diagonal) {}
virtual ~Proof() {}
public:
static bigint slack(int slack, int sec, int phim);
static bool use_top_gear(const FHE_PK& pk)
bool use_top_gear(const FHE_PK& pk)
{
return CowGearOptions::singleton.top_gear() and pk.p() > 2;
return CowGearOptions::singleton.top_gear() and pk.p() > 2 and
not diagonal;
}
bool get_diagonal() const
{
return diagonal;
}
static int n_ciphertext_per_proof(int sec, const FHE_PK& pk)
@@ -147,8 +156,8 @@ public:
{ return bigint(phim * sec * sec) << (sec / 2 + 8); }
NonInteractiveProof(int sec, const FHE_PK& pk,
int extra_slack) :
Proof(sec, pk, 1)
int extra_slack, bool diagonal = false) :
Proof(sec, pk, 1, diagonal)
{
bigint B;
B=128*sec*sec;
@@ -167,8 +176,8 @@ public:
{ (void)phim; return pow(2, 1.5 * sec + 1); }
InteractiveProof(int sec, const FHE_PK& pk,
int n_proofs = 1) :
Proof(sec, pk, n_proofs)
int n_proofs = 1, bool diagonal = false) :
Proof(sec, pk, n_proofs, diagonal)
{
bigint B;
B = bigint(1) << sec;

View File

@@ -1,5 +1,6 @@
#include "Prover.h"
#include "Verifier.h"
#include "FHE/P2Data.h"
#include "Tools/random.h"
@@ -27,7 +28,7 @@ Prover<FD,U>::Prover(Proof& proof, const FD& FieldD) :
template <class FD, class U>
void Prover<FD,U>::Stage_1(const Proof& P, octetStream& ciphertexts,
const AddableVector<Ciphertext>& c,
const FHE_PK& pk, bool Diag, bool binary)
const FHE_PK& pk, bool binary)
{
size_t allocate = 3 * c.size() * c[0].report_size(USED);
ciphertexts.resize_precise(allocate);
@@ -50,7 +51,9 @@ void Prover<FD,U>::Stage_1(const Proof& P, octetStream& ciphertexts,
// AE.randomize(Diag,binary);
// rd=RandPoly(phim,bd<<1);
// y[i]=AE.plaintext()+pr*rd;
y[i].randomize(G, P.B_plain_length, Diag, binary);
y[i].randomize(G, P.B_plain_length, P.get_diagonal(), binary);
if (P.get_diagonal())
assert(y[i].is_diagonal());
s[i].resize(3, P.phim);
s[i].generateUniform(G, P.B_rand_length);
rc.assign(s[i][0], s[i][1], s[i][2]);
@@ -78,10 +81,14 @@ bool Prover<FD,U>::Stage_2(Proof& P, octetStream& cleartexts,
#endif
cleartexts.reset_write_head();
cleartexts.store(P.V);
if (P.get_diagonal())
for (auto& xx : x)
assert(xx.is_diagonal());
for (i=0; i<P.V; i++)
{ z=y[i];
t=s[i];
P.apply_challenge(i, z, x, pk);
Check_Decoding(z, P.get_diagonal(), x[0].get_field());
P.apply_challenge(i, t, r, pk);
if (not P.check_bounds(z, t, i))
return false;
@@ -108,7 +115,7 @@ size_t Prover<FD,U>::NIZKPoK(Proof& P, octetStream& ciphertexts, octetStream& cl
const AddableVector<Ciphertext>& c,
const vector<U>& x,
const Proof::Randomness& r,
bool Diag,bool binary)
bool binary)
{
// AElement<T> AE;
// for (i=0; i<P.sec; i++)
@@ -123,7 +130,7 @@ size_t Prover<FD,U>::NIZKPoK(Proof& P, octetStream& ciphertexts, octetStream& cl
int cnt=0;
while (!ok)
{ cnt++;
Stage_1(P,ciphertexts,c,pk,Diag,binary);
Stage_1(P,ciphertexts,c,pk,binary);
P.set_challenge(ciphertexts);
// Check check whether we are OK, or whether we should abort
ok = Stage_2(P,cleartexts,x,r,pk);

View File

@@ -24,7 +24,7 @@ public:
Prover(Proof& proof, const FD& FieldD);
void Stage_1(const Proof& P, octetStream& ciphertexts, const AddableVector<Ciphertext>& c,
const FHE_PK& pk, bool Diag,
const FHE_PK& pk,
bool binary = false);
bool Stage_2(Proof& P, octetStream& cleartexts,
@@ -41,7 +41,7 @@ public:
const AddableVector<Ciphertext>& c,
const vector<U>& x,
const Proof::Randomness& r,
bool Diag,bool binary=false);
bool binary=false);
size_t report_size(ReportType type);
void report_size(ReportType type, MemoryUsage& res);

View File

@@ -22,8 +22,9 @@ SimpleEncCommitBase<T, FD, S>::SimpleEncCommitBase(const MachineBase& machine) :
template<class T,class FD,class S>
SimpleEncCommit<T, FD, S>::SimpleEncCommit(const PlayerBase& P, const FHE_PK& pk,
const FD& FTD, map<string, Timer>& timers, const MachineBase& machine,
int thread_num) :
NonInteractiveProofSimpleEncCommit<FD>(P, pk, FTD, timers, machine),
int thread_num, bool diagonal) :
NonInteractiveProofSimpleEncCommit<FD>(P, pk, FTD, timers, machine,
diagonal),
SimpleEncCommitFactory<FD>(pk, FTD, machine)
{
(void)thread_num;
@@ -32,13 +33,14 @@ SimpleEncCommit<T, FD, S>::SimpleEncCommit(const PlayerBase& P, const FHE_PK& pk
template <class FD>
NonInteractiveProofSimpleEncCommit<FD>::NonInteractiveProofSimpleEncCommit(
const PlayerBase& P, const FHE_PK& pk, const FD& FTD,
map<string, Timer>& timers, const MachineBase& machine) :
map<string, Timer>& timers, const MachineBase& machine,
bool diagonal) :
SimpleEncCommitBase_<FD>(machine),
P(P), pk(pk), FTD(FTD),
proof(machine.sec, pk, machine.extra_slack),
proof(machine.sec, pk, machine.extra_slack, diagonal),
#ifdef LESS_ALLOC_MORE_MEM
r(proof.U, this->pk.get_params()), prover(proof, FTD),
verifier(proof),
verifier(proof, FTD),
#endif
timers(timers)
{
@@ -72,7 +74,7 @@ void SimpleEncCommitFactory<FD>::next(Plaintext_<FD>& mess, Ciphertext& C)
mess = m[cnt];
C = c[cnt];
if (Proof::use_top_gear(pk))
if (get_proof().use_top_gear(pk))
{
mess = mess + mess;
C = C + C;
@@ -86,7 +88,10 @@ template <class FD>
void SimpleEncCommitFactory<FD>::prepare_plaintext(PRNG& G)
{
for (auto& mess : m)
mess.randomize(G);
if (get_proof().get_diagonal())
mess.randomize(G, Diagonal);
else
mess.randomize(G);
}
template<class T,class FD,class S>
@@ -126,7 +131,7 @@ size_t NonInteractiveProofSimpleEncCommit<FD>::generate_proof(AddableVector<Ciph
Prover<FD, Plaintext_<FD> > prover(proof, FTD);
#endif
size_t prover_memory = prover.NIZKPoK(proof, ciphertexts, cleartexts,
pk, c, m, r, false, false);
pk, c, m, r, false);
timers["Proving"].stop();
if (proof.top_gear)
@@ -187,7 +192,7 @@ size_t NonInteractiveProofSimpleEncCommit<FD>::create_more(octetStream& cipherte
#endif
timers["Verifying"].start();
verifier.NIZKPoK(others_ciphertexts, ciphertexts,
cleartexts, get_pk_for_verification(i), false, false);
cleartexts, get_pk_for_verification(i), false);
timers["Verifying"].stop();
add_ciphertexts(others_ciphertexts, i);
this->memory_usage.update("verifier", verifier.report_size(CAPACITY));
@@ -214,12 +219,12 @@ void SimpleEncCommit<T, FD, S>::add_ciphertexts(
template<class FD>
SummingEncCommit<FD>::SummingEncCommit(const Player& P, const FHE_PK& pk,
const FD& FTD, map<string, Timer>& timers, const MachineBase& machine,
int thread_num) :
int thread_num, bool diagonal) :
SimpleEncCommitFactory<FD>(pk, FTD, machine), SimpleEncCommitBase_<FD>(
machine), proof(machine.sec, pk, P.num_players()), pk(pk), FTD(
machine), proof(machine.sec, pk, P.num_players(), diagonal), pk(pk), FTD(
FTD), P(P), thread_num(thread_num),
#ifdef LESS_ALLOC_MORE_MEM
prover(proof, FTD), verifier(proof), preimages(proof.V,
prover(proof, FTD), verifier(proof, FTD), preimages(proof.V,
this->pk, FTD.get_prime(), P.num_players()),
#endif
timers(timers)
@@ -246,7 +251,7 @@ void SummingEncCommit<FD>::create_more()
#endif
this->generate_ciphertexts(this->c, this->m, r, pk, timers, proof);
this->timers["Stage 1 of proof"].start();
prover.Stage_1(proof, ciphertexts, this->c, this->pk, false, false);
prover.Stage_1(proof, ciphertexts, this->c, this->pk, false);
this->timers["Stage 1 of proof"].stop();
this->c.unpack(ciphertexts, this->pk);
@@ -307,7 +312,7 @@ void SummingEncCommit<FD>::create_more()
Verifier<FD> verifier(proof);
#endif
verifier.Stage_2(this->c, ciphertexts, cleartexts,
this->pk, false, false);
this->pk, false);
this->timers["Verifying"].stop();
this->cnt = proof.U - 1;
@@ -362,9 +367,9 @@ size_t SummingEncCommit<FD>::report_size(ReportType type)
template <class FD>
MultiEncCommit<FD>::MultiEncCommit(const Player& P, const vector<FHE_PK>& pks,
const FD& FTD, map<string, Timer>& timers, MachineBase& machine,
PairwiseGenerator<FD>& generator) :
PairwiseGenerator<FD>& generator, bool diagonal) :
NonInteractiveProofSimpleEncCommit<FD>(P, pks[P.my_real_num()], FTD,
timers, machine), pks(pks), P(P), generator(generator)
timers, machine, diagonal), pks(pks), P(P), generator(generator)
{
}

View File

@@ -65,13 +65,15 @@ public:
NonInteractiveProofSimpleEncCommit(const PlayerBase& P, const FHE_PK& pk,
const FD& FTD, map<string, Timer>& timers,
const MachineBase& machine);
const MachineBase& machine, bool diagonal = false);
virtual ~NonInteractiveProofSimpleEncCommit() {}
size_t generate_proof(AddableVector<Ciphertext>& c, vector<Plaintext_<FD> >& m,
octetStream& ciphertexts, octetStream& cleartexts);
size_t generate_proof(AddableVector<Ciphertext>& c,
vector<Plaintext_<FD> >& m, octetStream& ciphertexts,
octetStream& cleartexts);
size_t create_more(octetStream& my_ciphertext, octetStream& my_cleartext);
virtual size_t report_size(ReportType type);
using SimpleEncCommitBase_<FD>::report_size;
Proof& get_proof() { return proof; }
};
template <class FD>
@@ -96,6 +98,7 @@ public:
void next(Plaintext_<FD>& mess, Ciphertext& C);
virtual size_t report_size(ReportType type);
void report_size(ReportType type, MemoryUsage& res);
virtual Proof& get_proof() = 0;
};
template<class T,class FD,class S>
@@ -111,13 +114,15 @@ protected:
public:
SimpleEncCommit(const PlayerBase& P, const FHE_PK& pk, const FD& FTD,
map<string, Timer>& timers, const MachineBase& machine, int thread_num);
map<string, Timer>& timers, const MachineBase& machine,
int thread_num, bool diagonal = false);
void next(Plaintext_<FD>& mess, Ciphertext& C) { SimpleEncCommitFactory<FD>::next(mess, C); }
void create_more();
size_t report_size(ReportType type)
{ return SimpleEncCommitFactory<FD>::report_size(type) + EncCommitBase_<FD>::report_size(type); }
void report_size(ReportType type, MemoryUsage& res)
{ SimpleEncCommitFactory<FD>::report_size(type, res); SimpleEncCommitBase_<FD>::report_size(type, res); }
Proof& get_proof() { return NonInteractiveProofSimpleEncCommit<FD>::get_proof(); }
};
template <class FD>
@@ -146,13 +151,15 @@ public:
map<string, Timer>& timers;
SummingEncCommit(const Player& P, const FHE_PK& pk, const FD& FTD,
map<string, Timer>& timers, const MachineBase& machine, int thread_num);
map<string, Timer>& timers, const MachineBase& machine,
int thread_num, bool diagonal = false);
void next(Plaintext_<FD>& mess, Ciphertext& C) { SimpleEncCommitFactory<FD>::next(mess, C); }
void create_more();
size_t report_size(ReportType type);
void report_size(ReportType type, MemoryUsage& res)
{ SimpleEncCommitFactory<FD>::report_size(type, res); SimpleEncCommitBase_<FD>::report_size(type, res); }
Proof& get_proof() { return proof; }
};
template <class FD>
@@ -179,7 +186,7 @@ public:
MultiEncCommit(const Player& P, const vector<FHE_PK>& pks,
const FD& FTD,
map<string, Timer>& timers, MachineBase& machine,
PairwiseGenerator<FD>& generator);
PairwiseGenerator<FD>& generator, bool diagonal = false);
};
#endif /* FHEOFFLINE_SIMPLEENCCOMMIT_H_ */

View File

@@ -4,7 +4,8 @@
#include "Math/modp.hpp"
template <class FD>
Verifier<FD>::Verifier(Proof& proof) : P(proof)
Verifier<FD>::Verifier(Proof& proof, const FD& FieldD) :
P(proof), FieldD(FieldD)
{
#ifdef LESS_ALLOC_MORE_MEM
z.resize(proof.phim);
@@ -30,12 +31,28 @@ bool Check_Decoding(const Plaintext<T,FD,S>& AE,bool Diag)
return true;
}
template <class S>
bool Check_Decoding(const vector<S>& AE, bool Diag)
template <>
bool Check_Decoding(const vector<Proof::bound_type>& AE, bool Diag, const FFT_Data&)
{
(void)AE;
if (Diag)
throw not_implemented();
{
for (size_t i = 1; i < AE.size(); i++)
if (AE[i] != 0)
return false;
}
return true;
}
template <>
bool Check_Decoding(const vector<Proof::bound_type>& AE, bool Diag, const P2Data& p2d)
{
if (Diag)
{
Plaintext_<P2Data> tmp(p2d);
for (size_t i = 0; i < AE.size(); i++)
tmp.set_coeff(i, AE[i].get_limb(0) % 2);
return tmp.is_diagonal();
}
return true;
}
@@ -45,7 +62,7 @@ template <class FD>
void Verifier<FD>::Stage_2(
AddableVector<Ciphertext>& c,octetStream& ciphertexts,
octetStream& cleartexts,
const FHE_PK& pk,bool Diag,bool binary)
const FHE_PK& pk,bool binary)
{
unsigned int i, V;
@@ -76,12 +93,7 @@ void Verifier<FD>::Stage_2(
{ cout << "Fail Check 6 " << i << endl;
throw runtime_error("ciphertexts don't match");
}
}
// Now check decoding z[i]
for (i=0; i<V; i++)
{
if (!Check_Decoding(z,Diag))
if (!Check_Decoding(z,P.get_diagonal(),FieldD))
{ cout << "\tCheck : " << i << endl;
throw runtime_error("cleartext isn't diagonal");
}
@@ -100,16 +112,16 @@ void Verifier<FD>::Stage_2(
template <class FD>
void Verifier<FD>::NIZKPoK(AddableVector<Ciphertext>& c,
octetStream& ciphertexts, octetStream& cleartexts,
const FHE_PK& pk,bool Diag,
const FHE_PK& pk,
bool binary)
{
P.set_challenge(ciphertexts);
Stage_2(c,ciphertexts,cleartexts,pk,Diag,binary);
Stage_2(c,ciphertexts,cleartexts,pk,binary);
if (P.top_gear)
{
assert(not Diag);
assert(not P.get_diagonal());
assert(not binary);
c += c;
}

View File

@@ -3,6 +3,9 @@
#include "Proof.h"
template <class FD>
bool Check_Decoding(const vector<Proof::bound_type>& AE, bool Diag, FD& FieldD);
/* Defines the Verifier */
template <class FD>
class Verifier
@@ -11,20 +14,21 @@ class Verifier
AddableMatrix<Int_Random_Coins::value_type::value_type> t;
Proof& P;
const FD& FieldD;
public:
Verifier(Proof& proof);
Verifier(Proof& proof, const FD& FieldD);
void Stage_2(
AddableVector<Ciphertext>& c, octetStream& ciphertexts,
octetStream& cleartexts,const FHE_PK& pk,bool Diag,bool binary=false);
octetStream& cleartexts,const FHE_PK& pk,bool binary=false);
/* This is the non-interactive version using the ROM
- Creates space for all output values
- Diag flag mirrors that in Prover
*/
void NIZKPoK(AddableVector<Ciphertext>& c,octetStream& ciphertexts,octetStream& cleartexts,
const FHE_PK& pk,bool Diag,bool binary=false);
const FHE_PK& pk,bool binary=false);
size_t report_size(ReportType type) { return z.report_size(type) + t.report_size(type); }
};

View File

@@ -136,6 +136,7 @@
X(RUN_TAPE, MACH->run_tapes(EXTRA)) \
X(JOIN_TAPE, MACH->join_tape(R0)) \
X(USE, ) \
X(USE_INP, ) \
#define INSTRUCTIONS BIT_INSTRUCTIONS GC_INSTRUCTIONS

View File

@@ -9,6 +9,8 @@
#include "Processor/Data_Files.hpp"
#include "Processor/Instruction.hpp"
#include "Processor/Machine.hpp"
#include "Processor/FieldMachine.hpp"
#include "Protocols/MAC_Check.hpp"
#include "Protocols/fake-stuff.hpp"
#include "Protocols/Beaver.hpp"
@@ -26,4 +28,6 @@
#include "GC/ShareSecret.hpp"
#include "GC/TinierSharePrep.hpp"
#include "Math/gfp.hpp"
#endif /* MACHINES_SPDZ_HPP_ */

View File

@@ -0,0 +1,16 @@
/*
* highgear-party.cpp
*
*/
#include "Protocols/HighGearShare.h"
#include "SPDZ.hpp"
#include "Protocols/ChaiGearPrep.hpp"
int main(int argc, const char** argv)
{
ez::ezOptionParser opt;
CowGearOptions::singleton = CowGearOptions(opt, argc, argv, false);
DishonestMajorityFieldMachine<HighGearShare, HighGearShare, gf2n_short>(argc, argv, opt);
}

View File

@@ -0,0 +1,16 @@
/*
* lowgear-party.cpp
*
*/
#include "Protocols/LowGearShare.h"
#include "SPDZ.hpp"
#include "Protocols/CowGearPrep.hpp"
int main(int argc, const char** argv)
{
ez::ezOptionParser opt;
CowGearOptions::singleton = CowGearOptions(opt, argc, argv, false);
DishonestMajorityFieldMachine<LowGearShare, LowGearShare, gf2n_short>(argc, argv, opt);
}

View File

@@ -47,7 +47,7 @@ binary: rep-bin yao semi-bin-party.x tinier-party.x tiny-party.x ccd-party.x mal
ifeq ($(USE_NTL),1)
all: overdrive she-offline
gear: cowgear-party.x chaigear-party.x
gear: cowgear-party.x chaigear-party.x lowgear-party.x highgear-party.x
arithmetic: hemi-party.x soho-party.x gear
endif
@@ -186,10 +186,14 @@ hemi-party.x: $(FHEOFFLINE) $(GC_SEMI) $(OT)
soho-party.x: $(FHEOFFLINE) $(GC_SEMI) $(OT)
cowgear-party.x: $(FHEOFFLINE) Protocols/CowGearOptions.o $(OT)
chaigear-party.x: $(FHEOFFLINE) Protocols/CowGearOptions.o $(OT)
lowgear-party.x: $(FHEOFFLINE) $(OT) Protocols/CowGearOptions.o Protocols/LowGearKeyGen.o
highgear-party.x: $(FHEOFFLINE) $(OT) Protocols/CowGearOptions.o Protocols/HighGearKeyGen.o
static/hemi-party.x: $(FHEOFFLINE)
static/soho-party.x: $(FHEOFFLINE)
static/cowgear-party.x: $(FHEOFFLINE)
static/chaigear-party.x: $(FHEOFFLINE)
static/lowgear-party.x: $(FHEOFFLINE) Protocols/CowGearOptions.o Protocols/LowGearKeyGen.o
static/highgear-party.x: $(FHEOFFLINE) Protocols/CowGearOptions.o Protocols/HighGearKeyGen.o
mascot-party.x: Machines/SPDZ.o $(OT)
static/mascot-party.x: Machines/SPDZ.o
Player-Online.x: Machines/SPDZ.o $(OT)

View File

@@ -34,6 +34,11 @@ public:
{
return L * T::size();
}
static int size_in_bits()
{
return L * T::size_in_bits();
}
static string type_string()
{
return T::type_string() + "^" + to_string(L);

View File

@@ -146,8 +146,10 @@ void check_setup(string dir, bigint pr)
bigint p;
string filename = dir + "Params-Data";
ifstream(filename) >> p;
if (p == 0)
throw runtime_error("no modulus in " + filename);
if (p != pr)
throw runtime_error("wrong modulus in " + dir);
throw runtime_error("wrong modulus in " + filename);
}
string get_prep_sub_dir(const string& prep_dir, int nparties, int log2mod,

View File

@@ -24,7 +24,7 @@ public:
template<class T>
static void init(bool mont = true) { (void) mont; }
static void init_default(int, bool = true) {}
static void init_field() {}
static void init_field(const bigint& = {}) {}
static void read_or_generate_setup(const string&, const OnlineOptions&) {}
template<class T>

View File

@@ -67,6 +67,7 @@ public:
bigint& operator=(int n);
bigint& operator=(long n);
bigint& operator=(word n);
bigint& operator=(double f);
template<int X, int L>
bigint& operator=(const gfp_<X, L>& other);
template<int K>
@@ -138,6 +139,12 @@ inline bigint& bigint::operator=(word n)
return *this;
}
inline bigint& bigint::operator=(double f)
{
mpz_class::operator=(f);
return *this;
}
template<int K>
bigint::bigint(const Z2<K>& x)
{

View File

@@ -45,6 +45,14 @@ class modp_
inline_mpn_zero(x + M, L - M);
}
template<int X, int M>
modp_(const gfp_<X, M>& other) :
modp_()
{
assert(M <= L);
inline_mpn_copyi(x, other.get().get(), M);
}
const mp_limb_t* get() const { return x; }
void assign(const void* buffer, int t) { memcpy(x, buffer, t * sizeof(mp_limb_t)); }

View File

@@ -11,7 +11,15 @@
template<int L>
void modp_<L>::randomize(PRNG& G, const Zp_Data& ZpD)
{
G.randomBnd(x, ZpD.get_prA(), ZpD.pr_byte_length, ZpD.overhang_mask());
const int M = sizeof(mp_limb_t) * L;
switch (ZpD.pr_byte_length)
{
#define X(LL) case LL: G.randomBnd<LL>(x, ZpD.get_prA(), ZpD.overhang_mask()); break;
X(M) X(M-1) X(M-2) X(M-3) X(M-4) X(M-5) X(M-6) X(M-7)
#undef X
default:
G.randomBnd(x, ZpD.get_prA(), ZpD.pr_byte_length, ZpD.overhang_mask());
}
}
template<int L>

View File

@@ -155,25 +155,28 @@ void CryptoPlayer::send_receive_all_no_stats(const vector<vector<bool>>& channel
}
}
void CryptoPlayer::partial_broadcast(const vector<bool>& senders,
void CryptoPlayer::partial_broadcast(const vector<bool>& my_senders,
const vector<bool>& my_receivers,
vector<octetStream>& os) const
{
TimeScope ts(comm_stats["Partial broadcasting"].add(os[my_num()]));
sent += os[my_num()].get_length() * (num_players() - 1);
for (int offset = 1; offset < num_players(); offset++)
{
int other = get_player(offset);
bool receive = senders[other];
if (senders[my_num()])
bool receive = my_senders[other];
if (my_receivers[other])
{
this->senders[other]->request(os[my_num()]);
sent += os[my_num()].get_length();
}
if (receive)
this->receivers[other]->request(os[other]);
}
for (int offset = 1; offset < num_players(); offset++)
{
int other = get_player(offset);
bool receive = senders[other];
if (senders[my_num()])
bool receive = my_senders[other];
if (my_receivers[other])
this->senders[other]->wait(os[my_num()]);
if (receive)
this->receivers[other]->wait(os[other]);

View File

@@ -42,8 +42,8 @@ public:
const vector<octetStream>& to_send,
vector<octetStream>& to_receive) const;
void partial_broadcast(const vector<bool>& senders,
vector<octetStream>& os) const;
void partial_broadcast(const vector<bool>& my_senders,
const vector<bool>& my_receivers, vector<octetStream>& os) const;
void Broadcast_Receive_no_stats(vector<octetStream>& os) const;
};

View File

@@ -522,12 +522,24 @@ void Player::send_receive_all(const vector<vector<bool>>& channels,
size_t data = 0;
for (int i = 0; i < num_players(); i++)
if (i != my_num() and channels.at(my_num()).at(i))
data += to_send.at(i).get_length();
{
data += to_send.at(i).get_length();
#ifdef VERBOSE_COMM
cerr << "Send " << to_send.at(i).get_length() << " to " << i << endl;
#endif
}
TimeScope ts(comm_stats["Sending/receiving"].add(data));
sent += data;
send_receive_all_no_stats(channels, to_send, to_receive);
}
void Player::partial_broadcast(const vector<bool>& senders,
vector<octetStream>& os) const
{
partial_broadcast(senders, vector<bool>(num_players(), senders[my_num()]),
os);
}
template<class T>
void MultiPlayer<T>::send_receive_all_no_stats(
const vector<vector<bool>>& channels, const vector<octetStream>& to_send,

View File

@@ -218,7 +218,9 @@ public:
const vector<octetStream>& to_send,
vector<octetStream>& to_receive) const = 0;
virtual void partial_broadcast(const vector<bool>&,
virtual void partial_broadcast(const vector<bool>& senders,
vector<octetStream>& os) const;
virtual void partial_broadcast(const vector<bool>&, const vector<bool>&,
vector<octetStream>& os) const { unchecked_broadcast(os); }
// dummy functions for compatibility

View File

@@ -113,7 +113,8 @@ void set_up_client_socket(int& mysocket,const char* hostname,int Portnum)
if (fl < 0)
{
cout << attempts << " attempts" << endl;
cout << attempts << " attempts to " << hostname << ":" << Portnum
<< endl;
error("set_up_socket:connect:", hostname);
}

View File

@@ -261,7 +261,7 @@ void NPartyTripleGenerator<W>::generateInputs(int player)
mac_sum = (ot_multipliers[i_thread])->input_macs[j];
}
inputs[j] = {{share, mac_sum}, secrets[j]};
auto r = G.get<typename W::mac_key_type>();
auto r = G.get<typename W::input_check_type::share_type>();
check_sum += typename W::input_check_type(r * share, r * mac_sum);
}
inputs.resize(nTriplesPerLoop);

View File

@@ -60,6 +60,7 @@ public:
map<pair<bool, int>, long long> edabits;
DataPositions(int num_players = 0);
DataPositions(const Player& P) : DataPositions(P.num_players()) {}
~DataPositions();
void reset();

View File

@@ -16,7 +16,13 @@ void FixInput_<Integer>::read(std::istream& in, const int* params)
template<>
void FixInput_<bigint>::read(std::istream& in, const int* params)
{
#ifdef HIGH_PREC_INPUT
mpf_class x;
in >> x;
items[0] = x << *params;
#else
double x;
in >> x;
items[0] = x * (1 << *params);
#endif
}

View File

@@ -209,7 +209,7 @@ void Machine<sint, sgf2n>::fill_buffers(int thread_number, int tape_number,
dynamic_cast<BufferPrep<bit_type>&>(tinfo[thread_number].processor->share_thread.DataF);
for (int i = 0; i < DIV_CEIL(usage.files[DATA_GF2][DATA_TRIPLE],
bit_type::default_length); i++)
dest.push_triple(source.get_triple(bit_type::default_length));
dest.push_triple(source.get_triple_no_count(bit_type::default_length));
}
catch (bad_cast& e)
{

View File

@@ -194,7 +194,9 @@ void OnlineMachine::start_networking()
if (ipFileName.size() > 0) {
if (my_port != Names::DEFAULT_PORT)
throw runtime_error("cannot set port number when using IP file");
playerNames.init(playerno, pnbase, ipFileName);
if (nplayers == 0 and opt.isSet("-N"))
opt.get("-N")->getInt(nplayers);
playerNames.init(playerno, pnbase, ipFileName, nplayers);
} else {
if (not opt.get("-ext-server")->isSet)
{

View File

@@ -24,6 +24,9 @@ public:
void start(int player, int target, int source);
void stop(int player, int dest, int source);
T start(int player, const T& source);
typename T::clear stop(int player, const typename T::clear& masked);
};
#endif /* PROCESSOR_PRIVATEOUTPUT_H_ */

View File

@@ -8,24 +8,42 @@
template<class T>
void PrivateOutput<T>::start(int player, int target, int source)
{
proc.get_S_ref(target) = start(player, proc.get_S_ref(source));
}
template<class T>
T PrivateOutput<T>::start(int player, const T& source)
{
assert (player < proc.P.num_players());
open_type mask;
proc.DataF.get_input(proc.get_S_ref(target), mask, player);
proc.get_S_ref(target) += proc.get_S_ref(source);
T res;
proc.DataF.get_input(res, mask, player);
res += source;
if (player == proc.P.my_num())
masks.push_back(mask);
return res;
}
template<class T>
void PrivateOutput<T>::stop(int player, int dest, int source)
{
if (player == proc.P.my_num() and proc.Proc)
{
auto& value = proc.get_C_ref(dest);
value = (proc.get_C_ref(source) - masks.front());
auto& value = proc.get_C_ref(dest);
value = stop(player, proc.get_C_ref(source));
if (proc.Proc)
value.output(proc.Proc->private_output, false);
}
template<class T>
typename T::clear PrivateOutput<T>::stop(int player, const typename T::clear& source)
{
typename T::clear value;
if (player == proc.P.my_num())
{
value = source - masks.front();
masks.pop_front();
}
return value;
}

View File

@@ -39,6 +39,8 @@ SubProcessor<T>::SubProcessor(typename T::MAC_Check& MC,
template<class T>
SubProcessor<T>::~SubProcessor()
{
protocol.check();
for (size_t i = 0; i < personal_bit_preps.size(); i++)
{
auto& x = personal_bit_preps[i];
@@ -225,8 +227,9 @@ void Processor<sint, sgf2n>::split(const Instruction& instruction)
assert(unit == 64);
int n_inputs = instruction.get_size();
int n_bits = instruction.get_start().size() / n;
assert(share_thread.protocol != 0);
sint::split(Procb.S, instruction.get_start(), n_bits,
&read_Sp(instruction.get_r(0)), n_inputs, P);
&read_Sp(instruction.get_r(0)), n_inputs, *share_thread.protocol);
}

View File

@@ -85,13 +85,14 @@ if '2dense' in program.args:
program.disable_memory_warnings()
layers[-1].Y.input_from(0)
layers[0].X.input_from(0)
Y = sint.Matrix(n_test, 10)
X = sfix.Matrix(n_test, n_features)
Y.input_from(0)
X.input_from(0)
if not ('no_acc' in program.args and 'no_loss' in program.args):
layers[-1].Y.input_from(0)
layers[0].X.input_from(0)
Y.input_from(0)
X.input_from(0)
if 'always_acc' in program.args:
n_part_epochs = 1

View File

@@ -35,6 +35,8 @@ public:
Beaver(Player& P) : prep(0), MC(0), P(P) {}
Player& branch();
void init_mul(SubProcessor<T>* proc);
void init_mul(Preprocessing<T>& prep, typename T::MAC_Check& MC);
typename T::clear prepare_mul(const T& x, const T& y, int n = -1);

View File

@@ -12,6 +12,11 @@
#include <array>
template<class T>
Player& Beaver<T>::branch()
{
return P;
}
template<class T>
void Beaver<T>::init_mul(SubProcessor<T>* proc)

View File

@@ -20,6 +20,7 @@ public:
BrainPrep(SubProcessor<T>* proc, DataPositions& usage) :
BufferPrep<T>(usage), BitPrep<T>(proc, usage),
RingPrep<T>(proc, usage),
MaliciousDabitOnlyPrep<T>(proc, usage),
MaliciousRingPrep<T>(proc, usage)
{
}

View File

@@ -24,6 +24,11 @@ class ChaiGearPrep : public MaliciousRingPrep<T>
Generator& get_generator();
template<int>
void buffer_bits(true_type);
template<int>
void buffer_bits(false_type);
public:
static void basic_setup(Player& P);
static void key_setup(Player& P, mac_key_type alphai);
@@ -32,6 +37,7 @@ public:
ChaiGearPrep(SubProcessor<T>* proc, DataPositions& usage) :
BufferPrep<T>(usage), BitPrep<T>(proc, usage),
RingPrep<T>(proc, usage),
MaliciousDabitOnlyPrep<T>(proc, usage),
MaliciousRingPrep<T>(proc, usage), generator(0), square_producer(0),
input_producer(0)
{

View File

@@ -10,6 +10,8 @@
#include "FHEOffline/SimpleMachine.h"
#include "FHEOffline/Producer.h"
#include "FHEOffline/DataSetup.hpp"
template<class T>
MultiplicativeMachine* ChaiGearPrep<T>::machine = 0;
template<class T>
@@ -65,7 +67,8 @@ void ChaiGearPrep<T>::key_setup(Player& P, mac_key_type alphai)
assert(machine);
auto& setup = machine->setup.part<FD>();
auto& options = CowGearOptions::singleton;
setup.covert_secrets_generation(P, *machine, options.covert_security);
read_or_generate_secrets(setup, P, *machine, options.covert_security,
T::covert);
// adjust mac key
mac_key_type diff = alphai - setup.alphai;
@@ -169,14 +172,22 @@ void ChaiGearPrep<T>::buffer_inputs(int player)
template<class T>
inline void ChaiGearPrep<T>::buffer_bits()
{
buffer_bits<0>(T::clear::characteristic_two);
}
template<class T>
template<int>
void ChaiGearPrep<T>::buffer_bits(false_type)
{
buffer_bits_from_squares(*this);
}
template<>
inline void ChaiGearPrep<ChaiGearShare<gf2n_short>>::buffer_bits()
template<class T>
template<int>
void ChaiGearPrep<T>::buffer_bits(true_type)
{
buffer_bits_without_check();
this->buffer_bits_without_check();
assert(not this->bits.empty());
for (auto& bit : this->bits)
bit.force_to_bit();

View File

@@ -26,6 +26,8 @@ public:
const static bool needs_ot = false;
const static true_type covert;
ChaiGearShare()
{
}
@@ -37,5 +39,7 @@ public:
}
};
template<class T>
const true_type ChaiGearShare<T>::covert;
#endif /* PROTOCOLS_CHAIGEARSHARE_H_ */

View File

@@ -12,38 +12,44 @@ using namespace std;
CowGearOptions CowGearOptions::singleton;
CowGearOptions::CowGearOptions()
CowGearOptions::CowGearOptions(bool covert)
{
covert_security = 20;
lowgear_from_covert();
if (covert)
{
covert_security = 20;
}
else
{
covert_security = -1;
}
lowgear_security = 40;
use_top_gear = false;
}
void CowGearOptions::lowgear_from_covert()
{
lowgear_security = ceil(log2(covert_security));
}
CowGearOptions::CowGearOptions(ez::ezOptionParser& opt, int argc,
const char** argv) : CowGearOptions()
const char** argv, bool covert) : CowGearOptions(covert)
{
if (covert)
{
opt.add(
"", // Default.
0, // Required?
1, // Number of args expected.
0, // Delimiter if expecting multiple args.
("Covert security parameter c. "
"Cheating will be detected with probability 1/c (default: "
+ to_string(covert_security) + ")").c_str(), // Help description.
"-c", // Flag token.
"--covert-security" // Flag token.
);
}
opt.add(
"", // Default.
0, // Required?
1, // Number of args expected.
0, // Delimiter if expecting multiple args.
("Covert security parameter c. "
"Cheating will be detected with probability 1/c (default: "
+ to_string(covert_security) + ")").c_str(), // Help description.
"-c", // Flag token.
"--covert-security" // Flag token.
);
opt.add(
"", // Default.
0, // Required?
1, // Number of args expected.
0, // Delimiter if expecting multiple args.
"LowGear security parameter (default: ceil(log2(c))", // Help description.
"LowGear security parameter (default: 40)", // Help description.
"-l", // Flag token.
"--lowgear-security" // Flag token.
);
@@ -71,8 +77,6 @@ CowGearOptions::CowGearOptions(ez::ezOptionParser& opt, int argc,
if (covert_security > (1LL << lowgear_security))
insecure(", LowGear security less than key generation security");
}
else
lowgear_from_covert();
use_top_gear = opt.isSet("-T");
opt.resetArgs();
}

View File

@@ -12,21 +12,25 @@ class CowGearOptions
{
bool use_top_gear;
void lowgear_from_covert();
public:
static CowGearOptions singleton;
int covert_security;
int lowgear_security;
CowGearOptions();
CowGearOptions(ez::ezOptionParser& opt, int argc, const char** argv);
CowGearOptions(bool covert = true);
CowGearOptions(ez::ezOptionParser& opt, int argc, const char** argv,
bool covert = true);
bool top_gear()
{
return use_top_gear;
}
void set_top_gear(bool use)
{
use_top_gear = use;
}
};
#endif /* PROTOCOLS_COWGEAROPTIONS_H_ */

View File

@@ -24,6 +24,11 @@ class CowGearPrep : public MaliciousRingPrep<T>
PairwiseGenerator<FD>& get_generator();
template<int>
void buffer_bits(true_type);
template<int>
void buffer_bits(false_type);
public:
static void basic_setup(Player& P);
static void key_setup(Player& P, mac_key_type alphai);
@@ -33,6 +38,7 @@ public:
CowGearPrep(SubProcessor<T>* proc, DataPositions& usage) :
BufferPrep<T>(usage),
BitPrep<T>(proc, usage), RingPrep<T>(proc, usage),
MaliciousDabitOnlyPrep<T>(proc, usage),
MaliciousRingPrep<T>(proc, usage),
pairwise_generator(0)
{

View File

@@ -8,6 +8,7 @@
#include "Tools/Bundle.h"
#include "Protocols/ReplicatedPrep.hpp"
#include "FHEOffline/DataSetup.hpp"
template<class T>
PairwiseMachine* CowGearPrep<T>::pairwise_machine = 0;
@@ -39,8 +40,9 @@ void CowGearPrep<T>::basic_setup(Player& P)
auto& setup = machine.setup<FD>();
auto& options = CowGearOptions::singleton;
#ifdef VERBOSE
cerr << "Covert security parameter for key and MAC generation: "
<< options.covert_security << endl;
if (T::covert)
cerr << "Covert security parameter for key and MAC generation: "
<< options.covert_security << endl;
cerr << "LowGear security parameter: " << options.lowgear_security << endl;
#endif
setup.secure_init(P, machine, T::clear::length(), options.lowgear_security);
@@ -66,8 +68,8 @@ void CowGearPrep<T>::key_setup(Player& P, mac_key_type alphai)
auto& machine = *pairwise_machine;
auto& setup = machine.setup<FD>();
auto& options = CowGearOptions::singleton;
read_or_generate_covert_secrets(setup, P, machine,
options.covert_security);
read_or_generate_secrets(setup, P, machine,
options.covert_security, T::covert);
// adjust mac key
mac_key_type diff = alphai - setup.alphai;
@@ -149,14 +151,22 @@ void CowGearPrep<T>::buffer_inputs(int player)
template<class T>
inline void CowGearPrep<T>::buffer_bits()
{
buffer_bits<0>(T::clear::characteristic_two);
}
template<class T>
template<int>
void CowGearPrep<T>::buffer_bits(false_type)
{
buffer_bits_from_squares(*this);
}
template<>
inline void CowGearPrep<CowGearShare<gf2n_short>>::buffer_bits()
template<class T>
template<int>
void CowGearPrep<T>::buffer_bits(true_type)
{
buffer_bits_without_check();
this->buffer_bits_without_check();
assert(not this->bits.empty());
for (auto& bit : this->bits)
bit.force_to_bit();

View File

@@ -26,6 +26,8 @@ public:
const static bool needs_ot = false;
const static true_type covert;
CowGearShare()
{
}
@@ -37,4 +39,7 @@ public:
};
template<class T>
const true_type CowGearShare<T>::covert;
#endif /* PROTOCOLS_COWGEARSHARE_H_ */

View File

@@ -47,6 +47,11 @@ public:
}
#endif
FakeProtocol branch()
{
return P;
}
void init_mul(SubProcessor<T>*)
{
results.clear();

View File

@@ -68,8 +68,9 @@ public:
*this = a - b;
}
static void split(vector<bit_type>& dest, const vector<int>& regs, int n_bits,
const This* source, int n_inputs, Player& P);
static void split(vector<bit_type>& dest, const vector<int>& regs,
int n_bits, const This* source, int n_inputs,
GC::FakeSecret::Protocol& protocol);
};
#endif /* PROTOCOLS_FAKESHARE_H_ */

View File

@@ -10,7 +10,7 @@
template<class T>
void FakeShare<T>::split(vector<bit_type>& dest,
const vector<int>& regs, int n_bits, const This* source, int n_inputs,
Player&)
GC::FakeSecret::Protocol&)
{
assert(n_bits <= 64);
int unit = GC::Clear::N_BITS;

View File

@@ -0,0 +1,39 @@
/*
* KeyGen.cpp
*
*/
#include "FHEOffline/DataSetup.h"
#include "Processor/OnlineOptions.h"
#include "Protocols/HighGearKeyGen.hpp"
template<>
void PartSetup<FFT_Data>::key_and_mac_generation(Player& P,
MachineBase& machine, int, false_type)
{
auto& batch_size = OnlineOptions::singleton.batch_size;
auto backup = batch_size;
batch_size = 100;
bool done = false;
int n_limbs[2];
for (int i = 0; i < 2; i++)
n_limbs[i] = params.FFTD()[i].get_prD().get_t();
#define X(L, M) \
if (n_limbs[0] == L and n_limbs[1] == M) \
{ \
HighGearKeyGen<L, M>(P, params).run(*this, machine); \
done = true; \
}
X(5, 3) X(4, 3) X(3, 2)
if (not done)
throw runtime_error("not compiled for choice of parameters");
batch_size = backup;
}
template<>
void PartSetup<P2Data>::key_and_mac_generation(Player& P, MachineBase& machine,
int, false_type)
{
HighGearKeyGen<2, 2>(P, params).run(*this, machine);
}

View File

@@ -0,0 +1,71 @@
/*
* HighGearKeyGen.h
*
*/
#ifndef PROTOCOLS_HIGHGEARKEYGEN_H_
#define PROTOCOLS_HIGHGEARKEYGEN_H_
#include "LowGearKeyGen.h"
#include <deque>
using namespace std;
template<class T, class U>
class KeyGenBitFactory
{
U& keygen;
deque<T>& buffer;
public:
KeyGenBitFactory(U& keygen, deque<T>& buffer) :
keygen(keygen), buffer(buffer)
{
}
T get_bit()
{
if (buffer.empty())
keygen.buffer_mabits();
auto res = buffer.front();
buffer.pop_front();
return res;
}
};
template<int L, int M>
class HighGearKeyGen
{
public:
typedef KeyGenProtocol<5, L> Proto0;
typedef KeyGenProtocol<7, M> Proto1;
typedef typename Proto0::share_type share_type0;
typedef typename Proto1::share_type share_type1;
typedef typename share_type0::open_type open_type0;
typedef typename share_type1::open_type open_type1;
typedef ShareVector<share_type0> vector_type0;
typedef ShareVector<share_type1> vector_type1;
typedef typename share_type0::bit_type BT;
Player& P;
const FHE_Params& params;
Proto0 proto0;
Proto1 proto1;
deque<share_type0> bits0;
deque<share_type1> bits1;
HighGearKeyGen(Player& P, const FHE_Params& params);
void buffer_mabits();
template<class FD>
void run(PartSetup<FD>& setup, MachineBase& machine);
};
#endif /* PROTOCOLS_HIGHGEARKEYGEN_H_ */

View File

@@ -0,0 +1,159 @@
/*
* HighGearKeyGen.cpp
*
*/
#include "HighGearKeyGen.h"
#include "FHE/Rq_Element.h"
#include "LowGearKeyGen.hpp"
template<int L, int M>
HighGearKeyGen<L, M>::HighGearKeyGen(Player& P, const FHE_Params& params) :
P(P), params(params), proto0(P, params, 0), proto1(P, params, 1)
{
}
template<int L, int M>
void HighGearKeyGen<L, M>::buffer_mabits()
{
vector<BT> diffs;
vector<typename BT::open_type> open_diffs;
vector<share_type0> my_bits0;
vector<share_type1> my_bits1;
int batch_size = 1000;
auto& bmc = *GC::ShareThread<BT>::s().MC;
for (int i = 0; i < batch_size; i++)
{
share_type0 a0;
share_type1 a1;
BT b0, b1;
proto0.prep->get_dabit(a0, b0);
proto1.prep->get_dabit(a1, b1);
my_bits0.push_back(a0);
my_bits1.push_back(a1);
diffs.push_back(b0 + b1);
}
bmc.POpen(open_diffs, diffs, P);
bmc.Check(P);
for (int i = 0; i < batch_size; i++)
{
bits0.push_back(my_bits0[i]);
bits1.push_back(
my_bits1[i]
+ share_type1::constant(open_diffs.at(i), P.my_num(),
proto1.MC->get_alphai())
- my_bits1[i] * open_diffs.at(i) * 2);
}
}
template<int L, int M>
template<class FD>
void HighGearKeyGen<L, M>::run(PartSetup<FD>& setup, MachineBase& machine)
{
RunningTimer timer;
GlobalPRNG global_prng(P);
auto& fftd = params.FFTD();
AddableVector<open_type0> a0(params.phi_m()), a0_prime(params.phi_m());
AddableVector<open_type1> a1(params.phi_m()), a1_prime(params.phi_m());
a0.randomize(global_prng);
a1.randomize(global_prng);
a0_prime.randomize(global_prng);
a1_prime.randomize(global_prng);
KeyGenBitFactory<share_type0, HighGearKeyGen<L, M>> factory0(*this, bits0);
KeyGenBitFactory<share_type1, HighGearKeyGen<L, M>> factory1(*this, bits1);
vector_type0 sk0;
vector_type1 sk1;
proto0.secret_key(sk0, factory0);
proto1.secret_key(sk1, factory1);
vector_type0 e0, e0_prime;
vector_type1 e1, e1_prime;
proto0.binomial(e0, factory0);
proto0.binomial(e0_prime, factory0);
proto1.binomial(e1, factory1);
proto1.binomial(e1_prime, factory1);
auto f0 = sk0;
auto f0_prime = proto0.schur_product(f0, f0);
Rq_Element a(Ring_Element(fftd[0], evaluation, a0),
Ring_Element(fftd[1], evaluation, a1));
Rq_Element Sw_a(Ring_Element(fftd[0], evaluation, a0_prime),
Ring_Element(fftd[1], evaluation, a1_prime));
bigint p = setup.FieldD.get_prime();
bigint p1 = fftd[1].get_prime();
vector<open_type0> b0, b0_prime;
vector<open_type1> b1, b1_prime;
proto0.MC->POpen(b0, sk0 * a0 + e0 * p, P);
proto1.MC->POpen(b1, sk1 * a1 + e1 * p, P);
proto0.MC->POpen(b0_prime, sk0 * a0_prime + e0_prime * p - f0_prime * p1, P);
proto1.MC->POpen(b1_prime, sk1 * a1_prime + e1_prime * p, P);
Rq_Element b(Ring_Element(fftd[0], evaluation, b0),
Ring_Element(fftd[1], evaluation, b1));
Rq_Element Sw_b(Ring_Element(fftd[0], evaluation, b0_prime),
Ring_Element(fftd[1], evaluation, b1_prime));
setup.pk.assign(a, b, Sw_a, Sw_b);
vector<open_type0> s0_shares;
vector<open_type1> s1_shares;
for (int i = 0; i < params.phi_m(); i++)
{
s0_shares.push_back(sk0.at(i).get_share());
s1_shares.push_back(sk1.at(i).get_share());
}
setup.sk.assign({Ring_Element(fftd[0], evaluation, s0_shares),
Ring_Element(fftd[1], evaluation, s1_shares)});
GC::ShareThread<BT>::s().MC->Check(P);
#ifdef DEBUG_HIGHGEAR_KEYGEN
proto0.MC->POpen(s0_shares, sk0, P);
proto1.MC->POpen(s1_shares, sk1, P);
vector<open_type0> e0_open, e0_prime_open;
vector<open_type1> e1_open, e1_prime_open;
proto0.MC->POpen(e0_open, e0, P);
proto0.MC->POpen(e0_prime_open, e0_prime, P);
proto1.MC->POpen(e1_open, e1, P);
proto1.MC->POpen(e1_prime_open, e1_prime, P);
Rq_Element s(fftd, s0_shares, s1_shares);
Rq_Element e(fftd, e0_open, e1_open);
assert(b == s * a + e * p);
Rq_Element e_prime(fftd, e0_prime_open, e1_prime_open);
assert(Sw_b == s * Sw_a + e_prime * p - s * s * p1);
cerr << "Revealed secret key for check" << endl;
#endif
cerr << "Key generation took " << timer.elapsed() << " seconds" << endl;
timer.reset();
map<string, Timer> timers;
SimpleEncCommit_<FD> EC(P, setup.pk, setup.FieldD, timers, machine, 0, true);
Plaintext_<FD> alpha(setup.FieldD);
EC.next(alpha, setup.calpha);
assert(alpha.is_diagonal());
setup.alphai = alpha.element(0);
cerr << "MAC key generation took " << timer.elapsed() << " seconds" << endl;
#ifdef DEBUG_HIGHGEAR_KEYGEN
auto d = SemiMC<BasicSemiShare<FHE_SK>>().open(setup.sk, P).decrypt(
setup.calpha, setup.FieldD);
auto dd = SemiMC<SemiShare<typename FD::T>>().open(setup.alphai, P);
for (unsigned i = 0; i < d.num_slots(); i++)
assert(d.element(i) == dd);
cerr << "Revealed MAC key for check" << endl;
#endif
}

41
Protocols/HighGearShare.h Normal file
View File

@@ -0,0 +1,41 @@
/*
* HighGearShare.h
*
*/
#ifndef PROTOCOLS_HIGHGEARSHARE_H_
#define PROTOCOLS_HIGHGEARSHARE_H_
#include "ChaiGearShare.h"
template<class T>
class HighGearShare : public ChaiGearShare<T>
{
typedef HighGearShare This;
typedef ChaiGearShare<T> super;
public:
typedef MAC_Check_<This> MAC_Check;
typedef Direct_MAC_Check<This> Direct_MC;
typedef ::Input<This> Input;
typedef ::PrivateOutput<This> PrivateOutput;
typedef SPDZ<This> Protocol;
typedef ChaiGearPrep<This> LivePrep;
const static false_type covert;
HighGearShare()
{
}
template<class U>
HighGearShare(const U& other) :
super(other)
{
}
};
template<class T>
const false_type HighGearShare<T>::covert;
#endif /* PROTOCOLS_HIGHGEARSHARE_H_ */

View File

@@ -0,0 +1,34 @@
/*
* LowGearKeyGen.cpp
*
*/
#include "FHEOffline/DataSetup.h"
#include "Processor/OnlineOptions.h"
#include "Protocols/LowGearKeyGen.hpp"
template<>
void PairwiseSetup<FFT_Data>::key_and_mac_generation(Player& P,
PairwiseMachine& machine, int, false_type)
{
int n_limbs = params.FFTD()[0].get_prD().get_t();
switch (n_limbs)
{
#define X(L) case L: LowGearKeyGen<L>(P, machine, params).run(*this); break;
X(3) X(4) X(5) X(6)
#undef X
default:
throw runtime_error(
"not compiled for choice of parameters, add X("
+ to_string(n_limbs) + ") at " + __FILE__ + ":"
+ to_string(__LINE__ - 5));
}
}
template<>
void PairwiseSetup<P2Data>::key_and_mac_generation(Player& P,
PairwiseMachine& machine, int, false_type)
{
LowGearKeyGen<2>(P, machine, params).run(*this);
}

78
Protocols/LowGearKeyGen.h Normal file
View File

@@ -0,0 +1,78 @@
/*
* LowGearKeyGen.h
*
*/
#ifndef PROTOCOLS_LOWGEARKEYGEN_H_
#define PROTOCOLS_LOWGEARKEYGEN_H_
#include "ShareVector.h"
#include "FHEOffline/PairwiseMachine.h"
#include "Protocols/MascotPrep.h"
#include "Processor/Processor.h"
#include "GC/TinierSecret.h"
#include "Math/gfp.h"
template<int X, int L>
class KeyGenProtocol
{
public:
typedef Share<gfp_<X, L>> share_type;
typedef typename share_type::open_type open_type;
typedef ShareVector<share_type> vector_type;
protected:
Player& P;
const FHE_Params& params;
const FFT_Data& fftd;
SeededPRNG G;
DataPositions usage;
share_type get_bit()
{
return prep->get_bit();
}
public:
Preprocessing<share_type>* prep;
MAC_Check_<share_type>* MC;
SubProcessor<share_type>* proc;
KeyGenProtocol(Player& P, const FHE_Params& params, int level = 0);
~KeyGenProtocol();
void input(vector<vector_type>& shares, const Rq_Element& secret);
template<class T>
void binomial(vector_type& shares, T& prep);
template<class T>
void hamming(vector_type& shares, T& prep);
template<class T>
void secret_key(vector_type& shares, T& prep);
vector_type schur_product(const vector_type& x, const vector_type& y);
void output_to(int player, vector<open_type>& opened,
vector<share_type>& shares);
};
template<int L>
class LowGearKeyGen : public KeyGenProtocol<5, L>
{
typedef KeyGenProtocol<5, L> super;
typedef typename super::share_type share_type;
typedef typename super::open_type open_type;
typedef typename super::vector_type vector_type;
Player& P;
PairwiseMachine& machine;
void generate_keys(FHE_Params& params);
public:
LowGearKeyGen(Player& P, PairwiseMachine& machine, FHE_Params& params);
template<class FD>
void run(PairwiseSetup<FD>& setup);
};
#endif /* PROTOCOLS_LOWGEARKEYGEN_H_ */

284
Protocols/LowGearKeyGen.hpp Normal file
View File

@@ -0,0 +1,284 @@
/*
* LowGearKeyGen.cpp
*
*/
#include "LowGearKeyGen.h"
#include "FHE/Rq_Element.h"
#include "Tools/benchmarking.h"
#include "Machines/SPDZ.hpp"
#include "ShareVector.hpp"
template<int L>
LowGearKeyGen<L>::LowGearKeyGen(Player& P, PairwiseMachine& machine,
FHE_Params& params) :
KeyGenProtocol<5, L>(P, params), P(P), machine(machine)
{
}
template<int X, int L>
KeyGenProtocol<X, L>::KeyGenProtocol(Player& P, const FHE_Params& params,
int level) :
P(P), params(params), fftd(params.FFTD().at(level)), usage(P)
{
open_type::init_field(params.FFTD().at(level).get_prD().pr);
typename share_type::mac_key_type alphai;
if (OnlineOptions::singleton.live_prep)
{
prep = new MascotDabitOnlyPrep<share_type>(0, usage);
alphai.randomize(G);
}
else
{
prep = new Sub_Data_Files<share_type>(P.N,
get_prep_sub_dir<share_type>(P.num_players()), usage);
read_mac_key(get_prep_sub_dir<share_type>(P.num_players()), P.N, alphai);
}
MC = new MAC_Check_<share_type>(alphai);
proc = new SubProcessor<share_type>(*MC, *prep, P);
}
template<int X, int L>
KeyGenProtocol<X, L>::~KeyGenProtocol()
{
MC->Check(P);
usage.print_cost();
delete proc;
delete prep;
delete MC;
}
template<int X, int L>
void KeyGenProtocol<X, L>::input(vector<vector_type>& shares, const Rq_Element& secret)
{
assert(secret.level() == 0);
auto s = secret.get(0);
s.change_rep(evaluation);
auto& FFTD = s.get_FFTD();
auto& inputter = this->proc->input;
inputter.reset_all(P);
for (int i = 0; i < FFTD.num_slots(); i++)
inputter.add_from_all(s.get_element(i));
inputter.exchange();
shares.clear();
shares.resize(P.num_players());
for (int i = 0; i < FFTD.num_slots(); i++)
for (int j = 0; j < P.num_players(); j++)
shares[j].push_back(inputter.finalize(j));
}
template<int X, int L>
template<class T>
void KeyGenProtocol<X, L>::binomial(vector_type& shares, T& prep)
{
shares.resize(params.phi_m());
RunningTimer timer, total;
for (int i = 0; i < params.phi_m(); i++)
{
#ifdef VERBOSE
if (timer.elapsed() > 10)
{
cerr << i << "/" << params.phi_m() << ", throughput " <<
i / total.elapsed() << endl;
timer.reset();
}
#endif
auto& share = shares[i];
share = {};
for (int i = 0; i < params.get_DG().get_NewHopeB(); i++)
{
share += prep.get_bit();
share -= prep.get_bit();
}
}
shares.fft(fftd);
}
template<int X, int L>
template<class T>
void KeyGenProtocol<X, L>::hamming(vector_type& shares, T& prep)
{
shares.resize(params.phi_m());
int h = params.get_h();
assert(h > 0);
assert(shares.size() / h * h == shares.size());
int n_bits = log(shares.size() / h) / log(2);
// assert(size_t(h << n_bits) == shares.size());
for (auto& share : shares)
share = prep.get_bit();
auto& protocol = proc->protocol;
for (int i = 0; i < n_bits - 1; i++)
{
protocol.init_mul(proc);
for (auto& share : shares)
protocol.prepare_mul(share, prep.get_bit());
protocol.exchange();
for (auto& share : shares)
share = protocol.finalize_mul();
}
protocol.init_mul(proc);
auto one = share_type::constant(1, P.my_num(), MC->get_alphai());
for (auto& share : shares)
protocol.prepare_mul(share, prep.get_bit() * 2 - one);
protocol.exchange();
for (auto& share : shares)
share = protocol.finalize_mul();
shares.fft(fftd);
}
template<int X, int L>
template<class T>
void KeyGenProtocol<X, L>::secret_key(vector_type& shares, T& prep)
{
assert(params.get_h() != 0);
cerr << "Generate secret key by ";
if (params.get_h() > 0)
{
cerr << "Hamming weight" << endl;
hamming(shares, prep);
}
else
{
cerr << "binomial" << endl;
binomial(shares, prep);
}
}
template<int X, int L>
typename KeyGenProtocol<X, L>::vector_type KeyGenProtocol<X, L>::schur_product(
const vector_type& x, const vector_type& y)
{
vector_type res;
assert(x.size() == y.size());
auto& protocol = proc->protocol;
protocol.init_mul(proc);
for (size_t i = 0; i < x.size(); i++)
protocol.prepare_mul(x[i], y[i]);
protocol.exchange();
for (size_t i = 0; i < x.size(); i++)
res.push_back(protocol.finalize_mul());
return res;
}
template<int X, int L>
void KeyGenProtocol<X, L>::output_to(int player, vector<open_type>& opened,
vector<share_type>& shares)
{
PrivateOutput<share_type> po(*proc);
vector<share_type> masked;
for (auto& share : shares)
masked.push_back(po.start(player, share));
MC->POpen(opened, masked, P);
for (auto& x : opened)
x = po.stop(player, x);
}
template<int L>
void LowGearKeyGen<L>::generate_keys(FHE_Params& params)
{
RunningTimer timer;
auto& pk = machine.pk;
GlobalPRNG global_prng(P);
auto& FFTD = pk.get_params().FFTD()[0];
for (int i = 0; i < P.num_players(); i++)
{
vector_type sk;
this->secret_key(sk, *this);
vector<open_type> open_sk;
this->output_to(i, open_sk, sk);
if (P.my_num() == i)
machine.sk.assign(Ring_Element(FFTD, evaluation, open_sk));
vector_type e0;
this->binomial(e0, *this);
AddableVector<open_type> a0(pk.get_params().phi_m());
a0.randomize(global_prng);
vector<open_type> b0;
assert(machine.sk.p() != 0);
this->MC->POpen(b0, sk * a0 + e0 * machine.sk.p(), P);
machine.other_pks[i] = FHE_PK(params, machine.sk.p());
machine.other_pks[i].assign(Ring_Element(FFTD, evaluation, a0),
Ring_Element(FFTD, evaluation, b0));
}
this->MC->Check(P);
cerr << "Key generation took " << timer.elapsed() << " seconds" << endl;
}
template<int L>
template<class FD>
void LowGearKeyGen<L>::run(PairwiseSetup<FD>& setup)
{
generate_keys(setup.params);
machine.sk.check(machine.pk, setup.FieldD);
RunningTimer timer;
auto mac_key = SeededPRNG().get<typename FD::T>();
PairwiseGenerator<FD> generator(0, machine, &P);
map<string, Timer> timers;
MultiEncCommit<FD> EC(P, machine.other_pks, setup.FieldD,
timers, machine, generator, true);
assert(EC.proof.get_diagonal());
vector<Plaintext_<FD>> m(EC.proof.U, setup.FieldD);
for (auto& mm : m)
mm.assign_constant(mac_key);
AddableVector<Ciphertext> C;
octetStream ciphertexts, cleartexts;
EC.generate_proof(C, m, ciphertexts, cleartexts);
AddableVector<Ciphertext> others_ciphertexts;
others_ciphertexts.resize(EC.proof.U, machine.pk.get_params());
Verifier<FD> verifier(EC.proof, setup.FieldD);
verifier.NIZKPoK(others_ciphertexts, ciphertexts,
cleartexts, machine.pk, false);
machine.enc_alphas.clear();
for (int i = 0; i < P.num_players(); i++)
machine.enc_alphas.push_back(machine.other_pks[i]);
for (int i = 1; i < P.num_players(); i++)
{
int player = P.get_player(-i);
#ifdef VERBOSE_HE
cerr << "Sending proof with " << 1e-9 * ciphertexts.get_length() << "+"
<< 1e-9 * cleartexts.get_length() << " GB" << endl;
#endif
timers["Sending"].start();
P.pass_around(ciphertexts);
P.pass_around(cleartexts);
timers["Sending"].stop();
#ifdef VERBOSE_HE
cerr << "Checking proof of player " << i << endl;
#endif
timers["Verifying"].start();
verifier.NIZKPoK(others_ciphertexts, ciphertexts,
cleartexts, machine.other_pks[player], false);
timers["Verifying"].stop();
machine.enc_alphas.at(player) = others_ciphertexts.at(0);
}
setup.set_alphai(mac_key);
machine.enc_alphas.at(P.my_num()) = C.at(0);
auto test = machine.sk.decrypt(C[0], setup.FieldD);
for (int i = 0; i < setup.FieldD.num_slots(); i++)
assert(test.element(i) == mac_key);
cerr << "MAC key generation took " << timer.elapsed() << " seconds" << endl;
}

41
Protocols/LowGearShare.h Normal file
View File

@@ -0,0 +1,41 @@
/*
* LowGearShare.h
*
*/
#ifndef PROTOCOLS_LOWGEARSHARE_H_
#define PROTOCOLS_LOWGEARSHARE_H_
#include "CowGearShare.h"
template<class T>
class LowGearShare : public CowGearShare<T>
{
typedef LowGearShare This;
typedef CowGearShare<T> super;
public:
typedef MAC_Check_<This> MAC_Check;
typedef Direct_MAC_Check<This> Direct_MC;
typedef ::Input<This> Input;
typedef ::PrivateOutput<This> PrivateOutput;
typedef SPDZ<This> Protocol;
typedef CowGearPrep<This> LivePrep;
const static false_type covert;
LowGearShare()
{
}
template<class U>
LowGearShare(const U& other) :
super(other)
{
}
};
template<class T>
const false_type LowGearShare<T>::covert;
#endif /* PROTOCOLS_LOWGEARSHARE_H_ */

View File

@@ -40,6 +40,7 @@ MalRepRingPrepWithBits<T>::MalRepRingPrepWithBits(SubProcessor<T>* proc,
DataPositions& usage) :
BufferPrep<T>(usage), BitPrep<T>(proc, usage),
RingPrep<T>(proc, usage),
MaliciousDabitOnlyPrep<T>(proc, usage),
MaliciousRingPrep<T>(proc, usage), MalRepRingPrep<T>(proc, usage),
RingOnlyBitsFromSquaresPrep<T>(proc, usage),
SimplerMalRepRingPrep<T>(proc, usage)

View File

@@ -32,6 +32,7 @@ MaliciousRepPrepWithBits<T>::MaliciousRepPrepWithBits(SubProcessor<T>* proc,
DataPositions& usage) :
BufferPrep<T>(usage), MaliciousRepPrep<T>(proc, usage),
BitPrep<T>(proc, usage), RingPrep<T>(proc, usage),
MaliciousDabitOnlyPrep<T>(proc, usage),
MaliciousRingPrep<T>(proc, usage)
{
}
@@ -173,6 +174,7 @@ void MaliciousBitOnlyRepPrep<T>::buffer_bits()
auto buffer_size = this->buffer_size;
assert(honest_proc);
Player& P = honest_proc->P;
honest_prep.buffer_size = buffer_size;
bits.clear();
for (int i = 0; i < buffer_size; i++)
{

View File

@@ -12,21 +12,21 @@
#include "Spdz2kPrep.hpp"
template<class T>
void MaliciousRingPrep<T>::buffer_dabits(ThreadQueues* queues)
void MaliciousDabitOnlyPrep<T>::buffer_dabits(ThreadQueues* queues)
{
buffer_dabits<0>(queues, T::clear::characteristic_two);
}
template<class T>
template<int>
void MaliciousRingPrep<T>::buffer_dabits(ThreadQueues*, true_type)
void MaliciousDabitOnlyPrep<T>::buffer_dabits(ThreadQueues*, true_type)
{
throw runtime_error("only implemented for integer-like domains");
}
template<class T>
template<int>
void MaliciousRingPrep<T>::buffer_dabits(ThreadQueues* queues, false_type)
void MaliciousDabitOnlyPrep<T>::buffer_dabits(ThreadQueues* queues, false_type)
{
assert(this->proc != 0);
vector<dabit<T>> check_dabits;

View File

@@ -24,7 +24,8 @@ void MaliciousShamirMC<T>::init_open(const Player& P, int n)
reconstructions[i].resize(i);
for (int j = 0; j < i; j++)
reconstructions[i][j] =
Shamir<T>::get_rec_factor(j, i);
Shamir<T>::get_rec_factor(P.get_player(j),
P.num_players(), P.my_num(), i);
}
}
@@ -37,7 +38,7 @@ typename T::open_type MaliciousShamirMC<T>::finalize_open()
int threshold = ShamirMachine::s().threshold;
shares.resize(2 * threshold + 1);
for (size_t j = 0; j < shares.size(); j++)
shares[j].unpack((*this->os)[j]);
shares[j].unpack((*this->os)[this->player->get_player(j)]);
return reconstruct(shares);
}

View File

@@ -9,6 +9,7 @@ template<class T>
MaliciousShamirPO<T>::MaliciousShamirPO(Player& P) :
P(P), shares(P.num_players())
{
MC.init_open(P);
}
template<class T>

View File

@@ -10,7 +10,9 @@
template<class T>
MamaPrep<T>::MamaPrep(SubProcessor<T>* proc, DataPositions& usage) :
BufferPrep<T>(usage), BitPrep<T>(proc, usage),
RingPrep<T>(proc, usage), OTPrep<T>(proc, usage),
RingPrep<T>(proc, usage),
MaliciousDabitOnlyPrep<T>(proc, usage),
OTPrep<T>(proc, usage),
MaliciousRingPrep<T>(proc, usage)
{
this->params.amplify = true;

View File

@@ -58,6 +58,7 @@ public:
typedef MascotMultiplier<This> Multiplier;
typedef FixedVec<T, N> sacri_type;
typedef This input_type;
typedef This input_check_type;
typedef MamaRectangle<T, N> Square;
typedef typename T::Square Rectangle;
@@ -95,6 +96,12 @@ public:
super(other.get_share(), other.get_mac())
{
}
template<class U, class V>
MamaShare(const U& share, const V& mac) :
super(share, mac)
{
}
};
#endif /* PROTOCOLS_MAMASHARE_H_ */

View File

@@ -27,50 +27,88 @@ public:
};
template<class T>
class MascotTriplePrep : public OTPrep<T>
class MascotInputPrep : public OTPrep<T>
{
void buffer_inputs(int player);
public:
MascotTriplePrep(SubProcessor<T> *proc, DataPositions &usage) :
MascotInputPrep(SubProcessor<T> *proc, DataPositions &usage) :
BufferPrep<T>(usage), BitPrep<T>(proc, usage),
OTPrep<T>(proc, usage)
{
}
void buffer_triples();
void buffer_inputs(int player);
};
template<class T>
class MascotPrep: public virtual MaliciousRingPrep<T>,
class MascotTriplePrep : public MascotInputPrep<T>
{
public:
MascotTriplePrep(SubProcessor<T> *proc, DataPositions &usage) :
BufferPrep<T>(usage), BitPrep<T>(proc, usage),
MascotInputPrep<T>(proc, usage)
{
}
void buffer_triples();
};
template<class T>
class MascotDabitOnlyPrep : public virtual MaliciousDabitOnlyPrep<T>,
public virtual MascotTriplePrep<T>
{
public:
MascotDabitOnlyPrep(SubProcessor<T>* proc, DataPositions& usage) :
BufferPrep<T>(usage), BitPrep<T>(proc, usage),
RingPrep<T>(proc, usage),
MaliciousDabitOnlyPrep<T>(proc, usage),
MascotTriplePrep<T>(proc, usage)
{
}
virtual ~MascotDabitOnlyPrep()
{
}
virtual void buffer_bits();
};
template<class T>
class MascotPrep : public virtual MaliciousRingPrep<T>,
public virtual MascotDabitOnlyPrep<T>
{
public:
MascotPrep(SubProcessor<T>* proc, DataPositions& usage) :
BufferPrep<T>(usage), BitPrep<T>(proc, usage),
RingPrep<T>(proc, usage),
MaliciousDabitOnlyPrep<T>(proc, usage),
MaliciousRingPrep<T>(proc, usage),
MascotTriplePrep<T>(proc, usage)
MascotTriplePrep<T>(proc, usage),
MascotDabitOnlyPrep<T>(proc, usage)
{
}
virtual ~MascotPrep()
{
}
void buffer_bits() { throw runtime_error("use subclass"); }
virtual void buffer_bits()
{
MascotDabitOnlyPrep<T>::buffer_bits();
}
void buffer_edabits(bool strict, int n_bits, ThreadQueues* queues);
};
template<class T>
class MascotFieldPrep : public MascotPrep<T>
class MascotFieldPrep : public virtual MascotPrep<T>
{
void buffer_bits();
public:
MascotFieldPrep<T>(SubProcessor<T>* proc, DataPositions& usage) :
BufferPrep<T>(usage),
BitPrep<T>(proc, usage), RingPrep<T>(proc, usage),
MaliciousDabitOnlyPrep<T>(proc, usage),
MaliciousRingPrep<T>(proc, usage),
MascotTriplePrep<T>(proc, usage), MascotPrep<T>(proc, usage)
MascotTriplePrep<T>(proc, usage),
MascotDabitOnlyPrep<T>(proc, usage),
MascotPrep<T>(proc, usage)
{
}
};

View File

@@ -36,6 +36,10 @@ void OTPrep<T>::set_protocol(typename T::Protocol& protocol)
BitPrep<T>::set_protocol(protocol);
SubProcessor<T>* proc = this->proc;
assert(proc != 0);
// make sure not to use Montgomery multiplication
T::open_type::next::template init<typename T::open_type>(false);
triple_generator = new typename T::TripleGenerator(
BaseMachine::s().fresh_ot_setup(),
proc->P.N, -1,
@@ -66,7 +70,7 @@ void MascotTriplePrep<T>::buffer_triples()
}
template<class T>
void MascotFieldPrep<T>::buffer_bits()
void MascotDabitOnlyPrep<T>::buffer_bits()
{
this->params.generateBits = true;
auto& triple_generator = this->triple_generator;
@@ -78,7 +82,7 @@ void MascotFieldPrep<T>::buffer_bits()
}
template<class T>
void MascotTriplePrep<T>::buffer_inputs(int player)
void MascotInputPrep<T>::buffer_inputs(int player)
{
auto& triple_generator = this->triple_generator;
assert(triple_generator);

View File

@@ -56,13 +56,14 @@ public:
}
template<class U>
static void split(vector<U>& dest, const vector<int>& regs,
int n_bits, const super* source, int n_inputs, Player& P)
static void split(vector<U>& dest, const vector<int>& regs, int n_bits,
const super* source, int n_inputs,
typename bit_type::Protocol& protocol)
{
if (regs.size() / n_bits != 3)
throw runtime_error("only secure with three-way split");
super::split(dest, regs, n_bits, source, n_inputs, P);
super::split(dest, regs, n_bits, source, n_inputs, protocol);
}
};

View File

@@ -25,6 +25,8 @@ public:
PostSacrifice(Player& P);
~PostSacrifice();
Player& branch();
void init_mul(SubProcessor<T>* proc);
typename T::clear prepare_mul(const T& x, const T& y, int n = -1);
void exchange() { internal.exchange(); }

View File

@@ -18,6 +18,12 @@ PostSacrifice<T>::~PostSacrifice()
check();
}
template<class T>
Player& PostSacrifice<T>::branch()
{
return P;
}
template<class T>
void PostSacrifice<T>::init_mul(SubProcessor<T>* proc)
{

View File

@@ -41,9 +41,11 @@ public:
}
template<class U>
static void split(vector<U>& dest, const vector<int>& regs,
int n_bits, const Rep3Share2* source, int n_inputs, Player& P)
static void split(vector<U>& dest, const vector<int>& regs, int n_bits,
const Rep3Share2* source, int n_inputs,
typename U::Protocol& protocol)
{
auto& P = protocol.P;
int my_num = P.my_num();
assert(n_bits <= 64);
int unit = GC::Clear::N_BITS;

View File

@@ -14,6 +14,7 @@ class Rep4 : public ProtocolBase<T>
friend class Rep4RingPrep<T>;
typedef typename T::open_type open_type;
typedef array<ElementPRNG<typename T::open_type>, 3> prngs_type;
octetStreams send_os;
octetStreams receive_os;
@@ -21,6 +22,7 @@ class Rep4 : public ProtocolBase<T>
array<array<Hash, 4>, 4> send_hashes, receive_hashes;
array<vector<open_type>, 5> add_shares;
array<open_type, 5> dotprod_shares;
vector<int> bit_lengths;
class ResTuple
@@ -56,10 +58,14 @@ class Rep4 : public ProtocolBase<T>
false_type);
public:
array<ElementPRNG<typename T::open_type>, 3> rep_prngs;
prngs_type rep_prngs;
Player& P;
Rep4(Player& P);
Rep4(Player& P, prngs_type& prngs);
~Rep4();
Rep4 branch();
void init_mul(SubProcessor<T>* proc = 0);
void init_mul(Preprocessing<T>& prep, typename T::MAC_Check& MC);
@@ -78,6 +84,10 @@ public:
void trunc_pr(const vector<int>& regs, int size, SubProcessor<T>& proc);
template<class U>
void split(vector<T>& dest, const vector<int>& regs, int n_bits,
const U* source, int n_inputs);
int get_n_relevant_players() { return 2; }
};

View File

@@ -24,6 +24,40 @@ Rep4<T>::Rep4(Player& P) :
rep_prngs[i].SetSeed(to_receive[P.get_player(i)].get_data());
}
template<class T>
Rep4<T>::Rep4(Player& P, prngs_type& prngs) :
my_num(P.my_num()), P(P)
{
for (int i = 0; i < 3; i++)
rep_prngs[i].SetSeed(prngs[i]);
}
template<class T>
Rep4<T>::~Rep4()
{
for (auto& x : receive_hashes)
for (auto& y : x)
if (y.size > 0)
{
check();
return;
}
for (auto& x : send_hashes)
for (auto& y : x)
if (y.size > 0)
{
check();
return;
}
}
template<class T>
Rep4<T> Rep4<T>::branch()
{
return {P, rep_prngs};
}
template<class T>
void Rep4<T>::init_mul(SubProcessor<T>*)
{
@@ -184,7 +218,7 @@ template<class T>
void Rep4<T>::init_dotprod(SubProcessor<T>*)
{
init_mul();
next_dotprod();
dotprod_shares = {};
}
template<class T>
@@ -192,15 +226,16 @@ void Rep4<T>::prepare_dotprod(const T& x, const T& y)
{
auto a = get_addshares(x, y);
for (int i = 0; i < 5; i++)
add_shares[i].back() += a[i];
dotprod_shares[i] += a[i];
}
template<class T>
void Rep4<T>::next_dotprod()
{
for (auto& a : add_shares)
a.push_back({});
for (int i = 0; i < 5; i++)
add_shares[i].push_back(dotprod_shares[i]);
bit_lengths.push_back(-1);
dotprod_shares = {};
}
template<class T>
@@ -234,7 +269,6 @@ T Rep4<T>::finalize_mul(int)
template<class T>
T Rep4<T>::finalize_dotprod(int)
{
this->counter++;
return finalize_mul();
}
@@ -297,6 +331,7 @@ void Rep4<T>::trunc_pr(const vector<int>& regs, int size,
SubProcessor<T>& proc, false_type)
{
assert(regs.size() % 4 == 0);
this->trunc_pr_counter += size * regs.size() / 4;
typedef typename T::open_type open_type;
vector<TruncPrTupleWithGap<open_type>> infos;
@@ -419,3 +454,76 @@ void Rep4<T>::trunc_pr(const vector<int>& regs, int size,
}
}
}
template<class T>
template<class U>
void Rep4<T>::split(vector<T>& dest, const vector<int>& regs, int n_bits,
const U* source, int n_inputs)
{
assert(regs.size() / n_bits == 2);
assert(n_bits <= 64);
int unit = GC::Clear::N_BITS;
int my_num = P.my_num();
int i0 = -1;
switch (my_num)
{
case 0:
i0 = 1;
break;
case 1:
i0 = 0;
break;
case 2:
i0 = 1;
break;
case 3:
i0 = 0;
break;
}
vector<BitVec> to_share;
init_mul();
for (int k = 0; k < DIV_CEIL(n_inputs, unit); k++)
{
int start = k * unit;
int m = min(unit, n_inputs - start);
square64 square;
for (int j = 0; j < m; j++)
{
auto& input_share = source[j + start];
auto input_value = input_share[i0] + input_share[i0 + 1];
square.rows[j] = Integer(input_value).get();
}
square.transpose(m, n_bits);
for (int j = 0; j < n_bits; j++)
{
to_share.push_back(square.rows[j]);
bit_lengths.push_back(m);
}
}
array<PointerVector<ResTuple>, 2> results;
for (auto& x : results)
x.resize(to_share.size());
prepare_joint_input(0, 1, 3, 2, to_share, results[0]);
prepare_joint_input(2, 3, 1, 0, to_share, results[1]);
P.send_receive_all(channels, send_os, receive_os);
finalize_joint_input(0, 1, 3, 2, results[0]);
finalize_joint_input(2, 3, 1, 0, results[1]);
for (int k = 0; k < DIV_CEIL(n_inputs, unit); k++)
{
for (int j = 0; j < n_bits; j++)
for (int i = 0; i < 2; i++)
{
auto res = results[i].next().res;
dest.at(regs.at(2 * j + i) + k) = res;
}
}
}

Some files were not shown because too many files have changed in this diff Show More