├── README.md ├── RSA_VRF.py └── requirements.txt /README.md: -------------------------------------------------------------------------------- 1 | # Verifiable-Random-Functions 2 | 3 | We implemented RSA VRF on Python2 fulfilling the properties of trusted uniqueness, trusted collision resistance, and full pseudorandomness. 4 | 5 | USAGE: python RSA_VRF.py [alpha] 6 | 7 | This code takes alpha and generates a proof and then proceeds to verify it. You can modify the size of the proof by modifying the variable k. 8 | The slides are in the LaTeX PDF and make sure to install the libraries in the requirements.txt. 9 | 10 | Implemented psudo code from https://www.ietf.org/archive/id/draft-vcelak-nsec5-08.txt 11 | -------------------------------------------------------------------------------- /RSA_VRF.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import binascii 3 | import operator 4 | import math 5 | import sys 6 | from sys import argv 7 | from cryptography.hazmat.backends import default_backend 8 | from cryptography.hazmat.primitives.asymmetric import rsa 9 | 10 | def integer_byte_size(n): 11 | '''Returns the number of bytes necessary to store the integer n.''' 12 | quanta, mod = divmod(integer_bit_size(n), 8) 13 | if mod or n == 0: 14 | quanta += 1 15 | return quanta 16 | 17 | def integer_bit_size(n): 18 | '''Returns the number of bits necessary to store the integer n.''' 19 | if n == 0: 20 | return 1 21 | s = 0 22 | while n: 23 | s += 1 24 | n >>= 1 25 | return s 26 | 27 | def integer_ceil(a, b): 28 | '''Return the ceil integer of a div b.''' 29 | quanta, mod = divmod(a, b) 30 | if mod: 31 | quanta += 1 32 | return quanta 33 | 34 | class RsaPublicKey(object): 35 | __slots__ = ('n', 'e', 'bit_size', 'byte_size') 36 | 37 | def __init__(self, n, e): 38 | self.n = n 39 | self.e = e 40 | self.bit_size = integer_bit_size(n) 41 | self.byte_size = integer_byte_size(n) 42 | 43 | def __repr__(self): 44 | return '' % (self.n, self.e, self.bit_size) 45 | 46 | def rsavp1(self, s): 47 | if not (0 <= s <= self.n-1): 48 | raise Exception("s not within 0 and n - 1") 49 | return self.rsaep(s) 50 | 51 | def rsaep(self, m): 52 | if not (0 <= m <= self.n-1): 53 | raise Exception("m not within 0 and n - 1") 54 | return pow(m, self.e, self.n) 55 | 56 | class RsaPrivateKey(object): 57 | __slots__ = ('n', 'd', 'bit_size', 'byte_size') 58 | 59 | def __init__(self, n, d): 60 | self.n = n 61 | self.d = d 62 | self.bit_size = integer_bit_size(n) 63 | self.byte_size = integer_byte_size(n) 64 | 65 | def __repr__(self): 66 | return '' % (self.n, self.d, self.bit_size) 67 | 68 | def rsadp(self, c): 69 | if not (0 <= c <= self.n-1): 70 | raise Exception("c not within 0 and n - 1") 71 | return pow(c, self.d, self.n) 72 | 73 | def rsasp1(self, m): 74 | if not (0 <= m <= self.n-1): 75 | raise Exception("m not within 0 and n - 1") 76 | return self.rsadp(m) 77 | 78 | def i2osp(x, x_len): 79 | ''' 80 | Converts the integer x to its big-endian representation of length 81 | x_len. 82 | ''' 83 | # if x > 256**x_len: 84 | # raise ValueError("integer too large") 85 | h = hex(x)[2:] 86 | if h[-1] == 'L': 87 | h = h[:-1] 88 | if len(h) & 1 == 1: 89 | h = '0%s' % h 90 | x = binascii.unhexlify(h) 91 | return b'\x00' * int(x_len-len(x)) + x 92 | 93 | def os2ip(x): 94 | ''' 95 | Converts the byte string x representing an integer reprented using the 96 | big-endian convient to an integer. 97 | ''' 98 | h = binascii.hexlify(x) 99 | return int(h, 16) 100 | 101 | def mgf1(mgf_seed, mask_len, hash_class=hashlib.sha1): 102 | ''' 103 | Mask Generation Function v1 from the PKCS#1 v2.0 standard. 104 | mgs_seed - the seed, a byte string 105 | mask_len - the length of the mask to generate 106 | hash_class - the digest algorithm to use, default is SHA1 107 | Return value: a pseudo-random mask, as a byte string 108 | ''' 109 | h_len = hash_class().digest_size 110 | if mask_len > 0x10000: 111 | raise ValueError('mask too long') 112 | T = b'' 113 | for i in xrange(0, integer_ceil(mask_len, h_len)): 114 | C = i2osp(i, 4) 115 | T = T + hash_class(mgf_seed + C).digest() 116 | return T[:mask_len] 117 | 118 | def VRF_prove(private_key, alpha, k): 119 | # k is the length of pi 120 | EM = mgf1(alpha, k-1) 121 | m = os2ip(EM) 122 | s = private_key.rsasp1(m) 123 | pi = i2osp(s, k) 124 | return pi 125 | 126 | def VRF_proof2hash(pi, hash=hashlib.sha1): 127 | beta = hash(pi).digest() 128 | return beta 129 | 130 | def VRF_verifying(public_key, alpha, pi, k): 131 | s = os2ip(pi) 132 | m = public_key.rsavp1(s) 133 | EM = i2osp(m, k-1) 134 | EM_ = mgf1(alpha, k-1) 135 | if EM == EM_: 136 | return "VALID" 137 | else: 138 | return "INVALID" 139 | 140 | if __name__ == "__main__": 141 | if len(argv) < 2: 142 | print "USAGE: python RSA_VRF.py [alpha]" 143 | exit(1) 144 | private_key = rsa.generate_private_key( 145 | public_exponent=65537, 146 | key_size=2048, 147 | backend=default_backend()) 148 | private_numbers = private_key.private_numbers() 149 | public_key = private_key.public_key() 150 | public_numbers = public_key.public_numbers() 151 | n = public_numbers.n 152 | e = public_numbers.e 153 | d = private_numbers.d 154 | k = 20 155 | public_key = RsaPublicKey(n, e) 156 | private_key = RsaPrivateKey(n, d) 157 | alpha = " ".join(argv[1:]) 158 | pi = VRF_prove(private_key, alpha, k) 159 | beta = VRF_proof2hash(pi) 160 | print(VRF_verifying(public_key, alpha, pi, k)) 161 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | cryptography 2.2.2 2 | --------------------------------------------------------------------------------