@@ -1272,7 +1272,7 @@ class PointEdwards(AbstractPoint):
12721272 x*y = T / Z
12731273 """
12741274
1275- def __init__ (self , curve , x , y , z , t , order = None ):
1275+ def __init__ (self , curve , x , y , z , t , order = None , generator = False ):
12761276 """
12771277 Initialise a point that uses the extended coordinates internally.
12781278 """
@@ -1284,6 +1284,8 @@ def __init__(self, curve, x, y, z, t, order=None):
12841284 else : # pragma: no branch
12851285 self .__coords = (x , y , z , t )
12861286 self .__order = order
1287+ self .__generator = generator
1288+ self .__precompute = []
12871289
12881290 @classmethod
12891291 def from_bytes (
@@ -1311,8 +1313,9 @@ def from_bytes(
13111313 supported
13121314 :param int order: the point order, must be non zero when using
13131315 generator=True
1314- :param bool generator: Ignored, may be used in the future
1315- to precompute point multiplication table.
1316+ :param bool generator: Flag to mark the point as a curve generator,
1317+ this will cause the library to pre-compute some values to
1318+ make repeated usages of the point much faster
13161319
13171320 :raises MalformedPointError: if the public point does not lay on the
13181321 curve or the encoding is invalid
@@ -1324,9 +1327,46 @@ def from_bytes(
13241327 curve , data , validate_encoding , valid_encodings
13251328 )
13261329 return PointEdwards (
1327- curve , coord_x , coord_y , 1 , coord_x * coord_y , order
1330+ curve , coord_x , coord_y , 1 , coord_x * coord_y , order , generator
13281331 )
13291332
1333+ def _maybe_precompute (self ):
1334+ if not self .__generator or self .__precompute :
1335+ return self .__precompute
1336+
1337+ # since this code will execute just once, and it's fully deterministic,
1338+ # depend on atomicity of the last assignment to switch from empty
1339+ # self.__precompute to filled one and just ignore the unlikely
1340+ # situation when two threads execute it at the same time (as it won't
1341+ # lead to inconsistent __precompute)
1342+ order = self .__order
1343+ assert order
1344+ precompute = []
1345+ i = 1
1346+ order *= 2
1347+ coord_x , coord_y , coord_z , coord_t = self .__coords
1348+ prime = self .__curve .p ()
1349+
1350+ doubler = PointEdwards (
1351+ self .__curve , coord_x , coord_y , coord_z , coord_t , order
1352+ )
1353+ # for "protection" against Minerva we need 1 or 2 more bits depending
1354+ # on order bit size, but it's easier to just calculate one
1355+ # point more always
1356+ order *= 4
1357+
1358+ while i < order :
1359+ doubler = doubler .scale ()
1360+ coord_x , coord_y = doubler .x (), doubler .y ()
1361+ coord_t = coord_x * coord_y % prime
1362+ precompute .append ((coord_x , coord_y , coord_t ))
1363+
1364+ i *= 2
1365+ doubler = doubler .double ()
1366+
1367+ self .__precompute = precompute
1368+ return self .__precompute
1369+
13301370 def x (self ):
13311371 """Return affine x coordinate."""
13321372 X1 , _ , Z1 , _ = self .__coords
@@ -1482,6 +1522,27 @@ def __rmul__(self, other):
14821522 """Multiply point by an integer."""
14831523 return self * other
14841524
1525+ def _mul_precompute (self , other ):
1526+ """Multiply point by integer with precomputation table."""
1527+ X3 , Y3 , Z3 , T3 , p , a = 0 , 1 , 1 , 0 , self .__curve .p (), self .__curve .a ()
1528+ _add = self ._add
1529+ for X2 , Y2 , T2 in self .__precompute :
1530+ rem = other % 4
1531+ if rem == 0 or rem == 2 :
1532+ other //= 2
1533+ elif rem == 3 :
1534+ other = (other + 1 ) // 2
1535+ X3 , Y3 , Z3 , T3 = _add (X3 , Y3 , Z3 , T3 , - X2 , Y2 , 1 , - T2 , p , a )
1536+ else :
1537+ assert rem == 1
1538+ other = (other - 1 ) // 2
1539+ X3 , Y3 , Z3 , T3 = _add (X3 , Y3 , Z3 , T3 , X2 , Y2 , 1 , T2 , p , a )
1540+
1541+ if not X3 or not T3 :
1542+ return INFINITY
1543+
1544+ return PointEdwards (self .__curve , X3 , Y3 , Z3 , T3 , self .__order )
1545+
14851546 def __mul__ (self , other ):
14861547 """Multiply point by an integer."""
14871548 X2 , Y2 , Z2 , T2 = self .__coords
@@ -1490,8 +1551,10 @@ def __mul__(self, other):
14901551 if other == 1 :
14911552 return self
14921553 if self .__order :
1493- # order*2 as a protection for Minerva
1554+ # order*2 as a " protection" for Minerva
14941555 other = other % (self .__order * 2 )
1556+ if self ._maybe_precompute ():
1557+ return self ._mul_precompute (other )
14951558
14961559 X3 , Y3 , Z3 , T3 = 0 , 1 , 1 , 0 # INFINITY in extended coordinates
14971560 p , a = self .__curve .p (), self .__curve .a ()
0 commit comments