def _SecFld(field): l = (field.order - 1).bit_length() name = f'SecFld{l}({field.__name__})' secfld = type(name, (SecureFiniteField, ), {'__slots__': ()}) secfld.__doc__ = 'Class of secret-shared finite field elements.' t = runtime.threshold m = len(runtime.parties) q = field.order if t == 0 or m < q: # TODO: cover case m=q using MDS codes secfld.subfield = None secfld.field = field else: secfld.subfield = field assert field.ext_deg == 1 # TODO: cover case ext_deg > 1 e = math.ceil(math.log(m + 1, q)) # ensure q**e > m with e>=2 modulus = finfields.find_irreducible(field.characteristic, e) secfld.field = finfields.GF(modulus) @classmethod def out_conv(cls, a): # field -> subfield assert a.value.degree() <= 0 return cls.subfield(int(a)) secfld._output_conversion = out_conv secfld.bit_length = l globals( )[name] = secfld # TODO: check name dynamic SecureFiniteField type sufficiently unique return secfld
def _pfield(l, f, p, n): k = runtime.options.sec_param if p is None: p = finfields.find_prime_root(l + max(f, k + 1) + 1, n=n) else: assert p.bit_length() > l + max(f, k + 1), f'Prime {p} too small.' return finfields.GF(p, f)
def test_f256(self): f256 = self.f256 self.assertFalse(f256(0)) self.assertTrue(f256(1)) self.assertEqual(f256(1) + 0, f256(0) + f256(1)) self.assertEqual(f256(1) + 1, f256(0)) self.assertEqual(f256(3) * 0, f256(0)) self.assertEqual(f256(3) * 1, f256(3)) self.assertEqual(f256(16) * f256(16), f256(27)) self.assertEqual(f256(32) * f256(16), f256(54)) self.assertEqual(f256(57) * f256(67), f256(137)) self.assertEqual(f256(67) * f256(57), f256(137)) self.assertEqual(f256(137) / f256(57), f256(67)) self.assertEqual(f256(137) / f256(67), f256(57)) a = f256(0) b = f256(1) a += b self.assertEqual(a, f256(1)) a += 1 self.assertEqual(a, f256(0)) a -= b self.assertEqual(a, f256(1)) a *= b self.assertEqual(a, f256(1)) a *= 1 self.assertEqual(a, f256(1)) a /= 1 self.assertEqual(a, f256(1)) a <<= 0 a = a >> 0 self.assertEqual(a, f256(1)) a <<= 2 self.assertEqual(a, f256(4)) a >>= 2 self.assertEqual(a, f256(1)) a = f256(3) # generator X + 1 s = [int((a**i).value) for i in range(255)] self.assertListEqual(sorted(s), list(range(1, 256))) s = [int((a**i).value) for i in range(-255, 0)] self.assertListEqual(sorted(s), list(range(1, 256))) f256 = finfields.GF( gfpx.GFpX(2)(391)) # primitive polynomial X^8 + X^7 + X^2 + X + 1 a = f256(2) # generator X s = [int((a**i).value) for i in range(255)] self.assertListEqual(sorted(s), list(range(1, 256))) a = f256(0) self.assertEqual(a.sqrt(), 0) with self.assertRaises(ZeroDivisionError): a.sqrt(INV=True) a = f256(177) self.assertTrue(a.is_sqr()) self.assertEqual(a.sqrt()**2, a) a = f256(255) self.assertEqual(a.sqrt()**2, a) self.assertEqual(len({f256(i) for i in range(-120, 259)}), 256)
def _pfield(l, f, p, n): k = runtime.options.sec_param if p is None: p = finfields.find_prime_root(l + f + k + 2, n=n) elif p.bit_length() <= l + f + k + 1: raise ValueError(f'Prime {p} too small.') return finfields.GF(p, f)
def test_field_caching(self): self.assertNotEqual(self.f2(1), self.f2p(1)) f2_cached = finfields.GF(gfpx.GFpX(2)(2)) self.assertEqual(self.f2(1), f2_cached(1)) self.assertEqual(self.f2(1) * f2_cached(1), self.f2(1)) f256_cached = finfields.GF(gfpx.GFpX(2)(283)) self.assertEqual(self.f256(3), f256_cached(3)) self.assertEqual(self.f256(3) * f256_cached(3), self.f256(5)) self.assertEqual(self.f256(48) * f256_cached(16), self.f256(45)) f2_cached = finfields.GF(2) self.assertEqual(self.f2p(1), f2_cached(1)) self.assertEqual(self.f2p(1) * f2_cached(1), 1) f19_cached = finfields.GF(19) self.assertEqual(self.f19(3), f19_cached(3)) self.assertEqual(self.f19(3) * f19_cached(3), 9) f101_cached = finfields.GF(101) self.assertEqual(self.f101(3), f101_cached(3)) self.assertEqual(self.f101(3) * f101_cached(23), 69)
def _pfield(l, f, p, n): k = runtime.options.sec_param if p is None: p = finfields.find_prime_root(l + f + k + 2, n=n) elif p.bit_length() <= l + f + k + 1: raise ValueError(f'Prime {p} too small.') field = finfields.GF(p) assert runtime.threshold == 0 or len( runtime.parties) < field.order # for Shamir secret sharing return field
def test_f256(self): f256 = self.f256 self.assertFalse(f256(0)) self.assertTrue(f256(1)) self.assertEqual(f256(1) + 0, f256(0) + f256(1)) self.assertEqual(f256(1) + 1, f256(0)) self.assertEqual(f256(3) * 0, f256(0)) self.assertEqual(f256(3) * 1, f256(3)) self.assertEqual(f256(16) * f256(16), f256(27)) self.assertEqual(f256(32) * f256(16), f256(54)) self.assertEqual(f256(57) * f256(67), f256(137)) self.assertEqual(f256(67) * f256(57), f256(137)) self.assertEqual(f256(137) / f256(57), f256(67)) self.assertEqual(f256(137) / f256(67), f256(57)) a = f256(0) b = f256(1) a += b self.assertEqual(a, f256(1)) a += 1 self.assertEqual(a, f256(0)) a -= b self.assertEqual(a, f256(1)) a *= b self.assertEqual(a, f256(1)) a *= 1 self.assertEqual(a, f256(1)) a /= 1 self.assertEqual(a, f256(1)) a <<= 0 a >>= 0 self.assertEqual(a, f256(1)) a <<= 2 self.assertEqual(a, f256(4)) a >>= 2 self.assertEqual(a, f256(1)) a = f256(3) # generator X + 1 s = [int((a**i).value) for i in range(255)] self.assertListEqual(sorted(s), list(range(1, 256))) s = [int((a**i).value) for i in range(-255, 0)] self.assertListEqual(sorted(s), list(range(1, 256))) f256 = finfields.GF( gfpx.GFpX(2)(391)) # primitive polynomial X^8 + X^7 + X^2 + X + 1 a = f256(2) # generator X s = [int((a**i).value) for i in range(255)] self.assertListEqual(sorted(s), list(range(1, 256))) a = f256(177) self.assertEqual(a.sqrt()**2, a) a = f256(255) self.assertEqual(a.sqrt()**2, a)
def setUp(self): self.f2 = finfields.GF(gfpx.GFpX(2)(2)) self.f256 = finfields.GF(gfpx.GFpX(2)(283)) # AES polynomial (283)_2 = X^8+X^4+X^3+X+1 self.f2p = finfields.GF(2) self.f19 = finfields.GF(19) # 19 % 4 = 3 self.f101 = finfields.GF(101) # 101 % 4 = 1 self.f101.is_signed = False self.f27 = finfields.GF(gfpx.GFpX(3)(46)) # irreducible polynomial X^3 + 2X^2 + 1 self.f81 = finfields.GF(gfpx.GFpX(3)(115)) # irreducible polynomial X^4 + X^3 + 2X + 1
def SecFld(order=None, modulus=None, char=None, ext_deg=None, min_order=None, signed=False): """Secure finite field of order q = p**d. Order q >= min_order. Field is prime (d = 1) by default and if modulus is prime. Extension degree d > 1 if order is a prime power p**d with d > 1, if modulus is a polynomial or a string or an integer > char, or if ext_deg is an integer > 1, or if min_order > char. """ # TODO: raise errors instead of assert statements if order is not None: p, d = gmpy2.factor_prime_power(order) char = char or p assert char == p ext_deg = ext_deg or d assert ext_deg == d # order now represented by (char, ext_deg) if isinstance(modulus, str): char = char or 2 modulus = gfpx.GFpX(char)(modulus) if isinstance(modulus, int): if char and modulus > char: modulus = gfpx.GFpX(char)(modulus) if isinstance(modulus, gfpx.Polynomial): char = char or modulus.p assert char == modulus.p ext_deg = ext_deg or modulus.degree() elif isinstance(modulus, int): char = char or modulus assert char == modulus ext_deg = ext_deg or 1 assert ext_deg == 1 else: assert modulus is None if min_order is None: char = char or 2 ext_deg = ext_deg or 1 min_order = char**ext_deg else: if char is None: ext_deg = ext_deg or 1 root, exact = gmpy2.iroot(min_order, ext_deg) min_char = root + (not exact ) # ceiling of min_order^(1/ext_deg) char = int(gmpy2.next_prime(min_char - 1)) else: if ext_deg is None: ext_deg = math.ceil(math.log(min_order, char)) if ext_deg == 1: modulus = char else: modulus = finfields.find_irreducible(char, ext_deg) order = order or char**ext_deg min_order = min_order or order assert min_order <= order field = finfields.GF(modulus) assert runtime.threshold == 0 or field.order > len(runtime.parties), \ 'Field order must exceed number of parties, unless threshold is 0.' # TODO: field.order >= number of parties for MDS field.is_signed = signed return _SecFld(field)
def setUp(self): self.f2 = finfields.GF(2) self.f19 = finfields.GF(19) self.f27 = finfields.GF(gfpx.GFpX(3)(46)) self.f256 = finfields.GF(gfpx.GFpX(2)(283))