NUMPY AES的实现明显慢于纯Python

时间:2016-09-06 20:16:17

标签: python numpy aes

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

AES中的一个主要操作是Shift Rows,其中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微秒的时间。

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

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日 - 感谢您的回答。为了回答“为什么”的问题,我正在研究运行数十万甚至数百万个样本明文/密文对。因此,虽然任何单一加密的时间差异都没什么区别,但从长远来看,我可以节省的任何时间都会产生巨大的差异。

1 个答案:

答案 0 :(得分:1)

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

这些4' roll'时间说明了这个

小清单:

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和最终索引数组。