ed25519_exts_ref.py 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #!/usr/bin/python
  2. # Copyright 2014, The Tor Project, Inc
  3. # See LICENSE for licensing information
  4. """
  5. Reference implementations for the ed25519 tweaks that Tor uses.
  6. Includes self-tester and test vector generator.
  7. """
  8. from slow_ed25519 import *
  9. import os
  10. import random
  11. import slownacl_curve25519
  12. import unittest
  13. import binascii
  14. #define a synonym that doesn't look like 1
  15. ell = l
  16. # This replaces expmod above and makes it go a lot faster.
  17. def expmod(b,e,m):
  18. return pow(b,e,m)
  19. def curve25519ToEd25519(c, sign):
  20. u = decodeint(c)
  21. y = ((u - 1) * inv(u + 1)) % q
  22. x = xrecover(y)
  23. if x & 1 != sign: x = q-x
  24. return encodepoint([x,y])
  25. def blindESK(esk, param):
  26. h = H("Derive temporary signing key" + param)
  27. mult = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
  28. s = decodeint(esk[:32])
  29. s_prime = (s * mult) % ell
  30. k = esk[32:]
  31. assert(len(k) == 32)
  32. k_prime = H("Derive temporary signing key hash input" + k)[:32]
  33. return encodeint(s_prime) + k_prime
  34. def blindPK(pk, param):
  35. h = H("Derive temporary signing key" + param)
  36. mult = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
  37. P = decodepoint(pk)
  38. return encodepoint(scalarmult(P, mult))
  39. def expandSK(sk):
  40. h = H(sk)
  41. a = 2**(b-2) + sum(2**i * bit(h,i) for i in range(3,b-2))
  42. k = ''.join([h[i] for i in range(b/8,b/4)])
  43. assert len(k) == 32
  44. return encodeint(a)+k
  45. def publickeyFromESK(h):
  46. a = decodeint(h[:32])
  47. A = scalarmult(B,a)
  48. return encodepoint(A)
  49. def signatureWithESK(m,h,pk):
  50. a = decodeint(h[:32])
  51. r = Hint(''.join([h[i] for i in range(b/8,b/4)]) + m)
  52. R = scalarmult(B,r)
  53. S = (r + Hint(encodepoint(R) + pk + m) * a) % l
  54. return encodepoint(R) + encodeint(S)
  55. def newSK():
  56. return os.urandom(32)
  57. # ------------------------------------------------------------
  58. MSG = "This is extremely silly. But it is also incredibly serious business!"
  59. class SelfTest(unittest.TestCase):
  60. def _testSignatures(self, esk, pk):
  61. sig = signatureWithESK(MSG, esk, pk)
  62. checkvalid(sig, MSG, pk)
  63. bad = False
  64. try:
  65. checkvalid(sig, MSG*2, pk)
  66. bad = True
  67. except Exception:
  68. pass
  69. self.failIf(bad)
  70. def testExpand(self):
  71. sk = newSK()
  72. pk = publickey(sk)
  73. esk = expandSK(sk)
  74. sig1 = signature(MSG, sk, pk)
  75. sig2 = signatureWithESK(MSG, esk, pk)
  76. self.assertEquals(sig1, sig2)
  77. def testSignatures(self):
  78. sk = newSK()
  79. esk = expandSK(sk)
  80. pk = publickeyFromESK(esk)
  81. pk2 = publickey(sk)
  82. self.assertEquals(pk, pk2)
  83. self._testSignatures(esk, pk)
  84. def testDerivation(self):
  85. priv = slownacl_curve25519.Private()
  86. pub = priv.get_public()
  87. ed_pub0 = publickeyFromESK(priv.private)
  88. sign = (ord(ed_pub0[31]) & 255) >> 7
  89. ed_pub1 = curve25519ToEd25519(pub.public, sign)
  90. self.assertEquals(ed_pub0, ed_pub1)
  91. def testBlinding(self):
  92. sk = newSK()
  93. esk = expandSK(sk)
  94. pk = publickeyFromESK(esk)
  95. param = os.urandom(32)
  96. besk = blindESK(esk, param)
  97. bpk = blindPK(pk, param)
  98. bpk2 = publickeyFromESK(besk)
  99. self.assertEquals(bpk, bpk2)
  100. self._testSignatures(besk, bpk)
  101. # ------------------------------------------------------------
  102. # From pprint.pprint([ binascii.b2a_hex(os.urandom(32)) for _ in xrange(8) ])
  103. RAND_INPUTS = [
  104. '26c76712d89d906e6672dafa614c42e5cb1caac8c6568e4d2493087db51f0d36',
  105. 'fba7a5366b5cb98c2667a18783f5cf8f4f8d1a2ce939ad22a6e685edde85128d',
  106. '67e3aa7a14fac8445d15e45e38a523481a69ae35513c9e4143eb1c2196729a0e',
  107. 'd51385942033a76dc17f089a59e6a5a7fe80d9c526ae8ddd8c3a506b99d3d0a6',
  108. '5c8eac469bb3f1b85bc7cd893f52dc42a9ab66f1b02b5ce6a68e9b175d3bb433',
  109. 'eda433d483059b6d1ff8b7cfbd0fe406bfb23722c8f3c8252629284573b61b86',
  110. '4377c40431c30883c5fbd9bc92ae48d1ed8a47b81d13806beac5351739b5533d',
  111. 'c6bbcce615839756aed2cc78b1de13884dd3618f48367a17597a16c1cd7a290b']
  112. # From pprint.pprint([ binascii.b2a_hex(os.urandom(16)) for _ in xrange(8) ])
  113. BLINDING_PARAMS = [
  114. '54a513898b471d1d448a2f3c55c1de2c0ef718c447b04497eeb999ed32027823',
  115. '831e9b5325b5d31b7ae6197e9c7a7baf2ec361e08248bce055908971047a2347',
  116. 'ac78a1d46faf3bfbbdc5af5f053dc6dc9023ed78236bec1760dadfd0b2603760',
  117. 'f9c84dc0ac31571507993df94da1b3d28684a12ad14e67d0a068aba5c53019fc',
  118. 'b1fe79d1dec9bc108df69f6612c72812755751f21ecc5af99663b30be8b9081f',
  119. '81f1512b63ab5fb5c1711a4ec83d379c420574aedffa8c3368e1c3989a3a0084',
  120. '97f45142597c473a4b0e9a12d64561133ad9e1155fe5a9807fe6af8a93557818',
  121. '3f44f6a5a92cde816635dfc12ade70539871078d2ff097278be2a555c9859cd0']
  122. PREFIX = "ED25519_"
  123. def writeArray(name, array):
  124. print "static const char *{prefix}{name}[] = {{".format(
  125. prefix=PREFIX,name=name)
  126. for a in array:
  127. h = binascii.b2a_hex(a)
  128. if len(h) > 70:
  129. h1 = h[:70]
  130. h2 = h[70:]
  131. print ' "{0}"\n "{1}",'.format(h1,h2)
  132. else:
  133. print ' "{0}",'.format(h)
  134. print "};\n"
  135. def makeTestVectors():
  136. secretKeys = [ binascii.a2b_hex(r) for r in RAND_INPUTS ]
  137. writeArray("SECRET_KEYS", secretKeys)
  138. expandedSecretKeys = [ expandSK(sk) for sk in secretKeys ]
  139. writeArray("EXPANDED_SECRET_KEYS", expandedSecretKeys)
  140. publicKeys = [ publickey(sk) for sk in secretKeys ]
  141. writeArray("PUBLIC_KEYS", publicKeys)
  142. writeArray("CURVE25519_PUBLIC_KEYS",
  143. (slownacl_curve25519.smult_curve25519_base(sk[:32])
  144. for sk in expandedSecretKeys))
  145. blindingParams = [ binascii.a2b_hex(r) for r in BLINDING_PARAMS ]
  146. writeArray("BLINDING_PARAMS", blindingParams)
  147. writeArray("BLINDED_SECRET_KEYS",
  148. (blindESK(expandSK(sk), bp)
  149. for sk,bp in zip(secretKeys,blindingParams)))
  150. writeArray("BLINDED_PUBLIC_KEYS",
  151. (blindPK(pk, bp) for pk,bp in zip(publicKeys,blindingParams)))
  152. writeArray("SELF_SIGNATURES",
  153. (signature(pk, sk, pk) for pk,sk in zip(publicKeys,secretKeys)))
  154. if __name__ == '__main__':
  155. import sys
  156. if len(sys.argv) == 1 or sys.argv[1] not in ("SelfTest", "MakeVectors"):
  157. print "You should specify one of 'SelfTest' or 'MakeVectors'"
  158. sys.exit(1)
  159. if sys.argv[1] == 'SelfTest':
  160. unittest.main()
  161. else:
  162. makeTestVectors()