【问题标题】:NUMPY Implementation of AES significantly slower than pure pythonAES的NUMPY实现明显慢于纯python
【发布时间】:2016-09-06 20:16:17
【问题描述】:

我正在考虑重新实现 SlowAES 代码 (http://anh.cs.luc.edu/331/code/aes.py) 以尝试利用 numpy 的原生数组支持。对我来说,我得到的反直觉结果是,SlowAES 的纯 Python 比使用 numpy 实现的相同功能快得多。这是我最清楚的例子。

AES 中的主要操作之一是移位行,其中 4x4 元素字节数组中的每一行都移位了一些位置(0 表示第 0 行,1 表示第 1 行,等等)。原始 Python 代码将此 4x4 字节状态数组视为一维 16 元素列表,然后使用切片创建虚拟行以进行旋转:

def rotate(word, n):
    return word[n:] + word [0:n]

def shiftRows(state):
    for i in range(4):
        state[i*4:i*4+4] = rotate(state[i*4:i*4+4], -i)

使用 16 个整数的列表在 shiftRows 上运行 timeit 会产生 3.47 微秒的时间。

在 numpy 中重新实现这个相同的函数,假设一个 4x4 整数输入数组,很简单:

def shiftRows(state):
    for i in range(4):
        state[i] = np.roll(state[i],-i)

但是,timeit 显示它的执行时间为 16.3 微秒。

我希望 numpy 的优化数组操作可能会产生更快的代码。我哪里错了?是否有某种方法可以实现比纯 Python 更快的 AES 实现?我想得到一些中间结果,所以 pycrypto 可能不适用(尽管如果这太慢,我可能需要再看一下)。

2016 年 9 月 7 日 - 感谢您的回答。为了回答“为什么”这个问题,我正在考虑运行数十万甚至数百万的样本明文/密文对。因此,虽然任何单一加密的时间差几乎没有什么区别,但从长远来看,我能节省的任何时间都可能产生巨大的影响。

【问题讨论】:

  • “是否有某种方法可以实现比纯 Python 更快的 AES 实现?”几乎肯定。在 C 中执行此操作并将绑定导出到 Python。但是,我怀疑这不是您要寻找的答案。
  • Numpy 通常有更多的“控制”,如果与普通的“精简”源相比,它会减慢它的速度。在此处查看roll 的源代码:github.com/numpy/numpy/blob/v1.11.0/numpy/core/…
  • 3.5 vs 16 微秒?这个问题会扩大到你可能会说 10 秒或几分钟的地方吗?我在这里没有看到大问题,除非这是一个优化问题。
  • 我假设 numpy 版本中的 block 实际上应该是 state

标签: python numpy aes


【解决方案1】:

简单的答案是创建数组有很多开销。因此,小列表上的操作通常比数组上的等价操作要快。如果数组版本像列表一样是迭代的,则尤其如此。对于大型数组,使用编译方法的操作会更快。

这 4 个“滚动”时间说明了这一点

对于一个小列表:

In [93]: timeit x=list(range(16)); x=x[8:]+x[:8]
100000 loops, best of 3: 2.75 µs per loop
In [94]: timeit y=np.arange(16); y=np.roll(y,8)
The slowest run took 40.90 times longer than the fastest. This could mean that an intermediate result is being cached.
100000 loops, best of 3: 14.5 µs per loop

对于一个大的:

In [95]: timeit x=list(range(1000)); x=x[500:]+x[:500]
10000 loops, best of 3: 52.9 µs per loop
In [96]: timeit y=np.arange(1000); y=np.roll(y,500)
The slowest run took 28.91 times longer than the fastest. This could mean that an intermediate result is being cached.
10000 loops, best of 3: 22.2 µs per loop

我们可以通过从计时循环中提取rangearange 步骤来进一步细化问题。

np.roll 操作本质上是:

y[np.concatenate((np.arange(8,16), np.arange(0,8)))]

这构造了 4 个数组,即 2 个arangeconcatenate 和最终的索引数组。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    • 1970-01-01
    相关资源
    最近更新 更多