-
-
Save a8x9/76233a8386fabc3d04e2baefade6a59d to your computer and use it in GitHub Desktop.
Simluation for DP-3T/documents#210
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
#!/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