52 lines
1.4 KiB
Python
52 lines
1.4 KiB
Python
#!/usr/bin/env python3
|
|
import argparse
|
|
import json
|
|
import pathlib
|
|
import re
|
|
|
|
|
|
def inv(value: int, prime: int) -> int:
|
|
return pow(value % prime, -1, prime)
|
|
|
|
|
|
def int_to_bytes(value: int) -> bytes:
|
|
return value.to_bytes(max(1, (value.bit_length() + 7) // 8), "big")
|
|
|
|
|
|
def recover_slope(share_a: dict, share_b: dict, prime: int) -> int:
|
|
x1, y1 = int(share_a["x"]), int(share_a["y"])
|
|
x2, y2 = int(share_b["x"]), int(share_b["y"])
|
|
return ((y2 - y1) * inv(x2 - x1, prime)) % prime
|
|
|
|
|
|
def recover_secret(share: dict, slope: int, prime: int) -> int:
|
|
return (int(share["y"]) - slope * int(share["x"])) % prime
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument(
|
|
"export",
|
|
nargs="?",
|
|
default="../public/escrow_export.json",
|
|
help="path to escrow_export.json",
|
|
)
|
|
args = parser.parse_args()
|
|
|
|
data = json.loads(pathlib.Path(args.export).read_text())
|
|
prime = int(data["field_prime"])
|
|
calibration = data["calibration_batch"]["shares"]
|
|
production_share = data["quarantine_batch"]["shares"][0]
|
|
|
|
slope = recover_slope(calibration[0], calibration[1], prime)
|
|
secret_int = recover_secret(production_share, slope, prime)
|
|
flag = int_to_bytes(secret_int).decode()
|
|
if not re.fullmatch(r"caplag\{[^{}]+\}", flag):
|
|
raise SystemExit("recovered secret is not a caplag flag")
|
|
print(flag)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|