Search code examples
ada

Type not visible in child package


I have the following parent package which defines several types

aes.ads

package AES is    
    type Byte is range 0..2**8  - 1;
    type Input_Buffer is array(Natural range <>) of Byte;
    type Output_Buffer is array(Natural range <>) of Byte;
    type Key is array(Natural range <>) of Byte;
    subtype AES_128_Key is Key(0..127);
    subtype AES_192_Key is Key(0..191);
    subtype AES_256_Key is Key(0..255);
    type Operation is (Encrypt, Decrypt);

    function AES_CBC_128(Input: Input_Buffer; Key: AES_128_Key; Op: Operation) return Output_Buffer;
    function AES_CBC_192(Input: Input_Buffer; Key: AES_192_Key; Op: Operation) return Output_Buffer;
    function AES_CBC_256(Input: Input_Buffer; Key: AES_256_Key; Op: Operation) return Output_Buffer;

private
    type Word is range 0..2**32 - 1;
    type State is array(0..3, 0..3) of Byte;
    type States is array(Natural range <>) of State;
    type Round_Key is array(0..16) of Byte;
    type Key_Schedule is array(Natural range <>) of Round_Key;
end AES;

aes.adb

with AES.AES_Cipher; use AES.AES_Cipher;
with AES.AES_Inv_Cipher; use AES.AES_Inv_Cipher;

package body AES is

-- other definitions

function AES_Common(St: State; K: Key; Op: Operation) return State is
    Schedule: Key_Schedule := Key_Expansion(K);
begin
    return (case Op is
        when Encrypt => Cipher(St, Schedule),
        when Decrypt => Inv_Cipher(St, Schedule)
    );
end AES_Common;

-- more definitions

end AES;

and then two child packages (aes-aes_inv_cipher is very similar to aes-aes_cipher so has been omitted)

aes-aes_cipher.ads

package AES.AES_Cipher is
    function Cipher(St: State; Schedule: Key_Schedule) return State;
end AES.AES_Cipher;

aes-aes_cipher.adb

package body AES.AES_Cipher is

function Cipher(St: State; Schedule: Key_Schedule) return State is
begin
    
    return St;
end Cipher;

end AES.AES_Cipher;

These are called from main.adb

with AES; use AES;

procedure Main is
    Input: Input_Buffer(0..35) := (others => Byte(44));
    K: AES_128_Key := (others => Byte(55));
    Output: Output_Buffer(0..35);
begin
    Output := AES_CBC_128(Input, K, Encrypt);
end Main;

This does not compile with the following error

aes-aes_cipher.ads:2:25: error: "State" is not visible (more references follow)
aes-aes_cipher.ads:2:25: error: non-visible (private) declaration at aes.ads:17
aes-aes_cipher.ads:2:42: error: "Key_Schedule" is not visible (more references follow)
aes-aes_cipher.ads:2:42: error: non-visible (private) declaration at aes.ads:20

I thought because aes-aes_cipher is a child package of aes it could access the private definitions in aes.ads but the error suggests otherwise. If this is not possible, how can I restructure the program so it works as expected? Removing private fixes it but those types should be private outside the package. I am using gnatmake version 13.2.0 on Windows.


Solution

  • This can be done by making the child package a private package.

    private package AES.AES_Cipher is
        function Cipher(St: State; Schedule: Key_Schedule) return State;
    end AES.AES_Cipher;
    

    This allows the child package to use the private parent types without exposing them publicly and still allows the parent package to use the child functions.

    Thank you to Jim Rogers for pointing me in the right direction and this answer for explaining how to do it.