from hashlib import sha384
from os import urandom
import binascii
import datetime

def validatedate(date):
    try:
        return datetime.datetime.strptime(date, "%Y-%m-%d").strftime('%Y-%m-%d') == date
    except ValueError:
        return False

def hhash(seed, name, surname, birthdate, idnumber):
  """Hashes the "hacker ID" from the seed, name, surname, birth date and id number provided"""
  if not validatedate(birthdate):
    raise ValueError("Birth date must be in format YYYY-MM-DD")
  name = name.encode("utf-8")
  surname = surname.encode("utf-8")
  birthdate = birthdate.encode("utf-8")
  idnumber = idnumber.encode("utf-8")
  return sha384(b"%s%d %d %d %d %s%s%s%s%s" % (seed, len(name), len(surname), len(birthdate), len(idnumber), name, surname, birthdate, idnumber, seed)).digest()

def create(name, surname, birthdate, idnumber):
  """Creates a "hacker ID" based on the name, surname, birth date and id number provided"""
  seed = urandom(1024//8)
  try:
    return binascii.hexlify(seed+hhash(seed, name, surname, birthdate, idnumber)).decode("ascii")
  except (UnicodeEncodeError, ValueError):
    return None

def verify(hid, name, surname, birthdate, idnumber):
  """Verifies the "hacker ID" hid based on the name, surname, birth date and id number provided"""
  try:
    hid = hid.encode("ascii")
  except UnicodeEncodeError:
    return False
  try:
    hid = binascii.unhexlify(hid)
  except binascii.Error:
    return False
  if len(hid) != (1024+384)//8:
    return False
  try:
    hhid = hhash(hid[0:1024//8], name, surname, birthdate, idnumber)
  except (UnicodeEncodeError, ValueError):
    return False
  return hhid == hid[1024//8:]

"""Here are some tests to ensure this works as intended"""
assert(sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest() == hhash(b"\x00"*128,"Test","Testertons","1967-01-02", "ESP12345678Z"))
assert(sha384(b"\x01"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x01"*128).digest() != hhash(b"\x00"*128,"Test","Testertons","1967-01-02", "ESP12345678Z"))
assert(sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Y"+b"\x00"*128).digest() != hhash(b"\x00"*128,"Test","Testertons","1967-01-02", "ESP12345678Z"))
assert(sha384(b"\x00"*128+b"4210 10 12 TestTestertons1967-01-02ESP12345678>"+b"\x00"*128).digest() != hhash(b"\x00"*128,"Test","Testertons","1967-01-02", "ESP12345678Z"))
assert(sha384(b"\x00"*128+b"3 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest() != hhash(b"\x00"*128,"Test","Testertons","1967-01-02", "ESP12345678Z"))
assert(create("Test","Testertons","1967-01-02", "ESP12345678Z") is not None)
assert(create("Testa","Testertons","1967-01-02", "ESP12345678Z") != create("Test","Testertons","1967-01-02", "ESP12345678Z"))
assert(create("Test","Testertons","1967-01-02", "ESP12345678Z") != create("Test","Testertons","1967-01-02", "ESP12345678Z"))
assert(create("Test","Testertons","1967-02-31", "ESP12345678Z") is None)
assert(create("Test","Testertons","1967-13-01", "ESP12345678Z") is None)
assert(create("Test","Testertons","1967-1-1", "ESP12345678Z") is None)
assert(verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Test","Testertons","1967-01-02", "ESP12345678Z"))
assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x01"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x01"*128).digest()).decode("ascii"),"Test","Testertons","1967-01-02", "ESP12345678Z"))
assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Test","Testertons","1967-01-02", "ESP12345678Y"))
assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Test","Testertons","1967-1-2", "ESP12345678Z"))
assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Test","Testertons","1967-13-02", "ESP12345678Z"))
assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Test","Testertons","1967-02-31", "ESP12345678Z"))
assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"4 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Tes","Testertons","1967-01-02", "ESP12345678Z"))
assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"4210 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Test","Testertons","1967-01-02", "ESP12345678Z"))
assert(not verify(binascii.hexlify(b"\x00"*128+sha384(b"\x00"*128+b"3 10 10 12 TestTestertons1967-01-02ESP12345678Z"+b"\x00"*128).digest()).decode("ascii"),"Test","Testertons","1967-01-02", "ESP12345678Z"))
assert(verify(create("Test","Testertons","1967-01-02", "ESP12345678Z"),"Test","Testertons","1967-01-02", "ESP12345678Z"))
assert(not verify(create("Test","Testertons","1967-01-02", "ESP12345678Z"),"Testa","Testertons","1967-01-02", "ESP12345678Z"))
assert(not verify(create("Test","Testertons","1967-01-02", "ESP12345678Z"),"Test","Testerton","1967-01-02", "ESP12345678Z"))
assert(not verify(create("Test","Testertons","1967-01-02", "ESP12345678Z"),"Test","Testertons","1967-01-12", "ESP12345678Z"))
assert(not verify(create("Test","Testertons","1967-01-02", "ESP12345678Z"),"Test","Testertons","1967-01-02", "ESP12345679Z"))

"""
This is intended to provide a way to safely authenticate a hacker's personal data when proofing ownership of something bound to their personal data (for example on the entrance of an event before receiving a physical token proving purchase of a ticket).
The event is supposed to bind the last 384-bits (48 bytes) of the hacker identifier to the ticket. The person is supposed to provide the first 1024-bits (128 bytes) along with their ID (card, passport, etc.) matching the data used to generate the personal data provided and ticket on the entrance for verification.

Requirements:
* Seed is kept private and only provided to the event organizers.
* A hacker must be able to generate an ID without using event infrastructure.
* An event is able to verify the generated ID on their own infrastructure.
* Creation and verification should be possible offline to prevent attacks.
* Changes on any of the input parameters will make ID verification fail (with a negligible probability).
* An attacker with the event part of the ID but without the seed can't obtain a hacker's personal data with a probability that is not negligible for guess.
* An attacker with the event part of the ID and seed can only verify if a set of inputs match the event part or not. I.e. can't extract any part of the input without knowing the others.
* An attacker cannot calculate a seed so that another set of data will match with a probability that is not negligible for try.

Assumptions:
* SHA384 isn't vulnerable to preimage attacks with a non negligble probability
* SHA384 isn't vulnerable to collision attacks with a non negligble probability
* os.urandom isn't predictable by an external attacker

Challenges:
I'm willing to pay you 1000EUR if before 2020-01-01 00:00CET you find the data values used to create the event string below (without asking me or attacking my computer)
'bfa6dffdfb06b488cf9ccd310b464a2f6e45189c6df994df82291ebd0d965cc12a9007103fd6c65f9ef849a16c3a4451'

I'm willing to pay you 1000EUR if before 2020-01-01 00:00CET you find a value for seed so that
verify(seed+'a352573fc6477a1ee2a224c73c754ad632f20a24b12a8b2ee5e995880cb17665f9609e97afdd131b316039d86440bd1f',"Hacker","Rebuyer","1967-05-23","SWE123321867G")  is True

'a352573fc6477a1ee2a224c73c754ad632f20a24b12a8b2ee5e995880cb17665f9609e97afdd131b316039d86440bd1f' is the result of create("Evil","Reseller","2001-03-12","FRA762345123H") with
seed '9cbdf7ec7a7d8540feda0acf402ab28b1967f41ba5bccabfd0655049487b3892ffdcc4aab5be10e39be336d6c68e3e7a266ed390a4f35cdd0e7c717af0ec8299a4dffd43a0dfb9ff63aba617617d5eae0a9d626c017e911b310b2c689b91a4928cb2a478fd8825284bdb6045e826171c5f811ecd54a806cfb5dfe7ebb9c87787'

Keep in mind that for verify to work seed must be 1024 bits long

Alternatively I'm willing to pay you 1000EUR if before 2020-01-01 00:00CET you find a method to find a seed so that it matches one of any personal data values I provide after you give me a 384-bit value of event hash of your choice in less than 6-months in a core i7-4710HQ.
I.e. if you can generate a 384-bit value that matches a set of name, surname, birthdate and idnumber that you can't know before actually generating said 384-bit value. This emulates "a resale attack" where the reseller can't know the personal data of any of the buyers before actually purchasing the ticket.
Keep in mind that I will want a proof of your attack before actually providing you with some data for this challenge.

I'm willing to pay you 100EUR if before 2020-01-01 00:00CET you find either of the name,  surname, birthdate or idnumber for the string below (without asking me or attacking my computer) and 1000 if you can find a way to do this in less than 6-months for any arbitrary value in a core i7-4710HQ.
'82ca48064ce274b4a4ebfc3f0f2263c214ee1311c0222fb75acc7a5b1c2edc71c0071ef441cbe302e2a4cec46e98d3d40cae3c7356723beb10e221b2cd8a46c0ed42685777441039ab778bdd0321aaff6356e88800baacaf0229b4deb3559b29ea735ae994d2fcf04c2a0d37fcc3554ca3ef44c12db4b60bd805da42ebdaface9e7b2934d000b1d913e04cd56c4740083009d42605e45ff66946b85a988ed15f9ca5b01798341f45eaf571c5d768000e'

If my data survives until then I will post the values used in challenges 1 and 3 before 2020-02-01 00:00CET

Dates are in YYYY-MM-DD format

I reserve the right to fix eventual errors in this challenge description and rejecting solutions which are against the spirit (breaking the cryptography) of the challenge.
"""
