diff options
author | Jed Barber <jjbarber@y7mail.com> | 2017-02-13 18:27:13 +1100 |
---|---|---|
committer | Jed Barber <jjbarber@y7mail.com> | 2017-02-13 18:27:13 +1100 |
commit | 2b8b55de4a18757e8d6769e458c84f7c1df1e261 (patch) | |
tree | cbd62219babccc04e57fa7708f88385a7f6413d3 /src/crypto-types-big_numbers-mod_utils.adb | |
parent | 2b842cb65ce29071d5786bdecc834c026d1f2db2 (diff) |
Swapped out crypto package for something smaller, revised other code and readme/notes slightly
Diffstat (limited to 'src/crypto-types-big_numbers-mod_utils.adb')
-rw-r--r-- | src/crypto-types-big_numbers-mod_utils.adb | 741 |
1 files changed, 0 insertions, 741 deletions
diff --git a/src/crypto-types-big_numbers-mod_utils.adb b/src/crypto-types-big_numbers-mod_utils.adb deleted file mode 100644 index 3c02df1..0000000 --- a/src/crypto-types-big_numbers-mod_utils.adb +++ /dev/null @@ -1,741 +0,0 @@ --- This program is free software; you can redistribute it and/or --- modify it under the terms of the GNU General Public License as --- published by the Free Software Foundation; either version 2 of the --- License, or (at your option) any later version. - --- This program is distributed in the hope that it will be useful, --- but WITHOUT ANY WARRANTY; without even the implied warranty of --- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU --- General Public License for more details. - --- You should have received a copy of the GNU General Public License --- along with this program; if not, write to the Free Software --- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA --- 02111-1307, USA. - --- As a special exception, if other files instantiate generics from --- this unit, or you link this unit with other files to produce an --- executable, this unit does not by itself cause the resulting --- executable to be covered by the GNU General Public License. This --- exception does not however invalidate any other reasons why the --- executable file might be covered by the GNU Public License. - -with Crypto.Types.Random; -with Crypto.Asymmetric.Prime_Tables; ---with Ada.Integer_Text_IO; use Ada.Integer_Text_IO; -with Ada.Text_IO; - -separate(Crypto.Types.Big_Numbers) - -package body Mod_Utils is - - pragma Optimize (Time); - use Crypto.Asymmetric.Prime_Tables; - - - --------------------------------------------------------------------------- - - function Patch(Item, N : Big_Unsigned) - return Big_Unsigned is - Diff : constant Big_Unsigned:=((Big_Unsigned_Last - N) + 1) mod N; - begin - return Add(Item,Diff,N); - end Patch; pragma Inline(Patch); - - --------------------------------------------------------------------------- - - function Add(Left, Right, N : Big_Unsigned) return Big_Unsigned is - L : constant Big_Unsigned := Left mod N; - R : constant Big_Unsigned := Right mod N; - Result : constant Big_Unsigned := L + R; - begin - if Result < Max(L,R) then - return Patch(Result,N); - else return - Result mod N; - end if; - end Add; - - --------------------------------------------------------------------------- - - function Sub(Left, Right, N : Big_Unsigned) return Big_Unsigned is - L : constant Big_Unsigned := Left mod N; - R : constant Big_Unsigned := Right mod N; - begin - if R > L then - return N - R + L; - else return L-R; - end if; - end Sub; - - --------------------------------------------------------------------------- - - function Div(Left, Right, N : Big_Unsigned) return Big_Unsigned is - begin - return Mult(Left,Inverse(Right,N),N); - end Div; pragma Inline(Div); - - - --------------------------------------------------------------------------- - - --from Erik-Zenners handout "Zahlentheoretische Algorithmen" - function Pow(Base, Exponent, N : Big_Unsigned) return Big_Unsigned is - L : constant Big_Unsigned := Base mod N; - R : constant Big_Unsigned := Exponent; - Result : Big_Unsigned := Big_Unsigned_One; - begin - if L = Big_Unsigned_Zero or L = Big_Unsigned_One then - return L; - elsif R = Big_Unsigned_Zero then return Big_Unsigned_One; - else - -- Square_And_Muliply - for I in reverse 0..Bit_Length(R)-1 loop - Result := Mult(Result,Result,N); - if (Shift_Right(R, I) mod 2) = Big_Unsigned_One then - Result := Mult(Result,L,N); - end if; - end loop; - return Result mod N; - end if; - end Pow; - - --------------------------------------------------------------------------- - - --based on Erik-Zenners handout "Zahlentheoretische Algorithmen" - -- (ext. Euklid) - -- This function returns Big_unsigned_Zero if X have no inverse mod n - function Inverse(X, N : Big_Unsigned) return Big_Unsigned is - B : Big_Unsigned := X mod N; - A : Big_Unsigned := N; - begin - -- if gcd(A,B) /= 1 then A have no inverse mod B - if B = Big_Unsigned_Zero or A = Big_Unsigned_Zero or - Gcd(A,B) /= Big_Unsigned_One then - return Big_Unsigned_Zero; - end if; - - declare - T : Big_Unsigned := Big_Unsigned_One; - Tstrich, Tempt : Big_Unsigned; - Q, R : Big_Unsigned; - begin - loop - Big_Div(A,B,Q,R); - if(R = Big_Unsigned_Zero) then - return T; - end if; - - A:=B; - B:=R; - - Tempt:=T; - - T:=Sub(Tstrich,Mult(Q,T,N),N); - - Tstrich:=Tempt; - end loop; - end; - end Inverse; - - --------------------------------------------------------------------------- - - function Get_Random(N : Big_Unsigned) return Big_Unsigned is - Result : Big_Unsigned; - begin - Random.Read(Result.Number); - - for I in reverse 0..N.Last_Index loop - if Result.Number(I) /= 0 then - Result.Last_Index := I; - exit; - end if; - end loop; - return Result mod N ; - end Get_Random; - - --------------------------------------------------------------------------- - - -- this function returns true if X is a Mersenne prim number - function Lucas_Lehmer_Test(X : Big_Unsigned) return Boolean is - Is_Mp : Boolean := false; - begin - - if X.Last_Index = 0 then - for I in 2..Word'Size-1 loop - if X.Number(0) = Shift_Left(2,I)-1 then - Is_Mp := True; - exit; - end if; - end loop; - if Is_Mp = False then return False; - end if; - else - for I in 0..X.Last_Index loop - if X.Number(I) /= Word'Last then return False; - end if; - end loop; - end if; - - declare - P : constant Word := Word(Bit_Length(X)-1); - S : Big_Unsigned := Big_Unsigned_Two+2; --S(1) = 4; - begin - for I in 2..P-1 loop - S := (Mult(S,S,X) - 2) mod X; - end loop; - - if S = Big_Unsigned_Zero then return True; - else return False; - end if; - end; - end Lucas_Lehmer_Test; - - --------------------------------------------------------------------------- - - --from Erik-Zenners handout "Zahlentheoretische Algorithmen" - function Is_Miller_Rabin_Witness(Wit, X : Big_Unsigned) return Boolean is - - B : constant Big_Unsigned := X-1; - Result : Big_Unsigned := Big_Unsigned_One; - Root : Big_Unsigned; - begin - for I in reverse 0..Bit_Length(B)-1 loop - Root := Result; - Result := Mult(Result, Result, X); - if ((Result = Big_Unsigned_One) and - (Root /= Big_Unsigned_One and Root /= B)) then return True; - elsif (Shift_Right(B,I) mod 2) = Big_Unsigned_One then - Result := Mult(Result, Wit, X); - end if; - end loop; - if Result /= Big_Unsigned_One then return True; - else return False; - end if; - end Is_Miller_Rabin_Witness; - - --------------------------------------------------------------------------- - - -- Test if Wit is a witness for N - -- If Wit is a wittness then N is no prime - function Is_Simple_Witness(Wit, N : Big_Unsigned) return Boolean is - begin - -- is Wit a "Miller-Rabin"-witness - if (Wit /= (N-Big_Unsigned_One)) and (Wit /= Big_Unsigned_One) and - Mult(Wit,Wit,N) = Big_Unsigned_One then return True; - - elsif Gcd(Wit,N) /= Big_Unsigned_One then return True; - - -- is Wit a "Fermat-Witness" - -- elsif Pow(Wit,N-1,N) /= Big_Unsigned_One then return True; - else return False; - end if; - end Is_Simple_Witness; - - --------------------------------------------------------------------------- - - - -- Returns true if N passes the specified number of Miller-Rabin tests. - function Passed_Miller_Rabin_Test(X : Big_Unsigned; S : Positive) - return Boolean is - Witness : Big_Unsigned; - begin - -- Do the tests - for I in 1..S loop - -- Generate a uniform random on (1, X) - loop - Witness := Get_Random(X); - exit when Witness > Big_Unsigned_One; - end loop; - if Is_Miller_Rabin_Witness(Witness, X) then - return False; - end if; - end loop; - return true; - end Passed_Miller_Rabin_Test; - - --------------------------------------------------------------------------- - - function Pass_Prime_Test(X : Big_Unsigned; Status : Hardness) - return Boolean is - Rounds : Natural; - X_Bit_Size : constant Natural := Bit_Length(X); - begin - if X < Big_Unsigned_Two then return False; - elsif Is_Even(X) then - if X = Big_Unsigned_Two then return True; - else return False; - end if; - end if; - - --X is odd - - for I in One_Digit_Primes'First+1..One_Digit_Primes'Last loop - if X = Word(One_Digit_Primes(I)) then return true; - elsif X mod Word(One_Digit_Primes(I)) = Big_Unsigned_Zero then - return False; - end if; - end loop; - - for I in Two_Digit_Primes'Range loop - if X = Word(Two_Digit_Primes(I)) then return true; - elsif X mod Word(Two_Digit_Primes(I)) = Big_Unsigned_Zero then - return False; - end if; - end loop; - - if Lucas_Lehmer_Test(X) then - return True; - end if; - - for I in Three_Digit_Primes'Range loop - if X = Word(Three_Digit_Primes(I)) then return true; - elsif X mod Word(Three_Digit_Primes(I)) = Big_Unsigned_Zero then - return False; - end if; - end loop; - - -- The relationship between the certainty and the number of rounds - -- we perform is given in the draft standard ANSI X9.80, "PRIME - -- NUMBER GENERATION, PRIMALITY TESTING, AND PRIMALITY CERTIFICATES". - -- Comment: - -- I don't have a look on this paper. =:) I borrowed this - -- "algorithmen" from the j2sdk1.4.1 library (java/math/BigInteger.java) - -- If you have the permission to send me the draft standard ANSI X9.80 - -- then send it, please! - -- I'm a student. I have no money for ANSI or IEEE drafts. :-( - -- It's right to require money to read a draft? - -- This really really sucks! SCNR! - - if (X_Bit_Size < 100) then Rounds := 50; - elsif (X_Bit_Size < 256) then Rounds := 27; - elsif (X_Bit_Size < 512) then Rounds := 15; - elsif (X_Bit_Size < 768) then Rounds := 8; - elsif (X_Bit_Size < 1024) then Rounds := 4; - else Rounds := 2; - end if; - - declare - Witness : Big_Unsigned; - begin - if Status = Weak then - for I in 1..Rounds loop - loop - Witness := Get_Random(X); - exit when Witness > Big_Unsigned_Two; - end loop; - if Is_Simple_Witness(Witness,X) then return False; - end if; - end loop; - else - for I in 1..Rounds loop - loop - Witness := Get_Random(X); - exit when Witness > Big_Unsigned_Two; - end loop; - if Is_Miller_Rabin_Witness(Witness,X) then return False; - end if; - end loop; - end if; - end; - return True; - end Pass_Prime_Test; - - --------------------------------------------------------------------------- - - - function Is_Prime(X : Big_Unsigned) return Boolean is - begin - return Pass_Prime_Test(X, Strong); - end Is_Prime; pragma Inline (Is_Prime); - - --------------------------------------------------------------------------- - - -- This function is faster then Is_prime but a lot of no strong pseudo - -- primes pass this test - function Looks_Like_A_Prime(X : Big_Unsigned) return Boolean is - begin - return Pass_Prime_Test(X, Weak); - end Looks_Like_A_Prime; pragma Inline(Looks_Like_A_Prime); - - --------------------------------------------------------------------------- - - function Get_Prime(N : Big_Unsigned) return Big_Unsigned is - Result : Big_Unsigned := Get_Random(N); - begin - if N <= Big_Unsigned_Two then - raise Constraint_Error; - end if; - - -- make sure that Result is odd - Result.Number(0) := Result.Number(0) or 1; - loop - if Is_Prime(Result) then return Result; - else Result := (Result+2) mod N ; - end if; - end loop; - end Get_Prime; - - - --------------------------------------------------------------------------- - - - function "mod"(Left : D_Big_Unsigned; Right : Big_Unsigned) - return Big_Unsigned; - - --------------------------------------------------------------------------- - - -- Result = Left * Right (mod N) - function Mult(Left, Right, N : Big_Unsigned) return Big_Unsigned is - T : DWord; - Carry : Word := 0; - R : D_Big_Unsigned; - begin - for I in 0..Left.Last_Index loop - for J in 0..Right.Last_Index loop - T := DWord(Left.Number(I)) * DWord(Right.Number(J)) - + DWord(R.Number(I+J)) + DWord(Carry); - - R.Number(I+J) := Word(T and DWord(Word'Last)); - - Carry:= Word(Shift_Right(T,Word'Size)); - end loop; - R.Number(I+Right.Last_Index+1) := Carry + - R.Number(I+Right.Last_Index+1); - Carry := 0; - end loop; - - for I in reverse 0..D_Max_Length loop - if R.Number(I) /= 0 then - R.Last_Index := I; - exit; - end if; - end loop; - return R mod N; - end Mult; - - --------------------------------------------------------------------------- - - - -- Returns a probability N-bit prime (Result). - function Get_N_Bit_Prime(N : Positive) return Big_Unsigned is - J : Big_Unsigned := Get_Random(Shift_Left(Big_Unsigned_One,N-2)); - Index : constant Natural := (N-1)/Word'Size; - Amount : constant Natural := (N-1) mod Word'Size; - Result : Big_Unsigned := Shift_Left(J,1); - - begin - if N = 1 or N > Size then - raise Constraint_Error; - end if; - - loop - -- Make sure that Result is an odd - Set_Least_Significant_Bit (Result); - - -- Make sure that Result is a N-Bit-Number; - Result.Number (Index) := Result.Number (Index) or - Shift_Left (Word (1), Amount); - - if Amount = 0 then - Result.Last_Index := Index; - end if; - - if Is_Prime(Result) then - return Result; - else - Result:=Result-2; - if Is_Prime(Result) then - return Result; - end if; - end if; - - J := Get_Random (Shift_Left (Big_Unsigned_One, N - 2)); - Result := Shift_Left (J, 1); - end loop; - - end Get_N_Bit_Prime; - - --------------------------------------------------------------------------- - - -- computes the jacobi-symbol - -- return value: - -- 0 : if X mod N = 0 - -- 1 : if X is a quadratic resuide mod N - -- -1 : if X is a quadratic non-resuide mod N - - function Jacobi(X, N : Big_Unsigned) return Integer is - A : Big_Unsigned := X mod N; - begin - - if Is_Even(N) then - raise Constraint_Error; - end if; - - if N = Big_Unsigned_One then return 1; - elsif A = Big_Unsigned_Zero then return 0; - elsif A = Big_Unsigned_One then return 1; - end if; - - while (A mod 4) = Big_Unsigned_Zero loop - exit when (A mod 4) = Big_Unsigned_Zero; - A := Shift_Right(A,2); - end loop; - - if Is_Even(A) then - if (N mod 8 = 1) or (N mod 8 = 7) then - return Jacobi(Shift_Right(A,1),N); - else return -1*Jacobi(Shift_Right(A,1),N); - end if; - else - if (A mod 4 = 1) or (N mod 4 = 1) then - return Jacobi(N mod A, A); - else return -1*Jacobi(N mod A, A); - end if; - end if; - end Jacobi; - - ---------------------------------------------------------------------------- - -----------------------------DOUBLE_SIZE------------------------------------ - ---------------------------------------------------------------------------- - - --only needed for multiplication mod N - --here we need 2*Size-bit numbers to avoid an overflow because - --if one of our provisional result t > BIG_Unsigned_Last - --then there ist no well known algortihm to compute the - -- result of an multiplication mod m - - -- same algorithm for D_Big_Unsigned as for Big_Unsigned - - function "="(Left, Right : D_Big_Unsigned) return Boolean is - begin - if Left.Last_Index = Right.Last_Index then - for I in 0..Left.Last_Index loop - if Left.Number(I) /= Right.Number(I) then return False; - end if; - end loop; - else return False; - end if; - return True; - end"="; - - ---------------------------------------------------------------------------- - - function Shift_Left(Value : D_Big_Unsigned; Amount : Natural) - return D_Big_Unsigned is - begin - if Amount >= (D_Max_Length+1)*Word'Size or - Value = D_Big_Unsigned_Zero - then return D_Big_Unsigned_Zero; - elsif Amount = 0 then return Value; - end if; - - declare - Result : D_Big_Unsigned; - Temp : DLimbs :=(others => 0); - L : constant Natural := Amount mod Word'Size; - R : constant Natural := Word'Size-L; - M : constant Natural := Amount/Word'Size; - begin - Temp(0) := Shift_Left(Value.Number(0), L); - - for I in 1..Value.Last_Index loop - Temp(I) := Shift_Right(Value.Number(I-1), R) + - Shift_Left(Value.Number(I), L); - end loop; - - if Value.Last_Index /= D_Max_Length then - Temp(Value.Last_Index+1):= - Shift_Right(Value.Number(Value.Last_Index), R); - end if; - - for I in Temp'Range loop - if (I+M) > D_Max_Length then - exit; - end if; - Result.Number(I+M):= Temp(I); - end loop; - - for I in reverse 0..D_Max_Length loop - if Result.Number(I) /=0 then - Result.Last_Index:=I; - exit; - end if; - end loop; - return Result; - end; - end Shift_Left; pragma Inline (Shift_Left); - - --------------------------------------------------------------------------- - - - function Bit_Length(X : D_Big_Unsigned) return Natural is - begin - if X = D_Big_Unsigned_Zero then - return 0; - end if; - - for I in reverse 0..Word'Size-1 loop - if Shift_Left(1,I) <= X.Number(X.Last_Index) then - return Word'Size * X.Last_Index + I + 1 ; - end if; - end loop; - return X.Last_Index * Word'Size; - end Bit_Length; pragma Inline (Bit_Length); - - - --------------------------------------------------------------------------- - - function "<"(Left, Right : D_Big_Unsigned) return Boolean is - begin - if Left.Last_Index < Right.Last_Index then return True; - elsif Left.Last_Index > Right.Last_Index then return False; - else - for I in reverse 0..Left.Last_Index loop - if Left.Number(I) < Right.Number(I) then return True; - elsif Left.Number(I) > Right.Number(I) then return False; - end if; - end loop; - end if; - return False; - end "<"; pragma Inline ("<"); - - --------------------------------------------------------------------------- - - function ">"(Left, Right : D_Big_Unsigned) return Boolean is - begin - return Right < Left; - end ">"; pragma Inline (">"); - - - - --------------------------------------------------------------------------- - - function ">="(Left, Right : D_Big_Unsigned) return Boolean is - begin - return not(Left < Right); - end ">="; pragma Inline (">="); - - --------------------------------------------------------------------------- - - function "+"(Left, Right : D_Big_Unsigned) return D_Big_Unsigned; - - function "-"(Left, Right : D_Big_Unsigned) return D_Big_Unsigned is - begin - if Left = Right then return D_Big_Unsigned_Zero; - elsif Left = Right+D_Big_Unsigned_One then return D_Big_Unsigned_One; - elsif Left+D_Big_Unsigned_One = Right then return D_Big_Unsigned_Last; - - -- add the modulus if Right > Left - elsif Right > Left then - return D_Big_Unsigned_Last - Right + Left + D_Big_Unsigned_One; - else - declare - Result : D_Big_Unsigned; - Carry : Word:=0; - begin - -- Remember Left > Right - for I in 0..Left.Last_Index loop - Result.Number(I) := Left.Number(I) - Right.Number(I) - Carry; - if (Right.Number(I) > Left.Number(I)) or - (Carry= 1 and Right.Number(I) = Left.Number(I)) - then Carry :=1; - else Carry :=0; - end if; - if Result.Number(I) /= 0 then - Result.Last_Index := I; - end if; - end loop; - return Result; - end; - end if; - end "-"; - - - --------------------------------------------------------------------------- - - function "mod"(Left : D_Big_Unsigned; Right : Big_Unsigned) - return Big_Unsigned is - begin - if Left.Last_Index <= Max_Length then - declare - L : Big_Unsigned; - begin - L.Last_Index := Left.Last_Index; - L.Number(0..Left.Last_Index) := Left.Number(0..Left.Last_Index); - return L mod Right; - end; - end if; - - if Right = Big_Unsigned_Zero then raise Division_By_Zero; - --elsif Right = Big_Unsigned_One then return Big_Unsigned_Zero; - end if; - - -- Now, there is only the case where (Left > Right), (Right /= 0) - -- and |Left|>|Right|. - - declare - Remainder : D_Big_Unsigned:=Left; - Temp_Right, R : D_Big_Unsigned; - Result : Big_Unsigned; - Diff: Natural; - - begin - Temp_Right.Last_Index := Right.Last_Index; - Temp_Right.Number(0..Right.Last_Index) := - Right.Number(0..Right.Last_Index); - R:=Temp_Right; - - while(Remainder >= R) loop - Diff := Bit_Length(Remainder) - Bit_Length(R); - if Diff = 0 then - Remainder := Remainder-R; - exit; - else Diff:=Diff-1; - end if; - Temp_Right := Shift_Left(R, Diff); - Remainder := Remainder-Temp_Right; - end loop; - - Result.Last_Index := Remainder.Last_Index; - Result.Number(0..Result.Last_Index) := - Remainder.Number(0..Result.Last_Index); - return Result; - end; - end "mod"; - - --------------------------------------------------------------------------- - - function "+"(Left, Right : D_Big_Unsigned) return D_Big_Unsigned is - Result : D_Big_Unsigned; - M : constant Natural := Natural'Max(Left.Last_Index, Right.Last_Index); - Temp : Word; - Carry : Word :=0; - begin - - for I in 0..M loop - Temp :=Carry; - Result.Number(I) := Left.Number(I) + Right.Number(I) +Temp; - if Result.Number(I) < Word'Max(Left.Number(I), Right.Number(I)) - then Carry := 1; - else Carry := 0; - end if; - end loop; - - if Carry =1 and M < Max_Length then - Result.Number(M+1) := 1; - Result.Last_Index := M+1; - else - -- Set Result.Last_Index - for I in reverse 0..M loop - if Result.Number(I) /= 0 then - Result.Last_Index := I; - return Result; - end if; - end loop; - end if; - return Result; - end "+"; - - --------------------------------------------------------------------------- - -end Mod_Utils; |