Time-Lock Puzzles (Send a Message to the Future)
Table of Contents
1. Time-Lock Puzzles 简介(给未来发送消息)
1996 年,R. L. Rivest, A. Shamir, and D. A. Wagner 在论文 Time-lock puzzles and timed-release crypto 中提出的 Time-lock puzzles,它解决的问题是: 如何加密一个消息,让这个消息不能马上被解密,甚至是消息的发送者也不能马上解密,必须经过一定时间后才能被解密?这相当于给未来发送消息。
2. Time-Lock Puzzles 算法
Alice 有消息
- Alice 随机选择两个素数
和 ,计算: 这个 就是 Euler's totient function 。 - Alice 计算
,其中 是每秒钟 Bob 可以计算平方再求模的次数。 - Alice 随机选择
做为 RC5 加密算法(论文中是使用的 RC5,但它已经过时,换为 AES 即可)中的密钥。 - Alice 使用密钥
对消息 进行加密,密文: - Alice 随机选择
满足 ,使用下面办法加密 : 需要说明的是, 就是对 进行连续 次的平方再求模运算,由第 2 步可知,计算它需要 秒钟。这太慢了,Alice 显然不能采用这样的方法来计算 ,Alice 采用下面技巧来快速计算 这样得到的 就是 ,但比直接算 快很多。 - Alice 把
发送给 Bob,Alice 删除所有其它变量,如 等都会被 Alice 删除。
Bob 要解密密文
2.1. 两种方法的简单演示
假设
Bob 计算
这两种方法计算出来的
2.2. 两种方法的时间对比
节 2 中提到对某个数
第一种是直接计算
表 1 给出了计算
t(计算平方求模的次数) | Bob 方法(直接计算) | Alice 方法(利用 |
---|---|---|
1000000 | 4.2795s | 0.0051s |
2000000 | 8.2409s | 0.0050s |
3000000 | 12.5669s | 0.0052s |
4000000 | 16.8149s | 0.0051s |
5000000 | 20.3919s | 0.0049s |
6000000 | 24.8932s | 0.0055s |
7000000 | 28.1989s | 0.0049s |
8000000 | 31.8169s | 0.0052s |
3. 生成未知阶的群(整数模 n 乘法群 )
不管
论文 Trustless unknown-order groups 中提到未知阶的群有一些应用:
- VDF
- Accumulator
- Zero-knowledge proof
基于前面的知识,我们得到了一种生成未知阶的群的方法: 随机选择大素数
有没有不需要 Trusted Setup 过程的生成未知阶的群的方法呢?有,使用虚二次域的类群(The class group of an imaginary quagratic number field),这里不介绍它。
4. LCS35 Cryptographic Challenge
论文 Time-lock puzzles and timed-release crypto 的作者 R.L. Rivest 在 1999 年为了庆祝 MIT Laboratory for Computer Science 35 周年,提出了一个密码学挑战,被称为 LCS35 挑战,内容是计算
在 20 年后,也就是 2019 年,这个密码学挑战被程序员 Bernard Fabrot 解决了,密文对应的明文为 !!! Happy Birthday LCS !!!
。由于 LCS35 已经被解决,Rivest 提出了一个类似的新挑战,在新挑战中
参考:
http://people.csail.mit.edu/rivest/lcs35-puzzle-description.txt
http://people.csail.mit.edu/rivest/pubs/Riv19f.new-puzzle.txt
5. Time-Lock Puzzles 和 VDF 的不同
Time-Lock Puzzles 和 Verifiable Delay Functions (VDF) 很像,VDF 的作者在论文 Verifiable Delay Functions 中总结了这两者的不同:
However, time-lock puzzles are not required to be universally verifiable and in all known constructions the verifier uses its secret state to prepare each puzzle and verify the results. VDFs, by contrast, may require an initial trusted setup but then must be usable on any randomly chosen input.
也就是说,Time-Lock Puzzles 并不是公开可验证的,只有知道秘密
6. 附录
6.1. 时间对比测试程序
#!/usr/bin/env python3 import time # p, q are 512-bit primes p = 8209077225464744046058125532749278512291234171215833952402836353080077624707567078652583737734960250522321797259257834136264573912281335421318629812420243 q = 10210866123026220402608723719512990963703414195418793555009957005900602373762304023225762792476205121987889212846523815929308691506724521213557799758686351 n = p*q phi = (p-1)*(q-1) a = 26709222073426371386944893319563814873828437081287914883853479639285555080105905753122291117627967664722212372127789775600885451856023491770260498070851477043567765086507488412082645344266097153356496584378260820598850038246370721277496827950170445707849823419867264814314535998513443626070856504384463494482 t_tests = [1000000, 2000000, 3000000, 4000000, 5000000, 6000000, 7000000, 8000000] # t 分别取这些值进行测试 for t in t_tests: t1 = time.time() result1 = a times = t while times != 0: result1 = result1 * result1 % n # 第一种方法,直接计算。这里有 t 次平方后再求模的运算。整个 while 循环可写为 result1 = pow(a, 2**t, n),计算时间差不多 times = times - 1 t2 = time.time() print("method 1, t = {}, time = {}".format(t, t2 - t1)) t1 = time.time() e = pow(2, t, phi) # 第二种方法,利用 Euler's totient function 加快计算 result2 = pow(a, e, n) t2 = time.time() print("method 2, t = {}, time = {}".format(t, t2 - t1)) assert result1 == result2
下面是在 2.2 GHz Intel Core i7 Processor 下的一个运行结果:
method 1, t = 1000000, time = 4.279543161392212 method 2, t = 1000000, time = 0.005108833312988281 method 1, t = 2000000, time = 8.240965127944946 method 2, t = 2000000, time = 0.005007743835449219 method 1, t = 3000000, time = 12.566895961761475 method 2, t = 3000000, time = 0.005189180374145508 method 1, t = 4000000, time = 16.81494688987732 method 2, t = 4000000, time = 0.0051081180572509766 method 1, t = 5000000, time = 20.39188504219055 method 2, t = 5000000, time = 0.004948139190673828 method 1, t = 6000000, time = 24.893248796463013 method 2, t = 6000000, time = 0.00545501708984375 method 1, t = 7000000, time = 28.19888401031494 method 2, t = 7000000, time = 0.004888057708740234 method 1, t = 8000000, time = 31.816866159439087 method 2, t = 8000000, time = 0.005177736282348633
6.2. Time-Lock Puzzles 实现
下面是 Time-Lock Puzzles 的一个实现:
#!/usr/bin/python # This code was taken from: # http://de.scribd.com/doc/32307363/Anti-Emulation-through-TimeLock-puzzles / Appendix A (at the very end) # All rights to their respective owners # Requires Python Cryptography Toolkit # http://www.amk.ca/python/code/crypto.html import time from Crypto.Util import number def make_puzzle(t): # Generate 512-bit primes p = number.getPrime(512) q = number.getPrime(512) n = p * q phi = (p - 1) * (q - 1) # AES key --- this is what we will encode into the puzzle solution key = number.getRandomInteger(128) # Need a random starting value for the puzzle, between 1 and n a = number.getRandomInteger(4096) a = a % n # *** puzzle shortcut *** # fast way to compute (a^2)^t (if you know phi) e = pow(2, t, phi) b = pow(a, e, n) # print("phi = {}, e = {}, p = {}, q = {}".format(phi, e, p, q)) # So b = (a^2)^t, and we encode the key into this solution ck = (key + b) % n return key, n, a, t, ck def solve_puzzle(n, a, t, ck): print("Working") while t != 0: # This while loop is equivalent to: a = pow(a, 2**t, n) a = a * a % n t = t - 1 return (ck - a) % n def main(): # Generate a new puzzle requiting 3000000 modular squarings to solve t = 3000000 (key, n, a, t, ck) = make_puzzle(t) # Use this key to encrypt a payload print("key = " + str(key)) print("puzzle (n = {}, a = {}, t = {}, ck = {})".format(n, a, t, ck)) # Recover the key t1 = time.time() solution = solve_puzzle(n, a, t, ck) t2 = time.time() print("solve_puzzle time =", t2 - t1) print("solution = " + str(solution)) if __name__ == "__main__": main()
代码改编于:Anti-Emulation Through TimeLock Puzzles, by Tim Ebringer