【问题标题】:Ada - Sensible code structure for SHA3 implementationAda - SHA3 实现的合理代码结构
【发布时间】:2019-09-13 11:37:55
【问题描述】:

我使用 SHA3 规范作为 Ada 编程语言的学习示例。

规范包含一系列称为排列的数据结构,其中有七种,它们的区别仅在于能够处理不同数量的数据。它们包含一个三维“状态数组”,其中前两个维度始终为 mod 5,第三个维度为 mod N,其中 N 仅限于以下几个值: 25、50、100、200、400、800 和 1600。

我通常认为使用泛型来区分每个包变体,但区别是数字,而不是类型。

如何合理地设计我的包/记录类型?

我能想到的唯一方法就是简单地创建一组显式类型...

package Perm_25 is...
package Perm_50 is...
package Perm_100 is...
package Perm_200 is...
package Perm_400 is...
package Perm_800 is...
package Perm_1600 is...

显然这是荒谬的,因为它很费力并且需要我复制大量代码,这会导致不一致。

此外,我不相信 OOP 在这里会有所帮助,因为除了某些数组维度之外,类型实际上并没有什么不同。

我应该如何解决这个问题?


编辑:感谢用户 @flyx 提供使用 Static_Predicate 子类型和可区分记录类型的提示。使用该建议,我设法编译了以下代码...

package body SHA3 is

  subtype Perm_w_Coeff_Type is Positive
    with Static_Predicate
      => Perm_w_Coeff_Type in 1 | 2 | 4 | 8 | 16 | 32 | 64;

  subtype Perm_l_Coeff_Type is Natural range 0 .. 6;

  type State_Array_Type is array (Natural range <>, Natural range <>, Natural range <>) of Boolean;

  -- (see FIPS202 section 3)
  type KECCAK_p_Permutation (bPW : b_Permutation_Width; numRounds : Positive; W_Coeff : Perm_w_Coeff_Type) is
    record
      b : b_Permutation_Width := bPW;


      -- initialise w based on a lookup table using b as its index
      -- (see FIPS202 section 3.1, table 1)
      w : Perm_w_Coeff_Type := (
          case bPW is
            when 25 => 1,
            when 50 => 2,
            when 100 => 4,
            when 200 => 8,
            when 400 => 16,
            when 800 => 32,
            when 1600 => 64
            );

      -- initialise l based on a lookup table using b as its index
      -- (see FIPS202 section 3.1, table 1)
      l : Perm_l_Coeff_Type := (
          case bPW is
            when 25 => 0,
            when 50 => 1,
            when 100 => 2,
            when 200 => 3,
            when 400 => 4,
            when 800 => 5,
            when 1600 => 6
            );

      n_sub_r : Positive := numRounds;

      State_Array : State_Array_Type (0 .. 4, 0 .. 4, 0 .. W_Coeff);
    end record;


  procedure Run is
  begin
    null;
  end Run;


end SHA3;

【问题讨论】:

  • Ada 在数字上制作通用包没有问题。

标签: ada


【解决方案1】:
subtype Third_Dimension_Type is Natural with
  Static_Predicate => Third_Dimension_Type in 25 | 50 | 100 | 200 | 400 | 800 | 1600;

我不知道你所说的“前两个维度总是 mod 5”是什么意思,但假设你的意思是它们有 5 个条目,结果数据类型将类似于:

type Permutation (Third_Dimension : Third_Dimension_Type) is record
   State : array (1..5, 1..5, 1..Third_Dimension) of Item_Type;
end record;

请注意,您不能指定采用两个离散范围和一个不定范围的数组类型(例如Third_Dimension_Type range &lt;&gt;),因此您需要改用区分记录。

【讨论】:

  • 这看起来很有希望。似乎我的 gnat (4.4.7) 版本不喜欢语法,所以我会在几个小时后在我的另一台 PC 上尝试这个,它安装了最新的 gnat 7.4.0(支持 2012)。
  • Static_Predicate 是 Ada 2012。对于早期的 Ada 版本,您只需将 Third_Dimension_Type 声明为 Natural 并且不能强制它只包含一个有效值。
  • 它奏效了!...有点:) 现在我有一大堆其他的语法噩梦要弄清楚。感谢您为我指明正确的方向。干杯。
  • 附注我已经用你的建议产生的代码更新了这个问题。它还没有接近完成,但它主要说明了我想要做什么。我认为接下来我要做的是弄清楚如何传入单个记录(而不是三个单独的字段),这使得维度大小更容易理解。
  • 您必须在判别式中使用 access 类型才能将所有内容都放在一个值中。我建议不要将wl 作为记录的一部分;它们似乎是b_Permutation_Width 上的函数,应该这样实现。记录中的默认值可以被覆盖,这肯定不是你想要的。
【解决方案2】:

我没有详细了解您的问题,但我正在回答一些引起我注意的问题:您说您不能使用泛型,因为更改的参数不是类型。但是,您可以使用值参数化泛型(并不是说在这种情况下这是最好的方法,但您可以这样做):

generic
   Foo : Integer := 5; -- Or any other type.
package Bar is ...

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-21
    • 1970-01-01
    • 2016-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多