@@ -246,15 +246,15 @@ private static int DivSteps30(int zeta, uint f0, uint g0, out ModInv32Trans2x2 t
246
246
247
247
248
248
//https://github.com/bitcoin-core/secp256k1/blob/1a81df826e2a24a1656fc28fc3076b62562216d9/src/util.h#L305
249
- static readonly byte [ ] DeBruijn = new byte [ 32 ]
249
+ private static readonly byte [ ] DeBruijn = new byte [ 32 ]
250
250
{
251
251
0x00 , 0x01 , 0x02 , 0x18 , 0x03 , 0x13 , 0x06 , 0x19 , 0x16 , 0x04 , 0x14 , 0x0A ,
252
252
0x10 , 0x07 , 0x0C , 0x1A , 0x1F , 0x17 , 0x12 , 0x05 , 0x15 , 0x09 , 0x0F , 0x0B ,
253
253
0x1E , 0x11 , 0x08 , 0x0E , 0x1D , 0x0D , 0x1C , 0x1B
254
254
} ;
255
255
// Determine the number of trailing zero bits in a (non-zero) 32-bit x.
256
256
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
257
- static int Ctz32Var ( uint x )
257
+ private static int Ctz32Var ( uint x )
258
258
{
259
259
// TODO: dotnet 3.0+ have: BitOperations.TrailingZeroCount()
260
260
Debug . Assert ( x != 0 ) ;
@@ -272,7 +272,7 @@ static int Ctz32Var(uint x)
272
272
// Return: final eta
273
273
//
274
274
// Implements the divsteps_n_matrix_var function from the explanation.
275
- static int DivSteps30Var ( int eta , uint f0 , uint g0 , out ModInv32Trans2x2 t )
275
+ private static int DivSteps30Var ( int eta , uint f0 , uint g0 , out ModInv32Trans2x2 t )
276
276
{
277
277
// Transformation matrix; see comments in DivSteps30().
278
278
uint u = 1 , v = 0 , q = 0 , r = 1 ;
@@ -343,7 +343,7 @@ static int DivSteps30Var(int eta, uint f0, uint g0, out ModInv32Trans2x2 t)
343
343
/// Jacobi tracking requires knowing (f mod 8) rather than just (f mod 2).
344
344
/// </summary>
345
345
/// <remarks>
346
- /// (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign
346
+ /// (*jacp & 1) is bitflipped if and only if the Jacobi symbol of (f | g) changes sign
347
347
/// by applying the returned transformation matrix to it. The other bits of *jacp may
348
348
/// change, but are meaningless.
349
349
/// </remarks>
@@ -353,9 +353,9 @@ static int DivSteps30Var(int eta, uint f0, uint g0, out ModInv32Trans2x2 t)
353
353
/// <param name="t">transition matrix</param>
354
354
/// <param name="jacp"></param>
355
355
/// <returns>final eta</returns>
356
- static int PosDivSteps30Var ( int eta , uint f0 , uint g0 , ModInv32Trans2x2 t , ref int jacp )
356
+ private static int PosDivSteps30Var ( int eta , uint f0 , uint g0 , out ModInv32Trans2x2 t , ref int jacp )
357
357
{
358
- /* Transformation matrix. */
358
+ // Transformation matrix.
359
359
uint u = 1 , v = 0 , q = 0 , r = 1 ;
360
360
uint f = f0 , g = g0 , m ;
361
361
ushort w ;
@@ -364,59 +364,62 @@ static int PosDivSteps30Var(int eta, uint f0, uint g0, ModInv32Trans2x2 t, ref i
364
364
365
365
while ( true )
366
366
{
367
- /* Use a sentinel bit to count zeros only up to i. */
367
+ // Use a sentinel bit to count zeros only up to i.
368
368
zeros = Ctz32Var ( g | ( uint . MaxValue << i ) ) ;
369
- /* Perform zeros divsteps at once; they all just divide g by two. */
369
+ // Perform zeros divsteps at once; they all just divide g by two.
370
370
g >>= zeros ;
371
371
u <<= zeros ;
372
372
v <<= zeros ;
373
373
eta -= zeros ;
374
374
i -= zeros ;
375
- /* Update the bottom bit of jac: when dividing g by an odd power of 2,
376
- * if (f mod 8) is 3 or 5, the Jacobi symbol changes sign. */
375
+ // Update the bottom bit of jac: when dividing g by an odd power of 2,
376
+ // if (f mod 8) is 3 or 5, the Jacobi symbol changes sign.
377
377
jac ^= ( int ) ( zeros & ( ( f >> 1 ) ^ ( f >> 2 ) ) ) ;
378
- /* We're done once we've done 30 posdivsteps. */
379
- if ( i == 0 ) break ;
378
+ // We're done once we've done 30 posdivsteps.
379
+ if ( i == 0 )
380
+ {
381
+ break ;
382
+ }
383
+
380
384
Debug . Assert ( ( f & 1 ) == 1 ) ;
381
385
Debug . Assert ( ( g & 1 ) == 1 ) ;
382
386
Debug . Assert ( ( u * f0 + v * g0 ) == f << ( 30 - i ) ) ;
383
387
Debug . Assert ( ( q * f0 + r * g0 ) == g << ( 30 - i ) ) ;
384
- /* If eta is negative, negate it and replace f,g with g,f. */
388
+ // If eta is negative, negate it and replace f,g with g,f.
385
389
if ( eta < 0 )
386
390
{
387
391
uint tmp ;
388
392
eta = - eta ;
389
- /* Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign
390
- * if both f and g are 3 mod 4. */
393
+ // Update bottom bit of jac: when swapping f and g, the Jacobi symbol changes sign
394
+ // if both f and g are 3 mod 4.
391
395
jac ^= ( int ) ( ( f & g ) >> 1 ) ;
392
396
tmp = f ; f = g ; g = tmp ;
393
397
tmp = u ; u = q ; q = tmp ;
394
398
tmp = v ; v = r ; r = tmp ;
395
399
}
396
- /* eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more
397
- * than i can be cancelled out (as we'd be done before that point), and no more than eta+1
398
- * can be done as its sign will flip once that happens. */
400
+ // eta is now >= 0. In what follows we're going to cancel out the bottom bits of g. No more
401
+ // than i can be cancelled out (as we'd be done before that point), and no more than eta+1
402
+ // can be done as its sign will flip once that happens.
399
403
limit = ( eta + 1 ) > i ? i : ( eta + 1 ) ;
400
- /* m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits). */
404
+ // m is a mask for the bottom min(limit, 8) bits (our table only supports 8 bits).
401
405
Debug . Assert ( limit > 0 && limit <= 30 ) ;
402
406
m = ( uint . MaxValue >> ( 32 - limit ) ) & 255U ;
403
- /* Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits. */
407
+ // Find what multiple of f must be added to g to cancel its bottom min(limit, 8) bits.
404
408
w = ( ushort ) ( ( g * Inv256 [ ( f >> 1 ) & 127 ] ) & m ) ;
405
- /* Do so. */
409
+ // Do so.
406
410
g += f * w ;
407
411
q += u * w ;
408
412
r += v * w ;
409
413
Debug . Assert ( ( g & m ) == 0 ) ;
410
414
}
411
- /* Return data in t and return value. */
412
- t . u = ( int ) u ;
413
- t . v = ( int ) v ;
414
- t . q = ( int ) q ;
415
- t . r = ( int ) r ;
416
- /* The determinant of t must be a power of two. This guarantees that multiplication with t
417
- * does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
418
- * will be divided out again). As each divstep's individual matrix has determinant 2 or -2,
419
- * the aggregate of 30 of them will have determinant 2^30 or -2^30. */
415
+
416
+ // Return data in t and return value.
417
+ t = new ModInv32Trans2x2 ( u , v , q , r ) ;
418
+
419
+ // The determinant of t must be a power of two. This guarantees that multiplication with t
420
+ // does not change the gcd of f and g, apart from adding a power-of-2 factor to it (which
421
+ // will be divided out again). As each divstep's individual matrix has determinant 2 or -2,
422
+ // the aggregate of 30 of them will have determinant 2^30 or -2^30.
420
423
Debug . Assert ( ( long ) t . u * t . r - ( long ) t . v * t . q == ( ( long ) 1 ) << 30 ||
421
424
( long ) t . u * t . r - ( long ) t . v * t . q == - ( ( ( long ) 1 ) << 30 ) ) ;
422
425
jacp = jac ;
@@ -430,7 +433,7 @@ static int PosDivSteps30Var(int eta, uint f0, uint g0, ModInv32Trans2x2 t, ref i
430
433
// in range (-2^30,2^30).
431
434
//
432
435
// This implements the update_de function from the explanation.
433
- internal static void UpdateDE30 ( ref ModInv32Signed30 d , ref ModInv32Signed30 e , ModInv32Trans2x2 t , in ModInv32ModInfo modinfo )
436
+ private static void UpdateDE30 ( ref ModInv32Signed30 d , ref ModInv32Signed30 e , ModInv32Trans2x2 t , in ModInv32ModInfo modinfo )
434
437
{
435
438
const int M30 = ( int ) ( uint . MaxValue >> 2 ) ;
436
439
int di , ei , md , me , sd , se ;
@@ -496,7 +499,7 @@ internal static void UpdateDE30(ref ModInv32Signed30 d, ref ModInv32Signed30 e,
496
499
// Compute (t/2^30) * [f, g], where t is a transition matrix for 30 divsteps.
497
500
//
498
501
// This implements the update_fg function from the explanation.
499
- static void UpdateFG30 ( ref ModInv32Signed30 f , ref ModInv32Signed30 g , ModInv32Trans2x2 t )
502
+ private static void UpdateFG30 ( ref ModInv32Signed30 f , ref ModInv32Signed30 g , ModInv32Trans2x2 t )
500
503
{
501
504
const int M30 = ( int ) ( uint . MaxValue >> 2 ) ;
502
505
int fi , gi ;
@@ -535,7 +538,7 @@ static void UpdateFG30(ref ModInv32Signed30 f, ref ModInv32Signed30 g, ModInv32T
535
538
// Version that operates on a variable number of limbs in f and g.
536
539
//
537
540
// This implements the update_fg function from the explanation in modinv64_impl.h.
538
- static void UpdateFG30Var ( int len , ref ModInv32Signed30 f , ref ModInv32Signed30 g , ModInv32Trans2x2 t )
541
+ private static void UpdateFG30Var ( int len , ref ModInv32Signed30 f , ref ModInv32Signed30 g , ModInv32Trans2x2 t )
539
542
{
540
543
const int M30 = ( int ) ( uint . MaxValue >> 2 ) ;
541
544
int fi , gi ;
@@ -665,10 +668,10 @@ public static void ComputeVar(ref ModInv32Signed30 x, ModInv32ModInfo modinfo)
665
668
UpdateDE30 ( ref d , ref e , t , modinfo ) ;
666
669
// Update f,g using that transition matrix.
667
670
# if DEBUG
668
- Debug . Assert ( MulCmp30 ( f , len , modinfo . modulus , - 1 ) > 0 ) ; /* f > -modulus */
669
- Debug . Assert ( MulCmp30 ( f , len , modinfo . modulus , 1 ) <= 0 ) ; /* f <= modulus */
670
- Debug . Assert ( MulCmp30 ( g , len , modinfo . modulus , - 1 ) > 0 ) ; /* g > -modulus */
671
- Debug . Assert ( MulCmp30 ( g , len , modinfo . modulus , 1 ) < 0 ) ; /* g < modulus */
671
+ Debug . Assert ( MulCmp30 ( f , len , modinfo . modulus , - 1 ) > 0 ) ; // f > -modulus
672
+ Debug . Assert ( MulCmp30 ( f , len , modinfo . modulus , 1 ) <= 0 ) ; // f <= modulus
673
+ Debug . Assert ( MulCmp30 ( g , len , modinfo . modulus , - 1 ) > 0 ) ; // g > -modulus
674
+ Debug . Assert ( MulCmp30 ( g , len , modinfo . modulus , 1 ) < 0 ) ; // g < modulus
672
675
#endif
673
676
UpdateFG30Var ( len , ref f , ref g , t ) ;
674
677
@@ -684,7 +687,10 @@ public static void ComputeVar(ref ModInv32Signed30 x, ModInv32ModInfo modinfo)
684
687
cond |= gv [ j ] ;
685
688
}
686
689
// If so, we're done.
687
- if ( cond == 0 ) break ;
690
+ if ( cond == 0 )
691
+ {
692
+ break ;
693
+ }
688
694
}
689
695
690
696
// Determine if len>1 and limb (len-1) of both f and g is 0 or -1.
@@ -698,7 +704,7 @@ public static void ComputeVar(ref ModInv32Signed30 x, ModInv32ModInfo modinfo)
698
704
{
699
705
fv [ len - 2 ] |= fn << 30 ;
700
706
gv [ len - 2 ] |= gn << 30 ;
701
- -- len ;
707
+ len -- ;
702
708
}
703
709
704
710
f = new ModInv32Signed30 ( fv ) ;
@@ -730,5 +736,94 @@ public static void ComputeVar(ref ModInv32Signed30 x, ModInv32ModInfo modinfo)
730
736
int [ ] tempArr = f . GetArray ( ) ;
731
737
x = Normalize30 ( d , tempArr [ len - 1 ] , modinfo ) ;
732
738
}
739
+
740
+
741
+ /// <summary>
742
+ /// Compute the Jacobi symbol for (x | modinfo->modulus). x must be coprime with modulus (and thus
743
+ /// cannot be 0, as modulus >= 3). All limbs of x must be non-negative. Returns 0 if the result
744
+ /// cannot be computed.
745
+ /// </summary>
746
+ /// <param name="x"></param>
747
+ /// <param name="modinfo"></param>
748
+ /// <returns></returns>
749
+ public static int Jacobi32MaybeVar ( in ModInv32Signed30 x , in ModInv32ModInfo modinfo )
750
+ {
751
+ // Start with f=modulus, g=x, eta=-1.
752
+ ModInv32Signed30 f = modinfo . modulus ;
753
+ ModInv32Signed30 g = x ;
754
+ int len = 9 ;
755
+ // eta = -delta; delta is initially 1
756
+ int eta = - 1 ;
757
+ int cond , fn , gn ;
758
+ int jac = 0 ;
759
+
760
+ // The input limbs must all be non-negative.
761
+ Debug . Assert ( g . v0 >= 0 && g . v1 >= 0 && g . v0 >= 0 && g . v3 >= 0 &&
762
+ g . v4 >= 0 && g . v5 >= 0 && g . v6 >= 0 && g . v7 >= 0 && g . v8 >= 0 ) ;
763
+
764
+ // If x > 0, then if the loop below converges, it converges to f=g=gcd(x,modulus). Since we
765
+ // require that gcd(x,modulus)=1 and modulus>=3, x cannot be 0. Thus, we must reach f=1 (or
766
+ // time out).
767
+ Debug . Assert ( ( g . v0 | g . v1 | g . v2 | g . v3 | g . v4 | g . v5 | g . v6 | g . v7 | g . v8 ) != 0 ) ;
768
+
769
+ const int JACOBI32_ITERATIONS =
770
+ #if DEBUG
771
+ 25 ;
772
+ #else
773
+ 50 ;
774
+ #endif
775
+ for ( int count = 0 ; count < JACOBI32_ITERATIONS ; count ++ )
776
+ {
777
+ // Compute transition matrix and new eta after 30 posdivsteps.
778
+ eta = PosDivSteps30Var ( eta , ( uint ) f . v0 | ( ( uint ) f . v1 << 30 ) , ( uint ) g . v0 | ( ( uint ) g . v1 << 30 ) , out ModInv32Trans2x2 t , ref jac ) ;
779
+ #if DEBUG
780
+ // Update f,g using that transition matrix.
781
+ Debug . Assert ( MulCmp30 ( f , len , modinfo . modulus , 0 ) > 0 ) ; // f > 0
782
+ Debug . Assert ( MulCmp30 ( f , len , modinfo . modulus , 1 ) <= 0 ) ; // f <= modulus
783
+ Debug . Assert ( MulCmp30 ( g , len , modinfo . modulus , 0 ) > 0 ) ; // g > 0
784
+ Debug . Assert ( MulCmp30 ( g , len , modinfo . modulus , 1 ) < 0 ) ; // g < modulus
785
+ #endif
786
+ UpdateFG30Var ( len , ref f , ref g , t ) ;
787
+
788
+ // If the bottom limb of f is 1, there is a chance that f=1.
789
+ int [ ] fv = f . GetArray ( ) ;
790
+ int [ ] gv = g . GetArray ( ) ;
791
+ if ( f . v0 == 1 )
792
+ {
793
+ cond = 0 ;
794
+ // Check if the other limbs are also 0.
795
+ for ( int j = 1 ; j < len ; j ++ )
796
+ {
797
+ cond |= fv [ j ] ;
798
+ }
799
+ // If so, we're done. If f=1, the Jacobi symbol (g | f)=1.
800
+ if ( cond == 0 )
801
+ {
802
+ return 1 - 2 * ( jac & 1 ) ;
803
+ }
804
+ }
805
+
806
+ // Determine if len>1 and limb (len-1) of both f and g is 0.
807
+ fn = fv [ len - 1 ] ;
808
+ gn = gv [ len - 1 ] ;
809
+ cond = ( len - 2 ) >> 31 ;
810
+ cond |= fn ;
811
+ cond |= gn ;
812
+ // If so, reduce length.
813
+ if ( cond == 0 )
814
+ {
815
+ len -- ;
816
+ }
817
+ #if DEBUG
818
+ Debug . Assert ( MulCmp30 ( f , len , modinfo . modulus , 0 ) > 0 ) ; // f > 0
819
+ Debug . Assert ( MulCmp30 ( f , len , modinfo . modulus , 1 ) <= 0 ) ; // f <= modulus
820
+ Debug . Assert ( MulCmp30 ( g , len , modinfo . modulus , 0 ) > 0 ) ; // g > 0
821
+ Debug . Assert ( MulCmp30 ( g , len , modinfo . modulus , 1 ) < 0 ) ; // g < modulus
822
+ #endif
823
+ }
824
+
825
+ // The loop failed to converge to f=g after 1500 iterations. Return 0, indicating unknown result.
826
+ return 0 ;
827
+ }
733
828
}
734
829
}
0 commit comments