選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 

129 行
3.2 KiB

  1. #!/usr/bin/env sage
  2. #coding: utf8
  3. proof.all(False)
  4. # parameters.
  5. ls = list(primes(3, 374)) + [587] # Elkies primes
  6. #ls = list(primes(3, 47)) + [97] # (a smaller example)
  7. p = 4 * prod(ls) - 1
  8. assert is_prime(p)
  9. print "\nElkies primes:", " ".join(map(str, ls))
  10. max_exp = ceil((sqrt(p) ** (1/len(ls)) - 1) / 2)
  11. assert (2 * max_exp + 1) ** len(ls) >= sqrt(p)
  12. print "exponents are chosen in the range {}..{}.".format(-max_exp, max_exp)
  13. base = GF(p)(0) # Montgomery coefficient of starting curve
  14. # helper functions.
  15. # NB: all the operations can be computed entirely over the prime field,
  16. # but for simplicity of this implementation we will make use of curves
  17. # defined over GF(p^2). note this slows everything down quite a bit.
  18. Fp2.<i> = GF(p**2, modulus = x**2 + 1)
  19. def montgomery_curve(A):
  20. return EllipticCurve(Fp2, [0, A, 0, 1, 0])
  21. # sage's isogeny formulas return Weierstraß curves, hence we need this...
  22. def montgomery_coefficient(E):
  23. Ew = E.change_ring(GF(p)).short_weierstrass_model()
  24. _, _, _, a, b = Ew.a_invariants()
  25. R.<z> = GF(p)[]
  26. r = (z**3 + a*z + b).roots(multiplicities=False)[0]
  27. s = sqrt(3 * r**2 + a)
  28. if not is_square(s): s = -s
  29. A = 3 * r / s
  30. assert montgomery_curve(A).change_ring(GF(p)).is_isomorphic(Ew)
  31. return GF(p)(A)
  32. # actual implementation.
  33. def private():
  34. return [randrange(-max_exp, max_exp + 1) for _ in range(len(ls))]
  35. def validate(A):
  36. while True:
  37. k = 1
  38. P = montgomery_curve(A).lift_x(GF(p).random_element())
  39. for l in ls:
  40. Q = (p + 1) // l * P
  41. if not Q: continue
  42. if l * Q: return False
  43. k *= l
  44. if k > 4 * sqrt(p): return True
  45. def action(pub, priv):
  46. E = montgomery_curve(pub)
  47. es = priv[:]
  48. while any(es):
  49. E._order = (p + 1)**2 # else sage computes this
  50. P = E.lift_x(GF(p).random_element())
  51. s = +1 if P.xy()[1] in GF(p) else -1
  52. k = prod(l for l, e in zip(ls, es) if sign(e) == s)
  53. P *= (p + 1) // k
  54. for i, (l, e) in enumerate(zip(ls, es)):
  55. if sign(e) != s: continue
  56. Q = k // l * P
  57. if not Q: continue
  58. Q._order = l # else sage computes this
  59. phi = E.isogeny(Q)
  60. E, P = phi.codomain(), phi(P)
  61. es[i] -= s
  62. k //= l
  63. return montgomery_coefficient(E)
  64. # example.
  65. print
  66. print "testing public-key validation on random ordinary curves (should be all 0s):\n ",
  67. for _ in range(16):
  68. while True:
  69. A = GF(p).random_element()
  70. if montgomery_curve(A).is_ordinary(): break
  71. print int(validate(A)),
  72. print
  73. privA = private()
  74. print "\nAlice's private key:\n ", " ".join(map('{:2d}'.format, privA))
  75. pubA = action(base, privA)
  76. print "\nAlice's public key:\n ", pubA,
  77. print " (valid: {})".format(int(validate(pubA)))
  78. privB = private()
  79. print "\nBob's private key:\n ", " ".join(map('{:2d}'.format, privB))
  80. pubB = action(base, privB)
  81. print "\nBob's public key:\n ", pubB,
  82. print " (valid: {})".format(int(validate(pubB)))
  83. sharedA = action(pubB, privA)
  84. print "\nAlice's shared secret:\n ", sharedA
  85. sharedB = action(pubA, privB)
  86. print "\nBob's shared secret:\n ", sharedB
  87. if sharedA == sharedB:
  88. print "\n--> equal!\n"
  89. else:
  90. print "\n--> NOT EQUAL?!\n"