-
+ 78D4C49FFCA81897F9E4832F272A46DF2DD8258BCD4502FFF7C716E4D8B7E67F5C96AEA13E193D44374FFADC7BF3487AE14C512257875D95C3414FD37C69F03A
ffa/libffa/fz_prime.adb
(0 . 0)(1 . 231)
380 ------------------------------------------------------------------------------
381 ------------------------------------------------------------------------------
382 -- This file is part of 'Finite Field Arithmetic', aka 'FFA'. --
383 -- --
384 -- (C) 2019 Stanislav Datskovskiy ( www.loper-os.org ) --
385 -- http://wot.deedbot.org/17215D118B7239507FAFED98B98228A001ABFFC7.html --
386 -- --
387 -- You do not have, nor can you ever acquire the right to use, copy or --
388 -- distribute this software ; Should you use this software for any purpose, --
389 -- or copy and distribute it to anyone or in any manner, you are breaking --
390 -- the laws of whatever soi-disant jurisdiction, and you promise to --
391 -- continue doing so for the indefinite future. In any case, please --
392 -- always : read and understand any software ; verify any PGP signatures --
393 -- that you use - for any purpose. --
394 -- --
395 -- See also http://trilema.com/2015/a-new-software-licensing-paradigm . --
396 ------------------------------------------------------------------------------
397
398 with Word_Ops; use Word_Ops;
399 with W_Pred; use W_Pred;
400 with W_Shifts; use W_Shifts;
401
402 with FZ_Basic; use FZ_Basic;
403 with FZ_QShft; use FZ_QShft;
404 with FZ_Arith; use FZ_Arith;
405 with FZ_Divis; use FZ_Divis;
406 with FZ_Pred; use FZ_Pred;
407 with FZ_Cmp; use FZ_Cmp;
408 with FZ_Barr; use FZ_Barr;
409 with FZ_ModEx; use FZ_ModEx;
410
411
412 package body FZ_Prime is
413
414 -- Find the highest power of 2 which divides N. ( or 0 if N is zero. )
415 function FZ_Count_Bottom_Zeros(N : in FZ) return FZBit_Index is
416
417 -- The result (default : 0, will remain 0 if N is in fact zero)
418 Index : Word := 0;
419
420 -- The currently-examined Word, starting from the highest
421 Ni : Word;
422
423 -- The most recently-seen nonzero Word, if indeed any exist
424 W : Word := 0;
425
426 -- 1 if currently-examined Word is zero, otherwise 0
427 NiZ : WBool;
428
429 begin
430
431 -- Find lowest non-zero Word (or simply stop at lowest, if N = 0)
432 for i in reverse 0 .. Indices(N'Length - 1) loop
433 Ni := N(N'First + i); -- Ni := current Word;
434 NiZ := W_ZeroP(Ni); -- ... is this Word = 0?
435 Index := W_Mux(Word(i), Index, NiZ); -- If NO, save its Index,
436 W := W_Mux(Ni, W, NiZ); -- ... and save the Word.
437 end loop;
438
439 -- Set Index to be the bit-position of the lowest non-zero Word:
440 Index := Shift_Left(Index, BitnessLog2); -- Index := Index * Bitness
441
442 -- Handle degenerate case: if W is equal to 0, Index is not changed;
443 -- Otherwise, start by advancing Index by an entire Word Bitness:
444 Index := Index + ((0 - W_NZeroP(W)) and Word(Bitness));
445
446 -- Now crank back the Index by the number of high bits of W (i.e.
447 -- starting from its top) that must be discarded for W to become zero:
448 for b in 1 .. Bitness loop
449
450 -- If W is non-zero at this time, decrement the Index:
451 Index := Index - W_NZeroP(W);
452
453 -- Advance W left, i.e. discard the top bit of it:
454 W := Shift_Left(W, 1);
455
456 end loop;
457
458 -- If N = 0, result will be 0; otherwise: length of bottom zeros in N.
459 return FZBit_Index(Index);
460
461 end FZ_Count_Bottom_Zeros;
462
463
464 -- Constant-Time Miller-Rabin Test on N using the given Witness.
465 -- Witness will be used as-is if it conforms to the valid bounds,
466 -- i.e. 2 <= Witness <= N - 2; otherwise will be transformed into a
467 -- valid Witness via modular arithmetic.
468 -- Outputs ONE if N WAS FOUND composite; ZERO if NOT FOUND.
469 -- Handles degenerate cases of N that M-R per se cannot eat:
470 -- N=0, N=1: ALWAYS 'FOUND COMPOSITE'; 2, 3 - ALWAYS 'NOT FOUND'.
471 -- If N is Even and not equal to 2, N is ALWAYS 'FOUND COMPOSITE.'
472 -- For ALL other N, the output is equal to that of the M-R test.
473 function FZ_MR_Composite_On_Witness(N : in FZ;
474 Witness : in FZ) return WBool is
475
476 -- Widths of N, Witness, and Result are equal :
477 subtype Width is Word_Index range N'Range;
478
479 -- Whether N is 'small' (i.e. 1 Word) and therefore possibly degenerate :
480 N_Is_Small : constant WBool := FZ_OneWordP(N);
481
482 -- Head of N, for detecting (and handling) the degenerate-N case :
483 N_Head : constant Word := FZ_Get_Head(N);
484
485 -- Zero and One are defined as COMPOSITE degenerate cases of N :
486 N_Is_Zero_Or_One : constant WBool
487 := N_Is_Small and (W_EqP(N_Head, 0) or W_EqP(N_Head, 1));
488
489 -- Two and Three are PRIME degenerate cases of N :
490 N_Is_Two : constant WBool := N_Is_Small and W_EqP(N_Head, 2);
491 N_Is_Three : constant WBool := N_Is_Small and W_EqP(N_Head, 3);
492
493 -- The COMPOSITE degenerate case of N where N != 2 and N is Even :
494 N_Ne_2_Is_Even : constant WBool :=
495 (1 - N_Is_Two) and (1 - W_OddP(N_Head));
496
497 -- Degeneracy latch. If N is Zero or One, then set immediately :
498 Degen_Composite : constant WBool := N_Is_Zero_Or_One or N_Ne_2_Is_Even;
499
500 -- Possible-primality latch. If N is Two or Three, then set immediately :
501 Possibly_Prime : WBool := N_Is_Two or N_Is_Three;
502
503 -- The writable copy of N that we will operate on :
504 X : FZ(Width) := N;
505
506 -- Potentially-replaced head of X (if degenerate N) :
507 X_Head : Word := N_Head;
508
509 -- Will be Barrettoid(X), for operations modulo X :
510 XBar : Barretoid(ZXMLength => X'Length + 1,
511 BarretoidLength => 2 * X'Length);
512
513 -- The Bound Witness, constrained to valid range 2 <= BW <= X - 2 :
514 BW : FZ(Width);
515
516 -- Head of BW, for detecting crossing of the lower bound :
517 BW_Head : Word;
518
519 -- X - 1 (for M-R proper, and to constrain BW) :
520 X_Minus_One : FZ(Width);
521
522 -- X - 1 = 2^R * K, with K odd :
523 K : FZ(Width);
524 R : FZBit_Index;
525
526 -- Working register for all M-R modular operations :
527 T : FZ(Width);
528
529 -- For subtraction where no underflow can happen, barring cosmic ray:
530 NoCarry : WZeroOrDie := 0;
531
532 begin
533
534 -- First: X, which will remain equal to N unless N is degenerate:
535
536 -- If N is one of the two prohibited small primes (2,3) X will become 5:
537 X_Head := W_Mux(A => X_Head, B => 5, Sel => Possibly_Prime);
538
539 -- If one of the two prohibited small composites (0,1), or even, then 9:
540 X_Head := W_Mux(A => X_Head, B => 9, Sel => Degen_Composite);
541
542 -- Given as we're stuck carrying out M-R even if N is degenerate case,
543 -- then let the M-R do The Right Thing, for added cosmic ray resistance.
544
545 -- X gets a new head, if N was a degenerate case; else keeps old head:
546 FZ_Set_Head(X, X_Head);
547
548 -- Compute X - 1. As now X > 3, underflow is not permitted:
549 FZ_Sub_W(X => X, W => 1, Difference => X_Minus_One,
550 Underflow => NoCarry);
551
552 -- Now, compute BW (Bound Witness), which satisfies 2 <= BW <= X - 2:
553
554 -- First, BW := Witness mod (X - 1). After this, 0 <= BW <= X - 2:
555 FZ_Mod(Dividend => Witness, Divisor => X_Minus_One, Remainder => BW);
556
557 -- Now, adjust BW if it is found to be below Two (the lower bound) :
558
559 -- Get head of BW:
560 BW_Head := FZ_Get_Head(BW);
561
562 -- If BW is equal to Zero or One, it will be forced to equal Two:
563 BW_Head := W_Mux(A => BW_Head,
564 B => 2,
565 Sel => FZ_OneWordP(BW) and
566 (W_EqP(BW_Head, 0) or W_EqP(BW_Head, 1)));
567
568 -- BW gets the new head, if it must; otherwise keeps its old head:
569 FZ_Set_Head(BW, BW_Head);
570
571 -- We finished adjusting X and BW for degeneracies, and can now M-R:
572
573 -- Generate Barrettoid(X) to use in all of the modulo-X operations:
574 FZ_Make_Barrettoid(Modulus => X, Result => XBar);
575
576 -- Find R >= 1, and odd K, where X − 1 = 2^R * K :
577
578 -- ... first, find R, the largest power of two which divides X - 1 :
579 R := FZ_Count_Bottom_Zeros(X_Minus_One);
580
581 -- ... and now obtain K := X / 2^R, i.e., K := X >> R :
582 FZ_Quiet_ShiftRight(N => X_Minus_One, ShiftedN => K, Count => R);
583
584 -- T := BW^K mod X
585 FZ_Mod_Exp_Barrett(Base => BW, Exponent => K, Bar => XBar, Result => T);
586
587 -- if T = 1 or T = X - 1, then X is possibly-prime:
588 Possibly_Prime := Possibly_Prime or
589 FZ_EqP_W(T, 1) or FZ_EqP(T, X_Minus_One);
590
591 -- Needs R - 1 times, but perform for max possible count (gated):
592 for i in 1 .. FZ_Bitness(N) - 1 loop
593
594 -- T := T^2 mod X
595 FZ_Mod_Sqr_Barrett(X => T, Bar => XBar, Product => T);
596
597 -- if T = X - 1, and i < R, then X is possibly-prime:
598 Possibly_Prime := Possibly_Prime or
599 (FZ_EqP(T, X_Minus_One) and W_LtP(Word(i), Word(R)));
600
601 end loop;
602
603 -- The output, which will be 1 iff X WAS FOUND to be composite via BW,
604 -- ... or if X was found to equal Zero or One (without regard to BW.)
605 return (1 - Possibly_Prime) or Degen_Composite;
606 -- If X was found to equal Two or Three, output will be 0 (under any BW).
607
608 end FZ_MR_Composite_On_Witness;
609
610 end FZ_Prime;