@@ -297,6 +297,62 @@ public bool IsHigh
297
297
}
298
298
}
299
299
300
+
301
+ /// <summary>
302
+ /// Multiply a scalar with the multiplicative inverse of 2
303
+ /// </summary>
304
+ /// <returns></returns>
305
+ public Scalar8x32 Half ( )
306
+ {
307
+ // Writing `/` for field division and `//` for integer division, we compute
308
+ //
309
+ // a/2 = (a - (a&1))/2 + (a&1)/2
310
+ // = (a >> 1) + (a&1 ? 1/2 : 0)
311
+ // = (a >> 1) + (a&1 ? n//2+1 : 0),
312
+ //
313
+ // where n is the group order and in the last equality we have used 1/2 = n//2+1 (mod n).
314
+ // For n//2, we have the constants SECP256K1_N_H_0, ...
315
+ //
316
+ // This sum does not overflow. The most extreme case is a = -2, the largest odd scalar.
317
+ // Here:
318
+ // - the left summand is: a >> 1 = (a - a&1)/2 = (n-2-1)//2 = (n-3)//2
319
+ // - the right summand is: a&1 ? n//2+1 : 0 = n//2+1 = (n-1)//2 + 2//2 = (n+1)//2
320
+ // Together they sum to (n-3)//2 + (n+1)//2 = (2n-2)//2 = n - 1, which is less than n.
321
+
322
+ uint mask = ( uint ) - ( b0 & 1U ) ;
323
+ ulong t = ( b0 >> 1 ) | ( b1 << 31 ) ;
324
+ Debug . Assert ( GetOverflow ( this ) == 0 ) ;
325
+
326
+ t += ( NH0 + 1U ) & mask ;
327
+ uint r0 = ( uint ) t ; t >>= 32 ;
328
+ t += ( b1 >> 1 ) | ( b2 << 31 ) ;
329
+ t += NH1 & mask ;
330
+ uint r1 = ( uint ) t ; t >>= 32 ;
331
+ t += ( b2 >> 1 ) | ( b3 << 31 ) ;
332
+ t += NH2 & mask ;
333
+ uint r2 = ( uint ) t ; t >>= 32 ;
334
+ t += ( b3 >> 1 ) | ( b4 << 31 ) ;
335
+ t += NH3 & mask ;
336
+ uint r3 = ( uint ) t ; t >>= 32 ;
337
+ t += ( b4 >> 1 ) | ( b5 << 31 ) ;
338
+ t += NH4 & mask ;
339
+ uint r4 = ( uint ) t ; t >>= 32 ;
340
+ t += ( b5 >> 1 ) | ( b6 << 31 ) ;
341
+ t += NH5 & mask ;
342
+ uint r5 = ( uint ) t ; t >>= 32 ;
343
+ t += ( b6 >> 1 ) | ( b7 << 31 ) ;
344
+ t += NH6 & mask ;
345
+ uint r6 = ( uint ) t ; t >>= 32 ;
346
+ uint r7 = ( uint ) t + ( b7 >> 1 ) + ( NH7 & mask ) ;
347
+
348
+ // The line above only computed the bottom 32 bits of r->d[7]. Redo the computation
349
+ // in full 64 bits to make sure the top 32 bits are indeed zero.
350
+ Debug . Assert ( ( t + ( b7 >> 1 ) + ( NH7 & mask ) ) >> 32 == 0 ) ;
351
+
352
+ return new Scalar8x32 ( r0 , r1 , r2 , r3 , r4 , r5 , r6 , r7 ) ;
353
+ }
354
+
355
+
300
356
private uint CheckOverflow ( )
301
357
{
302
358
uint yes = 0U ;
0 commit comments