7

Potrzebuję wdrożyć możliwie jak najszybciej lewe przesunięcie bitowe tablicy 16-bajtowej w JavaCard.Szybkie przesunięcie bitowe tablicy bajtów - podklucze CMAC:

Próbowałem ten kod:

private static final void rotateLeft(final byte[] output, final byte[] input) { 
     short carry = 0; 
     short i = (short) 16; 
     do { 
      --i; 
      carry = (short)((input[i] << 1) | carry); 
      output[i] = (byte)carry; 
      carry = (short)((carry >> 8) & 1); 
     } while (i > 0); 
} 

pomysłów jak poprawić występ? Myślałem o magii Util.getShort(...) i Util.setShort(...), ale nie udało mi się sprawić, by działała szybciej niż powyższa implementacja.

Jest to jedna z części obliczeń podkluczy CMAC i jest niestety często wykonywana. Jeśli znasz jakiś szybszy sposób obliczania podkluczy CMAC (oba podklucze w jednej pętli lub coś podobnego), proszę daj mi znać.

+0

Gromadzenie danych JavaCard jest zapisywane? Jeśli tak, to polecam przyjrzenie się wygenerowanemu kodowi bajtowemu i optymalizację z uwzględnieniem dostępnych instrukcji. Na przykład podejrzewam, że ints może być lepszy niż szorty, a rozwijanie pętli może przynieść ci kilka cykli. Poza tym podejrzewam, że zamierzasz wykonać więcej niż jedną arytmetyczną operację o rozszerzonej precyzji, więc prawdopodobnie lepiej jest wcześnie przełączyć się na szerszą liczbę całkowitą, aby przyspieszyć przetwarzanie i przekonwertować z powrotem 8-bitową macierz na końcu. – doynax

+0

@doynax nie ma 'int' lub' long' w JavaCard ... 'bajt' i' short' to wszystko, co masz. – vojta

+0

Przepraszam za to, że brzmi to jak szczególnie uciążliwe środowisko pracy. Nadal mam jednak rację, miej oko na wygenerowany kod bajtowy, aby upewnić się, że kompilator nie zdecyduje się wygenerować niepotrzebnych instrukcji 'i2s' na pośrednich wynikach z krótkim, ale nie tak naprawdę. – doynax

Odpowiedz

3

Jeśli chodzi o prędkość, znana długość, wersja zakodowana jest najszybsza (ale brzydka) Jeśli chcesz przesunąć więcej niż jeden bit, upewnij się, aby odpowiednio zaktualizować kod.

output[0] = (byte)((byte)(input[0] << 1) | (byte)((input[1] >> 7) & 1)); 
output[1] = (byte)((byte)(input[1] << 1) | (byte)((input[2] >> 7) & 1)); 
output[2] = (byte)((byte)(input[2] << 1) | (byte)((input[3] >> 7) & 1)); 
output[3] = (byte)((byte)(input[3] << 1) | (byte)((input[4] >> 7) & 1)); 
output[4] = (byte)((byte)(input[4] << 1) | (byte)((input[5] >> 7) & 1)); 
output[5] = (byte)((byte)(input[5] << 1) | (byte)((input[6] >> 7) & 1)); 
output[6] = (byte)((byte)(input[6] << 1) | (byte)((input[7] >> 7) & 1)); 
output[7] = (byte)((byte)(input[7] << 1) | (byte)((input[8] >> 7) & 1)); 
output[8] = (byte)((byte)(input[8] << 1) | (byte)((input[9] >> 7) & 1)); 
output[9] = (byte)((byte)(input[9] << 1) | (byte)((input[10] >> 7) & 1)); 
output[10] = (byte)((byte)(input[10] << 1) | (byte)((input[11] >> 7) & 1)); 
output[11] = (byte)((byte)(input[11] << 1) | (byte)((input[12] >> 7) & 1)); 
output[12] = (byte)((byte)(input[12] << 1) | (byte)((input[13] >> 7) & 1)); 
output[13] = (byte)((byte)(input[13] << 1) | (byte)((input[14] >> 7) & 1)); 
output[14] = (byte)((byte)(input[14] << 1) | (byte)((input[15] >> 7) & 1)); 
output[15] = (byte)(input[15] << 1); 

Użyj tablicy bajtów RAM!

+0

Dziękujemy! Jednak myślę, że używasz za dużo rzucania ...Możesz rzucić tylko końcowy wynik i zachować int tak długo, jak to możliwe ... – vojta

+0

Pamiętaj tylko: zaskakująco, rozwijanie w pętli nie jest najszybsze w ogóle, nawet jeśli chodzi o instrukcje niskiego poziomu asemblera. –

+0

@AntonSamsonov Jak to możliwe? – vojta

2

Może pomóc w buforowaniu kluczy podkomendy CMAC podczas wielokrotnego podpisywania przy użyciu tego samego klucza (to jest tego samego klucza sesji DESFire EV1). Podklucze są zawsze takie same dla danego klucza.

Myślę, że odpowiedź Davida mogłaby być jeszcze szybsza, gdyby używała dwóch zmiennych lokalnych do buforowania wartości odczytanych dwukrotnie z tego samego przesunięcia tablicy wejściowej (z moich obserwacji na JCOP, dostęp do tablicy jest dość drogi, nawet dla przejściowych tablic) .

EDIT: Mogę podać następujące implementacją, która 4 bitowe przesunięcie w prawo za pomocą krótkich (32-bitowe int wariant dla kart wspierającą byłoby jeszcze szybciej):

short pom=0; // X000 to be stored next 
short pom2; // loaded value 
short pom3; // 0XXX to be stored next 
short curOffset=PARAMS_TRACK2_OFFSET; 
while(curOffset<16) { 
    pom2=Util.getShort(mem_PARAMS, curOffset); 
    pom3=(short)(pom2>>>4); 
    curOffset=Util.setShort(mem_RAM, curOffset, (short)(pom|pom3)); 
    pom=(short)(pom2<<12); 
} 

uwaga, kod ten zakłada samych przesunięć w źródle i docelowym.

Możesz rozwinąć tę pętlę i użyć stałych parametrów, jeśli chcesz.