Skip to content

Instantly share code, notes, and snippets.

@a8x9
Created April 25, 2020 06:00
Show Gist options
  • Save a8x9/76233a8386fabc3d04e2baefade6a59d to your computer and use it in GitHub Desktop.
Save a8x9/76233a8386fabc3d04e2baefade6a59d to your computer and use it in GitHub Desktop.
Simluation for DP-3T/documents#210
#!/usr/bin/env python3
"""
This script simulates the blind signatures based protocol, proposed to improve the privacy of
infected users, when uploading EphIDs in the DP^3T protocol.
https://github.com/DP-3T/documents/issues/210
Dependency: pycryptodome: pip install pycryptodome
"""
from Crypto.PublicKey import RSA
from Crypto.Hash import SHA512
from Crypto.Util import number
from random import randrange
# convert between large integers and bytes
b2i = lambda b: int.from_bytes(b, 'big')
i2b = lambda i: i.to_bytes(number.ceil_div(i.bit_length(), 8), 'big')
class Backend:
"""
In practice, the signature does not have to be done on the backend, see second half of the
following post for more info:
https://github.com/DP-3T/documents/issues/210#issuecomment-619313110
"""
def __init__(self):
self.k = RSA.generate(2048)
def pubkey(self):
return self.k.e, self.k.n
def sign(self, data):
""" Text book RSA signature """
return pow(data, self.k.d, self.k.n)
def verify(self, sig, x):
""" Verify that sig^e = H(code) (mod N) """
if isinstance(x, int):
x = i2b(x)
x = b2i(SHA512.new(x).digest())
return pow(sig, self.k.e, self.k.n) == x
class BlindSignature:
""" https://en.wikipedia.org/wiki/Blind_signature#Blind_RSA_signatures """
def __init__(self, e, n, r):
"""
@param e: RSA public exponent
@param n: RSA modulus
@param r: random number < n, used in r^e blinding factor
"""
self.e = e
self.n = n
self.r = r
def blind(self, x):
"""
@return: m = H(x) * r^e (mod N)
"""
if isinstance(x, int):
x = i2b(x)
x = b2i(SHA512.new(x).digest())
return (x * pow(self.r, self.e, self.n)) % self.n
def unblind(self, s):
"""
@return: s * r^{-1} (mod N)
"""
return (s * number.inverse(self.r, self.n)) % self.n
if __name__ == '__main__':
import sys
# test with different backend private keys
for _ in range(10):
backend = Backend()
e, n = backend.pubkey()
# test with different blinding factors r^e
for _ in range(10):
r = randrange(n)
bs = BlindSignature(e, n, r)
# test with different authorization codes x
for _ in range(10):
x = randrange(n)
m = bs.blind(x)
sb = backend.sign(m)
s = bs.unblind(sb)
assert backend.verify(s, x)
print(".", end='')
sys.stdout.flush()
print()
print("Test successfully passed!")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment