7

Ich muss so schnell wie möglich die linke Bitverschiebung eines 16-Byte-Arrays in JavaCard implementieren.Schnelle Bitverschiebung eines Bytearrays - CMAC-Unterschlüssel

habe ich versucht, diesen Code:

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

Irgendwelche Ideen, wie man die Performace verbessern? Ich dachte an etwas Util.getShort(...) und Util.setShort(...) Magie, aber ich schaffte es nicht, es schneller als die Implementierung oben zu arbeiten.

Dies ist ein Teil der CMAC-Unterschlüssel Berechnung und es wird leider oft gemacht. Falls Sie einen schnelleren Weg zur Berechnung von CMAC-Unterschlüsseln (beide Unterschlüssel in einer Schleife oder ähnlichem) kennen, lassen Sie es mich bitte wissen.

+0

Ich nehme an, JavaCard ist interpated? Wenn das der Fall ist, würde ich empfehlen, dass Sie sich den generierten Byte-Code ansehen und ihn mit dem verfügbaren Befehlssatz optimieren. Zum Beispiel vermute ich, dass Ints Shorts vorzuziehen sind, und dass das Loop-Abrollverfahren Ihnen ein paar Zyklen einbringen könnte. Darüber hinaus vermute ich, dass Sie mehr als eine einzige arithmetische Operation mit erweiterter Genauigkeit ausführen werden, daher ist es wahrscheinlich ratsam, früh auf eine breitere Ganzzahl zu wechseln, um die Verarbeitung zu beschleunigen, und am Ende ein 8-Bit-Array zu konvertieren. – doynax

+0

@doynax gibt es keine 'int' oder' long' in JavaCard ... 'byte' und' short' ist alles was du hast. – vojta

+0

Sorry, klingt wie eine besonders lähmende Umgebung, mit der man arbeiten kann. Mein Punkt bleibt jedoch, behalte den erzeugten Byte-Code im Auge, um sicherzustellen, dass der Compiler nicht entscheidet, unnötige 'i2s'-Anweisungen für die Zwischen-Kurz-von-int-aber-nicht-wirklich-Ergebnisse zu erzeugen. – doynax

Antwort

3

Wenn es um Geschwindigkeit geht, bekannte Länge, hart codierte Version ist die schnellste (aber hässlich). Wenn Sie mehr als ein Bit verschieben müssen, stellen Sie sicher, dass Sie den Code entsprechend aktualisieren.

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

Und RAM-Byte-Array verwenden!

+0

Danke! Allerdings denke ich, dass du zu viel Casting verwendest ...Du kannst nur das Endergebnis werfen und int so lange wie möglich behalten ... – vojta

+0

Nur zu bemerken: Überraschenderweise ist Loop Enrolling im Allgemeinen nicht die schnellste, selbst wenn es um Low-Level-Assembler-Anweisungen geht. –

+0

@AntonSamsonov Wie ist das möglich? – vojta

2

Es kann hilfreich sein, CMAC-Unterschlüssel im Cache zu speichern, wenn wiederholt mit demselben Schlüssel (d. H. Demselben DESFire EV1-Sitzungsschlüssel) signiert wird. Die Unterschlüssel sind für den angegebenen Schlüssel immer gleich.

Ich denke Davids Antwort könnte noch schneller sein, wenn es zwei lokale Variablen verwendet, um die doppelt gelesenen Werte vom selben Offset des Input-Arrays zu cachen (aus meinen Beobachtungen auf JCOP ist der Array-Zugriff selbst für transiente Arrays ziemlich teuer) .

EDIT: Ich kann die folgende Implementierung schaffen, das tut 4-Bit-Verschiebung nach rechts kurz mit (32-Bit-int-Variante für Karten unterstützt es noch schneller wäre):

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

Vorsicht, nimmt dieser Code gleiche Offsets in Quelle und Ziel.

Sie können diese Schleife ausrollen und bei Bedarf konstante Parameter verwenden.

Verwandte Themen