shamir.py 1.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  1. from typing import List, Tuple
  2. import utils
  3. UPPER = (2**8)**64
  4. PRIME = (2**8)**64 + 75
  5. def inverse(num: int) -> int:
  6. return pow(num, PRIME - 2, PRIME)
  7. def mod(num: int) -> int:
  8. return num % PRIME
  9. def rand_coefficient() -> int:
  10. with open('/dev/random', 'rb') as f:
  11. return utils.bytes_to_long(f.read(64))
  12. def generate_polynomial(num_coeff: int, intercept: int) -> List[int]:
  13. assert num_coeff >= 1
  14. return [rand_coefficient() for _ in range(num_coeff - 1)] + [intercept]
  15. def eval_polynomial(polynomial: List[int], point: int):
  16. result = 0
  17. for coeff in polynomial:
  18. result = (result * point + coeff) % PRIME
  19. return result
  20. def secret_to_parts(secret: int, k: int, n: int) -> List[int]:
  21. assert 0 <= secret < UPPER
  22. assert 0 < k <= n
  23. while True:
  24. polynomial = generate_polynomial(k, secret)
  25. parts = [eval_polynomial(polynomial, point)
  26. for point in range(1, n + 1)]
  27. # Check that all parts fit in 64 bytes, otherwise try with new polynomial
  28. if all(part < UPPER for part in parts):
  29. return parts
  30. def parts_to_secret(parts: List[Tuple[int, int]]) -> int:
  31. secret = 0
  32. for part_id, secret_part in parts:
  33. current = secret_part
  34. for other_id, _ in parts:
  35. if other_id == part_id:
  36. continue
  37. current = mod(current * mod(-other_id))
  38. current = mod(current * inverse(mod(part_id - other_id)))
  39. secret = mod(secret + current)
  40. return secret