utils.py 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. from cryptography.hazmat.primitives import serialization, hashes
  2. from cryptography.hazmat.primitives.asymmetric import rsa, padding
  3. from cryptography.hazmat.backends import default_backend
  4. from cryptography.exceptions import InvalidSignature
  5. import random
  6. import joblib
  7. import pickle
  8. def extended_euclidean_algorithm(a, b):
  9. """
  10. Returns a three-tuple (gcd, x, y) such that
  11. a * x + b * y == gcd, where gcd is the greatest
  12. common divisor of a and b.
  13. This function implements the extended Euclidean
  14. algorithm and runs in O(log b) in the worst case.
  15. """
  16. s, old_s = 0, 1
  17. t, old_t = 1, 0
  18. r, old_r = b, a
  19. while r != 0:
  20. quotient = old_r // r
  21. old_r, r = r, old_r - quotient * r
  22. old_s, s = s, old_s - quotient * s
  23. old_t, t = t, old_t - quotient * t
  24. return old_r, old_s, old_t
  25. def inverse_of(n, p):
  26. """
  27. Returns the multiplicative inverse of
  28. n modulo p.
  29. This function returns an integer m such that
  30. (n * m) % p == 1.
  31. """
  32. gcd, x, y = extended_euclidean_algorithm(n, p)
  33. assert (n * x + p * y) % p == gcd
  34. if gcd != 1:
  35. # Either n is 0, or p is not a prime number.
  36. raise ValueError(
  37. '{} has no multiplicative inverse '
  38. 'modulo {}'.format(n, p))
  39. else:
  40. return x % p
  41. '''
  42. @param nums: list of weight
  43. @param true_rnd_fn: truely random function
  44. @return zero-based index of the truely selected element
  45. '''
  46. def weighted_random(nums, true_rnd_fn=random.random):
  47. """
  48. nums is list of weight, it return the truely random
  49. weighted value.
  50. """
  51. L = len(nums)
  52. pair = [(i, nums[i]) for i in range(L)]
  53. pair.sort(key=lambda p: p[1])
  54. tot = sum([pair[i][1] for i in range(L)])
  55. frequency = [pair[i][1]/tot for i in range(L)]
  56. acc_prop = [sum(frequency[:i+1]) for i in range(L)]
  57. rnd = true_rnd_fn()
  58. for elected in range(L):
  59. if rnd<=acc_prop[elected]:
  60. break
  61. return pair[elected][0]
  62. '''
  63. @param data: data is dictionary of list of (pk_i, s_i) public key,
  64. and stake respectively of the corresponding stakeholder U_i,
  65. seed of the leader election function.
  66. '''
  67. def encode_genesis_data(data):
  68. return pickle.dumps(data)
  69. def decode_gensis_data(encoded_data):
  70. return pickle.loads(encoded_data)
  71. '''
  72. TODO this is a adhoc solution
  73. this has is used to compute the state of block from the previous block
  74. '''
  75. def state_hash(obj):
  76. return hash(obj)
  77. '''
  78. TODO this is a adhoc solution
  79. this is used to generate VRF's sk from some seed
  80. note there is a need for nounce to be concatenated with the seed,
  81. just in case two stakeholders started with the same seed
  82. (for the time being the seed is provided by the stakeholder, it's stakeholder passowrd)
  83. '''
  84. def vrf_hash(seed):
  85. return hash(seed)
  86. def generate_sig_keys(private_key_password):
  87. ''' Generating the keys pair. Cryptographic algorithm used is for demostranation porpuses only. '''
  88. private_key = rsa.generate_private_key(
  89. public_exponent=65537,
  90. key_size=2048
  91. )
  92. encrypted_pem_private_key = private_key.private_bytes(
  93. encoding=serialization.Encoding.PEM,
  94. format=serialization.PrivateFormat.PKCS8,
  95. encryption_algorithm=serialization.BestAvailableEncryption(
  96. private_key_password.encode()))
  97. pem_public_key = private_key.public_key().public_bytes(
  98. encoding=serialization.Encoding.PEM,
  99. format=serialization.PublicFormat.SubjectPublicKeyInfo
  100. )
  101. return encrypted_pem_private_key, pem_public_key
  102. def sign_message(password, private_key, message):
  103. ''' Signs a message using private_key. '''
  104. privkey = serialization.load_pem_private_key(
  105. private_key, password=password.encode(), backend=default_backend())
  106. signed_message = privkey.sign(
  107. message.encode(),
  108. padding.PSS(
  109. mgf=padding.MGF1(hashes.SHA256()),
  110. salt_length=padding.PSS.MAX_LENGTH),
  111. hashes.SHA256()
  112. )
  113. return signed_message
  114. def verify_signature(public_key, message, signed_message):
  115. ''' Verifies a message against a public key. '''
  116. pubkey = serialization.load_pem_public_key(
  117. public_key, backend=default_backend())
  118. try:
  119. pubkey.verify(
  120. signed_message,
  121. message.encode(),
  122. padding.PSS(
  123. mgf=padding.MGF1(hashes.SHA256()),
  124. salt_length=padding.PSS.MAX_LENGTH),
  125. hashes.SHA256())
  126. return True
  127. except InvalidSignature:
  128. return False