You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

335 lines
9.6 KiB

  1. from ctypes import *
  2. from base64 import *
  3. DECAF = CDLL("libdecaf.so")
  4. F = GF(2^448-2^224-1)
  5. d = -39081
  6. E = EllipticCurve(F,[0,2-4*d,0,1,0])
  7. p_tor4 = E.lift_x(-1)
  8. Tor = [p_tor4 * i for i in xrange(4)]
  9. q = 2^446-0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d
  10. FQ = GF(q)
  11. passing = True
  12. # TODO: pathological cases
  13. # TODO: Elligator
  14. # TODO: double scalar mul
  15. def random_array(length):
  16. answer = "".join([chr(randint(0,255)) for i in xrange(length)])
  17. return answer
  18. def from_le(buf):
  19. return sum([256^i * ord(x) for i,x in enumerate(buf)])
  20. def youfail(why,n):
  21. print ("Fail on test %d!"%n), why
  22. global passing
  23. passing = False
  24. def run_test(i):
  25. try:
  26. s = DecafScalar.random()
  27. t = DecafScalar.random()
  28. p = DecafPoint.random()
  29. q = DecafPoint.random()
  30. s*p + t*q
  31. if s*(t*p) != (s*t)*p:
  32. raise Exception("Mul doesn't work")
  33. (p+q-p-q).ser() # i guess...
  34. except Exception, e:
  35. youfail(e,i)
  36. def run_all_tests(n = 100):
  37. for testno in xrange(n):
  38. run_test(testno)
  39. if passing:
  40. print "Passed all %d tests." % n
  41. def to_le(x,n):
  42. x = int(x)
  43. if x >= 256^n:
  44. raise Exception("Integer too big in to_le(%d,%d)" % (x,n))
  45. return "".join([chr(x>>(8*i) & 255) for i in xrange(n)])
  46. class DecafScalar():
  47. _UNDER = c_uint64 * int(7)
  48. def __init__(self,cstruct=None,scalar=None):
  49. if cstruct is None:
  50. cstruct = DecafScalar._UNDER()
  51. memmove(addressof(cstruct),
  52. DECAF.decaf_448_scalar_zero,
  53. 8*7
  54. )
  55. if scalar is None:
  56. scalar = E(0)
  57. self.cstruct = cstruct
  58. self.scalar = scalar
  59. self._check()
  60. @staticmethod
  61. def _c_deser(str):
  62. buffer = (c_uint8*int(56)).from_buffer_copy(str)
  63. cstruct = DecafScalar._UNDER()
  64. ret = DECAF.decaf_448_scalar_decode(cstruct,buffer,c_uint64(-1))
  65. if ret != -1:
  66. raise Exception("scalar didn't decode")
  67. return cstruct
  68. @staticmethod
  69. def _sage_deser(str):
  70. s = from_le(str)
  71. if s >= FQ.cardinality(): raise Exception("scalar didn't decode")
  72. return FQ(s)
  73. def __eq__(self,other):
  74. csays = bool(DECAF.decaf_448_scalar_eq(self.cstruct,other.cstruct))
  75. sagesays = any([self.scalar == other.scalar + t for t in Tor])
  76. if csays != sagesays:
  77. raise Exception("C and SAGE don't agree: %d %d" % (csays, sagesays))
  78. return csays
  79. def __ne__(self,other):
  80. return not self==other
  81. def __add__(self,other):
  82. cstruct = DecafScalar._UNDER()
  83. DECAF.decaf_448_scalar_add(cstruct,self.cstruct,other.cstruct)
  84. return DecafScalar(cstruct,self.scalar + other.scalar)
  85. def __sub__(self,other):
  86. cstruct = DecafScalar._UNDER()
  87. DECAF.decaf_448_scalar_sub(cstruct,self.cstruct,other.cstruct)
  88. return DecafScalar(cstruct,self.scalar - other.scalar)
  89. def __mul__(self,other):
  90. if isinstance(other,DecafScalar):
  91. cstruct = DecafScalar._UNDER()
  92. DECAF.decaf_448_scalar_mul(cstruct,self.cstruct,other.cstruct)
  93. return DecafScalar(cstruct,self.scalar * other.scalar)
  94. elif isinstance(other,DecafPoint):
  95. cstruct = DecafPoint._UNDER()
  96. DECAF.decaf_448_point_scalarmul(cstruct,other.cstruct,self.cstruct)
  97. return DecafPoint(cstruct,int(self.scalar) * other.point)
  98. else: raise Exception("Nope")
  99. def __div__(self,other):
  100. return self / other.inverse()
  101. def inverse(self):
  102. cstruct = DecafScalar._UNDER()
  103. z = DECAF.decaf_448_scalar_invert(cstruct,self.cstruct)
  104. if bool(z) != (self.scalar == 0):
  105. raise Exception("C and SAGE don't agree")
  106. return DecafScalar(cstruct,1/self.scalar)
  107. def __neg__(self):
  108. cstruct = DecafScalar._UNDER()
  109. DECAF.decaf_448_scalar_negate(cstruct,self.cstruct)
  110. return DecafScalar(cstruct,-self.scalar)
  111. def __str__(self):
  112. return " ".join(["%02x"%ord(b) for b in self.ser()])
  113. def __repr__(self):
  114. return "DecafScalar.fromInt(%d)" % self.scalar
  115. @classmethod
  116. def fromInt(cls,i):
  117. return cls.deser(to_le(i,56))
  118. def to64(self):
  119. return b64encode(self.ser())
  120. @classmethod
  121. def from64(cls,str):
  122. return cls.deser(b64decode(str))
  123. @classmethod
  124. def deser(cls,str):
  125. good = True
  126. try: cstruct = cls._c_deser(str)
  127. except Exception: good = False
  128. good2 = True
  129. try: scalar = cls._sage_deser(str)
  130. except Exception: good2 = False
  131. if good != good2:
  132. raise Exception("C and SAGE don't agree")
  133. elif not good:
  134. raise Exception("scalar didn't decode")
  135. return cls(cstruct,scalar)
  136. @classmethod
  137. def random(cls):
  138. while True:
  139. try: return cls.deser(random_array(56))
  140. except Exception: pass
  141. @staticmethod
  142. def _c_ser(cstruct):
  143. buffer = (c_uint8*int(56))()
  144. DECAF.decaf_448_scalar_encode(buffer,cstruct)
  145. return str(bytearray(buffer))
  146. def ser(self):
  147. return self._c_ser(self.cstruct)
  148. @staticmethod
  149. def _sage_ser(P):
  150. return to_le(P,56)
  151. def _check(self):
  152. ss = self._sage_ser(self.scalar)
  153. cs = self._c_ser(self.cstruct)
  154. if ss != cs:
  155. print ss
  156. print cs
  157. raise Exception("Check failed!")
  158. return True
  159. class DecafPoint():
  160. _UNDER = c_uint64 * int(8*4)
  161. def __init__(self,cstruct=None,point=None):
  162. if cstruct is None:
  163. cstruct = DecafPoint._UNDER()
  164. memmove(addressof(cstruct),
  165. DECAF.decaf_448_point_identity,
  166. 8*8*4
  167. )
  168. if point is None:
  169. point = E(0)
  170. self.cstruct = cstruct
  171. self.point = point
  172. self._check()
  173. @staticmethod
  174. def _c_deser(str):
  175. buffer = (c_uint8*int(56)).from_buffer_copy(str)
  176. cstruct = DecafPoint._UNDER()
  177. ret = DECAF.decaf_448_point_decode(cstruct,buffer,c_uint64(-1))
  178. if ret != -1:
  179. raise Exception("Point didn't decode")
  180. return cstruct
  181. @staticmethod
  182. def _sage_deser(str):
  183. s = from_le(str)
  184. if s > (F.cardinality()-1)/2: raise Exception("Point didn't decode")
  185. if (s==0): return E(0)
  186. if not E.is_x_coord(s^2): raise Exception("Point didn't decode")
  187. P = E.lift_x(s^2)
  188. t = P.xy()[1] / s
  189. if is_odd(int(2*t/s)): P = -P
  190. return P
  191. def __eq__(self,other):
  192. csays = bool(DECAF.decaf_448_point_eq(self.cstruct,other.cstruct))
  193. sagesays = any([self.point == other.point + t for t in Tor])
  194. if csays != sagesays:
  195. raise Exception("C and SAGE don't agree: %d %d" % (csays, sagesays))
  196. return csays
  197. def __ne__(self,other):
  198. return not self==other
  199. def __add__(self,other):
  200. cstruct = DecafPoint._UNDER()
  201. DECAF.decaf_448_point_add(cstruct,self.cstruct,other.cstruct)
  202. return DecafPoint(cstruct,self.point + other.point)
  203. def __sub__(self,other):
  204. cstruct = DecafPoint._UNDER()
  205. DECAF.decaf_448_point_sub(cstruct,self.cstruct,other.cstruct)
  206. return DecafPoint(cstruct,self.point - other.point)
  207. def __mul__(self,other):
  208. if isinstance(other,DecafScalar):
  209. return other*self
  210. else:
  211. raise Exception("nope")
  212. def __div__(self,other):
  213. if isinstance(other,DecafScalar):
  214. return other.inverse()*self
  215. else:
  216. raise Exception("nope")
  217. def __neg__(self):
  218. cstruct = DecafPoint._UNDER()
  219. DECAF.decaf_448_point_negate(cstruct,self.cstruct)
  220. return DecafPoint(cstruct,-self.point)
  221. def __str__(self):
  222. return " ".join(["%02x"%ord(b) for b in self.ser()])
  223. def __repr__(self):
  224. return "DecafPoint.from64('%s')" % self.to64()
  225. def to64(self):
  226. return b64encode(self.ser())
  227. @classmethod
  228. def from64(cls,str):
  229. return cls.deser(b64decode(str))
  230. @classmethod
  231. def deser(cls,str):
  232. good = True
  233. try: cstruct = cls._c_deser(str)
  234. except Exception: good = False
  235. good2 = True
  236. try: point = cls._sage_deser(str)
  237. except Exception: good2 = False
  238. if good != good2:
  239. raise Exception("C and SAGE don't agree")
  240. elif not good:
  241. raise Exception("Point didn't decode")
  242. return cls(cstruct,point)
  243. @classmethod
  244. def random(cls):
  245. while True:
  246. try: return cls.deser(random_array(56))
  247. except Exception: pass
  248. @staticmethod
  249. def _c_ser(cstruct):
  250. buffer = (c_uint8*int(56))()
  251. DECAF.decaf_448_point_encode(buffer,cstruct)
  252. return str(bytearray(buffer))
  253. def ser(self):
  254. return self._c_ser(self.cstruct)
  255. @staticmethod
  256. def _sage_ser(P):
  257. if P == E(0): return to_le(0,56)
  258. x,y = P.xy()
  259. s = sqrt(x)
  260. if s==0: return to_le(0,56)
  261. if is_odd(int(2*y/s^2)): s = 1/s
  262. if int(s) > (F.cardinality()-1)/2: s = -s
  263. return to_le(s,56)
  264. def _check(self):
  265. ss = self._sage_ser(self.point)
  266. cs = self._c_ser(self.cstruct)
  267. if ss != cs:
  268. print ss
  269. print cs
  270. raise Exception("Check failed!")
  271. return True
  272. run_all_tests()