3.3-votes-and-notarization.py 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. # Section 3.3 from "Streamlet: Textbook Streamlined Blockchains"
  2. from cryptography.hazmat.primitives import serialization, hashes
  3. from cryptography.hazmat.primitives.asymmetric import rsa, padding
  4. from cryptography.hazmat.backends import default_backend
  5. from cryptography.exceptions import InvalidSignature
  6. # Cryptographic algorithm used is for demostranation porpuses only.
  7. # Generating the keys pair.
  8. def generate_keys(private_key_password):
  9. private_key = rsa.generate_private_key(
  10. public_exponent=65537,
  11. key_size=2048
  12. )
  13. encrypted_pem_private_key = private_key.private_bytes(
  14. encoding=serialization.Encoding.PEM,
  15. format=serialization.PrivateFormat.PKCS8,
  16. encryption_algorithm=serialization.BestAvailableEncryption(private_key_password.encode())
  17. )
  18. pem_public_key = private_key.public_key().public_bytes(
  19. encoding=serialization.Encoding.PEM,
  20. format=serialization.PublicFormat.SubjectPublicKeyInfo
  21. )
  22. return encrypted_pem_private_key, pem_public_key
  23. # Signs a message using private_key.
  24. def sign_message(password, private_key, message):
  25. privkey = serialization.load_pem_private_key(private_key, password=password.encode(), backend=default_backend())
  26. signed_message = privkey.sign(
  27. message.encode(),
  28. padding.PSS(
  29. mgf=padding.MGF1(hashes.SHA256()),
  30. salt_length=padding.PSS.MAX_LENGTH),
  31. hashes.SHA256()
  32. )
  33. return signed_message
  34. # Verifies a message against a public key.
  35. def verify_signature(public_key, message, signed_message):
  36. pubkey = serialization.load_pem_public_key(public_key, backend=default_backend())
  37. try:
  38. pubkey.verify(
  39. signed_message,
  40. message.encode(),
  41. padding.PSS(
  42. mgf=padding.MGF1(hashes.SHA256()),
  43. salt_length=padding.PSS.MAX_LENGTH),
  44. hashes.SHA256())
  45. return True
  46. except InvalidSignature:
  47. return False
  48. # When a node votes on a block, it simply signs it with the private key, and broadcasts the message to rest nodes.
  49. message = "block"
  50. node_password = "node_password"
  51. node_private_key, node_public_key = generate_keys(node_password)
  52. signed_message = sign_message(node_password, node_private_key, message)
  53. # When nodes receive votes, they verify them against nodes public key.
  54. assert(verify_signature(node_public_key, message, signed_message))
  55. # If votes for that specific block are >=2n/3, node marks block as notarized.