@@ -1272,7 +1272,7 @@ class PointEdwards(AbstractPoint):
1272
1272
x*y = T / Z
1273
1273
"""
1274
1274
1275
- def __init__ (self , curve , x , y , z , t , order = None ):
1275
+ def __init__ (self , curve , x , y , z , t , order = None , generator = False ):
1276
1276
"""
1277
1277
Initialise a point that uses the extended coordinates internally.
1278
1278
"""
@@ -1284,6 +1284,8 @@ def __init__(self, curve, x, y, z, t, order=None):
1284
1284
else : # pragma: no branch
1285
1285
self .__coords = (x , y , z , t )
1286
1286
self .__order = order
1287
+ self .__generator = generator
1288
+ self .__precompute = []
1287
1289
1288
1290
@classmethod
1289
1291
def from_bytes (
@@ -1311,8 +1313,9 @@ def from_bytes(
1311
1313
supported
1312
1314
:param int order: the point order, must be non zero when using
1313
1315
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
1316
1319
1317
1320
:raises MalformedPointError: if the public point does not lay on the
1318
1321
curve or the encoding is invalid
@@ -1324,9 +1327,46 @@ def from_bytes(
1324
1327
curve , data , validate_encoding , valid_encodings
1325
1328
)
1326
1329
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
1328
1331
)
1329
1332
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
+
1330
1370
def x (self ):
1331
1371
"""Return affine x coordinate."""
1332
1372
X1 , _ , Z1 , _ = self .__coords
@@ -1482,6 +1522,27 @@ def __rmul__(self, other):
1482
1522
"""Multiply point by an integer."""
1483
1523
return self * other
1484
1524
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
+
1485
1546
def __mul__ (self , other ):
1486
1547
"""Multiply point by an integer."""
1487
1548
X2 , Y2 , Z2 , T2 = self .__coords
@@ -1490,8 +1551,10 @@ def __mul__(self, other):
1490
1551
if other == 1 :
1491
1552
return self
1492
1553
if self .__order :
1493
- # order*2 as a protection for Minerva
1554
+ # order*2 as a " protection" for Minerva
1494
1555
other = other % (self .__order * 2 )
1556
+ if self ._maybe_precompute ():
1557
+ return self ._mul_precompute (other )
1495
1558
1496
1559
X3 , Y3 , Z3 , T3 = 0 , 1 , 1 , 0 # INFINITY in extended coordinates
1497
1560
p , a = self .__curve .p (), self .__curve .a ()
0 commit comments