Last active
January 3, 2022 11:43
-
-
Save y-yu/d8897e9dce479b620606 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from charm.toolbox.integergroup import IntegerGroupQ | |
from charm.core.math.integer import toInt | |
import random | |
from functools import reduce | |
group = IntegerGroupQ() | |
group.paramgen(512) | |
cards = 52 | |
# Utility Functions | |
def odd_random(): | |
while True: | |
r = group.random() | |
if not toInt(r) % 2 == 0: | |
break | |
return r | |
def make_pi(n = cards): | |
xs = [(random.random(), i) for i in range(n)] | |
return [x[1] for x in sorted(xs)] | |
def permute(pi, d): | |
assert len(pi) == len(d) | |
return [d[i] for i in pi] | |
def compose(pi2, pi1): | |
assert len(pi1) == len(pi2) | |
return [pi1[i] for i in pi2] | |
def inverse(pi): | |
xs = [(pi[i], i) for i in range(len(pi))] | |
return [x[1] for x in sorted(xs)] | |
def mask(s): | |
return [random.choice([True, False]) for _ in range(s)] | |
# operation | |
def procedure_32(deck): | |
r = [ odd_random() for _ in range(len(deck)) ] | |
c = [(x[0][0] ** x[1], x[0][1] ** x[1]) for x in zip(deck, r)] | |
p = make_pi() | |
assert len(p) == len(deck) | |
return (permute(p, c), r, p) | |
def procedure_33(ca, cb, r, pi): | |
def f(i): | |
db_i, ab_i = cb[i] | |
da_i, aa_i = ca[pi[i]] | |
r_i = r[pi[i]] | |
return db_i == (da_i ** r_i) and ab_i == (aa_i ** r_i) | |
return all( f(i) for i in range(cards) ) | |
def protocol_48(ci_1, ci, pi, r, s): | |
c = [ procedure_32(ci) for _ in range(s) ] | |
u = mask(s) | |
def f(i): | |
c_ik, r_ik, pi_ik = c[i] | |
if u[i]: | |
return procedure_33(ci, c_ik, r_ik, pi_ik) | |
else: | |
pi_ = compose(pi_ik, pi) | |
r_ = permute( inverse(pi_), [ r[pi_[j]] * r_ik[pi_ik[j]] for j in range(cards) ] ) | |
return procedure_33(ci_1, c_ik, r_, pi_) | |
return all( f(i) for i in range(s) ) | |
def protocol_47(c0, s, players): | |
ci_1 = c0 | |
for p in players: | |
ci, ri, pii = procedure_32(ci_1) | |
assert protocol_48(ci_1, ci, pii, ri, s) == True | |
ci_1 = ci | |
return ci | |
def cp_proof(alpha, beta, er, er_1, c, r, a, b): | |
return alpha ** r == a * (beta ** c) and er ** r == b * (er_1 ** c) | |
# Class | |
class Player: | |
def __init__(self, alpha, room): | |
self.key = group.random() | |
self.beta = alpha ** self.key | |
self.room = room | |
self.hands = [] | |
def send_r(self, s, c): | |
return s + c * self.key | |
def draw(self, n = 0): | |
room = self.room | |
assert n < len(room.deck) | |
def fn_er(er_1, p): | |
if p is self: | |
return er_1 | |
else: | |
er = er_1 ** (p.key ** -1) | |
for p_ in room.players: | |
if not p_ is p: | |
s, c = group.random(), group.random() | |
a, b = room.alpha ** s, er ** s | |
r = p.send_r(s, c) | |
assert cp_proof(room.alpha, p.beta, er, er_1, c, r, a, b) | |
return er | |
d, a = room.deck[n] | |
en = reduce(fn_er, room.players, a) ** (self.key ** -1) | |
def get_card(xs): | |
for x, i in zip(xs, range(len(xs))): | |
if en ** x == d: | |
return i | |
return -1 | |
c = get_card(room.x) | |
assert c > -1 | |
del room.deck[n] | |
self.hands.append( (c, en) ) | |
return c | |
def open(self, n): | |
assert n < len(self.hands) | |
card, en = self.hands[n] | |
for p in self.room.players: | |
if not p is self: | |
for p_ in self.room.players: | |
if not p_ is p: | |
s, c = group.random(), group.random() | |
a, b = self.room.alpha ** s, en ** s | |
r = self.send_r(s, c) | |
en_1 = en ** self.key | |
assert cp_proof(self.room.alpha, self.beta, en, en_1, c, r, a, b) | |
return card | |
class Room: | |
def setup(self, number): | |
self.alpha = group.randomGen() | |
self.x = [ odd_random() for _ in range(cards) ] | |
self.players = [ Player(self.alpha, self) for _ in range(number) ] | |
self.beta = reduce( lambda x, y: x ** y.key, self.players, self.alpha ) | |
self.c0 = [ (self.alpha ** self.x[i], self.beta) for i in range(cards) ] | |
def shuffle(self, s): | |
self.deck = protocol_47(self.c0, s, self.players) | |
r = Room() | |
r.setup(3) | |
r.shuffle(10) | |
for _ in range(cards): | |
r.players[0].draw() | |
print( sorted([x[0] for x in r.players[0].hands]) ) | |
print( [r.players[0].open(i) for i in range(cards)] ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment