7

Devo implementare il più veloce spostamento di bit di sinistra di un array di 16 byte in JavaCard.Spostamento veloce di bit di un array di byte - Sottochiavi CMAC

Ho provato questo codice:

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); 
} 

Delle idee come migliorare la performace? Stavo pensando ad alcuni Util.getShort(...) e Util.setShort(...) magia, ma non sono riuscito a farlo funzionare più velocemente rispetto all'implementazione di cui sopra.

Questa è una parte del calcolo delle sottochiavi CMAC e purtroppo viene eseguita abbastanza spesso. Nel caso in cui si conosca un modo più veloce per calcolare le sottochiavi CMAC (entrambe le sottochiavi in ​​un ciclo o qualcosa del genere), per favore, fammi sapere.

+0

Raccolgo che JavaCard è interpeted? In tal caso, mi raccomando di dare un'occhiata al codice byte generato e ottimizzare con le istruzioni disponibili in mente. Ad esempio, sospetto che gli inte siano preferibili ai cortometraggi e che lo srotolamento del loop potrebbe farti guadagnare alcuni cicli. Oltre a ciò, sospetto che si stia facendo più di una singola operazione aritmetica di precisione estesa, quindi è probabilmente consigliabile passare a un intero più ampio in anticipo per un'elaborazione più rapida e convertire la parte posteriore di un array a 8 bit alla fine. – doynax

+0

@doynax non c'è 'int' o' long' in JavaCard ... 'byte' e' short' è tutto ciò che hai. – vojta

+0

Mi dispiace, suona come un ambiente particolarmente paralizzante con cui lavorare. Il mio punto rimane comunque, tenere d'occhio il codice byte generato per assicurare che il compilatore non decida di generare istruzioni 'i2s 'non necessarie sui risultati intermedi a breve di int-ma-not-really. – doynax

risposta

3

Quando si tratta di velocità, la lunghezza nota, la versione codificata è la più veloce (ma brutta). Se è necessario spostare più di un bit, assicurarsi di aggiornare il codice di conseguenza.

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); 

E utilizzare array di byte RAM!

+0

Grazie! Tuttavia, penso che tu usi troppo casting ...Potresti trasmettere solo il risultato finale e mantenerlo il più a lungo possibile ... – vojta

+0

Solo per notare: sorprendentemente, lo srotolamento del ciclo non è il più veloce in generale, anche quando si tratta di istruzioni di assemblatore di basso livello. –

+0

@AntonSamsonov Com'è possibile? – vojta

2

Potrebbe essere utile memorizzare nella cache le sottochiavi CMAC durante la firma ripetuta utilizzando la stessa chiave (ad esempio la stessa chiave di sessione DESFire EV1). Le sottochiavi sono sempre le stesse per la chiave data.

Penso che la risposta di David potrebbe essere ancora più veloce se usasse due variabili locali per memorizzare nella cache i valori letti due volte dallo stesso offset dell'array di input (dalle mie osservazioni su JCOP, l'accesso dell'array è abbastanza costoso anche per gli array transienti) .

EDIT: posso fornire la seguente implementazione che fa 4 bit spostamento destra utilizzando breve (int variante a 32 bit per schede sostiene sarebbe ancora più veloce):

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); 
} 

Attenzione, questo codice assume stessi offset nella fonte e nella destinazione.

È possibile srotolare questo ciclo e utilizzare i parametri costanti, se desiderato.

Problemi correlati