Skip to content

Instantly share code, notes, and snippets.

@judofyr
Last active December 16, 2015 11:28
Show Gist options
  • Save judofyr/5427303 to your computer and use it in GitHub Desktop.
Save judofyr/5427303 to your computer and use it in GitHub Desktop.
Secret Secure Relative Age Service
# paillier.py and primes.py attached below are verbatim from
# https://github.com/mikeivanov/paillier
#
# This code is licenced under # LGPL v3.
#
# Usage
# Person 1: python age.py MY_AGE
# Person 2: python age.py MY_AGE OUTPUT_FROM_PERSON1
#
# Person 2 should then post the output here and I can publicize the relative age.
#
# NOTE: The output from Person 1 should *only* be shared with Person 2.
# If I get access to the first output I will know both your ages.
from paillier import *
from primes import *
import sys
# judofyr's public key
pub = PublicKey(185032292726542690797901404500539311787)
age = int(sys.argv[1])
if len(sys.argv) == 2:
print encrypt(pub, age)
else:
other = int(sys.argv[2])
print e_add_const(pub, other, 100-age)
import math
import primes
def invmod(a, p, maxiter=1000000):
"""The multiplicitive inverse of a in the integers modulo p:
a * b == 1 mod p
Returns b.
(http://code.activestate.com/recipes/576737-inverse-modulo-p/)"""
if a == 0:
raise ValueError('0 has no inverse mod %d' % p)
r = a
d = 1
for i in xrange(min(p, maxiter)):
d = ((p // r + 1) * d) % p
r = (d * a) % p
if r == 1:
break
else:
raise ValueError('%d has no inverse mod %d' % (a, p))
return d
def modpow(base, exponent, modulus):
"""Modular exponent:
c = b ^ e mod m
Returns c.
(http://www.programmish.com/?p=34)"""
result = 1
while exponent > 0:
if exponent & 1 == 1:
result = (result * base) % modulus
exponent = exponent >> 1
base = (base * base) % modulus
return result
class PrivateKey(object):
def __init__(self, p, q, n):
self.l = (p-1) * (q-1)
self.m = invmod(self.l, n)
class PublicKey(object):
def __init__(self, n):
self.n = n
self.n_sq = n * n
self.g = n + 1
def generate_keypair(bits):
p = primes.generate_prime(bits / 2)
q = primes.generate_prime(bits / 2)
n = p * q
return PrivateKey(p, q, n), PublicKey(n)
def encrypt(pub, plain):
while True:
r = primes.generate_prime(long(round(math.log(pub.n, 2))))
if r > 0 and r < pub.n:
break
x = pow(r, pub.n, pub.n_sq)
cipher = (pow(pub.g, plain, pub.n_sq) * x) % pub.n_sq
return cipher
def e_add(pub, a, b):
"""Add one encrypted integer to another"""
return a * b % pub.n_sq
def e_add_const(pub, a, n):
"""Add constant n to an encrypted integer"""
return a * modpow(pub.g, n, pub.n_sq) % pub.n_sq
def e_mul_const(pub, a, n):
"""Multiplies an ancrypted integer by a constant"""
return modpow(a, n, pub.n_sq)
def decrypt(priv, pub, cipher):
x = pow(cipher, priv.l, pub.n_sq) - 1
plain = ((x // pub.n) * priv.m) % pub.n
return plain
import random
import sys
def ipow(a, b, n):
"""calculates (a**b) % n via binary exponentiation, yielding itermediate
results as Rabin-Miller requires"""
A = a = long(a % n)
yield A
t = 1L
while t <= b:
t <<= 1
# t = 2**k, and t > b
t >>= 2
while t:
A = (A * A) % n
if t & b:
A = (A * a) % n
yield A
t >>= 1
def rabin_miller_witness(test, possible):
"""Using Rabin-Miller witness test, will return True if possible is
definitely not prime (composite), False if it may be prime."""
return 1 not in ipow(test, possible-1, possible)
smallprimes = (2,3,5,7,11,13,17,19,23,29,31,37,41,43,
47,53,59,61,67,71,73,79,83,89,97)
def default_k(bits):
return max(64, 2 * bits)
def is_probably_prime(possible, k=None):
if possible == 1:
return True
if k is None:
k = default_k(possible.bit_length())
for i in smallprimes:
if possible == i:
return True
if possible % i == 0:
return False
for i in xrange(k):
test = random.randrange(2, possible - 1) | 1
if rabin_miller_witness(test, possible):
return False
return True
def generate_prime(bits, k=None):
"""Will generate an integer of b bits that is probably prime
(after k trials). Reasonably fast on current hardware for
values of up to around 512 bits."""
assert bits >= 8
if k is None:
k = default_k(bits)
while True:
possible = random.randrange(2 ** (bits-1) + 1, 2 ** bits) | 1
if is_probably_prime(possible, k):
return possible
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment