Big Numbers

Note

Big numbers are supported by

  • GNAT Community Edition 2020

  • GCC 11

  • GCC 10 (draft, no user defined literals)

Ada 2022 introduces big integers and big real types.

Big Integers

The package Ada.Numerics.Big_Numbers.Big_Integers contains a type Big_Integer and corresponding operations such as comparison (=, <, >, <=, >=), arithmetic (+, -, *, /, rem, mod, abs, **), Min, Max and Greatest_Common_Divisor. The type also has Integer_Literal and Put_Image aspects redefined, so you can use it in a natural manner.

Ada.Text_IO.Put_Line (Big_Integer'Image(2 ** 256));
115792089237316195423570985008687907853269984665640564039457584007913129639936

Tiny RSA implementation

Note

Note that you shouldn't use Big_Numbers for cryptography because it's vulnerable to timing side-channels attacks.

We can implement the RSA algorithm in a few lines of code. The main operation of RSA is (md) mod n. But you can't just write m ** d, because these are really big numbers and the result won't fit into memory. However, if you keep intermediate result mod n during the md calculation, it will work. Let's write this operation as a function:

    
    
    
        
pragma Ada_2022; with Ada.Numerics.Big_Numbers.Big_Integers; use Ada.Numerics.Big_Numbers.Big_Integers; -- Calculate M ** D mod N function Power_Mod (M, D, N : Big_Integer) return Big_Integer;
function Power_Mod (M, D, N : Big_Integer) return Big_Integer is function Is_Odd (X : Big_Integer) return Boolean is (X mod 2 /= 0); Result : Big_Integer := 1; Exp : Big_Integer := D; Mult : Big_Integer := M mod N; begin while Exp /= 0 loop -- Loop invariant is Power_Mod'Result = Result * Mult**Exp mod N if Is_Odd (Exp) then Result := (Result * Mult) mod N; end if; Mult := Mult ** 2 mod N; Exp := Exp / 2; end loop; return Result; end Power_Mod;

Let's check this with the example from Wikipedia. In that example, the public key is (n = 3233, e = 17) and the message is m = 65. The encrypted message is me mod n = 6517 mod 3233 = 2790 = c.

Ada.Text_IO.Put_Line (Power_Mod (M => 65, D => 17, N => 3233)'Image);
2790

To decrypt it with the public key (n = 3233, d = 413), we need to calculate cd mod n = 2790413 mod 3233:

Ada.Text_IO.Put_Line (Power_Mod (M => 2790, D => 413, N => 3233)'Image);
65

So 65 is the original message m. Easy!

Here is the complete code snippet:

    
    
    
        
pragma Ada_2022; with Ada.Text_IO; with Ada.Numerics.Big_Numbers.Big_Integers; use Ada.Numerics.Big_Numbers.Big_Integers; procedure Main is -- Calculate M ** D mod N function Power_Mod (M, D, N : Big_Integer) return Big_Integer is function Is_Odd (X : Big_Integer) return Boolean is (X mod 2 /= 0); Result : Big_Integer := 1; Exp : Big_Integer := D; Mult : Big_Integer := M mod N; begin while Exp /= 0 loop -- Loop invariant is Power_Mod'Result = Result * Mult**Exp mod N if Is_Odd (Exp) then Result := (Result * Mult) mod N; end if; Mult := Mult ** 2 mod N; Exp := Exp / 2; end loop; return Result; end Power_Mod; begin Ada.Text_IO.Put_Line (Big_Integer'Image (2 ** 256)); -- Encrypt: Ada.Text_IO.Put_Line (Power_Mod (M => 65, D => 17, N => 3233)'Image); -- Decrypt: Ada.Text_IO.Put_Line (Power_Mod (M => 2790, D => 413, N => 3233)'Image); end Main;

Big Reals

In addition to Big_Integer, Ada 2022 provides Big Reals.

References