From 00b990d21954c029b8abdd6695fc33cb5e4afcdb Mon Sep 17 00:00:00 2001 From: vub Date: Tue, 7 Feb 2017 08:39:28 -0500 Subject: [PATCH] Made pairing impl python3-friendly --- casper_sm/test.py | 25 +++++++++++++++++-------- zksnark/bn128_curve.py | 8 ++++---- zksnark/bn128_field_elements.py | 23 +++++++++++++++++++---- zksnark/bn128_pairing.py | 2 +- zksnark/bn128_pairing_test.py | 14 +++++++------- 5 files changed, 48 insertions(+), 24 deletions(-) diff --git a/casper_sm/test.py b/casper_sm/test.py index eb53a57..9e736cb 100644 --- a/casper_sm/test.py +++ b/casper_sm/test.py @@ -2,14 +2,16 @@ # in the randao-based single-chain Casper. import random +# Reward for mining a block with nonzero skips +NON_PRIMARY_REWARD = 0.5 # Penalty for mining a dunkle -DUNKLE_PENALTY = 1 +DUNKLE_PENALTY = 0.75 # Penalty to a main-chain block which has a dunkle as a sister -DUNKLE_SISTER_PENALTY = 0.8 +DUNKLE_SISTER_PENALTY = 0.375 # Attacker stake power (out of 100). Try setting this value to any # amount, even values above 50! -attacker_share = 40 +attacker_share = 60 # A simulated Casper randao def randao_successor(parent, index): @@ -78,7 +80,7 @@ class Chain(): self.randao = new_randao self.time += skips self.length += 1 - self.me += 1 + self.me += NON_PRIMARY_REWARD if skips else 1 def extend_them(self, skips): new_randao = randao_successor(self.randao, skips) @@ -86,7 +88,7 @@ class Chain(): self.randao = new_randao self.time += skips self.length += 1 - self.them += 1 + self.them += NON_PRIMARY_REWARD if skips else 1 def add_my_dunkles(self, n): self.me -= n * DUNKLE_PENALTY @@ -96,7 +98,8 @@ class Chain(): self.them -= n * DUNKLE_PENALTY self.me -= n * DUNKLE_SISTER_PENALTY - +my_total_loss = 0 +their_total_loss = 0 for strat_id in range(2**len(scenarios)): # Strategy map: scenario to 0 = publish, 1 = selfish-validate @@ -105,7 +108,7 @@ for strat_id in range(2**len(scenarios)): # 0 = don't reveal until the "main chain" looks like it's close to catching up insta_reveal = strat_id % 2 - print 'Testing strategy: %r, insta_reveal: %d', (strategy, insta_reveal) + print 'Testing strategy: %r, insta_reveal: %d' % (strategy, insta_reveal) pubchain = Chain(randao=random.randrange(10**20)) @@ -167,5 +170,11 @@ for strat_id in range(2**len(scenarios)): pass # print 'Score deltas: me %.2f them %.2f, time delta %d' % (pubchain.me - old_me, pubchain.them - old_them, time - old_time) - gf = (pubchain.them - 100000. * (100 - attacker_share) / 100) / (pubchain.me - 100000 * attacker_share / 100) + my_loss = 100000 * attacker_share / 100 - pubchain.me + their_loss = 100000 * (100 - attacker_share) / 100 - pubchain.them + my_total_loss += my_loss + their_total_loss += their_loss + gf = their_loss / my_loss if my_loss > 0 else 999.99 print 'My revenue: %d, their revenue: %d, griefing factor %.2f' % (pubchain.me, pubchain.them, gf) + +print 'Total griefing factor: %.2f' % (their_total_loss / my_total_loss) diff --git a/zksnark/bn128_curve.py b/zksnark/bn128_curve.py index 0c68dc4..368a84d 100644 --- a/zksnark/bn128_curve.py +++ b/zksnark/bn128_curve.py @@ -17,8 +17,8 @@ b12 = FQ12([3] + [0] * 11) # Generator for curve over FQ G1 = (FQ(1), FQ(2)) # Generator for twisted curve over FQ2 -G2 = (FQ2([16260673061341949275257563295988632869519996389676903622179081103440260644990L, 11559732032986387107991004021392285783925812861821192530917403151452391805634L]), - FQ2([15530828784031078730107954109694902500959150953518636601196686752670329677317L, 4082367875863433681332203403145435568316851327593401208105741076214120093531L])) +G2 = (FQ2([16260673061341949275257563295988632869519996389676903622179081103440260644990, 11559732032986387107991004021392285783925812861821192530917403151452391805634]), + FQ2([15530828784031078730107954109694902500959150953518636601196686752670329677317, 4082367875863433681332203403145435568316851327593401208105741076214120093531])) # Check that a point is on the curve defined by y**2 == x**3 + b def is_on_curve(pt, b): @@ -62,9 +62,9 @@ def multiply(pt, n): elif n == 1: return pt elif not n % 2: - return multiply(double(pt), n / 2) + return multiply(double(pt), n // 2) else: - return add(multiply(double(pt), int(n / 2)), pt) + return add(multiply(double(pt), int(n // 2)), pt) # Check that the G1 curve works fine assert add(add(double(G1), G1), G1) == double(double(G1)) diff --git a/zksnark/bn128_field_elements.py b/zksnark/bn128_field_elements.py index bee25f6..d12e733 100644 --- a/zksnark/bn128_field_elements.py +++ b/zksnark/bn128_field_elements.py @@ -1,6 +1,12 @@ import sys sys.setrecursionlimit(10000) +# python3 compatibility +try: + foo = long +except: + long = int + # The prime modulus of the field field_modulus = 21888242871839275222246405745257275088696311157297823662689037894645226208583 # See, it's prime! @@ -61,20 +67,26 @@ class FQ(): assert isinstance(on, (int, long)) return FQ(self.n * inv(on, field_modulus) % field_modulus) + def __truediv__(self, other): + return self.__div__(other) + def __rdiv__(self, other): on = other.n if isinstance(other, FQ) else other assert isinstance(on, (int, long)), on return FQ(inv(self.n, field_modulus) * on % field_modulus) + def __rtruediv__(self, other): + return self.__rdiv__(other) + def __pow__(self, other): if other == 0: return FQ(1) elif other == 1: return FQ(self.n) elif other % 2 == 0: - return (self * self) ** (other / 2) + return (self * self) ** (other // 2) else: - return ((self * self) ** int(other / 2)) * self + return ((self * self) ** int(other // 2)) * self def __eq__(self, other): if isinstance(other, FQ): @@ -166,15 +178,18 @@ class FQP(): assert isinstance(other, self.__class__) return self * other.inv() + def __truediv__(self, other): + return self.__div__(other) + def __pow__(self, other): if other == 0: return self.__class__([1] + [0] * (self.degree - 1)) elif other == 1: return self.__class__(self.coeffs) elif other % 2 == 0: - return (self * self) ** (other / 2) + return (self * self) ** (other // 2) else: - return ((self * self) ** int(other / 2)) * self + return ((self * self) ** int(other // 2)) * self # Extended euclidean algorithm used to find the modular inverse def inv(self): diff --git a/zksnark/bn128_pairing.py b/zksnark/bn128_pairing.py index 0927232..a3ffa8b 100644 --- a/zksnark/bn128_pairing.py +++ b/zksnark/bn128_pairing.py @@ -62,7 +62,7 @@ def miller_loop(Q, P): R = add(R, Q1) f = f * linefunc(R, nQ2, P) # R = add(R, nQ2) This line is in many specifications but it technically does nothing - return f ** ((field_modulus ** 12 - 1) / curve_order) + return f ** ((field_modulus ** 12 - 1) // curve_order) # Pairing computation def pairing(Q, P): diff --git a/zksnark/bn128_pairing_test.py b/zksnark/bn128_pairing_test.py index 50992fa..1f9c040 100644 --- a/zksnark/bn128_pairing_test.py +++ b/zksnark/bn128_pairing_test.py @@ -3,22 +3,22 @@ from bn128_pairing import pairing, neg, G2, G1, multiply, FQ12, curve_order p1 = pairing(G2, G1) pn1 = pairing(G2, neg(G1)) assert p1 * pn1 == FQ12.one() -print 'Pairing check against negative in G1 passed' +print('Pairing check against negative in G1 passed') np1 = pairing(neg(G2), G1) assert p1 * np1 == FQ12.one() assert pn1 == np1 -print 'Pairing check against negative in G2 passed' +print('Pairing check against negative in G2 passed') assert p1 ** curve_order == FQ12.one() -print 'Pairing output has correct order' +print('Pairing output has correct order') p2 = pairing(G2, multiply(G1, 2)) assert p1 * p1 == p2 -print 'Pairing bilinearity in G1 passed' +print('Pairing bilinearity in G1 passed') assert p1 != p2 and p1 != np1 and p2 != np1 -print 'Pairing is non-degenerate' +print('Pairing is non-degenerate') po2 = pairing(multiply(G2, 2), G1) assert p1 * p1 == po2 -print 'Pairing bilinearity in G2 passed' +print('Pairing bilinearity in G2 passed') p3 = pairing(multiply(G2, 27), multiply(G1, 37)) po3 = pairing(G2, multiply(G1, 999)) assert p3 == po3 -print 'Composite check passed' +print('Composite check passed')