view viff/test/bedoza/test_bedoza_triple.py @ 1574:0d3b99e1e3eb
BeDOZa: Connected zero-knowledge proof to the remaining protocol.
| author |
Thomas P Jakobsen <tpj@cs.au.dk> |
| date |
Mon Oct 04 21:51:33 2010 +0200 (19 months ago) |
| parents |
d2d8fda44084 |
| children |
|
line source
1 # Copyright 2010 VIFF Development Team.
3 # This file is part of VIFF, the Virtual Ideal Functionality Framework.
5 # VIFF is free software: you can redistribute it and/or modify it
6 # under the terms of the GNU Lesser General Public License (LGPL) as
7 # published by the Free Software Foundation, either version 3 of the
8 # License, or (at your option) any later version.
10 # VIFF is distributed in the hope that it will be useful, but WITHOUT
11 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
13 # Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with VIFF. If not, see <http://www.gnu.org/licenses/>.
19 from exceptions import AssertionError
23 # We don't need secure random numbers for test purposes.
24 from random import Random
26 from twisted.internet.defer import gatherResults, Deferred, DeferredList
28 from viff.test.util import protocol
29 from viff.constants import TEXT
30 from viff.runtime import gather_shares, Share
31 from viff.config import generate_configs
32 from viff.field import FieldElement, GF
33 from viff.config import generate_configs
35 from viff.bedoza.bedoza import BeDOZaShare
36 from viff.bedoza.keylist import BeDOZaKeyList
37 from viff.bedoza.bedoza_triple import TripleGenerator, ModifiedPaillier
38 from viff.bedoza.shares import PartialShare, PartialShareContents
39 from viff.bedoza.util import _send, _convolute, _convolute_gf_elm
40 from viff.bedoza.add_macs import add_macs
41 from viff.bedoza.share_generators import ShareGenerator, PartialShareGenerator
42 from viff.bedoza.share import generate_partial_share_contents
44 from viff.test.bedoza.util import BeDOZaTestCase, skip_if_missing_packages
45 from viff.test.bedoza.util import TestShareGenerator
48 # Ok to use non-secure random generator in tests.
49 #from viff.util import rand
53 class DataTransferTest(BeDOZaTestCase):
56 def test_convolute_int(self, runtime):
57 res = _convolute(runtime, runtime.id)
59 self.assertEquals(runtime.players.keys(), result)
60 runtime.schedule_callback(res, verify)
64 def test_send(self, runtime):
65 msg_send = [100 * p + runtime.id for p in runtime.players]
66 msg_receive = [100 * runtime.id + p for p in runtime.players]
67 res = _send(runtime, msg_send)
69 self.assertEquals(msg_receive, result)
70 runtime.schedule_callback(res, verify)
74 def test_convolute_field_element(self, runtime):
76 res = _convolute_gf_elm(runtime, Zp(runtime.id))
78 self.assertEquals(runtime.players.keys(), result)
79 runtime.schedule_callback(res, verify)
83 class ModifiedPaillierTest(BeDOZaTestCase):
86 def test_modified_paillier_can_decrypt_encrypted_one(self, runtime):
87 paillier = ModifiedPaillier(runtime, Random(234838))
89 encrypted_val = paillier.encrypt(val)
90 decrypted_val = paillier.decrypt(encrypted_val)
91 self.assertEquals(val, decrypted_val)
94 def test_modified_paillier_with_different_randomness_are_not_equal(self, runtime):
95 random = Random(3423434)
96 n = runtime.players[runtime.id].pubkey['n']
97 paillier = ModifiedPaillier(runtime, Random(random.getrandbits(128)))
99 random_elm = random.randint(1, long(n))
100 encrypted_val_1 = paillier.encrypt(val, random_elm=random_elm)
101 encrypted_val_2 = paillier.encrypt(val, random_elm=random_elm)
102 self.assertEquals(encrypted_val_1, encrypted_val_2)
105 def test_modified_paillier_with_same_randomness_are_equal(self, runtime):
106 random = Random(234333)
107 paillier = ModifiedPaillier(runtime, Random(random.getrandbits(128)))
108 n = runtime.players[runtime.id].pubkey['n']
110 random_elm_1 = random.randint(1, long(n))
111 random_elm_2 = (random_elm_1 + 1) % n
112 encrypted_val_1 = paillier.encrypt(val, random_elm=random_elm_1)
113 encrypted_val_2 = paillier.encrypt(val, random_elm=random_elm_1)
114 self.assertEquals(encrypted_val_1, encrypted_val_2)
117 def test_modified_paillier_can_decrypt_encrypted_zero(self, runtime):
118 paillier = ModifiedPaillier(runtime, Random(338301))
120 encrypted_val = paillier.encrypt(val)
121 decrypted_val = paillier.decrypt(encrypted_val)
122 self.assertEquals(val, decrypted_val)
125 def test_modified_paillier_can_decrypt_encrypted_minus_one(self, runtime):
126 paillier = ModifiedPaillier(runtime, Random(19623))
128 encrypted_val = paillier.encrypt(val)
129 decrypted_val = paillier.decrypt(encrypted_val)
130 self.assertEquals(val, decrypted_val)
133 def test_modified_paillier_can_decrypt_encrypted_max_val(self, runtime):
134 paillier = ModifiedPaillier(runtime, Random(825604))
135 n = runtime.players[runtime.id].pubkey['n']
137 encrypted_val = paillier.encrypt(val)
138 decrypted_val = paillier.decrypt(encrypted_val)
139 self.assertEquals(val, decrypted_val)
142 def test_modified_paillier_can_decrypt_encrypted_min_val(self, runtime):
143 paillier = ModifiedPaillier(runtime, Random(554424))
144 n = runtime.players[runtime.id].pubkey['n']
146 encrypted_val = paillier.encrypt(val)
147 decrypted_val = paillier.decrypt(encrypted_val)
148 self.assertEquals(val, decrypted_val)
151 def test_modified_paillier_can_decrypt_encrypted_positive(self, runtime):
152 paillier = ModifiedPaillier(runtime, Random(777737))
154 encrypted_val = paillier.encrypt(val)
155 decrypted_val = paillier.decrypt(encrypted_val)
156 self.assertEquals(val, decrypted_val)
159 def test_encrypting_too_large_number_raises_exception(self, runtime):
160 paillier = ModifiedPaillier(runtime, Random(825604))
161 n = runtime.players[runtime.id].pubkey['n']
162 val = 1 + (n - 1) / 2
163 self.assertRaises(AssertionError, paillier.encrypt, val)
166 def test_encrypting_too_small_number_raises_exception(self, runtime):
167 paillier = ModifiedPaillier(runtime, Random(554424))
168 n = runtime.players[runtime.id].pubkey['n']
169 val = -(n - 1) / 2 - 1
170 self.assertRaises(AssertionError, paillier.encrypt, val)
173 def test_modified_paillier_can_encrypt_to_other(self, runtime):
174 paillier = ModifiedPaillier(runtime, Random(57503))
176 for p in runtime.players:
177 msg.append(paillier.encrypt(runtime.id, player_id=p))
178 received = _send(runtime, msg)
180 plain = [paillier.decrypt(e) for e in enc]
181 self.assertEquals(range(1, self.num_players + 1), plain)
182 runtime.schedule_callback(received, verify)
186 def partial_share(random, runtime, Zp, val, paillier=None):
188 paillier_random = Random(random.getrandbits(128))
189 paillier = ModifiedPaillier(runtime, paillier_random)
190 share_random = Random(random.getrandbits(128))
191 gen = PartialShareGenerator(Zp, runtime, share_random, paillier)
192 return gen.generate_share(Zp(val))
195 class PartialShareGeneratorTest(BeDOZaTestCase):
198 def test_shares_have_correct_type(self, runtime):
200 share = partial_share(Random(23499), runtime, Zp, 7)
202 self.assertEquals(Zp, share.value.field)
203 runtime.schedule_callback(share, test)
207 def test_shares_are_additive(self, runtime):
209 share = partial_share(Random(34993), runtime, GF(23), secret)
210 def convolute(share):
211 values = _convolute_gf_elm(runtime, share.value)
213 self.assertEquals(secret, sum(vals))
214 runtime.schedule_callback(values, test_sum)
215 runtime.schedule_callback(share, convolute)
219 def test_encrypted_shares_decrypt_correctly(self, runtime):
220 random = Random(3423993)
223 paillier = ModifiedPaillier(runtime, Random(random.getrandbits(128)))
224 share = partial_share(Random(random.getrandbits(128)), runtime, GF(modulus), secret, paillier=paillier)
226 decrypted_share = paillier.decrypt(share.enc_shares[runtime.id - 1])
227 decrypted_shares = _convolute(runtime, decrypted_share)
229 self.assertEquals(secret, sum(vals) % modulus)
230 runtime.schedule_callback(decrypted_shares, test_sum)
231 runtime.schedule_callback(share, decrypt)
234 class ShareGeneratorTest(BeDOZaTestCase):
237 def test_encrypted_real_share_open_correctly(self, runtime):
238 random = Random(3423993)
242 u_bound = 2**(4 * bits_in_p)
245 paillier = ModifiedPaillier(runtime, Random(random.getrandbits(128)))
247 share_random = Random(random.getrandbits(128))
248 gen = ShareGenerator(Zp, runtime, share_random, paillier, u_bound, alpha)
249 share = gen.generate_share(7)
251 self.assertEquals(7, v)
252 r = runtime.open(share)
253 runtime.schedule_callback(r, check)
257 def test_encrypted_random_real_shares_open_correctly(self, runtime):
258 random = Random(3423993)
262 u_bound = 2**(4 * bits_in_p)
265 paillier = ModifiedPaillier(runtime, Random(random.getrandbits(128)))
267 share_random = Random(random.getrandbits(128))
268 gen = TestShareGenerator(Zp, runtime, share_random, paillier, u_bound, alpha)
269 shares = gen.generate_random_shares(7)
270 expected_result = [9,16,7,12,3,5,6]
272 for inx, share in enumerate(shares):
273 def check(v, expected_result):
274 self.assertEquals(expected_result, v)
275 r = runtime.open(share)
277 runtime.schedule_callback(r, check, expected_result[inx])
278 return gather_shares(results)
280 class AddMacsTest(BeDOZaTestCase):
285 def test_add_macs_produces_correct_sharing(self, runtime):
286 # TODO: Here we use the open method of the BeDOZa runtime in
287 # order to verify the macs of the generated full share. In
288 # order to be more unit testish, this test should use its own
289 # way of verifying these.
293 random = Random(283883)
294 paillier_random = Random(random.getrandbits(128))
295 paillier = ModifiedPaillier(runtime, random)
297 add_macs_random = Random(random.getrandbits(128))
299 shares_random = Random(random.getrandbits(128))
301 shares.append(partial_share(shares_random, runtime, Zp, secret, paillier=paillier))
302 shares.append(partial_share(shares_random, runtime, Zp, secret + 1, paillier=paillier))
303 shares.append(partial_share(shares_random, runtime, Zp, secret + 2, paillier=paillier))
304 shares.append(partial_share(shares_random, runtime, Zp, secret + 3, paillier=paillier))
307 u_bound = 2**(4 * bits_in_p)
310 zs = add_macs(runtime, Zp, u_bound, alpha,
311 add_macs_random, paillier, shares)
312 def verify(open_shares):
314 for open_share in open_shares:
315 self.assertEquals(inx, open_share.value)
320 opened_shares.append(runtime.open(s))
321 d = gather_shares(opened_shares)
322 d.addCallback(verify)
327 # def test_add_macs_preserves_value_of_sharing(self, runtime):
328 # partial_share = self._generate_partial_share_of(42)
329 # full_share = TripleGenerator()._add_macs(partial_share)
330 # secret = self._open_sharing(full_share)
331 # self.assertEquals(42, secret)
332 # return partial_share
333 # #test_add_macs_preserves_value_of_sharing.skip = "nyi"
336 # def test_add_macs_preserves_value_of_zero_sharing(self, runtime):
337 # partial_share = self._generate_partial_share_of(0)
338 # full_share = TripleGenerator()._add_macs(partial_share)
339 # secret = self._open_sharing(full_share)
340 # self.assertEquals(0, secret)
341 # return partial_share
342 # #test_add_macs_preserves_value_of_zero_sharing.skip = "nyi"
345 class TripleTest(BeDOZaTestCase):
350 def test_generate_triples_generates_correct_single_triple(self, runtime):
353 random = Random(574566 + runtime.id)
354 triple_generator = TripleGenerator(runtime, self.security_parameter, p, random)
355 triples = triple_generator._generate_triples(1)
357 def check((a, b, c)):
358 self.assertEquals(c, a * b)
361 d1 = runtime.open(triple.a)
362 d2 = runtime.open(triple.b)
363 d3 = runtime.open(triple.c)
364 d = gatherResults([d1, d2, d3])
365 runtime.schedule_callback(d, check)
368 for triple in triples:
369 runtime.schedule_callback(triple, open)
370 return gatherResults(triples)
373 def test_generate_triples_generates_correct_triples(self, runtime):
378 random = Random(574566 + runtime.id)
379 triple_generator = TripleGenerator(runtime, self.security_parameter, p, random)
381 triples = triple_generator._generate_triples(10)
383 def check((a, b, c)):
384 self.assertEquals(c, a * b)
387 d1 = runtime.open(triple.a)
388 d2 = runtime.open(triple.b)
389 d3 = runtime.open(triple.c)
390 d = gatherResults([d1, d2, d3])
391 runtime.schedule_callback(d, check)
394 for triple in triples:
395 runtime.schedule_callback(triple, open)
396 return gatherResults(triples)
399 def test_generate_triple_candidates_generates_correct_triples(self, runtime):
404 random = Random(283883)
405 triple_generator = TripleGenerator(runtime, self.security_parameter, p, random)
407 triples = triple_generator._generate_triple_candidates(5)
409 for inx in xrange(len(triples) // 3):
410 self.assertEquals(triples[10 + inx], triples[inx] * triples[5 + inx])
413 opened_shares.append(runtime.open(s))
414 d = gather_shares(opened_shares)
415 d.addCallback(verify)
418 class MulTest(BeDOZaTestCase):
423 def test_mul_computes_correct_result(self, runtime):
426 random = Random(283883)
427 triple_generator = TripleGenerator(runtime, 32, p, random)
431 ais = [Zp(6), Zp(6), Zp(6), Zp(6)]
435 cs.append(triple_generator.paillier.encrypt(b2.value, 2))
440 r1 = triple_generator._mul(1, 2, n, ais, cs)
443 pc = tuple(runtime.program_counter)
444 runtime.protocols[2].sendData(pc, TEXT, str(share.value))
446 r1.addCallback(check1)
449 r1 = triple_generator._mul(1, 2, n)
454 def check_additivity(zi, zj):
455 self.assertEquals((Zp(long(zi)) + zj).value, 8)
458 d.addCallback(check_additivity, share.value)
459 runtime._expect_data(1, TEXT, d)
462 self.assertEquals(share.value, 0)
463 return gatherResults(deferreds)
464 r1.addCallback(check)
468 def test_mul_same_player_inputs_and_receives(self, runtime):
471 random = Random(283883)
472 triple_generator = TripleGenerator(runtime, self.security_parameter, p, random)
476 ais = [Zp(6), Zp(6), Zp(6), Zp(6)]
480 cs.append(triple_generator.paillier.encrypt(b2.value, 2))
484 r1 = triple_generator._mul(2, 2, n, ais, cs)
488 self.assertEquals(share.value, 8)
491 r1.addCallback(check)
495 class ShareTest(BeDOZaTestCase):
500 def test_share_protocol_single(self, runtime):
503 random = Random(3455433 + runtime.id)
504 elms = [Zp(runtime.id)]
505 paillier_random = Random(random.getrandbits(128))
506 zk_random = Random(random.getrandbits(128))
507 paillier = ModifiedPaillier(runtime, paillier_random)
508 partial_shares = generate_partial_share_contents(
509 elms, runtime, paillier, k, zk_random)
511 def decrypt(share_contents):
512 self.assertEquals(1, len(share_contents))
513 decrypted_share = paillier.decrypt(
514 share_contents[0].enc_shares[runtime.id - 1])
515 decrypted_shares = _convolute(runtime, decrypted_share)
517 self.assertEquals([Zp(e) for e in [1, 2, 3]], vals)
518 runtime.schedule_callback(decrypted_shares, test_sum)
520 runtime.schedule_callback(partial_shares, decrypt)
521 return partial_shares
524 def test_share_protocol_multi(self, runtime):
527 random = Random(345453 + runtime.id)
528 elms = [Zp(runtime.id), Zp(runtime.id * 3)]
529 paillier_random = Random(random.getrandbits(128))
530 zk_random = Random(random.getrandbits(128))
531 paillier = ModifiedPaillier(runtime, paillier_random)
532 partial_shares = generate_partial_share_contents(
533 elms, runtime, paillier, k, zk_random)
535 def decrypt(share_contents):
536 self.assertEquals(2, len(share_contents))
537 decrypted_shares = [paillier.decrypt(
538 share_contents[i].enc_shares[runtime.id - 1])
540 decrypted_shares = [_convolute(runtime, decrypted_shares[i])
542 def test_sum(vals, should_be):
543 self.assertEquals([Zp(e) for e in should_be], vals)
544 runtime.schedule_callback(
545 decrypted_shares[0], test_sum, [1, 2, 3])
546 runtime.schedule_callback(
547 decrypted_shares[1], test_sum, [3, 6, 9])
549 runtime.schedule_callback(partial_shares, decrypt)
550 return partial_shares
553 class FullMulTest(BeDOZaTestCase):
558 def test_fullmul_computes_the_correct_result(self, runtime):
563 random = Random(283883)
564 triple_generator = TripleGenerator(runtime, self.security_parameter, p, random)
566 paillier = triple_generator.paillier
570 share_as.append(partial_share(random, runtime, GF(p), 6, paillier=paillier))
571 share_bs.append(partial_share(random, runtime, GF(p), 7, paillier=paillier))
572 share_as.append(partial_share(random, runtime, GF(p), 5, paillier=paillier))
573 share_bs.append(partial_share(random, runtime, GF(p), 4, paillier=paillier))
574 share_as.append(partial_share(random, runtime, GF(p), 2, paillier=paillier))
575 share_bs.append(partial_share(random, runtime, GF(p), 3, paillier=paillier))
578 share_zs = triple_generator._full_mul(share_as, share_bs)
581 self.assertEquals(8, Zp(sum(ls[0])))
582 self.assertEquals(3, Zp(sum(ls[1])))
583 self.assertEquals(6, Zp(sum(ls[2])))
586 value = _convolute(runtime, share.value.value)
588 d = gatherResults(values)
589 runtime.schedule_callback(d, test_sum)
592 d = gatherResults(share_zs)
597 def test_fullmul_encrypted_values_are_the_same_as_the_share(self, runtime):
602 random = Random(283883)
603 triple_generator = TripleGenerator(runtime, self.security_parameter, p, random)
605 paillier = triple_generator.paillier
609 share_as.append(partial_share(random, runtime, GF(p), 6, paillier=paillier))
610 share_bs.append(partial_share(random, runtime, GF(p), 7, paillier=paillier))
611 share_as.append(partial_share(random, runtime, GF(p), 5, paillier=paillier))
612 share_bs.append(partial_share(random, runtime, GF(p), 4, paillier=paillier))
613 share_as.append(partial_share(random, runtime, GF(p), 2, paillier=paillier))
614 share_bs.append(partial_share(random, runtime, GF(p), 3, paillier=paillier))
616 share_zs = triple_generator._full_mul(share_as, share_bs)
620 def test_enc(enc_shares, value):
621 all_the_same, zi_enc = reduce(lambda x, y: (x[0] and x[1] == y, y), enc_shares, (True, enc_shares[0]))
622 zi_enc = triple_generator.paillier.decrypt(zi_enc)
623 self.assertEquals(value, Zp(zi_enc))
625 for inx, enc_share in enumerate(share.enc_shares):
626 d = _convolute(runtime, enc_share)
627 if runtime.id == inx + 1:
628 d.addCallback(test_enc, share.value)
629 all_enc_shares.append(d)
630 return gatherResults(all_enc_shares)
632 d = gatherResults(share_zs)
637 skip_if_missing_packages(
639 ModifiedPaillierTest,
640 PartialShareGeneratorTest,