2012-07-14 72 views
3

我已經寫在MATLAB我自己的SHA1的實現,它給正確的哈希值。然而,它非常慢(我的Core i7-2760QM上的字符串1000 a需要9.9秒),我認爲這種慢度是由MATLAB如何實現按位邏輯運算(bitand,bitor,,bitcmp)和按位整數的位移(bitshiftbitrolbitror)。如何優化MATLAB位操作

尤其是我不知道需要建造定點數值對象爲bitrolbitror使用fi命令,因爲反正在英特爾x86彙編有rolror既爲各種規模的寄存器和存儲器地址。然而,bitshift速度相當快(它不需要任何定點數字結構,常規uint64變量工作正常),這使情況變得陌生:爲什麼在MATLAB bitrolbitror需要使用fi構建的定點數字對象,而bitshift不,當裝配水平都歸結到shlshrrolror

因此,在C/C寫這個函數++作爲.mex文件之前,我很樂意知道是否有什麼辦法改善這種功能的性能。我知道對SHA1有一些特定的優化,但如果按位旋轉的基本實現非常慢,那不是問題。

測試一點點與tictoc,這是顯而易見的是什麼使得它慢是與bitrolfi環。有兩個這樣的循環:

%# Define some variables. 
FFFFFFFF = uint64(hex2dec('FFFFFFFF')); 

%# constants: K(1), K(2), K(3), K(4). 
K(1) = uint64(hex2dec('5A827999')); 
K(2) = uint64(hex2dec('6ED9EBA1')); 
K(3) = uint64(hex2dec('8F1BBCDC')); 
K(4) = uint64(hex2dec('CA62C1D6')); 

W = uint64(zeros(1, 80)); 

... some other code here ... 

%# First slow loop begins here. 

for index = 17:80 
    W(index) = uint64(bitrol(fi(bitxor(bitxor(bitxor(W(index-3), W(index-8)), W(index-14)), W(index-16)), 0, 32, 0), 1)); 
end 

%# First slow loop ends here. 

H = sha1_handle_block_struct.H; 

A = H(1); 
B = H(2); 
C = H(3); 
D = H(4); 
E = H(5); 

%# Second slow loop begins here. 

for index = 1:80 
    rotatedA = uint64(bitrol(fi(A, 0, 32, 0), 5)); 

    if (index <= 20) 
     % alternative #1. 
     xorPart = bitxor(D, (bitand(B, (bitxor(C, D))))); 
     xorPart = bitand(xorPart, FFFFFFFF); 
     temp = rotatedA + xorPart + E + W(index) + K(1); 
    elseif ((index >= 21) && (index <= 40)) 
     % FIPS. 
     xorPart = bitxor(bitxor(B, C), D); 
     xorPart = bitand(xorPart, FFFFFFFF); 
     temp = rotatedA + xorPart + E + W(index) + K(2); 
    elseif ((index >= 41) && (index <= 60)) 
     % alternative #2. 
     xorPart = bitor(bitand(B, C), bitand(D, bitxor(B, C))); 
     xorPart = bitand(xorPart, FFFFFFFF); 
     temp = rotatedA + xorPart + E + W(index) + K(3); 
    elseif ((index >= 61) && (index <= 80)) 
     % FIPS. 
     xorPart = bitxor(bitxor(B, C), D); 
     xorPart = bitand(xorPart, FFFFFFFF); 
     temp = rotatedA + xorPart + E + W(index) + K(4); 
    else 
     error('error in the code of sha1_handle_block.m!'); 
    end 

temp = bitand(temp, FFFFFFFF); 
E = D; 
D = C; 
C = uint64(bitrol(fi(B, 0, 32, 0), 30)); 
B = A; 
A = temp; 
end 

%# Second slow loop ends here. 

tictoc,消息的SHA1哈希整個計算abc發生在我的筆記本電腦周圍0.63秒,其中約0.23秒在第一個慢環和周圍通過測量在第二個慢循環中爲0.38秒。那麼在編寫.mex文件之前,有什麼方法可以在MATLAB中優化這些循環?

回答

4

有此DataHash從MATLAB文件交換是快速計算SHA-1散列閃電。
我跑到下面的代碼:

x = 'The quick brown fox jumped over the lazy dog'; %# Just a short sentence 
y = repmat('a', [1, 1e6]);       %# A million a's 
opt = struct('Method', 'SHA-1', 'Format', 'HEX', 'Input', 'bin'); 
tic, x_hashed = DataHash(uint8(x), opt), toc 
tic, y_hashed = DataHash(uint8(y), opt), toc 

,並得到了以下結果:

x_hashed = F6513640F3045E9768B239785625CAA6A2588842
Elapsed time is 0.029250 seconds.

y_hashed = 34AA973CD4C4DAA4F61EEB2BDBAD27316534016F
Elapsed time is 0.020595 seconds.

我用random online SHA-1 tool驗證了結果,計算結果確實是正確的。另外,a的散列速度比第一句快1.5倍。

那麼如何DataHash這麼快呢?使用java.security.MessageDigest庫,不會少於!
如果您對使用MATLAB的SHA-1快速函數感興趣,這是一條可行的路線。但是,如果這只是一個實現快速位級操作的練習,那麼MATLAB並沒有真正處理它們,在大多數情況下,您將不得不求助於MEX。

+0

在我看來,加速SHA1的選項是使用'java.security.MessageDigest'庫或編寫一個MEX函數。正如我打算讓我的MATLAB代碼與GNU Octave兼容(也希望將GNU Octave用作開發環境),並且似乎在處理Java和Octave之間存在一些差異,使用Java庫是一個非理想的解決方案。然而,'DataHash'非常快,因此在執行MEX解決方案之前就可以完成這項工作,或者找到另一種有效實現SHA1的方法,而無需使用Java。 – nrz 2012-07-15 11:00:03

+0

將我自己的fMRI分析工具箱移植到Octave是我的一個長期項目,我不想基於此來限制答案。無論如何,我目前需要的是一種有效的方式來計算大型文件(在MATLAB中)的SHA1,以便能夠繼續開發,'DataHash'是一個可行的解決方案。 – nrz 2012-07-15 11:34:01

+0

@nrz:Octave具有兼容的MEX API來編寫C擴展。他們也有自己的API來編寫OCT文件(相當於MATLAB中的MEX文件)。 – Amro 2012-07-15 11:45:58

3

爲什麼在MATLAB bitrol和bitror需要固定點數字對象與網絡連接構成,而位位移不

bitrol和bitror都不是適用於的uint該組的按位的邏輯功能的一部分。它們是定點工具箱的一部分,它還包含適用於定點輸入的bitand,bitshift等變體。

,如果你想只使用UINT函數嘗試bitrol可以表示成兩個bitshifts,一個BITAND和BITOR。雖然這可能會更慢。

+0

通過替換我所有的'bitrol(fi(...'代碼與我自己的旋轉左功能SHA1計算時間爲1000'a'從9.9秒下降到大約0.42秒,所以現在比以前快23.5倍。然而,計算SHA1哈希得到更長的消息(例如,在FIPS文檔中的一百萬(10^6)'a'的示例消息仍然需要大約422秒(我的原始代碼花費了9430秒來計算),而運行'在bash中的時間printf'a%.0s'{1..1000000} | sha1sum'只需要0.953秒,因此,比我原來的速度快23.5倍,但仍比'sha1sum'慢大約440倍。 – nrz 2012-07-14 10:40:01

3

由於大多數MATLAB函數,bitand,bitorbitxor是向量化的。所以,你得到了很多更快,如果你給這些函數向量輸入,而不是對每個元素調用它們在一個循環

例子:

%# create two sets of 10k random numbers 
num = 10000; 
hex = 'ABCDEF'; 
A = uint64(hex2dec(hex(randi(16, [num 16])))); 
B = uint64(hex2dec(hex(randi(16, [num 16])))); 

%# compare loop vs. vectorized call 
tic 
C1 = zeros(size(A), class(A)); 
for i=1:numel(A) 
    C1(i) = bitxor(A(i),B(i)); 
end 
toc 

tic 
C2 = bitxor(A,B); 
toc 

assert(isequal(C1,C2)) 

的時機:

Elapsed time is 0.139034 seconds. 
Elapsed time is 0.000960 seconds. 

這是命令規模更快!

問題是,據我所知,SHA-1計算不能很好地矢量化。所以你可能無法利用這種矢量化。

作爲一個實驗,我實現了一個純粹基於MATLAB的功能可按計算這樣的位操作:

function num = my_bitops(op,A,B) 
    %# operation to perform: not, and, or, xor 
    if ischar(op) 
     op = str2func(op); 
    end 

    %# integer class: uint8, uint16, uint32, uint64 
    clss = class(A); 
    depth = str2double(clss(5:end)); 

    %# bit exponents 
    e = 2.^(depth-1:-1:0); 

    %# convert to binary 
    b1 = logical(dec2bin(A,depth)-'0'); 
    if nargin == 3 
     b2 = logical(dec2bin(B,depth)-'0'); 
    end 

    %# perform binary operation 
    if nargin < 3 
     num = op(b1); 
    else 
     num = op(b1,b2); 
    end 

    %# convert back to integer 
    num = sum(bsxfun(@times, cast(num,clss), cast(e,clss)), 2, 'native'); 
end 

不幸的是,在性能方面,這是更糟糕:

tic, C1 = bitxor(A,B); toc 
tic, C2 = my_bitops('xor',A,B); toc 
assert(isequal(C1,C2)) 

的時機:

Elapsed time is 0.000984 seconds. 
Elapsed time is 0.485692 seconds. 

結論:寫一個MEX函數或搜索文件交換到s如果有人已經:)

+0

據我所知,SHA1不能有效的矢量化。您的'my_bitops'函數似乎是一種有趣的方法,可以加快MATLAB中按位運算的計算速度,但不幸的是,它不能解決性能問題。我認爲EitanT提到的'DataHash'將是我寫MEX函數或使用其他人編寫的MEX之前要走的路。 – nrz 2012-07-15 11:13:31