I have come to realize that my only contributions to this forum are off-topic rants and reviving threads from 2019. To contribute at least a little, I want to share a script that I have started to use recently and enjoy a lot.
The fundamental problem that I wanted to solve is “how can I lock myself out of websites and programs without permanently locking myself out”. For example, there are neat apps that can monitor my YouTube consumption and close the app when I exceed my budget. Unfortunately, the purpose of these apps can be simply defeated by uninstalling them.
I use “Lock Me Out” on my Android phone, and they provide a feature to password lock the app while blocking is active. That prevents me from uninstalling the app, but of course setting a password is not too helpful if the person who you want to lock out is yourself. The developers suggest giving the password to a friend so that you cannot work around this mechanism. That’s a good idea, but I am weirdly individualistic sometimes, and I prefer to keep the keys in my hand.
Ideally, I would have something like a timelock where I write down the password, lock it in with a timer, and not access it until the time is over. People in this forum have suggested such a device. And again, while it is a good idea, I wouldn’t say I like the idea of having an additional piece of hardware to solve a digital problem.
Luckily, there is a straightforward digital solution. I want to think that I first come up with this idea by myself, but when I googled it a couple of years ago, I found that the legendary Gwern had already written about it in 2011. So, if you would like an in-depth explanation, click on that link (it’s the section about chained-hashes that is relevant for this post).
One way to implement a timelock is to use hash functions. Hash functions take input and compute an output deterministically. The beauty is that you cannot predict the result. You have to do the work and execute the function. For example, you could start with the phrase “secret-password,” put it into your hash function and get the output “oN5CKH6G” in a certain amount of time, say one second.
By repeatedly using the output as the input for the same function, we can spend an arbitrary amount of time (or iterations) until we get a final string, our time password. We can use this password like a regular password, except we throw it away once we have used it to lock the app (or whatever our use-case is).
Lastly, to restore the password, we need to remember our initial input and the number of iterations we have executed. For example, here I am running one hundred million iterations which take about 90 seconds on my machine.
And at the end, I get a nice random time password. One could post-process the final string to allow only certain characters or shorten the length, as some websites require it.
Now, you can see whatever amount of time I am willing to spend initially; I will later have that same amount as a buffer to defeat Akrasia. I have noticed that waiting ten minutes to open up Reddit is already more than enough in practice.
Lastly, here is the code if anybody wants to try it. It requires Python 3. I am using the code with 3.9, but it should work with 3.4 too. I have replaced the f-strings with format.
hash.py
#!/usr/bin/env python3
import hashlib
import sys
import time
import getpass
def get_input():
total_count = 0
while not total_count:
try:
# We do the double conversion thing to allow 10ex notation
total_count = int(float(input("Enter count: ")))
except:
print("Enter a positive integer.")
seed, seed_check = "a", "b"
while seed != seed_check:
seed = getpass.getpass()
seed_check = getpass.getpass(prompt="Confirm password: ")
if seed != seed_check:
print("Passwords must match.")
return total_count, seed
def print_progress(total_count, passed_time, current_count):
projected_time = total_count * passed_time / current_count
progress_time = "[{:.2f} / {:.2f}s".format(passed_time, projected_time)
progress_percent = current_count / total_count * 100
progress_percent = "- {:.2f}%]".format(progress_percent)
print(progress_time, progress_percent, " ", end='\r')
if __name__ == "__main__":
total_count, seed = get_input()
start_time = time.time()
current_time = start_time
m = hashlib.sha256()
m.update(seed.encode())
for current_count in range(total_count):
if time.time() - current_time > 1:
current_time = time.time()
passed_time = current_time - start_time
print_progress(total_count, passed_time, current_count)
m.update(m.digest())
print("{} hashes done. Final result:".format(total_count))
print(m.hexdigest())