def Norm(b, k, f, kappa, simplex_flag=False): """ Computes secret integer values [c] and [v_prime] st. 2^{k-1} <= c < 2^k and c = b*v_prime """ # For simplex, we can get rid of computing abs(b) temp = None if simplex_flag == False: temp = types.sint(b < 0) elif simplex_flag == True: temp = types.cint(0) sign = 1 - 2 * temp # 1 - 2 * [b < 0] absolute_val = sign * b #next 2 lines actually compute the SufOR for little indian encoding bits = absolute_val.bit_decompose(k)[::-1] suffixes = AdvInteger.PreOR(bits)[::-1] z = [0] * k for i in range(k - 1): z[i] = suffixes[i] - suffixes[i + 1] z[k - 1] = suffixes[k - 1] #doing complicated stuff to compute v = 2^{k-m} acc = types.cint(0) for i in range(k): acc += AdvInteger.two_power(k - i - 1) * z[i] part_reciprocal = absolute_val * acc signed_acc = sign * acc return part_reciprocal, signed_acc
def Int2FL(a, gamma, l, kappa): lam = gamma - 1 s = types.sint() AdvInteger.LTZ(s, a, gamma, kappa) z = AdvInteger.EQZ(a, gamma, kappa) a = (1 - 2 * s) * a a_bits = AdvInteger.BitDec(a, lam, lam, kappa) a_bits.reverse() b = AdvInteger.PreOR(a_bits) t = a * (1 + sum(2**i * (1 - b_i) for i, b_i in enumerate(b))) p = -(lam - sum(b)) if lam > l: if types.sfloat.round_nearest: v, overflow = TruncRoundNearestAdjustOverflow( t, gamma - 1, l, kappa) p = p + overflow else: v = types.sint() AdvInteger.Trunc(v, t, gamma - 1, gamma - l - 1, kappa, False) #TODO: Shouldnt this be only gamma else: v = 2**(l - gamma + 1) * t p = (p + gamma - 1 - l) * (1 - z) return v, p, z, s
def SDiv_ABZS12(a, b, l, kappa): theta = int(ceil(log(l, 2))) x = b y = a for i in range(theta - 1): y = y * ((2**(l + 1)) - x) y = AdvInteger.TruncPr(y, 2 * l + 1, l, kappa) x = x * ((2**(l + 1)) - x) x = AdvInteger.TruncPr(x, 2 * l + 1, l, kappa) y = y * ((2**(l + 1)) - x) y = AdvInteger.TruncPr(y, 2 * l + 1, l, kappa) return y
def FLRound(x, mode): """ Rounding with floating point output. *mode*: 0 -> floor, 1 -> ceil, -1 > trunc """ v1, p1, z1, s1, l, k = x.v, x.p, x.z, x.s, x.vlen, x.plen a = types.sint() AdvInteger.LTZ(a, p1, k, x.kappa) b = p1.less_than(-l + 1, k, x.kappa) v2, inv_2pow_p1 = AdvInteger.Oblivious_Trunc(v1, l, -a * (1 - b) * x.p, x.kappa, True) c = AdvInteger.EQZ(v2, l, x.kappa) if mode == -1: away_from_zero = 0 mode = x.s else: away_from_zero = mode + s1 - 2 * mode * s1 v = v1 - v2 + (1 - c) * inv_2pow_p1 * away_from_zero d = v.equal(AdvInteger.two_power(l), l + 1, x.kappa) v = d * AdvInteger.two_power(l - 1) + (1 - d) * v v = a * ((1 - b) * v + b * away_from_zero * AdvInteger.two_power(l - 1)) + (1 - a) * v1 s = (1 - b * mode) * s1 z = AdvInteger.or_op(AdvInteger.EQZ(v, l, x.kappa), z1) v = v * (1 - z) p = ((p1 + d * a) * (1 - b) + b * away_from_zero * (1 - l)) * (1 - z) return v, p, z, s
def cint_cint_division(a, b, k, f): """ Goldschmidt method implemented with SE aproximation: http://stackoverflow.com/questions/2661541/picking-good-first-estimates-for-goldschmidt-division """ from types import cint, Array from library import for_range # theta can be replaced with something smaller # for safety we assume that is the same theta from previous GS method theta = int(ceil(log(k / 3.5) / log(2))) two = cint(2) * AdvInteger.two_power(f) sign_b = cint(1) - 2 * cint(b < 0) sign_a = cint(1) - 2 * cint(a < 0) absolute_b = b * sign_b absolute_a = a * sign_a w0 = approximate_reciprocal(absolute_b, k, f, theta) A = Array(theta, cint) B = Array(theta, cint) W = Array(theta, cint) A[0] = absolute_a B[0] = absolute_b W[0] = w0 @for_range(1, theta) def block(i): A[i] = (A[i - 1] * W[i - 1]) >> f B[i] = (B[i - 1] * W[i - 1]) >> f W[i] = two - B[i] return (sign_a * sign_b) * A[theta - 1]
def lin_app_SQ(b, k, f): alpha = types.cfix((-0.8099868542) * 2**(k)) beta = types.cfix(1.787727479 * 2**(2 * k)) # obtain normSQ parameters c, v, m, W = FixedPt.norm_SQ(types.sint(b), k) # c is now escalated w = alpha * load_sint( c, types.sfix) + beta # equation before b and reduction by order of k # m even or odd determination m_bit = types.sint() AdvInteger.Mod2(m_bit, m, int(math.ceil(math.log(k, 2))), w.kappa, False) m = load_sint(m_bit, types.sfix) # w times v this way both terms have 2^3k and can be symplified w = w * v factor = 1.0 / (2**(3.0 * k - 2 * f)) w = w * factor # w escalated to 3k -2 * f # normalization factor W* 1/2 ^{f/2} w = w * W * types.cfix(1.0 / (2**(f / 2.0))) # now we need to elminate an additional root of 2 in case m was odd sqr_2 = types.cfix((2**(1 / 2.0))) w = (1 - m) * w + sqr_2 * w * m return w
def sint_cint_division(a, b, k, f, kappa): """ type(a) = sint, type(b) = cint """ from types import cint, sint, Array from library import for_range theta = int(ceil(log(k / 3.5) / log(2))) two = cint(2) * AdvInteger.two_power(f) sign_b = cint(1) - 2 * cint(b < 0) sign_a = sint(1) - 2 * sint(a < 0) absolute_b = b * sign_b absolute_a = a * sign_a w0 = approximate_reciprocal(absolute_b, k, f, theta) A = Array(theta, sint) B = Array(theta, cint) W = Array(theta, cint) A[0] = absolute_a B[0] = absolute_b W[0] = w0 @for_range(1, theta) def block(i): A[i] = AdvInteger.TruncPr(A[i - 1] * W[i - 1], 2 * k, f, kappa) temp = (B[i - 1] * W[i - 1]) >> f # no reading and writing to the same variable in a for loop. W[i] = two - temp B[i] = temp return (sign_a * sign_b) * A[theta - 1]
def trunc(x): if type(x) is types.sfix: return AdvInteger.Oblivious_Trunc(x.v, x.k, x.f, x.kappa) elif type(x) is types.sfloat: v, p, z, s = floatingpoint.FLRound(x, 0) return types.sfloat(v, p, z, s, x.err) return x
def MSB(b, k): # calculation of z # x in order 0 - k if (k > types.program.bit_length): raise OverflowError("The supported bit \ lenght of the application is smaller than k") x_order = b.bit_decompose(k) x = [0] * k # x i now inverted for i in range(k - 1, -1, -1): x[k - 1 - i] = x_order[i] # y is inverted for PReOR and then restored y_order = AdvInteger.PreOR(x) # y in order (restored in orginal order y = [0] * k for i in range(k - 1, -1, -1): y[k - 1 - i] = y_order[i] # obtain z z = [0] * (k + 1 - k % 2) for i in range(k - 1): z[i] = y[i] - y[i + 1] z[k - 1] = y[k - 1] return z
def approximate_reciprocal(divisor, k, f, theta): """ returns aproximation of 1/divisor where type(divisor) = cint """ from types import cint, Array, MemValue, regint from library import for_range, if_ def twos_complement(x): bits = x.bit_decompose(k)[::-1] bit_array = Array(k, cint) bit_array.assign(bits) twos_result = MemValue(cint(0)) @for_range(k) def block(i): val = twos_result.read() val <<= 1 val += 1 - bit_array[i] twos_result.write(val) return twos_result.read() + 1 bit_array = Array(k, cint) bits = divisor.bit_decompose(k)[::-1] bit_array.assign(bits) cnt_leading_zeros = MemValue(regint(0)) flag = MemValue(regint(0)) cnt_leading_zeros = MemValue(regint(0)) normalized_divisor = MemValue(divisor) @for_range(k) def block(i): flag.write(flag.read() | bit_array[i] == 1) @if_(flag.read() == 0) def block(): cnt_leading_zeros.write(cnt_leading_zeros.read() + 1) normalized_divisor.write(normalized_divisor << 1) q = MemValue(AdvInteger.two_power(k)) e = MemValue(twos_complement(normalized_divisor.read())) @for_range(theta) def block(i): qread = q.read() eread = e.read() qread += (qread * eread) >> k eread = (eread * eread) >> k q.write(qread) e.write(eread) res = q >> cint(2 * k - 2 * f - cnt_leading_zeros) return res
def SDiv_mono(a, b, l, kappa): theta = int(ceil(log(l / 3.5) / log(2))) alpha = two_power(2 * l) w = types.cint(int(2.9142 * two_power(l))) - 2 * b x = alpha - b * w y = a * w y = AdvInteger.TruncPr(y, 2 * l + 1, l + 1, kappa) for i in range(theta - 1): y = y * (alpha + x) # keep y with l bits y = AdvInteger.TruncPr(y, 3 * l, 2 * l, kappa) x = x**2 # keep x with 2l bits x = AdvInteger.TruncPr(x, 4 * l, 2 * l, kappa) y = y * (alpha + x) y = AdvInteger.TruncPr(y, 3 * l, 2 * l, kappa) return y
def Div(a, b, k, f, kappa, simplex_flag=False): theta = int(ceil(log(k / 3.5) / log(2))) alpha = AdvInteger.two_power(2 * f) w = AppRcr(b, k, f, kappa, simplex_flag) x = alpha - b * w y = a * w y = AdvInteger.TruncPr(y, 2 * k, f, kappa) for i in range(theta): y = y * (alpha + x) x = x * x y = AdvInteger.TruncPr(y, 2 * k, 2 * f, kappa) x = AdvInteger.TruncPr(x, 2 * k, 2 * f, kappa) y = y * (alpha + x) y = AdvInteger.TruncPr(y, 2 * k, 2 * f, kappa) return y
def AppRcr(b, k, f, kappa, simplex_flag=False): """ Approximate reciprocal of [b]: Given [b], compute [1/b] """ alpha = types.cint(int(2.9142 * 2**k)) c, v = Norm(b, k, f, kappa, simplex_flag) #v should be 2**{k - m} where m is the length of the bitwise repr of [b] d = alpha - 2 * c w = d * v w = AdvInteger.TruncPr(w, 2 * k, 2 * (k - f)) # now w * 2 ^ {-f} should be an initial approximation of 1/b return w
def FLLT(fl_a, fl_b): t = fl_a.err if isinstance(fl_b, types.sfloat): t = t + fl_b.err t = t == 0 z1 = fl_a.z z2 = fl_b.z s1 = fl_a.s s2 = fl_b.s a = fl_a.p.less_than(fl_b.p, fl_a.plen, fl_a.kappa) c = AdvInteger.EQZ(fl_a.p - fl_b.p, fl_a.plen, fl_a.kappa) d = ((1 - 2 * fl_a.s) * fl_a.v).less_than((1 - 2 * fl_b.s) * fl_b.v, fl_a.vlen + 1, fl_a.kappa) cd = c * d ca = c * a b1 = cd + a - ca b2 = cd + 1 + ca - c - a s12 = fl_a.s * fl_b.s z12 = fl_a.z * fl_b.z b = (z1 - z12) * (1 - s2) + (z2 - z12) * s1 + (1 + z12 - z1 - z2) * \ (s1 - s12 + (1 + s12 - s1 - s2) * b1 + s12 * b2) * t return b
def SDiv(a, b, l, kappa): theta = int(ceil(log(l / 3.5) / log(2))) alpha = AdvInteger.two_power(2 * l) beta = 1 / types.cint(AdvInteger.two_power(l)) w = types.cint(int(2.9142 * AdvInteger.two_power(l))) - 2 * b x = alpha - b * w y = a * w y = AdvInteger.TruncPr(y, 2 * l, l, kappa) x2 = types.sint() AdvInteger.Mod2m(x2, x, 2 * l + 1, l, kappa, False) x1 = (x - x2) * beta for i in range(theta - 1): y = y * (x1 + two_power(l)) + AdvInteger.TruncPr( y * x2, 2 * l, l, kappa) y = AdvInteger.TruncPr(y, 2 * l + 1, l + 1, kappa) x = x1 * x2 + AdvInteger.TruncPr(x2**2, 2 * l + 1, l + 1, kappa) x = x1 * x1 + AdvInteger.TruncPr(x, 2 * l + 1, l - 1, kappa) x2 = types.sint() AdvInteger.Mod2m(x2, x, 2 * l, l, kappa, False) x1 = (x - x2) * beta y = y * (x1 + two_power(l)) + AdvInteger.TruncPr(y * x2, 2 * l, l, kappa) y = AdvInteger.TruncPr(y, 2 * l + 1, l - 1, kappa) return y
def floor_fx(x): return load_sint(AdvInteger.Trunc(x.v, x.k - x.f, x.f, x.kappa), type(x))
def block(i): A[i] = AdvInteger.TruncPr(A[i - 1] * W[i - 1], 2 * k, f, kappa) temp = (B[i - 1] * W[i - 1]) >> f # no reading and writing to the same variable in a for loop. W[i] = two - temp B[i] = temp
def TruncRoundNearestAdjustOverflow(a, length, target_length, kappa): t = AdvInteger.TruncRoundNearest(a, length, length - target_length, kappa) overflow = t.greater_equal(AdvInteger.two_power(target_length), target_length + 1, kappa) s = (1 - overflow) * t + overflow * t / 2 return s, overflow