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.
 
 
 
 
 

345 lines
9.9 KiB

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