# [CUDA] RC6 / Serpent / Twofish / AES / MARS



## boss3D (28. November 2013)

Hi @ all!

Ich muss für ein Projekt im Studium mehrere Verschlüsselungs-Algorithmen in CUDA benchmarken. Wo ich die Algorithmen hernehme, ist dabei egal. 

ATM arbeite ich daran, RC6 nach CUDA zu portieren. Einen C Code habe ich auf github gefunden, und gleich mal eine main Funktion dazugebastelt. Da ich nahezu 0 Erfahrungen mit CUDA habe und mir das jetzt selbst Schritt für Schritt beibringen darf, habe ich für den Anfang erstmal die "Idiotenlösung" gewählt, und einfach versucht, die beiden Haupt-(CPU)-Funktionen in 2 GPU-Funktionen aufzurufen. So sieht das ganze derzeit aus:

```
#include <cuda_runtime.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "RC6.h"

#define P32 0xB7E15163
#define Q32 0x9E3779B9

uint32_t rotl32(uint32_t a, uint8_t n){
        n &= 0x1f;
        return ( (a<<n)| (a>>(32-n)) );
}
uint32_t rotr32(uint32_t a, uint8_t n){
        n &= 0x1f;
        return ( (a>>n)| (a<<(32-n)) );
}

uint8_t rc6_init(void* key, uint16_t keylength_b, rc6_ctx_t *s){
        return rc6_initl(key, keylength_b, 20, s);
}


uint8_t rc6_initl(void* key, uint16_t keylength_b, uint8_t rounds, rc6_ctx_t *s){
        uint8_t i,j;
        uint16_t v,p,c;
        uint32_t a,b, l=0;
        if (rounds>125)
                return 2;
        [COLOR=blue][B]if(!(s->S=malloc((2*rounds+4)*sizeof(uint32_t))))[/B]                return 1;

        s->rounds=rounds;

        c = keylength_b/32;
        if (keylength_b%32){
                ++c;
                j=(keylength_b%32)/8;
                if(keylength_b%8)
                        ++j;
                for (i=0; i<j; ++i)
                        ((uint8_t*)&l)[i] = ((uint8_t*)key)[(c-1)*4 + i];
        } else {
                l = ((uint32_t*)key)[c-1];
        }

        s->S[0] = P32;
        for(i=1; i<2*rounds+4; ++i){
                s->S[i] = s->S[i-1] + Q32;
        }

        a=b=j=i=0;
        v = 3 * ((c > 2*rounds+4)?c:(2*rounds+4));
        for(p=1; p<=v; ++p){
                a = s->S[i] = rotl32(s->S[i] + a + b, 3);
                if (j==c-1){
                        b = l = rotl32(l+a+b, a+b);
                } else {
                        b = ((uint32_t*)key)[j] = rotl32(((uint32_t*)key)[j]+a+b, a+b);
                }
                i = (i+1) % (2*rounds+4);
                j = (j+1) % c;
        }
        return 0;
}

void rc6_free(rc6_ctx_t *s){
        free(s->S);
}

#define LG_W 5
#define A (((uint32_t*)block)[0])
#define B (((uint32_t*)block)[1])
#define C (((uint32_t*)block)[2])
#define D (((uint32_t*)block)[3])

void rc6_enc(void* block, rc6_ctx_t *s) {
    uint8_t i;
    uint32_t t,u,x;

    B += s->S[0];
    D += s->S[1];

    for (i=1; i<=s->rounds; ++i){
        t = rotl32(B * (2*B+1), LG_W);
        u = rotl32(D * (2*D+1), LG_W);
        A = rotl32((A ^ t), u) + s->S[2*i];
        C = rotl32((C ^ u), t) + s->S[2*i+1];
        x = A;
        A = B;
        B = C;
        C = D;
        D = x;
    }
    A += s->S[2*s->rounds+2];
    C += s->S[2*s->rounds+3];
}

void rc6_dec(void* block, rc6_ctx_t *s){
    uint8_t i;
    uint32_t t,u,x;

    C -= s->S[2*s->rounds+3];
    A -= s->S[2*s->rounds+2];

    for (i=s->rounds; i>0; --i){
        x=D;
        D=C;
        C=B;
        B=A;
        A=x;
        u = rotl32(D * (2*D+1), LG_W);
        t = rotl32(B * (2*B+1), LG_W);
        C = rotr32(C - s->S[2*i+1], t) ^ u;
        A = rotr32(A - s->S[2*i+0], u) ^ t;
    }
    D -= s->S[1];
    B -= s->S[0];
}

[COLOR=blue][B]__global__ void rc6enc() {
    rc6_enc();
}

__global__ void rc6dec() {
    rc6_enc();
}[/B]
int main(void) {
    float elapsedTime=0.0;

    cudaEvent_t start, stop;
    cudaEventCreate(&start);
    cudaEventCreate(&stop);

    cudaEventRecord( start, 0 );

    rc6enc<<<1,1>>>();
    rc6dec<<<1,1>>>();

    cudaEventRecord( stop, 0 );
    cudaEventSynchronize( stop );

    cudaEventElapsedTime( &elapsedTime, start, stop );

    printf("time: %.4f ms\n", elapsedTime);

    return 0;
}
```


```
#pragma once

#ifndef RC6_H_
#define RC6_H_

#include <stdint.h>

typedef struct rc6_ctx_st{
        uint8_t         rounds;         /* specifys the number of rounds; default: 20 */
        uint32_t*       S;                      /* the round-keys */
} rc6_ctx_t;


uint8_t rc6_init(void* key, uint16_t keylength_b, rc6_ctx_t *s);

uint8_t rc6_initl(void* key, uint16_t keylength_b, uint8_t rounds, rc6_ctx_t *s);

void rc6_enc(void* block, rc6_ctx_t *s);
void rc6_dec(void* block, rc6_ctx_t *s);

void rc6_free(rc6_ctx_t *s);
#endif /* RC6_H_ */
```
^^ Die blau markierten Zeilen sind zur Zeit das Problem. Bei den beiden Funktionen fehlen die Parameter, die ich den CPU-Funktionen übergeben muss, aber ich weiß nicht so recht, wie genau ich die da reinschreiben soll. Und bei der if-Zeile gibt's ein Pointer Problem, das sich mir auch noch nicht so ganz erschließt ... 




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Für jede Hilfe bin ich dankbar!


----------



## Leandros (28. November 2013)

*AW: [CUDA] RC6*

Was ist Zeile 30? Der Malloc call?


----------



## boss3D (28. November 2013)

*AW: [CUDA] RC6*

^^ Ja, das ist das Pointer-Problem in der if- bzw. malloc-Zeile ... Dort sehe ich den Fehler (im nicht selbst-geschriebenem Code!) noch nicht. Bei meinen beiden eingefügten GPU Funktionen weiß ich, dass jeweils 2 Parameter an die internen Funktionsaufrufe übergeben werden müssten, aber ich weiß noch nicht, wie genau ich "block" und "*s" da reinkriegen soll, sodass das auch funktioniert ...


----------



## Leandros (28. November 2013)

*AW: [CUDA] RC6*

Ich denke, der fehler mit malloc sollte so zu lösen sein.

Verständlich:

```
s->S = (uint32_t *)malloc((2 * rounds + 4) * sizeof(uint32_t));
    if (!s->S)
        return 1;
```

Kurz:

```
if(!(s->S=(uint32_t*)malloc((2*rounds+4)*sizeof(uint32_t))))
     return 1;
```

malloc returned immer void*. Allerdings scheint s->S ein uint32_t* zu sein, daher schmeisst dein compiler einen error raus, weil es eine fehlerhafte pointer zuweisung ist. Einfach nach uint32_t* casten und gut ist. Für das nächste mal: http://www.cplusplus.com/reference/cstdlib/malloc/
Was ist jetzt dein zweiter Fehler? Das habe ich noch nicht ganz Verstanden.


----------



## boss3D (29. November 2013)

*AW: [CUDA] RC6*

^^Ok, danke.

Das zweite Problem sind die Funktionsparameter. Die Host-Funktionen haben folgende Header:

```
void rc6_enc(void* block, rc6_ctx_t *s) {
```


```
void rc6_dec(void* block, rc6_ctx_t *s) {
```
Und ich habe mir zwei GPU Funktionen gemacht, in denen diese beiden Host-Funktionen aufgerufen werden. Jetzt muss ich aber dort irgendwie deren Parameter reinbringen. Und daran scheitert's noch ...

Irgendwie so:

```
__global__ void rc6enc() {
    rc6_enc(block, *s);
}
```
Nur genau so funktioniert's natürlich nicht. Ich bin mir auch nicht ganz sicher, ob diese Lösung wirklich das machen würde, was ich brauche: Dass dann der ganze Host Code wirklich von der GPU berechnet wird.


----------



## sebi707 (29. November 2013)

*AW: [CUDA] RC6*

Du kannst an die Device Funktionen auch einfach Parameter übergeben, allerdings wird hier mit Pointern gearbeitet und du kannst nicht einfach Pointer von der CPU an GPU Funktionen übergeben. Du musst zuerst auf der GPU Speicher reservieren, die Daten von der CPU dorthin kopieren und dann den Pointer auf den GPU Memory an die Funktion übergeben.

Außerdem wirst du so wie du es momentan planst vermutlich keinen Geschwindigkeitsvorteil von GPU gegenüber der CPU feststellen, da du nur einen Thread und einen Block auf der GPU startest. Die Geschwindigkeit der GPU ergibt sich vor allem aus der hohen Parallelität mit der selbst 1000 Threads parallel bearbeitet werden. Ob sich RC4 oder andere Verschlüsselungen parallelisieren lassen weiß ich auch nicht. Je nach eingesetztem Modus lassen sich wenigstens die einzelnen Blöcke parallel verschlüsseln und entschlüsseln.

Deinen Fragen nach schätze ich deine Programmiererfahrungen in C/C++ eher gering ein und vermute, dass du diese Aufgabe nicht in absehbarer Zeit vernünftig gelöst kriegst. Ich würde mich eher nach einer bereits für CUDA angepassten Bibliothek umsehen. Eine Anpassung an CUDA ist nicht mal eben damit getan an ein paar Funktionen das __global__ Keyword dran zu schreiben.


----------



## boss3D (30. November 2013)

*AW: [CUDA] RC6*

Dass es bei CUDA vor allem um Parallelisierung geht, ist mir klar, allerdings ist Performance (noch) nicht das Primärziel. Das wichtigste ist im Moment, überhaupt erstmal einen RC6 Code zu kriegen, der auf der GPU läuft. Optimiert, soweit dann möglich, wird danach.
Dass ich die Anzahl der Thread über die Parameter der aufrufenden Funktion angebe, weiß ich auch. Das ist ja die zweite Zahl in den spitzen Klammern, wenn ich das jetzt richtig in Erinnerung habe. 

C-Kenntnisse hätte ich eigentlich schon (mal gehabt), allerdings im ersten Semester meines Studiums. Jetzt bin ich ein gutes Stück weiter und hatte schon seit fast 1 Jahr überhaupt gar nichts mehr mit C zu tun. Man vergisst das doch erstaunlich schnell, wenn man sich nicht damit befasst. Jetzt fürs Projekt muss ich mich aber wieder damit beschäftigen.

Ich schau mir das jetzt erstmal mit dem GPU Memory an, allerdings weiß ich noch nicht so wirklich, was genau ich von der CPU dort hin kopieren soll. Was genau ist das/der "block"? Oder Pointer *s? Muss ich mir noch anschauen ...
^^ Wenn ich das mit den beiden Parametern noch schaffe, müsste das ganze m. E. schon auf der GPU lauffähig sein. Dass es eine Idiotenlösung ist, den ganzen CPU Code quasi in eine __global__ Funktion "einzupacken", habe ich ja gesagt, aber fürs erste geht's wirklich mal nur um Lauffähigkeit.


----------



## sebi707 (30. November 2013)

*AW: [CUDA] RC6*

Der rc6_ctx_t *s Pointer speichert wohl einen internen Zustand, wie die verwendeten Schlüssel und Anzahl der Runden. Der void* block Pointer enthält einen Block der zu verschlüsselnden Daten. Scheinbar ist dieser bei RC6 immer 16 Bytes groß. Beides musst du vorm Aufruf von deiner rc6enc/dec Funktion in den GPU Memory kopieren. Der void* block Pointer enthält danach die verschlüsselten Daten, also den danach wieder zum Host kopieren falls du an den Daten interessiert bist.

Zu beachten ist auf jeden Fall, dass du im Host Code nirgendwo einen Pointer, der mit cudaMalloc reserviert wurde, dereferenzierst. Du kannst die Daten im GPU Memory nicht direkt verändern und musst den Umweg über das Kopieren vom Host Memory mithilfe von cudaMemcpy gehen (oder eine GPU Funktion aufrufen, die die Daten initialisiert).


----------



## Crymes (1. Dezember 2013)

Wenn du nir mit der parallelisierung rumexperimentieren willst ohne dich in Cuda einarbeiten zu müssen, ist Java aparapi oder C++ AMP ganz nett.


----------



## Crysis nerd (1. Dezember 2013)

*AW: [CUDA] RC6*



Crymes schrieb:


> Wenn du nir mit der parallelisierung rumexperimentieren willst *ohne* dich in Cuda einarbeiten zu müssen, [...]


.....


boss3D schrieb:


> Ich *muss* für ein Projekt im Studium mehrere Verschlüsselungs-Algorithmen *in CUDA* benchmarken.


----------



## boss3D (1. Dezember 2013)

*AW: [CUDA] RC6*

So, ich habe das jetzt mal umzusetzen versucht, und ich denke, die ungefähre Richtung stimmt?! Ein paar Fehler habe ich noch in der Umsetzung:

```
#include <cuda_runtime.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "RC6.h"

#define P32 0xB7E15163
#define Q32 0x9E3779B9

uint32_t rotl32(uint32_t a, uint8_t n){
        n &= 0x1f;
        return ( (a<<n)| (a>>(32-n)) );
}
uint32_t rotr32(uint32_t a, uint8_t n){
        n &= 0x1f;
        return ( (a>>n)| (a<<(32-n)) );
}

uint8_t rc6_init(void* key, uint16_t keylength_b, rc6_ctx_t *s){
        return rc6_initl(key, keylength_b, 20, s);
}


uint8_t rc6_initl(void* key, uint16_t keylength_b, uint8_t rounds, rc6_ctx_t *s){
        uint8_t i,j;
        uint16_t v,p,c;
        uint32_t a,b, l=0;
        if (rounds>125)
                return 2;
        if(!(s->S=(uint32_t*)malloc((2*rounds+4)*sizeof(uint32_t))))
                return 1;

        s->rounds=rounds;

        c = keylength_b/32;
        if (keylength_b%32){
                ++c;
                j=(keylength_b%32)/8;
                if(keylength_b%8)
                        ++j;
                for (i=0; i<j; ++i)
                        ((uint8_t*)&l)[i] = ((uint8_t*)key)[(c-1)*4 + i];
        } else {
                l = ((uint32_t*)key)[c-1];
        }

        s->S[0] = P32;
        for(i=1; i<2*rounds+4; ++i){
                s->S[i] = s->S[i-1] + Q32;
        }

        a=b=j=i=0;
        v = 3 * ((c > 2*rounds+4)?c:(2*rounds+4));
        for(p=1; p<=v; ++p){
                a = s->S[i] = rotl32(s->S[i] + a + b, 3);
                if (j==c-1){
                        b = l = rotl32(l+a+b, a+b);
                } else {
                        b = ((uint32_t*)key)[j] = rotl32(((uint32_t*)key)[j]+a+b, a+b);
                }
                i = (i+1) % (2*rounds+4);
                j = (j+1) % c;
        }
        return 0;
}

void rc6_free(rc6_ctx_t *s){
        free(s->S);
}

#define LG_W 5
#define A (((uint32_t*)block)[0])
#define B (((uint32_t*)block)[1])
#define C (((uint32_t*)block)[2])
#define D (((uint32_t*)block)[3])

void rc6_enc(void* block, rc6_ctx_t *s) {
    uint8_t i;
    uint32_t t,u,x;

    B += s->S[0];
    D += s->S[1];

    for (i=1; i<=s->rounds; ++i){
        t = rotl32(B * (2*B+1), LG_W);
        u = rotl32(D * (2*D+1), LG_W);
        A = rotl32((A ^ t), u) + s->S[2*i];
        C = rotl32((C ^ u), t) + s->S[2*i+1];
        x = A;
        A = B;
        B = C;
        C = D;
        D = x;
    }
    A += s->S[2*s->rounds+2];
    C += s->S[2*s->rounds+3];
}

void rc6_dec(void* block, rc6_ctx_t *s) {
    uint8_t i;
    uint32_t t,u,x;

    C -= s->S[2*s->rounds+3];
    A -= s->S[2*s->rounds+2];

    for (i=s->rounds; i>0; --i){
        x=D;
        D=C;
        C=B;
        B=A;
        A=x;
        u = rotl32(D * (2*D+1), LG_W);
        t = rotl32(B * (2*B+1), LG_W);
        C = rotr32(C - s->S[2*i+1], t) ^ u;
        A = rotr32(A - s->S[2*i+0], u) ^ t;
    }
    D -= s->S[1];
    B -= s->S[0];
}

[COLOR=blue][B]__global__ void rc6enc(void* block, rc6_ctx_t *s) {
    rc6_enc(block, s);
}

__global__ void rc6dec(void* block, rc6_ctx_t *s) {
    rc6_enc(block, s);
}[/B]
int main(void) {
    rc6_ctx_t s_var;
    void block_var;
    float elapsedTime=0.0;

    [COLOR=blue][B]rc6_ctx_t *s;
    cudaMalloc((void**)&s, sizeof(rc6_ctx_t));
    void *block;
    cudaMalloc((void**)&block, sizeof(void));[/B]
    [COLOR=blue][B]cudaMemcpy(s_var, sizeof(rc6_ctx_t), cudaMemcpyHostToDevice);
    cudaMemcpy(block_var, sizeof(void), cudaMemcpyHostToDevice);[/B]
    cudaEvent_t start, stop;
    cudaEventCreate(&start);
    cudaEventCreate(&stop);

    cudaEventRecord( start, 0 );

    [COLOR=blue][B]rc6enc<<<1,1>>>(block, s);
    rc6dec<<<1,1>>>(block, s);[/B]
    cudaEventRecord( stop, 0 );
    cudaEventSynchronize( stop );

    cudaEventElapsedTime( &elapsedTime, start, stop );

    printf("time: %.4f ms\n", elapsedTime);

    [COLOR=blue][B]cudaFree(s);
    cudaFree(block);[/B]
    return 0;
}
```



			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Am void block_var scheitert's jetzt noch. Da meint er was von wegen incomplete type. 
Natürlich ist void Blödsinn, aber die selbe Fehlermeldung kommt auch bei anderen Datentypen.

BTW: Was das für Daten sind, die durch den Algorithmus fließen, spielt überhaupt keine Rolle. Es geht wirklich NUR um die Performance beim Ver- und Entschlüsseln (nachdem das ganze überhaupt erstmal unter CUDA läuft, woran ich gerade arbeite). Wie die Daten danach aussehen, ist egal, allerdings muss es natürlich eine korrekte Ver- bzw. Entschlüsselung bleiben. Den eigentlichen Code darf ich nicht verpfuschen, nur um ihn lauffähig zu kriegen.


----------



## Crysis nerd (1. Dezember 2013)

*AW: [CUDA] RC6*

Ähm wieso soll dein block_var denn vom typ void sein? Du weißt dass void für "nichts" steht oder? Was soll das speichern? Meinst du void* ? Aber selbst das wäre nicht zu empfehlen...


----------



## boss3D (1. Dezember 2013)

*AW: [CUDA] RC6*

Habe ich ja geschrieben, dass void Blödsinn ist. Es gibt keine "nichts-Variablen", aber ich weiß (noch) nicht, was ich sonst aus block bzw. block_var machen soll. Ich habe mich erstmal nur daran orientiert, dass es halt im host-Funktions-Kopf mit void* angegeben ist ...


----------



## boss3D (8. Dezember 2013)

*AW: [CUDA] RC6*

Hat keiner einer Idee, welchen Datentyp ich statt void für die block Variable(n) nehmen könnte? Ich habe schon die einfachen Datentypen durchprobiert, aber jedes Mal heißt's "incomplete type is not allowed" ...


----------



## Crysis nerd (8. Dezember 2013)

*AW: [CUDA] RC6*

WTF...
du musst doch selber wissen, was du da überhaupt speichern möchtest? Wenn du so fragst, machst du den Eindruck als wenn du dir Code zusammenkopiert hast. Außerdem sollte cudaMemcpy doch 4 Parameter haben und nicht 3? NVIDIA CUDA Library: cudaMemcpy
Und dann musst du auch die Adresse von z.B. s_var übergeben und nicht einfach nur s_var... 
Also entweder ich habe dein Geheimnis nicht verstanden oder du kopierst dir nur Code ohne den Sinn überhaupt im Ansatz zu verstehen...


----------



## boss3D (8. Dezember 2013)

*AW: [CUDA] RC6*

Der Code ist NICHT von mir! (siehe Startpost)
Ich habe mir einen C-COde von RC6 gegoogelt und muss den unter CUDA lauffähig machen ...

Es ist auch völlig egal, welche Art von Daten durch den RC6 laufen, solange der RC6 ansich das richtige damit macht. Ich habe die Frage mit den Datentypen eher so gemeint, dass keiner funktioniert, den ich bis jetzt ausprobiert habe (int, char, Felder davon, ...). K. A. welcher Datentyp gehen würde. DAS wollte ich eigentlich wissen.

Und die Adresse von s_var wird doch eh übergeben?! &s_var.
^^ In Zeile 139 wird ja auch kein Fehler gemeldet.


----------



## sebi707 (8. Dezember 2013)

*AW: [CUDA] RC6*

Also ich hatte ja schon geschrieben, dass ein RC6 Block immer 16 Bytes groß ist also würde sich ein char Array mit 16 Elementen eignen. Da beliebige Pointer zu void* konvertiert werden in C kannst du das auch einfach so an die Funktion übergeben. Außerdem noch einige weitere Punkte die mir aufgefallen sind:
- Die Konvertierung zu (void**) bei cudaMalloc ist eigentlich unnötig
- Du nutzt cudaMemcpy falsch. cudaMemcpy hat 4 Argumente und nicht 3. Richtig würde ein Aufruf etwa so aussehen: cudaMemcpy(s, &s_var, sizeof(rc6_ctx_t), cudaMemcpyHostToDevice);
- Dir fehlt die Initialisierung von s_var. Dies muss passieren bevor du die Daten zur Grafikkarte kopierst. Das initialisieren übernimmt die rc6_init Funktion.

So in etwa würde ich die main Funktion schreiben (ungetestet):


```
char* key = "meingeheimespasswort";
rc6_ctx_t s_var;
rc6_init(key, strlen(key), &s_var); // ich hoffe strlen ist richtig und die abschließende '\0' wird nicht mitgezählt 

char block_var[16] = {0}; // block_var eventuell mit richtigen daten füllen

rc6_ctx_t *s;
cudaMalloc(&s, sizeof(s_var));
cudaMemcpy(s, &s_var, sizeof(s_var), cudaMemcpyHostToDevice);

char* block;
cudaMalloc(&block, sizeof(block_var));
cudaMemcpy(block, block_var, sizeof(block_var), cudaMemcpyHostToDevice);

rc6enc<<<1,1>>>(block, s);
rc6dec<<<1,1>>>(block, s);

cudaFree(s);
cudaFree(block);
```
Ich würde dir in jedem Fall dazu raten deine C-Kenntnisse etwas aufzufrischen, denn deine Versuche sehen wie relativ planloses ausprobieren aus. Richtiger Umgang mit Pointern sollte man für dieses Vorhaben schon mitbringen.

Edit: Ich seh grade, dass das rc6_ctx_t struct auch noch Pointer enthält. Du musst für diese Daten also auch noch Platz auf der GPU reservieren und dorthin kopieren.


----------



## boss3D (8. Dezember 2013)

*AW: [CUDA] RC6*

^^ Ok, danke. Ich probiere das mal aus. "Herumprobieren" ist es leider wirklich, aber nach 1 Jahr kein C und dafür einem halben Jahr Java (keine pointer!) sieht das erstmal alles ein bisschen fremd aus ...

Wenn das mit char und char Arrays funktioniert, muss ich das halt dann auch in den anderen Algorithmen (AES, Serpent, Twofish, MARS) beachten, weil ich die ja gegeneinander benchmarken muss. Das macht ja nur Sinn, wenn sie den exakt selben Input verarbeiten.


----------



## sebi707 (8. Dezember 2013)

*AW: [CUDA] RC6*

Wie grade im edit schon geschrieben habe ich noch nicht beachtet, dass rc6_ctx_t auch Pointer enthält. Ich kann dir also so schon garantieren, dass das Programm schön abstürzen wird wenn es denn so compiliert. Wenn du das aber berücksichtigst müsste es grundlegend erstmal funktionieren.


----------



## boss3D (8. Dezember 2013)

*AW: [CUDA] RC6*

Die main müsste jetzt stimmen, aber dafür habe ich 2 Errors gekriegt, die ich zuvor nicht hatte (siehe Screenshot in Post #11):




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



(Dir fehlt in deinem Mustercode ein "&" im zweiten cudaMemcpy vor Parameter 2)


----------



## sebi707 (8. Dezember 2013)

*AW: [CUDA] RC6*

Wie die Fehlermeldung sagt rufst du eine Host-Funktion von der __global__ Funktion auf. Du musst einfach vor alle Funktionen, die innerhalb der __global__ Funktion aufgerufen werden ein __device__ schreiben, um diese zu Device-Funktionen zu machen.

Im Mustercode fehlt nicht wirklich ein & sondern ist in diesem Fall optional, da Arrays zu Pointern zerfallen.


----------



## boss3D (8. Dezember 2013)

*AW: [CUDA] RC6*

Okay, so kriege ich das ganze zum Laufen und die Errors weg ... allerdings kommen dafür 18 Warnings. Ich hoffe, das ist nicht schlimm?!




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.


----------



## sebi707 (8. Dezember 2013)

*AW: [CUDA] RC6*

Die Funktionen die in den ersten beiden warnings genannt werden auch im header als __device__ deklarieren sollte die warnings beheben.


----------



## boss3D (8. Dezember 2013)

*AW: [CUDA] RC6*

Was meinst du? Im header steht doch "__device__ void rc6_enc(blabla) {"


----------



## sebi707 (8. Dezember 2013)

*AW: [CUDA] RC6*

Da ich deinen geänderten Code nicht sehen kann, kann ich leider nur vermuten wo jetzt überall __device__ steht. Allerdings besagen die ersten beiden Warnungen, dass die Funktion rc6_end und rc6_dec erneut deklariert wurden allerdings jetzt mit __device__ statt wie vorher __host__. Offensichtlich sind also die Funktionen rc6_end und rc6_dec nicht einheitlich deklariert. Ich vermute also, du hast nur in der *.c Datei (oder *.cu für CUDA) überall __device__ davor geschrieben aber die *.h Datei (also den Header) vergessen. Kann ich ohne Code natürlich nur spekulieren aber danach sieht die Warnung aus.


----------



## boss3D (8. Dezember 2013)

*AW: [CUDA] RC6*

In der .h Datei hatte ich testweise __device__ vor die beiden Funktionen geschrieben, aber dann sofort nach dem Kompilieren der .cu Datei wieder jede Menge Errors bekommen ...




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Deswegen habe ich dann in der .h Datei auf "__device__" verzichtet und lebe lieber mit den Warnings.

Hier nochmal der gesamte Code:

```
#include <cuda_runtime.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "RC6.h"

#define P32 0xB7E15163
#define Q32 0x9E3779B9

uint32_t rotl32(uint32_t a, uint8_t n){
        n &= 0x1f;
        return ( (a<<n)| (a>>(32-n)) );
}
uint32_t rotr32(uint32_t a, uint8_t n){
        n &= 0x1f;
        return ( (a>>n)| (a<<(32-n)) );
}

uint8_t rc6_init(void* key, uint16_t keylength_b, rc6_ctx_t *s){
        return rc6_initl(key, keylength_b, 20, s);
}


uint8_t rc6_initl(void* key, uint16_t keylength_b, uint8_t rounds, rc6_ctx_t *s){
        uint8_t i,j;
        uint16_t v,p,c;
        uint32_t a,b, l=0;
        if (rounds>125)
                return 2;
        if(!(s->S=(uint32_t*)malloc((2*rounds+4)*sizeof(uint32_t))))
                return 1;

        s->rounds=rounds;

        c = keylength_b/32;
        if (keylength_b%32){
                ++c;
                j=(keylength_b%32)/8;
                if(keylength_b%8)
                        ++j;
                for (i=0; i<j; ++i)
                        ((uint8_t*)&l)[i] = ((uint8_t*)key)[(c-1)*4 + i];
        } else {
                l = ((uint32_t*)key)[c-1];
        }

        s->S[0] = P32;
        for(i=1; i<2*rounds+4; ++i){
                s->S[i] = s->S[i-1] + Q32;
        }

        a=b=j=i=0;
        v = 3 * ((c > 2*rounds+4)?c:(2*rounds+4));
        for(p=1; p<=v; ++p){
                a = s->S[i] = rotl32(s->S[i] + a + b, 3);
                if (j==c-1){
                        b = l = rotl32(l+a+b, a+b);
                } else {
                        b = ((uint32_t*)key)[j] = rotl32(((uint32_t*)key)[j]+a+b, a+b);
                }
                i = (i+1) % (2*rounds+4);
                j = (j+1) % c;
        }
        return 0;
}

void rc6_free(rc6_ctx_t *s){
        free(s->S);
}

#define LG_W 5
#define A (((uint32_t*)block)[0])
#define B (((uint32_t*)block)[1])
#define C (((uint32_t*)block)[2])
#define D (((uint32_t*)block)[3])

__device__ void rc6_enc(void* block, rc6_ctx_t *s) {
    uint8_t i;
    uint32_t t,u,x;

    B += s->S[0];
    D += s->S[1];

    for (i=1; i<=s->rounds; ++i){
        t = rotl32(B * (2*B+1), LG_W);
        u = rotl32(D * (2*D+1), LG_W);
        A = rotl32((A ^ t), u) + s->S[2*i];
        C = rotl32((C ^ u), t) + s->S[2*i+1];
        x = A;
        A = B;
        B = C;
        C = D;
        D = x;
    }
    A += s->S[2*s->rounds+2];
    C += s->S[2*s->rounds+3];
}

__device__ void rc6_dec(void* block, rc6_ctx_t *s) {
    uint8_t i;
    uint32_t t,u,x;

    C -= s->S[2*s->rounds+3];
    A -= s->S[2*s->rounds+2];

    for (i=s->rounds; i>0; --i){
        x=D;
        D=C;
        C=B;
        B=A;
        A=x;
        u = rotl32(D * (2*D+1), LG_W);
        t = rotl32(B * (2*B+1), LG_W);
        C = rotr32(C - s->S[2*i+1], t) ^ u;
        A = rotr32(A - s->S[2*i+0], u) ^ t;
    }
    D -= s->S[1];
    B -= s->S[0];
}

__global__ void rc6enc(char* block, rc6_ctx_t *s) {
    rc6_enc(block, s);
}

__global__ void rc6dec(char* block, rc6_ctx_t *s) {
    rc6_enc(block, s);
}

int main(void) {
    char* key = "meingeheimespasswort";
    rc6_ctx_t s_var;
    rc6_ctx_t *s;
    rc6_init(key, strlen(key), &s_var);
    char block_var[16] = {0};
    float elapsedTime=0.0;

    cudaMalloc(&s, sizeof(rc6_ctx_t));
    cudaMemcpy(s, &s_var, sizeof(s_var), cudaMemcpyHostToDevice);

    char* block;
    cudaMalloc(&block, sizeof(block_var));
    cudaMemcpy(block, &block_var, sizeof(block_var), cudaMemcpyHostToDevice);

    cudaEvent_t start, stop;
    cudaEventCreate(&start);
    cudaEventCreate(&stop);

    cudaEventRecord( start, 0 );

    rc6enc<<<1,1>>>(block, s);
    rc6dec<<<1,1>>>(block, s);

    cudaEventRecord( stop, 0 );
    cudaEventSynchronize( stop );

    cudaEventElapsedTime( &elapsedTime, start, stop );

    printf("time: %.4f ms\n", elapsedTime);

    cudaFree(s);
    cudaFree(block);

    return 0;
}
```


```
#pragma once

#ifndef RC6_H_
#define RC6_H_

#include <stdint.h>

typedef struct rc6_ctx_st{
        uint8_t         rounds;         /* specifys the number of rounds; default: 20 */
        uint32_t*       S;                      /* the round-keys */
} rc6_ctx_t;


uint8_t rc6_init(void* key, uint16_t keylength_b, rc6_ctx_t *s);

uint8_t rc6_initl(void* key, uint16_t keylength_b, uint8_t rounds, rc6_ctx_t *s);

__device__ void rc6_enc(void* block, rc6_ctx_t *s);
__device__ void rc6_dec(void* block, rc6_ctx_t *s);

void rc6_free(rc6_ctx_t *s);
#endif /* RC6_H_ */
```


----------



## sebi707 (8. Dezember 2013)

*AW: [CUDA] RC6*

Auch vor die rotl32 und rotr32 Funktionen musst du __device__ schreiben. Generell alle Funktionen, die von der __global__ Funktion aus aufgerufen werden (und Funktionen, die von diesen Funktionen aufgerufen werden) müssen __device__ sein, da ja alles auf der GPU ausgeführt werden soll.


----------



## boss3D (8. Dezember 2013)

*AW: [CUDA] RC6*

Wenn ich vor alle Funktionen im .h File "__device__" schreibe, kann ich das ganze zumindest auf 3 Errors reduzieren ...




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.


----------



## sebi707 (8. Dezember 2013)

*AW: [CUDA] RC6*

Alle Funktionen hab ich gar nicht gesagt. Ich sagte alle Funktionen, die von deiner __global__ Funktion aus aufgerufen werden. Dazu zählen nicht rc6_init, rc6_initl und rc6_free, die du ja sogar vom Host Code aufrufst. Hab mir grade nochmal den Code angeguckt und die rotl32, rotr32 Funktionen werden sowohl vom Host Code (rc6_initl) und vom Device Code (rc6_enc/rc6_dec) aus aufgerufen. Solche Funktionen müssen mit beiden Keywords __host__ und __device__ versehen werden. Also nochmal zusammenfassend:

rc6_enc, rc6_enc: __device__
rc6_init, rc6_initl, rc6_free: __host__ (kann weggelassen werden da standardeinstellung)
rotl32, rotr32: __device__ __host__


----------



## boss3D (8. Dezember 2013)

*AW: [CUDA] RC6*

Jetzt sind die Errors weg, 6 Warnings bleiben ... aber das ist jetzt auch kein Weltuntergang. M. E. kann man's so lassen ... außer du weißt, wie ich die Warnings auch noch wegkriegen könnte. Für Variablen gibt's meines Wissens nach keine CUDA-spezifischen Wörter?! So weiß er halt nicht genau, auf welchen Speicher die Pointer zeigen und nimmt (glücklicherweise) autmatisch den GPU-Speicher (?) an.




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.


----------



## sebi707 (8. Dezember 2013)

*AW: [CUDA] RC6*

Ich denke die Warnungen können so bleiben, allerdings ist genau dieser S pointer im rc6_ctx_t struct der Teil den du noch manuell auf die GPU kopieren musst damit es dann funktioniert. Eventuell sind dann auch die Warnungen weg.


----------



## boss3D (28. Dezember 2013)

*AW: [CUDA] RC6*

Ich habe mich jetzt noch eine Weile mit dem Code beschäftigt, vor allem, weil ich ihn auch noch bestmöglich parallelisieren soll, aber was mir vorher noch aufgefallen ist: Ich bekomme immer nur _"time: 0.0000 ms"_ als Ergebnis der Zeitmessung raus. Das verwundert mich trotz der geringen Datenmenge auch bei einer alten/schwachen 9600M GT doch. 

Angenommen, _char block_var[16] = "aaaaaaaaaaaaaaa"_, und ich verschlüssele das mit unserem RC6 Code, dann würde ich mir doch erwarten, dass das vielleicht 5 ms, oder irgendwas ähnliches in der Größenordnung dauert?!

Habe ich irgendeinen Fehler in der Zeitmessung? 

```
int main(void) {
    char* key = "meingeheimespasswort";
    rc6_ctx_t s_var;
    rc6_ctx_t *s;
    rc6_init(key, strlen(key), &s_var);
    char block_var[16] = {0};

    cudaMalloc(&s, sizeof(rc6_ctx_t));
    cudaMemcpy(s, &s_var, sizeof(s_var), cudaMemcpyHostToDevice);

    char* block;
    cudaMalloc(&block, sizeof(block_var));
    cudaMemcpy(block, &block_var, sizeof(block_var), cudaMemcpyHostToDevice);

    [COLOR=royalblue][B]cudaEvent_t start, stop;
    cudaEventCreate(&start);
    cudaEventCreate(&stop);
    cudaEventRecord( start, 0 );[/B]
    rc6enc<<<1,1>>>(block, s);
    rc6dec<<<1,1>>>(block, s);

    [COLOR=royalblue][B]cudaEventRecord( stop, 0 );
    cudaEventSynchronize( stop );
    float elapsedTime;
    cudaEventElapsedTime( &elapsedTime, start, stop );[/B]
    [COLOR=royalblue][B]printf("time: %.4f ms\n", elapsedTime);
    
    cudaEventDestroy( start );
    cudaEventDestroy( stop );[/B]
    cudaFree(s);
    cudaFree(block);

    return 0;
}
```


----------



## sebi707 (29. Dezember 2013)

*AW: [CUDA] RC6*

Der Code sieht OK aus. Das mit den 0ms scheint zwar unwahrscheinlich, aber nicht völlig ausgeschlossen. Ein paar Bytes hin und her schieben dauert nicht wirklich lange. Ich tippe aber eher darauf, dass eine der CUDA-Funktionen fehlgeschlagen ist. Um das zu überprüfen solltest du den Rückgabewert aller cuda... Funktionen überprüfen. Dazu verwende ich selbst folgende Helperfunction:


```
#define HandleError(x) HandleErrorImpl(x, __FILE__, __LINE__)

inline void HandleErrorImpl(cudaError error, const char* file, int line)
{
  if(error != cudaSuccess)
  {
    std::cerr << file << ":" << line << " " << cudaGetErrorString(error) << std::endl;
    exit(1);
  }
}
```

Falls du nur C und nicht C++ benutzt dann einfach den Kram mit cerr durch printf ersetzen und den Dateinamen, Zeilennummer und Fehlerbeschreibung anzeigt. Jetzt einfach noch um alle CUDA-Funktionen ein HandleError() drum packen, also sowas wie:


```
HandleError( cudaEventCreate(&start) );
HandleError( cudaEventCreate(&stop) );
```

Ist zwar etwas nervig, aber unverzichtbar bei der Fehlersuche. Nach einem Kernelaufruf mit der name<<<x,y>>> Syntax kann auch ein HandleError( cudaGetLastError() ); nicht schaden. Falls dann keine Fehler und immer noch 0ms angezeigt werden, dann dauert die ausführung wohl tatsächlich nur so lange.


----------



## boss3D (29. Dezember 2013)

*AW: [CUDA] RC6*

Irgendwas habe ich beim printf falsch gemacht, aber zumindest wissen wir jetzt, dass der Fehler beim synchronize in Zeile 161 liegt ...




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



*[Edit]*
Wenn ich den Error mit nem %s ausgeben lassen, heißt's "unspecified launch failure":




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.


----------



## sebi707 (29. Dezember 2013)

*AW: [CUDA] RC6*

Ja du musst das schon mit %s ausgeben. Die file variable und was cudaGetErrorString zurück gibt sind beides strings. Also sowas: printf("%s:%i %s", ...)

"unspecified launch failure" heißt wohl, dass irgendwas mit deiner Kernel Funktion nicht in Ordnung ist. Zugriffe auf Speicher, der nicht initialisiert ist oder sowas. Hast du eigentlich schon die Daten vom Pointer im rc6_ctx_t struct auch auf die GPU Kopiert? Sonst liegt es garantiert daran.


----------



## boss3D (29. Dezember 2013)

*AW: [CUDA] RC6*

Hab's jetzt mit %s %d %s ausgeben lassen: "../src/RC6.cu: 161 unspecified launch failure". Dass der Fehler im cu File ist, war eh klar. Nur was soll ich mir jetzt unter dem launch failure vorstellen?

*[Edit]*
rounds und *S? Nein?! Ich habe nur die cudaMemcpys, die s/s_var und block/block_var in den GPU Speicher kopieren ...


----------



## boss3D (29. Dezember 2013)

*AW: [CUDA] RC6*

Hm ... wir haben doch eh schon für das ganze struct rc6_ctx_t Speicher allokiert?! Und unser s ist doch dieser Pointer?! Irgendwie verstehe ich gerade nicht, was ich noch machen soll. 

Mich verwirrt das auch, dass wir einen eigenen char* key haben, obwohl doch in S die Rundenschlüssel gespeichert werden sollten?!


----------



## sebi707 (29. Dezember 2013)

*AW: [CUDA] RC6*

Wenn du dir die rc6_initl Funktion nochmal anguckst, dann findest du dort folgende Zeile:

```
if(!(s->S=(uint32_t*)malloc((2*rounds+4)*sizeof(uint32_t))))
```
Diese Daten musst du auch auf die GPU kopieren. An den Parametern vom malloc siehst du wie groß der Speicherbereich ist. Um das ganze dann auf die GPU zu kopieren brauchst du dann etwa folgenden Code:


```
rc6_ctx_t temp = s_var;
cudaMalloc(&temp.S, (2*s_var.rounds+4)*sizeof(uint32_t));
cudaMemcpy(temp.S, s_var.S, (2*s_var.rounds+4)*sizeof(uint32_t), cudaMemcpyHostToDevice);

rc6_ctx_t* s;
cudaMalloc(&s, sizeof(temp));
cudaMemcpy(s, &temp, sizeof(temp), cudaMemcpyHostToDevice);
```
Code ungetestet

Edit: Wir haben zwar für das rc6_ctx_t struct Speicher reserviert aber wenn du dir das struct anguckst so stellst du fest, dass dieses struct wiederum einen Pointer auf einen Speicherbereich enthält. Diesen Speicherbereich muss man manuell kopieren, da das kopieren des Structs selbst nur den Pointer kopiert aber nicht die Daten wohin der Pointer zeigt.

Den char* key brauchen wir nur einmal für die rc6_init Funktion, die daraus dann die Rundenschlüssel generiert. Man hätte den Wert auch direkt an die rc6_init Funktion übergeben können aber dann müsste man die länge des Strings von Hand zählen. So kann man strlen benutzen.

Noch etwas Erklärung zu dem Beispielcode oben: Zuerst erstelle ich eine Kopie des s_var Structs und tausche den Pointer durch einen von CUDA reservieren Pointer aus. Danach werden die Daten vom ursprünglichen s_var Struct kopiert. Abschließend kopieren wir das ganze temp Struct auf die GPU.


----------



## boss3D (29. Dezember 2013)

*AW: [CUDA] RC6*

*s hatten wir schon deklariert, ansonsten stimmt's jetzt mit dieser Code-Ergänzung. Die Zeit kommt mir auch schon vernünftiger vor:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Jetzt muss ich nur noch durchschauen, wofür diese ganzen Variablen und Pointer stehen. Bei S hatte ich angenommen, dass das der jeweilige Rundenschlüssel sei, aber warum haben wir dann einen eigenen char* key definiert? Und *s ist wohl einfach der Pointer auf S?!
Wozu brauchen wir eigentlich s_var? Das ist ne Variable an deren Adresse wir irgendwas speichern?! Die Daten, auf die der Pointer *s zeiget?! Das wäre ja dann der Rundenschlüssel?!

Und in tmp (bzw. temp bei dir) speichern wir nochmal s_var, da komme ich nicht ganz mit. 

In block_var werden die Daten gespeichert, auf die der Pointer *block zeigt, oder wie?

*[Edit]*
Okay, jetzt verstehe ich's schon eher. Eine Frage noch, nur damit ich das richtig verstehe: Der aktuelle Code verschlüsselt 16 0er, oder (char block_var[16] = {0})? Andere Daten sehe ich sonst nirgends.


----------



## sebi707 (29. Dezember 2013)

*AW: [CUDA] RC6*

Ja das sieht ja schonmal gut aus. Zeile 145 und 146 kannst du übrigens streichen, da du jetzt zweimal Speicher reservierst für das s struct. Da du von den ganzen Pointern verwirrt zu sein scheinst hier nochmal zusammenfassend alles:

Erstmal musst du Pointer auf dem RAM und auf der GPU unterscheiden. Da beides nur gewöhnliche Pointer sind muss man aufpassen welcher Pointer im RAM oder auf der GPU liegt. Außerdem braucht man viele Pointer doppelt wenn man zwischen CPU und GPU Daten kopiert. Normalerweise schreibe ich ein h_ oder d_ für host bzw. device vor die Variablennamen um diese auseinander zu halten. Vor der Sache mit dem temp hatten wir folgende Variablen (fehlen eventuell einige unwichtige):

Host variablen: char* key, rc6_ctx_t s_var, char block_var[]
Device variablen: rc6_ctx_t *s, char* block;

Dabei ist s die GPU Variante von s_var und block die GPU Variante von block_var. Den key brauchen wir nur auf der CPU, da wir damit unser s_var initialisieren. An sich wäre alles recht überschaulich wenn das rc6_ctx_t Struct nicht selbst nochmal einen Pointer enthalten würde, wie hier zu sehen ist:

```
typedef struct rc6_ctx_st{
        uint8_t         rounds;         /* specifys the number of rounds; default: 20 */
        uint32_t*       S;                      /* the round-keys */
} rc6_ctx_t;
```
Wir müssen also auch noch dafür sorgen, dass die Daten wohin der S Pointer zeigt auch auf die GPU kopiert werden. Dazu erstelle ich erstmal eine Kopie von der s_var Variable und sorge dafür, dass der S Pointer auf Speicher in der GPU zeigt. Anschließend kopiere ich noch die daten von s_var.S nach temp.S womit ich dann die Rundenschlüssel schonmal auf der GPU habe. Anschließend fehlt nur noch, dass wir die ganze temp Variable auf die GPU kopieren. Diese Variable heißt momentan s. Das Kopieren von block_var nach block ist wieder einfach, da wir keine verschachtelten Pointer beachten müssen. Ich hoffe die erklärung hat dir geholfen und dich nicht noch mehr verwirrt.

Edit: Ja richtig. char block_var[16] = {0} enthält 16 Bytes die alle 0 sind. Du könntest aber auch irgendwas anderes schreiben wie char block_var[] = "mein toller text". Sollte nur mindestens 16 Zeichen lang sein, da dies der Blockgröße entspricht, die RC6 immer aufeinmal verschlüsselt.


----------



## boss3D (29. Dezember 2013)

*AW: [CUDA] RC6*

^^ Danke, ja, die Erklärung hat nochmal sehr geholfen! 

Zur Parallelisierung, um die ich mich jetzt kümmern muss, habe ich vorerst folgende Fragen:


> ```
> __global__ void rc6enc(char* block, rc6_ctx_t *s) {
> int b = threadIdx.x;
> rc6_enc(block + 16*b, s);
> ...


1.) Muss ich nicht dazu auch irgendwie den threadIdx.x (wieso heißt das eigentlich "threadIdx", wenn es sich doch um die Indexe der Blöcke handelt?) an die Funktion übergeben? Noch ein int b in die Parameterliste eintragen? Auch in der main?

2.) Wie lasse ich die Blöcke durchlaufen? Könnte ich bei deiner Variante von oben nach der zweiten Zeile in der Funktion noch ein (threadIdx.x)++; anhängen? Bzw. b++; müsste doch nach dem ersten Block dann auch schon reichen?!

3.) Wo genau nehme ich Daten in einer Größe von ~ 100 MB her? Ich dachte, meine Daten wären, was auch immer ich in char block_var[16] = ... reinschreibe?! Aber das können ja nur 15 Zeichen (+ '\0') sein?!

*[EDIT]*
Habe gerade noch dein Edit gelesen: Bei mir kann ich maximal 15 Zeichen einsetzen. Mit der Nullterminierung sind's dann 16, und das war's. Wenn ich mehr Zeichen einsetze, wie z. B. "mein toller text", kommt ein Error, dass ich nicht 17 Zeichen nehmen könne, um ein 16 Zeichen char Feld zu initialisieren.


----------



## sebi707 (29. Dezember 2013)

*AW: [CUDA] RC6*

1) Nein das threadId.x wird von CUDA bereitgestellt und muss nicht übergeben werden. Die Variable heißt schon richtig, da der zweite Paramter in den <<<x, y>>> Klammern die Anzahl der Threads angibt. Es gibt neben Threads aber auch noch Blöcke in CUDA (nicht mit den Blöcken von RC6 zu verwechseln). Blöcke wirst du später auch noch brauchen, da es ein Limit von 512 Threads (oder 256 Threads weiß grade nicht genau und kommt auch auf die Hardware an) pro CUDA Block gibt. Rechnet man also 16 Byte * 512 Threads dann ist man grade mal bei 8KB. Um also irgendwas in der nähe von 100MB zu verarbeiten würde man nicht nur einen Block starten sondern auch noch einige Hundert Blöcke mit jeweils 512 Threads (oder auch weniger Threads pro Block aber dafür mehr Blöcke, muss man dann testen was am schnellsten ist). Um den aktuellen Block zu identifizieren gibts dann auch die automatisch bereitgestellte Variable blockIdx.x.

2) Die Blöcke laufen automatisch durch. Du musst dir vorstellen die rc6enc läuft schon parallel auf der GPU und in jeder Variante hat threadIdx.x einen anderen Wert. Wenn du später auch noch die Blöcke berücksichten willst dann sieht die Berechnung etwa so aus:
int b = blockIdx.x * blockDim.x + threadIdx.x;
Der Name blockDim ist meiner meinung nach etwas verwirrend gewählt aber gibt die Anzahl der Threads pro Block an (also der zweite Parameter bei <<<x, y>>>). Wenn man darüber etwas nachdenkt sollte einem klar werden, dass so alle Werte durchlaufen werden. Die ganzen Variablen haben übrigens mehere Komponenten daher steht immer noch das .x dahinter. Für mehrdimensionale Arrays ist das ganz praktisch aber das brauchen wir hier nicht.

3) Die Größe von 100MB muss natürlich wenigstens auf der GPU reserviert werden. Wenn dich eh nicht interessiert was verschlüsselt wird dann kannst du die block_var[] Variable auf der CPU einfach weglassen und dann nur die block Variable mit der gewünschten Größe reservieren. Statt cudaMemcpy kannst du dann cudaMemset benutzen um alle Bytes auf 0 zu setzen. Ich würde dir raten am Anfang der main() Funktion eine Variable int threads oder so anzulegen, um die Anzahl der Threads feszulegen. Dann kannst du einfach 16*threads Bytes für die block Variable reservieren und das auch als Parameter benutzten. Also rc6enc<<<1,threads>>>(block, s). Dann kannst du einfach mit der Anzahl der Threads spielen und den optimalen Wert für deine GPU finden. Das gleiche dann später auch für die Anzahl der CUDA-Blöcke.

Edit: Wenn du schon mehr als 16 Zeichen in ein char block_var[16] schreiben willst dann musst du natürlich auch das Array größer wählen. Leider kannst du nicht sowas wie char block_var[16*threads] schreiben sondern musst das dynamisch reservieren. Also char* block_var = (char*)malloc(16*threads); Dann funktioniert allerdings das sizeof(block_var) nicht mehr wie gewünscht sondern gibt nur noch die größe des Pointers zurück und nicht die Größe des Speicherbereichs. In dem Code kommt jedenfalls irgendwo sizeof(block_var) vor. Da muss dann auch überall 16*threads stehen.


----------



## boss3D (29. Dezember 2013)

*AW: [CUDA] RC6*

Okay, klingt gar nicht sooo schwer. Ich war auch gerade dabei, mir das mit den Blöcken und Threads noch in einem nVidia CUDA PDF genauer anzuschauen. Ich kann mich aber erst heute Nacht damit beschäftigen. Sobald's was neues gibt, melde ich mich. Schon mal vielen Dank bis hierher!


----------



## boss3D (29. Dezember 2013)

*AW: [CUDA] RC6*

Laut Wikipedia kann CUDA bereits seit Version 2.0 1024 Threads pro Block haben. Meine Rechnung ist daher folgende:

100 MB = 104857600 Byte
1 Thread = 16 Byte
1024 Threads = 16384 Bytes
104857600 / 16384 = 6400 Blocks
--> <<<6400,1024>>>

Den Code habe ich daher jetzt erstmal soweit angepasst:

```
#include <cuda_runtime.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include "RC6.h"

#define P32 0xB7E15163
#define Q32 0x9E3779B9

#define HandleError(x) HandleErrorImpl(x, __FILE__, __LINE__)

__device__ __host__ uint32_t rotl32(uint32_t a, uint8_t n){
        n &= 0x1f;
        return ( (a<<n)| (a>>(32-n)) );
}
__device__ __host__ uint32_t rotr32(uint32_t a, uint8_t n){
        n &= 0x1f;
        return ( (a>>n)| (a<<(32-n)) );
}

uint8_t rc6_init(void* key, uint16_t keylength_b, rc6_ctx_t *s){
        return rc6_initl(key, keylength_b, 20, s);
}


uint8_t rc6_initl(void* key, uint16_t keylength_b, uint8_t rounds, rc6_ctx_t *s){
        uint8_t i,j;
        uint16_t v,p,c;
        uint32_t a,b, l=0;
        if (rounds>125)
                return 2;
        if(!(s->S=(uint32_t*)malloc((2*rounds+4)*sizeof(uint32_t))))
                return 1;

        s->rounds=rounds;

        c = keylength_b/32;
        if (keylength_b%32){
                ++c;
                j=(keylength_b%32)/8;
                if(keylength_b%8)
                        ++j;
                for (i=0; i<j; ++i)
                        ((uint8_t*)&l)[i] = ((uint8_t*)key)[(c-1)*4 + i];
        } else {
                l = ((uint32_t*)key)[c-1];
        }

        s->S[0] = P32;
        for(i=1; i<2*rounds+4; ++i){
                s->S[i] = s->S[i-1] + Q32;
        }

        a=b=j=i=0;
        v = 3 * ((c > 2*rounds+4)?c:(2*rounds+4));
        for(p=1; p<=v; ++p){
                a = s->S[i] = rotl32(s->S[i] + a + b, 3);
                if (j==c-1){
                        b = l = rotl32(l+a+b, a+b);
                } else {
                        b = ((uint32_t*)key)[j] = rotl32(((uint32_t*)key)[j]+a+b, a+b);
                }
                i = (i+1) % (2*rounds+4);
                j = (j+1) % c;
        }
        return 0;
}

void rc6_free(rc6_ctx_t *s){
        free(s->S);
}

#define LG_W 5
#define A (((uint32_t*)block)[0])
#define B (((uint32_t*)block)[1])
#define C (((uint32_t*)block)[2])
#define D (((uint32_t*)block)[3])

__device__ void rc6_enc(void* block, rc6_ctx_t *s) {
    uint8_t i;
    uint32_t t,u,x;

    B += s->S[0];
    D += s->S[1];

    for (i=1; i<=s->rounds; ++i){
        t = rotl32(B * (2*B+1), LG_W);
        u = rotl32(D * (2*D+1), LG_W);
        A = rotl32((A ^ t), u) + s->S[2*i];
        C = rotl32((C ^ u), t) + s->S[2*i+1];
        x = A;
        A = B;
        B = C;
        C = D;
        D = x;
    }
    A += s->S[2*s->rounds+2];
    C += s->S[2*s->rounds+3];
}

__device__ void rc6_dec(void* block, rc6_ctx_t *s) {
    uint8_t i;
    uint32_t t,u,x;

    C -= s->S[2*s->rounds+3];
    A -= s->S[2*s->rounds+2];

    for (i=s->rounds; i>0; --i){
        x=D;
        D=C;
        C=B;
        B=A;
        A=x;
        u = rotl32(D * (2*D+1), LG_W);
        t = rotl32(B * (2*B+1), LG_W);
        C = rotr32(C - s->S[2*i+1], t) ^ u;
        A = rotr32(A - s->S[2*i+0], u) ^ t;
    }
    D -= s->S[1];
    B -= s->S[0];
}

__global__ void rc6enc(char* block, rc6_ctx_t *s) {
    [COLOR=royalblue][B]int b = blockIdx.x*blockDim.x + threadIdx.x;[/B]    rc6_enc(block + 16*b, s);
}

__global__ void rc6dec(char* block, rc6_ctx_t *s) {
    [COLOR=royalblue][B]int b = blockIdx.x*blockDim.x + threadIdx.x;[/B]    rc6_enc(block + 16*b, s);
}

inline void HandleErrorImpl(cudaError error, const char* file, int line) {
    if (error != cudaSuccess) {
        printf("%s: %d %s", file, line, cudaGetErrorString(error));
        exit(1);
    }
}

int main(void) {
    char* key = "meingeheimespasswort";
    [COLOR=royalblue][B]int threads = 1024;
    int blocks = 6400;[/B]    rc6_ctx_t s_var;
    rc6_ctx_t *s;
    rc6_init(key, strlen(key), &s_var);
    [COLOR=royalblue][B]char* block_var = (char*)malloc(16*threads);
    block_var = "Gaaaaaaaaaanz laaaaanger Testring";[/B]
    char* block;
    cudaMalloc(&block, sizeof([COLOR=royalblue][B]16*threads[/B]));
    cudaMemcpy(block, &block_var, sizeof([COLOR=royalblue][B]16*threads[/B]), cudaMemcpyHostToDevice);

    rc6_ctx_t tmp = s_var;
    cudaMalloc(&tmp.S, (2*s_var.rounds+4)*sizeof(uint32_t));
    cudaMemcpy(tmp.S, s_var.S, (2*s_var.rounds+4)*sizeof(uint32_t), cudaMemcpyHostToDevice);

    cudaMalloc(&s, sizeof(tmp));
    cudaMemcpy(s, &tmp, sizeof(tmp), cudaMemcpyHostToDevice);

    cudaEvent_t start, stop;
    HandleError(cudaEventCreate(&start));
    HandleError(cudaEventCreate(&stop));
    HandleError(cudaEventRecord( start, 0 ));

    [COLOR=royalblue][B]rc6enc<<<blocks,threads>>>(block, s);
    rc6dec<<<blocks,threads>>>(block, s);[/B]
    HandleError(cudaEventRecord( stop, 0 ));
    HandleError(cudaEventSynchronize( stop ));
    float elapsedTime;
    HandleError(cudaEventElapsedTime( &elapsedTime, start, stop ));

    printf("time: %.4f ms\n", elapsedTime);

    HandleError(cudaEventDestroy( start ));
    HandleError(cudaEventDestroy( stop ));

    cudaFree(s);
    cudaFree(block);

    return 0;
}
```
Bei deinem Punkt 3) und dem Edit blicke ich noch nicht so ganz durch. Das muss ich mir jetzt noch durchüberlegen. Speziell das mit dem Reservieren der 100 MB ...

Auf jeden Fall ist die zeitliche Verbesserung jetzt schon beeindruckend:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



*[Edit]*
Das mit den 100 MB würde wohl so aussehen:

```
cudaMemset( , 0, sizeof(int)*26214400); // = 100 MB (int = 4 Byte)???
```
Mir fehlt nur der Pointer to device memory. Den muss ich mir noch überlegen. Soweit ich das verstehe, wären dann 100 MB im VRAM reserviert, aber es hängt von der Länge meines beliebig gewählten Text-Strings ab, wie viel davon dann tatsächlich belegt wird?! Der Rest bleibt 0er, es werden aber immer die vollen 100 MB verschlüsselt?!
Am Ende könnte es dann sein, dass z. B. 10 KB Text + jede Menge 0er hintendran (bis eben das Ende der 100 MB erreicht ist) verschlüsselt werden, oder?


----------



## sebi707 (29. Dezember 2013)

*AW: [CUDA] RC6*

Wenn du das direkt mit mehreren Blöcken machen willst dann ist diese Berechnung falsch:

```
char* block_var = (char*)malloc(16*threads);
```
Du musst dann natürlich 16*threads*blocks Bytes reservieren. Die Zuweisung

```
block_var = "Gaaaaaaaaaanz laaaaanger Testring";
```
ist auch nicht richtig. Dadurch kopierst du nicht den Text in den grade reservierten Speicher, sondern der block_var Pointer zeigt jetzt auf den Text den du eingegeben hast. Falls du Text kopieren willst bietet sich strcpy an:

```
strcpy(block_var, "langer text"); // aufpassen, dass block_var groß genug ist
```
Da dir die Daten, die verschlüsstelt werden aber eh nicht so wichtig sind kannst du den ganzen krams mit der block_var weglassen und machst nur folgendes:

```
char* block;
cudaMalloc(&block, 16*threads*blocks);
cudaMemset(block, 0, 16*threads*blocks);
```
Statt ein cudaMemcpy aus der block_var setzt du mit cudaMemset einfach den gesamten Speicher auf 0.

Die zeitliche verbesserung ist merkwürdig. Ich vermute fast es gibt wieder irgendwo einen Fehler. Die Zeit sollte bei vielen Threads und Blöcken ja erstmal zunehmen, nur auf die Gesamtdatenmenge bezogen wird es schneller. Ich würde mir dazu 16*threads*blocks/elapsedTime ausgeben lassen. Eventuell das ganze von Byte pro Millisekunde noch in MB pro Sekunde umrechnen. Je mehr MB/s umso besser ist es natürlich.

Laut dieser Liste hier (https://developer.nvidia.com/cuda-gpus) kann  deine 9600M GT nur Compute Capability 1.0. Also wird das wohl nichts mit  1024 Threads pro Block. Die volle Zahl an Threads pro Blocks  auszunutzen macht meistens eh keinen Sinn, da es je nach Hardware das  Optimum bei weniger Threads pro Block und dafür mehr Blöcken liegt. Sobald es dann läuft würde ich also mit der Thread und Blockanzahl etwas rumspielen. Die 100MB sind auch nicht so eng zu sehen aber die Menge an zu verschlüsselten Daten sollte nicht nur bei einigen KB liegen, da dann mehr Zeit fürs Kopieren und Starten der Kernel drauf geht.

Edit: Da hab ich grade auch noch einen Fehler übersehen und einfach mitkopiert. sizeof(16*threads) ist natürlich Quatsch. Das sizeof() muss weg.


----------



## boss3D (30. Dezember 2013)

*AW: [CUDA] RC6*

Also ich habe das jetzt noch gemäß deiner Erklärung geändert, und wenn ich das richtig verstanden habe, werden jetzt 100 MB in lauter 0er ver- und dann wieder entschlüsselt?!

Vorrausgesetzt, der Code und meine "wilde Rechnerei" im printf stimmen, wären wir jetzt auf der 9600M GT bei 27 MB/sec, was ich bei der Hardware für beachtlich halte. 

Die Frage ist halt: Was macht die 9600M GT, wenn mehr Threads angegeben sind, als sie pro Block verarbeiten kann? Rechnet die dann automatisch nur mit 512 Threads und ich verliere 50 MB? Das Benchmarksystem sind dann wie gesagt 2x GTX 560 Ti SLI, die mit den 1024 Threads kein Problem haben sollten ...




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        




```
printf("time: %.f MB/sec\n, ((16*threads*blocks")/1048576)/(elapsedTime*1000));
```


----------



## sebi707 (30. Dezember 2013)

*AW: [CUDA] RC6*

Wenn du mehr Threads pro Block angibst, wie von der Hardware verarbeitet werden können dann startet der Kernel erst gar nicht. Sollte dann hoffentlich eine Fehlermeldung bei einem der HandleError() geben. Eigentlich müsstest du diesen Wert auch noch mal 2 nehmen, da du ja ver- und danach wieder entschlüsselst. Wären wir bei 52MB/s was durchaus annehmbar klingt. Aber wie gesagt ist es nicht besonders sinnvoll die vollen 1024 Threads zu nutzen auch wenn die GPU das kann. Wenn ich mich nicht irre waren 256 Threads bei einer GTX 570 am schnellsten. Aber du musst dann einfach mal an der Anzahl Threads und Blöcke spielen und gucken was am meisten Datendurchsatz bringt. Anzahl der Threads sollte aber eine Zweierpotenz sein. Anzahl der Blöcke ist frei wählbar.

Edit: Ich weiß grade gar nicht ob dein Code so schon auf mehreren GPUs parallel läuft. In dem System womit ich gearbeitet hab waren 2x GTX 570 aber nicht per SLI verbunden glaube ich. Jedenfalls liefen da die Berechnungen immer nur auf einer GPU, außer man kümmert sich extra darum alle GPUs anzusprechen.


----------



## boss3D (30. Dezember 2013)

*AW: [CUDA] RC6*

Ein Problem gibt's noch: Von 1 - 1024 kann ich jede beliebige 2er Potenz für die Threads wählen, ABER wenn ich bei den Blöcken eine gewisse Anzahl überschreite, kommt wieder dieser failure error, den wir schon mal hatten. Ich weiß nicht, wo genau die Grenze liegt, aber ich habe z. B. mal die Threads auf 512 gesetzt und dafür die Anzahl der Blöcke auf 12800 verdoppelt (um immer noch die 100 MB zu haben) --> Error. 

BTW: Wenn ich das richtig verstanden habe, werden jetzt 100 MB in lauter 0er ver- und dann wieder entschlüsselt?!

*[EDIT]*
Der Error ist wieder in der synchronize Zeile (168, siehe Screenshot oben). Habe eben 256 Threads in 25600 Blocks (sind ebenfalls 100 MB) ausprobiert und ihn wieder bekommen. Gibt's in CUDA auch Block-Limits für unterschiedliche Grafikkarten?


----------



## sebi707 (30. Dezember 2013)

*AW: [CUDA] RC6*

Mh laut CUDA Programming Guide liegt das Limit bei 65535 Blöcken bis es dann mit Compute Capability 3 nochmal angehoben wird. Musst du wohl einfach so viele Blöcke nehmen wie noch geht und dann gucken ob die Zeit noch sinnvoll gemessen wird oder schon zu kurz ist. Wenn die Zeit zu kurz ist dann kannst du den Kernel auch einfach häufiger hintereinander aufrufen. Kommt der Fehler eigentlich sofort oder dauert es kurz? Ich weiß, dass zumindest unter Windows der Grafikkarten Treiber abgeschossen wird wenn ein Kernel Aufruf länger als 3 Sekunden oder so dauert. Eventuell gibts sowas unter Linux auch.


----------



## boss3D (30. Dezember 2013)

*AW: [CUDA] RC6*

Ich bin hier unter Kubuntu 13.10 unterwegs ... und es dauert immer ziemlich lange (bei sehr hoher Block-Anzahl) bis der Fehler kommt. Eben musste ich den Laptop "gewaltsam" neustarten, weil sich gleich alles aufgehängt hatte.


----------



## sebi707 (30. Dezember 2013)

*AW: [CUDA] RC6*

Ja vermutlich wird dann der Kernelaufruf einfach abgebrochen weil er zu lange dauert. Statt die Blockanzahl weiter zu erhöhen dann einfach den Kernel mehrmals nacheinander starten. Das ganze jedenfalls irgendwie so wählen, dass die Messdauer ein paar Sekunden beträgt.


----------



## boss3D (30. Dezember 2013)

*AW: [CUDA] RC6*

Wahrscheinlich habe ich wieder einen Denkfehler, aber wenn ich z. B. sage: 256 Threads und 6400 Blocks, dann wären das 25 MB. Wenn ich jetzt also rc6enc und rc6dec jeweils 4 Mal hintereinander aufrufe, dann werden doch immer nur die selben 25 MB ver- und entschlüsselt?! Was, wenn ich aber wirklich 100 MB Daten habe? Dann bleiben 75 MB liegen?!

*[EDIT]*
Nö, geht eh nicht. 256 Threads, 6400 Blocks und 4x enc/dec liefert ebenfalls einen Error: the launch timed out and was terminated

^^ Das einzige, das vernünftig geht, sind 1024 Threads und 6400 Blocks, obwohl meine 9600M GT gar nicht mehr wie 512 Threads schaffen dürfte.


----------



## boss3D (30. Dezember 2013)

*AW: [CUDA] RC6 / Serpent*

*Serpent*

Ich denke, RC6 kann man so lassen?! Sobald ich dann das Benchmarksystem habe, kann ich mit den Anzahlen der Threads und Blocks herumprobieren so viel ich will. Auf der 9600M GT läufts eben nur bis <<<6400,1024>>>, was aber für einen ersten Test ja auch gereicht hat.

Heute habe ich mir gleich einen Serpent Code besorgt, den's zufällig sogar schon in CUDA gab, allerdings musste ich da auch noch genug *hinzufügen*, um den für meine Zwecke anzupassen. Das ist dabei rausgekommen:

Serpent.cu

```
// serpent.cpp - written and placed in the public domain by Wei Dai

/* Adapted for TrueCrypt */

#ifdef TC_WINDOWS_BOOT
#pragma optimize ("t", on)
#endif

// GWAT
//#include "Serpent.h"
#ifndef HEADER_Crypto_Serpent
#define HEADER_Crypto_Serpent

//#include "/home/arthur/Desktop/truecrypt-7.1a-source/Common/Tcdefs.h"
/*
Legal Notice: Some portions of the source code contained in this file were
derived from the source code of Encryption for the Masses 2.02a, which is
Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
Agreement for Encryption for the Masses'. Modifications and additions to
the original source code (contained in this file) and all other portions
of this file are Copyright (c) 2003-2010 TrueCrypt Developers Association
and are governed by the TrueCrypt License 3.0 the full text of which is
contained in the file License.txt included in TrueCrypt binary and source
code distribution packages. */

#ifndef TCDEFS_H
#define TCDEFS_H

#define TC_APP_NAME                                                "TrueCrypt"

// Version displayed to user
#define VERSION_STRING                                        "7.1a"

// Version number to compare against driver
#define VERSION_NUM                                                0x071a

// Release date
#define TC_STR_RELEASE_DATE                                "February 7, 2012"
#define TC_RELEASE_DATE_YEAR                        2012
#define TC_RELEASE_DATE_MONTH                        2

#define BYTES_PER_KB 1024LL
#define BYTES_PER_MB 1048576LL
#define BYTES_PER_GB 1073741824LL
#define BYTES_PER_TB 1099511627776LL
#define BYTES_PER_PB 1125899906842624LL

/* GUI/driver errors */

#define WIDE(x) (LPWSTR)L##x

#ifdef _MSC_VER

typedef __int8 int8;
typedef __int16 int16;
typedef __int32 int32;
typedef unsigned __int8 byte;
typedef unsigned __int16 uint16;
typedef unsigned __int32 uint32;

#ifdef TC_NO_COMPILER_INT64
typedef unsigned __int32        TC_LARGEST_COMPILER_UINT;
#else
typedef unsigned __int64        TC_LARGEST_COMPILER_UINT;
typedef __int64 int64;
typedef unsigned __int64 uint64;
#endif

#else // !_MSC_VER

#include <inttypes.h>
#include <limits.h>
[COLOR=royalblue][B]#include <stdio.h>

#define HandleError(x) HandleErrorImpl(x, __FILE__, __LINE__)[/B]
typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint8_t byte;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;

#if UCHAR_MAX != 0xffU
#error UCHAR_MAX != 0xff
#endif
#define __int8 char

#if USHRT_MAX != 0xffffU
#error USHRT_MAX != 0xffff
#endif
#define __int16 short

#if UINT_MAX != 0xffffffffU
#error UINT_MAX != 0xffffffff
#endif
#define __int32 int

typedef uint64 TC_LARGEST_COMPILER_UINT;

#define BOOL int
#ifndef FALSE
#define FALSE 0
#define TRUE 1
#endif

#endif // !_MSC_VER

#define TC_INT_TYPES_DEFINED

// Integer types required by Cryptolib
typedef unsigned __int8 uint_8t;
typedef unsigned __int16 uint_16t;
typedef unsigned __int32 uint_32t;
#ifndef TC_NO_COMPILER_INT64
typedef uint64 uint_64t;
#endif

typedef union
{
        struct
        {
                unsigned __int32 LowPart;
                unsigned __int32 HighPart;
        };
#ifndef TC_NO_COMPILER_INT64
        uint64 Value;
#endif

} UINT64_STRUCT;

#ifdef TC_WINDOWS_BOOT

#        ifdef __cplusplus
extern "C"
#        endif
void ThrowFatalException (int line);

#        define TC_THROW_FATAL_EXCEPTION        ThrowFatalException (__LINE__)
#elif defined (TC_WINDOWS_DRIVER)
#        define TC_THROW_FATAL_EXCEPTION KeBugCheckEx (SECURITY_SYSTEM, __LINE__, 0, 0, 'TC')
#else
#        define TC_THROW_FATAL_EXCEPTION        *(char *) 0 = 0
#endif

#ifdef TC_WINDOWS_DRIVER

#include <ntifs.h>
#include <ntddk.h>                /* Standard header file for nt drivers */
#include <ntdddisk.h>                /* Standard I/O control codes */

#define TCalloc(size) ((void *) ExAllocatePoolWithTag( NonPagedPool, size, 'MMCT' ))
#define TCfree(memblock) ExFreePoolWithTag( memblock, 'MMCT' )

#define DEVICE_DRIVER

#ifndef BOOL
typedef int BOOL;
#endif

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE !TRUE
#endif

#else                                /* !TC_WINDOWS_DRIVER */

#define TCalloc malloc
#define TCfree free

#ifdef _WIN32

#ifndef TC_LOCAL_WIN32_WINNT_OVERRIDE
#        undef _WIN32_WINNT
#        define        _WIN32_WINNT 0x0501        /* Does not apply to the driver */
#endif

#include <windows.h>                /* Windows header */
#include <commctrl.h>                /* The common controls */
#include <process.h>                /* Process control */
#include <winioctl.h>
#include <stdio.h>                /* For sprintf */

#endif                                /* _WIN32 */

#endif                                /* !TC_WINDOWS_DRIVER */

#ifndef TC_TO_STRING
#        define TC_TO_STRING2(n) #n
#        define TC_TO_STRING(n) TC_TO_STRING2(n)
#endif

#ifdef DEVICE_DRIVER
#        if defined (DEBUG) || 0
#                if 1 // DbgPrintEx is not available on Windows 2000
#                        define Dump DbgPrint
#                else
#                        define Dump(...) DbgPrintEx (DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, __VA_ARGS__)
#                endif
#                define DumpMem(...) DumpMemory (__VA_ARGS__)
#        else
#                define Dump(...)
#                define DumpMem(...)
#        endif
#endif

#if !defined (trace_msg) && !defined (TC_WINDOWS_BOOT)
#        ifdef DEBUG
#                ifdef DEVICE_DRIVER
#                        define trace_msg Dump
#                elif defined (_WIN32)
#                        define trace_msg(...) do { char msg[2048]; _snprintf (msg, sizeof (msg), __VA_ARGS__); OutputDebugString (msg); } while (0)
#                endif
#                define trace_point trace_msg (__FUNCTION__ ":" TC_TO_STRING(__LINE__) "\n")
#        else
#                define trace_msg(...)
#                define trace_point
#        endif
#endif

#ifdef DEVICE_DRIVER
#        define TC_EVENT KEVENT
#        define TC_WAIT_EVENT(EVENT) KeWaitForSingleObject (&EVENT, Executive, KernelMode, FALSE, NULL)
#elif defined (_WIN32)
#        define TC_EVENT HANDLE
#        define TC_WAIT_EVENT(EVENT) WaitForSingleObject (EVENT, INFINITE)
#endif

#ifdef _WIN32
#define burn(mem,size) do { volatile char *burnm = (volatile char *)(mem); int burnc = size; RtlSecureZeroMemory (mem, size); while (burnc--) *burnm++ = 0; } while (0)
#else
#define burn(mem,size) do { volatile char *burnm = (volatile char *)(mem); int burnc = size; while (burnc--) *burnm++ = 0; } while (0)
#endif

// The size of the memory area to wipe is in bytes amd it must be a multiple of 8.
#ifndef TC_NO_COMPILER_INT64
#        define FAST_ERASE64(mem,size) do { volatile uint64 *burnm = (volatile uint64 *)(mem); int burnc = size >> 3; while (burnc--) *burnm++ = 0; } while (0)
#else
#        define FAST_ERASE64(mem,size) do { volatile unsigned __int32 *burnm = (volatile unsigned __int32 *)(mem); int burnc = size >> 2; while (burnc--) *burnm++ = 0; } while (0)
#endif

#ifdef TC_WINDOWS_BOOT
#        ifndef max
#                define max(a,b) (((a) > (b)) ? (a) : (b))
#        endif

#        ifdef __cplusplus
extern "C"
#        endif
void EraseMemory (void *memory, int size);

#        undef burn
#        define burn EraseMemory
#endif

#ifdef MAX_PATH
#define TC_MAX_PATH                MAX_PATH
#else
#define TC_MAX_PATH                260        /* Includes the null terminator */
#endif

#define TC_STR_RELEASED_BY "Released by TrueCrypt Foundation on " TC_STR_RELEASE_DATE

#define MAX_URL_LENGTH        2084 /* Internet Explorer limit. Includes the terminating null character. */

#define TC_HOMEPAGE "http://www.truecrypt.org/"
#define TC_APPLINK "http://www.truecrypt.org/applink?version=" VERSION_STRING
#define TC_APPLINK_SECURE "https://www.truecrypt.org/applink?version=" VERSION_STRING

enum
{
        /* WARNING: ADD ANY NEW CODES AT THE END (DO NOT INSERT THEM BETWEEN EXISTING). DO *NOT* DELETE ANY
        EXISTING CODES! Changing these values or their meanings may cause incompatibility with other versions
        (for example, if a new version of the TrueCrypt installer receives an error code from an installed
        driver whose version is lower, it will report and interpret the error incorrectly). */

        ERR_SUCCESS                                                                = 0,
        ERR_OS_ERROR                                                        = 1,
        ERR_OUTOFMEMORY                                                        = 2,
        ERR_PASSWORD_WRONG                                                = 3,
        ERR_VOL_FORMAT_BAD                                                = 4,
        ERR_DRIVE_NOT_FOUND                                                = 5,
        ERR_FILES_OPEN                                                        = 6,
        ERR_VOL_SIZE_WRONG                                                = 7,
        ERR_COMPRESSION_NOT_SUPPORTED                        = 8,
        ERR_PASSWORD_CHANGE_VOL_TYPE                        = 9,
        ERR_PASSWORD_CHANGE_VOL_VERSION                        = 10,
        ERR_VOL_SEEKING                                                        = 11,
        ERR_VOL_WRITING                                                        = 12,
        ERR_FILES_OPEN_LOCK                                                = 13,
        ERR_VOL_READING                                                        = 14,
        ERR_DRIVER_VERSION                                                = 15,
        ERR_NEW_VERSION_REQUIRED                                = 16,
        ERR_CIPHER_INIT_FAILURE                                        = 17,
        ERR_CIPHER_INIT_WEAK_KEY                                = 18,
        ERR_SELF_TESTS_FAILED                                        = 19,
        ERR_SECTOR_SIZE_INCOMPATIBLE                        = 20,
        ERR_VOL_ALREADY_MOUNTED                                        = 21,
        ERR_NO_FREE_DRIVES                                                = 22,
        ERR_FILE_OPEN_FAILED                                        = 23,
        ERR_VOL_MOUNT_FAILED                                        = 24,
        DEPRECATED_ERR_INVALID_DEVICE                        = 25,
        ERR_ACCESS_DENIED                                                = 26,
        ERR_MODE_INIT_FAILED                                        = 27,
        ERR_DONT_REPORT                                                        = 28,
        ERR_ENCRYPTION_NOT_COMPLETED                        = 29,
        ERR_PARAMETER_INCORRECT                                        = 30,
        ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG        = 31,
        ERR_NONSYS_INPLACE_ENC_INCOMPLETE                = 32,
        ERR_USER_ABORT                                                        = 33
};

#endif         // #ifndef TCDEFS_H

#ifdef __cplusplus
extern "C"
{
#endif

void serpent_set_key(const unsigned __int8 userKey[], int keylen, unsigned __int8 *ks);
void serpent_encrypt(const unsigned __int8 *inBlock, unsigned __int8 *outBlock, unsigned __int8 *ks);
void serpent_decrypt(const unsigned __int8 *inBlock, unsigned __int8 *outBlock, unsigned __int8 *ks);

#ifdef __cplusplus
}
#endif

#endif // HEADER_Crypto_Serpent
//END GWAT

// GWAT
//#include "/home/arthur/Desktop/truecrypt-7.1a-source/Common/Endian.h"
/*
Legal Notice: Some portions of the source code contained in this file were
derived from the source code of Encryption for the Masses 2.02a, which is
Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
Agreement for Encryption for the Masses'. Modifications and additions to
the original source code (contained in this file) and all other portions
of this file are Copyright (c) 2003-2009 TrueCrypt Developers Association
and are governed by the TrueCrypt License 3.0 the full text of which is
contained in the file License.txt included in TrueCrypt binary and source
code distribution packages. */

#ifndef TC_ENDIAN_H
#define TC_ENDIAN_H

//#include "/home/arthur/Desktop/truecrypt-7.1a-source/Common/Tcdefs.h"

#if defined(__cplusplus)
extern "C"
{
#endif

#ifdef _WIN32

#        ifndef LITTLE_ENDIAN
#                define LITTLE_ENDIAN 1234
#        endif
#        ifndef BYTE_ORDER
#                define BYTE_ORDER LITTLE_ENDIAN
#        endif

#elif !defined(BYTE_ORDER)

#        ifdef TC_MACOSX
#                include <machine/endian.h>
#        elif defined (TC_BSD)
#                include <sys/endian.h>
#        elif defined (TC_SOLARIS)
#                include <sys/types.h>
#                define LITTLE_ENDIAN 1234
#                define BIG_ENDIAN 4321
#                ifdef _BIG_ENDIAN
#                        define BYTE_ORDER BIG_ENDIAN
#                else
#                        define BYTE_ORDER LITTLE_ENDIAN
#                endif
#        else
#                include <endian.h>
#        endif

#        ifndef BYTE_ORDER
#                ifndef __BYTE_ORDER
#                        error Byte order cannot be determined (BYTE_ORDER undefined)
#                endif

#                define BYTE_ORDER __BYTE_ORDER
#        endif

#        ifndef LITTLE_ENDIAN
#                define LITTLE_ENDIAN __LITTLE_ENDIAN
#        endif

#        ifndef BIG_ENDIAN
#                define BIG_ENDIAN __BIG_ENDIAN
#        endif

#endif // !BYTE_ORDER

/* Macros to read and write 16, 32, and 64-bit quantities in a portable manner.
These functions are implemented as macros rather than true functions as
the need to adjust the memory pointers makes them somewhat painful to call
in user code */

#define mputInt64(memPtr,data) \
        *memPtr++ = ( unsigned char ) ( ( ( data ) >> 56 ) & 0xFF ), \
        *memPtr++ = ( unsigned char ) ( ( ( data ) >> 48 ) & 0xFF ), \
        *memPtr++ = ( unsigned char ) ( ( ( data ) >> 40 ) & 0xFF ), \
        *memPtr++ = ( unsigned char ) ( ( ( data ) >> 32 ) & 0xFF ), \
        *memPtr++ = ( unsigned char ) ( ( ( data ) >> 24 ) & 0xFF ), \
        *memPtr++ = ( unsigned char ) ( ( ( data ) >> 16 ) & 0xFF ), \
        *memPtr++ = ( unsigned char ) ( ( ( data ) >> 8 ) & 0xFF ), \
        *memPtr++ = ( unsigned char ) ( ( data ) & 0xFF )

#define mputLong(memPtr,data) \
        *memPtr++ = ( unsigned char ) ( ( ( data ) >> 24 ) & 0xFF ), \
        *memPtr++ = ( unsigned char ) ( ( ( data ) >> 16 ) & 0xFF ), \
        *memPtr++ = ( unsigned char ) ( ( ( data ) >> 8 ) & 0xFF ), \
        *memPtr++ = ( unsigned char ) ( ( data ) & 0xFF )

#define mputWord(memPtr,data) \
        *memPtr++ = ( unsigned char ) ( ( ( data ) >> 8 ) & 0xFF ), \
        *memPtr++ = ( unsigned char ) ( ( data ) & 0xFF )

#define mputByte(memPtr,data)        \
        *memPtr++ = ( unsigned char ) data

#define mputBytes(memPtr,data,len) \
        memcpy (memPtr,data,len); \
        memPtr += len;

#define mgetInt64(memPtr)                 \
        ( memPtr += 8, ( ( unsigned __int64 ) memPtr[ -8 ] << 56 ) | ( ( unsigned __int64 ) memPtr[ -7 ] << 48 ) | \
        ( ( unsigned __int64 ) memPtr[ -6 ] << 40 ) | ( ( unsigned __int64 ) memPtr[ -5 ] << 32 ) | \
        ( ( unsigned __int64 ) memPtr[ -4 ] << 24 ) | ( ( unsigned __int64 ) memPtr[ -3 ] << 16 ) | \
         ( ( unsigned __int64 ) memPtr[ -2 ] << 8 ) | ( unsigned __int64 ) memPtr[ -1 ] )

#define mgetLong(memPtr)                 \
        ( memPtr += 4, ( ( unsigned __int32 ) memPtr[ -4 ] << 24 ) | ( ( unsigned __int32 ) memPtr[ -3 ] << 16 ) | \
         ( ( unsigned __int32 ) memPtr[ -2 ] << 8 ) | ( unsigned __int32 ) memPtr[ -1 ] )

#define mgetWord(memPtr)                 \
        ( memPtr += 2, ( unsigned short ) memPtr[ -2 ] << 8 ) | ( ( unsigned short ) memPtr[ -1 ] )

#define mgetByte(memPtr)                \
        ( ( unsigned char ) *memPtr++ )

#if BYTE_ORDER == BIG_ENDIAN
#        define LE16(x) MirrorBytes16(x)
#        define LE32(x) MirrorBytes32(x)
#        define LE64(x) MirrorBytes64(x)
#else
#        define LE16(x) (x)
#        define LE32(x) (x)
#        define LE64(x) (x)
#endif

#if BYTE_ORDER == LITTLE_ENDIAN
#        define BE16(x) MirrorBytes16(x)
#        define BE32(x) MirrorBytes32(x)
#        define BE64(x) MirrorBytes64(x)
#else
#        define BE16(x) (x)
#        define BE32(x) (x)
#        define BE64(x) (x)
#endif

unsigned __int16 MirrorBytes16 (unsigned __int16 x);
unsigned __int32 MirrorBytes32 (unsigned __int32 x);
#ifndef TC_NO_COMPILER_INT64
uint64 MirrorBytes64 (uint64 x);
#endif
void LongReverse ( unsigned __int32 *buffer , unsigned byteCount );

#if defined(__cplusplus)
}
#endif

#endif /* TC_ENDIAN_H */
//END GWAT

#include <memory.h>

// GWAT
#include <cuda.h>
#include <cuda_runtime_api.h>

#if defined(_WIN32) && !defined(_DEBUG)
#include <stdlib.h>
#define rotlFixed _rotl
#define rotrFixed _rotr
#else
#define rotlFixed(x,n) (((x) << (n)) | ((x) >> (32 - (n))))
#define rotrFixed(x,n) (((x) >> (n)) | ((x) << (32 - (n))))
#endif

// linear transformation
#define LT(i,a,b,c,d,e)        {\
        a = rotlFixed(a, 13);        \
        c = rotlFixed(c, 3);         \
        d = rotlFixed(d ^ c ^ (a << 3), 7);         \
        b = rotlFixed(b ^ a ^ c, 1);         \
        a = rotlFixed(a ^ b ^ d, 5);                 \
        c = rotlFixed(c ^ d ^ (b << 7), 22);}

// inverse linear transformation
#define ILT(i,a,b,c,d,e)        {\
        c = rotrFixed(c, 22);        \
        a = rotrFixed(a, 5);         \
        c ^= d ^ (b << 7);        \
        a ^= b ^ d;                 \
        b = rotrFixed(b, 1);         \
        d = rotrFixed(d, 7) ^ c ^ (a << 3);        \
        b ^= a ^ c;                 \
        c = rotrFixed(c, 3);         \
        a = rotrFixed(a, 13);}

// order of output from S-box functions
#define beforeS0(f) f(0,a,b,c,d,e)
#define afterS0(f) f(1,b,e,c,a,d)
#define afterS1(f) f(2,c,b,a,e,d)
#define afterS2(f) f(3,a,e,b,d,c)
#define afterS3(f) f(4,e,b,d,c,a)
#define afterS4(f) f(5,b,a,e,c,d)
#define afterS5(f) f(6,a,c,b,e,d)
#define afterS6(f) f(7,a,c,d,b,e)
#define afterS7(f) f(8,d,e,b,a,c)

// order of output from inverse S-box functions
#define beforeI7(f) f(8,a,b,c,d,e)
#define afterI7(f) f(7,d,a,b,e,c)
#define afterI6(f) f(6,a,b,c,e,d)
#define afterI5(f) f(5,b,d,e,c,a)
#define afterI4(f) f(4,b,c,e,a,d)
#define afterI3(f) f(3,a,b,e,c,d)
#define afterI2(f) f(2,b,d,e,c,a)
#define afterI1(f) f(1,a,b,c,e,d)
#define afterI0(f) f(0,a,d,b,e,c)

// The instruction sequences for the S-box functions
// come from Dag Arne Osvik's paper "Speeding up Serpent".

#define S0(i, r0, r1, r2, r3, r4) \
{ \
r3 ^= r0; \
r4 = r1; \
r1 &= r3; \
r4 ^= r2; \
r1 ^= r0; \
r0 |= r3; \
r0 ^= r4; \
r4 ^= r3; \
r3 ^= r2; \
r2 |= r1; \
r2 ^= r4; \
r4 = ~r4; \
r4 |= r1; \
r1 ^= r3; \
r1 ^= r4; \
r3 |= r0; \
r1 ^= r3; \
r4 ^= r3; \
}

#define I0(i, r0, r1, r2, r3, r4) \
{ \
r2 = ~r2; \
r4 = r1; \
r1 |= r0; \
r4 = ~r4; \
r1 ^= r2; \
r2 |= r4; \
r1 ^= r3; \
r0 ^= r4; \
r2 ^= r0; \
r0 &= r3; \
r4 ^= r0; \
r0 |= r1; \
r0 ^= r2; \
r3 ^= r4; \
r2 ^= r1; \
r3 ^= r0; \
r3 ^= r1; \
r2 &= r3; \
r4 ^= r2; \
}

#define S1(i, r0, r1, r2, r3, r4) \
{ \
r0 = ~r0; \
r2 = ~r2; \
r4 = r0; \
r0 &= r1; \
r2 ^= r0; \
r0 |= r3; \
r3 ^= r2; \
r1 ^= r0; \
r0 ^= r4; \
r4 |= r1; \
r1 ^= r3; \
r2 |= r0; \
r2 &= r4; \
r0 ^= r1; \
r1 &= r2; \
r1 ^= r0; \
r0 &= r2; \
r0 ^= r4; \
}

#define I1(i, r0, r1, r2, r3, r4) \
{ \
r4 = r1; \
r1 ^= r3; \
r3 &= r1; \
r4 ^= r2; \
r3 ^= r0; \
r0 |= r1; \
r2 ^= r3; \
r0 ^= r4; \
r0 |= r2; \
r1 ^= r3; \
r0 ^= r1; \
r1 |= r3; \
r1 ^= r0; \
r4 = ~r4; \
r4 ^= r1; \
r1 |= r0; \
r1 ^= r0; \
r1 |= r4; \
r3 ^= r1; \
}

#define S2(i, r0, r1, r2, r3, r4) \
{ \
r4 = r0; \
r0 &= r2; \
r0 ^= r3; \
r2 ^= r1; \
r2 ^= r0; \
r3 |= r4; \
r3 ^= r1; \
r4 ^= r2; \
r1 = r3; \
r3 |= r4; \
r3 ^= r0; \
r0 &= r1; \
r4 ^= r0; \
r1 ^= r3; \
r1 ^= r4; \
r4 = ~r4; \
}

#define I2(i, r0, r1, r2, r3, r4) \
{ \
r2 ^= r3; \
r3 ^= r0; \
r4 = r3; \
r3 &= r2; \
r3 ^= r1; \
r1 |= r2; \
r1 ^= r4; \
r4 &= r3; \
r2 ^= r3; \
r4 &= r0; \
r4 ^= r2; \
r2 &= r1; \
r2 |= r0; \
r3 = ~r3; \
r2 ^= r3; \
r0 ^= r3; \
r0 &= r1; \
r3 ^= r4; \
r3 ^= r0; \
}

#define S3(i, r0, r1, r2, r3, r4) \
{ \
r4 = r0; \
r0 |= r3; \
r3 ^= r1; \
r1 &= r4; \
r4 ^= r2; \
r2 ^= r3; \
r3 &= r0; \
r4 |= r1; \
r3 ^= r4; \
r0 ^= r1; \
r4 &= r0; \
r1 ^= r3; \
r4 ^= r2; \
r1 |= r0; \
r1 ^= r2; \
r0 ^= r3; \
r2 = r1; \
r1 |= r3; \
r1 ^= r0; \
}

#define I3(i, r0, r1, r2, r3, r4) \
{ \
r4 = r2; \
r2 ^= r1; \
r1 &= r2; \
r1 ^= r0; \
r0 &= r4; \
r4 ^= r3; \
r3 |= r1; \
r3 ^= r2; \
r0 ^= r4; \
r2 ^= r0; \
r0 |= r3; \
r0 ^= r1; \
r4 ^= r2; \
r2 &= r3; \
r1 |= r3; \
r1 ^= r2; \
r4 ^= r0; \
r2 ^= r4; \
}

#define S4(i, r0, r1, r2, r3, r4) \
{ \
r1 ^= r3; \
r3 = ~r3; \
r2 ^= r3; \
r3 ^= r0; \
r4 = r1; \
r1 &= r3; \
r1 ^= r2; \
r4 ^= r3; \
r0 ^= r4; \
r2 &= r4; \
r2 ^= r0; \
r0 &= r1; \
r3 ^= r0; \
r4 |= r1; \
r4 ^= r0; \
r0 |= r3; \
r0 ^= r2; \
r2 &= r3; \
r0 = ~r0; \
r4 ^= r2; \
}

#define I4(i, r0, r1, r2, r3, r4) \
{ \
r4 = r2; \
r2 &= r3; \
r2 ^= r1; \
r1 |= r3; \
r1 &= r0; \
r4 ^= r2; \
r4 ^= r1; \
r1 &= r2; \
r0 = ~r0; \
r3 ^= r4; \
r1 ^= r3; \
r3 &= r0; \
r3 ^= r2; \
r0 ^= r1; \
r2 &= r0; \
r3 ^= r0; \
r2 ^= r4; \
r2 |= r3; \
r3 ^= r0; \
r2 ^= r1; \
}

#define S5(i, r0, r1, r2, r3, r4) \
{ \
r0 ^= r1; \
r1 ^= r3; \
r3 = ~r3; \
r4 = r1; \
r1 &= r0; \
r2 ^= r3; \
r1 ^= r2; \
r2 |= r4; \
r4 ^= r3; \
r3 &= r1; \
r3 ^= r0; \
r4 ^= r1; \
r4 ^= r2; \
r2 ^= r0; \
r0 &= r3; \
r2 = ~r2; \
r0 ^= r4; \
r4 |= r3; \
r2 ^= r4; \
}

#define I5(i, r0, r1, r2, r3, r4) \
{ \
r1 = ~r1; \
r4 = r3; \
r2 ^= r1; \
r3 |= r0; \
r3 ^= r2; \
r2 |= r1; \
r2 &= r0; \
r4 ^= r3; \
r2 ^= r4; \
r4 |= r0; \
r4 ^= r1; \
r1 &= r2; \
r1 ^= r3; \
r4 ^= r2; \
r3 &= r4; \
r4 ^= r1; \
r3 ^= r0; \
r3 ^= r4; \
r4 = ~r4; \
}

#define S6(i, r0, r1, r2, r3, r4) \
{ \
r2 = ~r2; \
r4 = r3; \
r3 &= r0; \
r0 ^= r4; \
r3 ^= r2; \
r2 |= r4; \
r1 ^= r3; \
r2 ^= r0; \
r0 |= r1; \
r2 ^= r1; \
r4 ^= r0; \
r0 |= r3; \
r0 ^= r2; \
r4 ^= r3; \
r4 ^= r0; \
r3 = ~r3; \
r2 &= r4; \
r2 ^= r3; \
}

#define I6(i, r0, r1, r2, r3, r4) \
{ \
r0 ^= r2; \
r4 = r2; \
r2 &= r0; \
r4 ^= r3; \
r2 = ~r2; \
r3 ^= r1; \
r2 ^= r3; \
r4 |= r0; \
r0 ^= r2; \
r3 ^= r4; \
r4 ^= r1; \
r1 &= r3; \
r1 ^= r0; \
r0 ^= r3; \
r0 |= r2; \
r3 ^= r1; \
r4 ^= r0; \
}

#define S7(i, r0, r1, r2, r3, r4) \
{ \
r4 = r2; \
r2 &= r1; \
r2 ^= r3; \
r3 &= r1; \
r4 ^= r2; \
r2 ^= r1; \
r1 ^= r0; \
r0 |= r4; \
r0 ^= r2; \
r3 ^= r1; \
r2 ^= r3; \
r3 &= r0; \
r3 ^= r4; \
r4 ^= r2; \
r2 &= r0; \
r4 = ~r4; \
r2 ^= r4; \
r4 &= r0; \
r1 ^= r3; \
r4 ^= r1; \
}

#define I7(i, r0, r1, r2, r3, r4) \
{ \
r4 = r2; \
r2 ^= r0; \
r0 &= r3; \
r2 = ~r2; \
r4 |= r3; \
r3 ^= r1; \
r1 |= r0; \
r0 ^= r2; \
r2 &= r4; \
r1 ^= r2; \
r2 ^= r0; \
r0 |= r2; \
r3 &= r4; \
r0 ^= r3; \
r4 ^= r1; \
r3 ^= r4; \
r4 |= r0; \
r3 ^= r2; \
r4 ^= r2; \
}

// key xor
#define KX(r, a, b, c, d, e)        {\
        a ^= k[4 * r + 0]; \
        b ^= k[4 * r + 1]; \
        c ^= k[4 * r + 2]; \
        d ^= k[4 * r + 3];}


#ifdef TC_MINIMIZE_CODE_SIZE

static void S0f (unsigned __int32 *r0, unsigned __int32 *r1, unsigned __int32 *r2, unsigned __int32 *r3, unsigned __int32 *r4)
{
        *r3 ^= *r0;
        *r4 = *r1;
        *r1 &= *r3;
        *r4 ^= *r2;
        *r1 ^= *r0;
        *r0 |= *r3;
        *r0 ^= *r4;
        *r4 ^= *r3;
        *r3 ^= *r2;
        *r2 |= *r1;
        *r2 ^= *r4;
        *r4 = ~*r4;
        *r4 |= *r1;
        *r1 ^= *r3;
        *r1 ^= *r4;
        *r3 |= *r0;
        *r1 ^= *r3;
        *r4 ^= *r3;
}

static void S1f (unsigned __int32 *r0, unsigned __int32 *r1, unsigned __int32 *r2, unsigned __int32 *r3, unsigned __int32 *r4)
{
    *r0 = ~*r0;
    *r2 = ~*r2;
    *r4 = *r0;
    *r0 &= *r1;
    *r2 ^= *r0;
    *r0 |= *r3;
    *r3 ^= *r2;
    *r1 ^= *r0;
    *r0 ^= *r4;
    *r4 |= *r1;
    *r1 ^= *r3;
    *r2 |= *r0;
    *r2 &= *r4;
    *r0 ^= *r1;
    *r1 &= *r2;
    *r1 ^= *r0;
    *r0 &= *r2;
    *r0 ^= *r4;
}

static void S2f (unsigned __int32 *r0, unsigned __int32 *r1, unsigned __int32 *r2, unsigned __int32 *r3, unsigned __int32 *r4)
{
        *r4 = *r0;
        *r0 &= *r2;
        *r0 ^= *r3;
        *r2 ^= *r1;
        *r2 ^= *r0;
        *r3 |= *r4;
        *r3 ^= *r1;
        *r4 ^= *r2;
        *r1 = *r3;
        *r3 |= *r4;
        *r3 ^= *r0;
        *r0 &= *r1;
        *r4 ^= *r0;
        *r1 ^= *r3;
        *r1 ^= *r4;
        *r4 = ~*r4;
}

static void S3f (unsigned __int32 *r0, unsigned __int32 *r1, unsigned __int32 *r2, unsigned __int32 *r3, unsigned __int32 *r4)
{
        *r4 = *r0;
        *r0 |= *r3;
        *r3 ^= *r1;
        *r1 &= *r4;
        *r4 ^= *r2;
        *r2 ^= *r3;
        *r3 &= *r0;
        *r4 |= *r1;
        *r3 ^= *r4;
        *r0 ^= *r1;
        *r4 &= *r0;
        *r1 ^= *r3;
        *r4 ^= *r2;
        *r1 |= *r0;
        *r1 ^= *r2;
        *r0 ^= *r3;
        *r2 = *r1;
        *r1 |= *r3;
        *r1 ^= *r0;
}

static void S4f (unsigned __int32 *r0, unsigned __int32 *r1, unsigned __int32 *r2, unsigned __int32 *r3, unsigned __int32 *r4)
{
        *r1 ^= *r3;
        *r3 = ~*r3;
        *r2 ^= *r3;
        *r3 ^= *r0;
        *r4 = *r1;
        *r1 &= *r3;
        *r1 ^= *r2;
        *r4 ^= *r3;
        *r0 ^= *r4;
        *r2 &= *r4;
        *r2 ^= *r0;
        *r0 &= *r1;
        *r3 ^= *r0;
        *r4 |= *r1;
        *r4 ^= *r0;
        *r0 |= *r3;
        *r0 ^= *r2;
        *r2 &= *r3;
        *r0 = ~*r0;
        *r4 ^= *r2;
}

static void S5f (unsigned __int32 *r0, unsigned __int32 *r1, unsigned __int32 *r2, unsigned __int32 *r3, unsigned __int32 *r4)
{
        *r0 ^= *r1;
        *r1 ^= *r3;
        *r3 = ~*r3;
        *r4 = *r1;
        *r1 &= *r0;
        *r2 ^= *r3;
        *r1 ^= *r2;
        *r2 |= *r4;
        *r4 ^= *r3;
        *r3 &= *r1;
        *r3 ^= *r0;
        *r4 ^= *r1;
        *r4 ^= *r2;
        *r2 ^= *r0;
        *r0 &= *r3;
        *r2 = ~*r2;
        *r0 ^= *r4;
        *r4 |= *r3;
        *r2 ^= *r4;
}

static void S6f (unsigned __int32 *r0, unsigned __int32 *r1, unsigned __int32 *r2, unsigned __int32 *r3, unsigned __int32 *r4)
{
        *r2 = ~*r2;
        *r4 = *r3;
        *r3 &= *r0;
        *r0 ^= *r4;
        *r3 ^= *r2;
        *r2 |= *r4;
        *r1 ^= *r3;
        *r2 ^= *r0;
        *r0 |= *r1;
        *r2 ^= *r1;
        *r4 ^= *r0;
        *r0 |= *r3;
        *r0 ^= *r2;
        *r4 ^= *r3;
        *r4 ^= *r0;
        *r3 = ~*r3;
        *r2 &= *r4;
        *r2 ^= *r3;
}

static void S7f (unsigned __int32 *r0, unsigned __int32 *r1, unsigned __int32 *r2, unsigned __int32 *r3, unsigned __int32 *r4)
{
        *r4 = *r2;
        *r2 &= *r1;
        *r2 ^= *r3;
        *r3 &= *r1;
        *r4 ^= *r2;
        *r2 ^= *r1;
        *r1 ^= *r0;
        *r0 |= *r4;
        *r0 ^= *r2;
        *r3 ^= *r1;
        *r2 ^= *r3;
        *r3 &= *r0;
        *r3 ^= *r4;
        *r4 ^= *r2;
        *r2 &= *r0;
        *r4 = ~*r4;
        *r2 ^= *r4;
        *r4 &= *r0;
        *r1 ^= *r3;
        *r4 ^= *r1;
}

static void KXf (const unsigned __int32 *k, unsigned int r, unsigned __int32 *a, unsigned __int32 *b, unsigned __int32 *c, unsigned __int32 *d)
{
        *a ^= k[r];
        *b ^= k[r + 1];
        *c ^= k[r + 2];
        *d ^= k[r + 3];
}

#endif // TC_MINIMIZE_CODE_SIZE

#ifndef TC_MINIMIZE_CODE_SIZE

void serpent_set_key(const unsigned __int8 userKey[], int keylen, unsigned __int8 *ks)
{
        unsigned __int32 a,b,c,d,e;
        unsigned __int32 *k = (unsigned __int32 *)ks;
        unsigned __int32 t;
        int i;

        for (i = 0; i < keylen / (int)sizeof(__int32); i++)
                k[i] = LE32(((unsigned __int32*)userKey)[i]);

        if (keylen < 32)
                k[keylen/4] |= (unsigned __int32)1 << ((keylen%4)*8);

        k += 8;
        t = k[-1];
        for (i = 0; i < 132; ++i)
                k[i] = t = rotlFixed(k[i-8] ^ k[i-5] ^ k[i-3] ^ t ^ 0x9e3779b9 ^ i, 11);
        k -= 20;

#define LK(r, a, b, c, d, e)        {\
        a = k[(8-r)*4 + 0];                \
        b = k[(8-r)*4 + 1];                \
        c = k[(8-r)*4 + 2];                \
        d = k[(8-r)*4 + 3];}

#define SK(r, a, b, c, d, e)        {\
        k[(8-r)*4 + 4] = a;                \
        k[(8-r)*4 + 5] = b;                \
        k[(8-r)*4 + 6] = c;                \
        k[(8-r)*4 + 7] = d;}        \

        for (i=0; i<4; i++)
        {
                afterS2(LK); afterS2(S3); afterS3(SK);
                afterS1(LK); afterS1(S2); afterS2(SK);
                afterS0(LK); afterS0(S1); afterS1(SK);
                beforeS0(LK); beforeS0(S0); afterS0(SK);
                k += 8*4;
                afterS6(LK); afterS6(S7); afterS7(SK);
                afterS5(LK); afterS5(S6); afterS6(SK);
                afterS4(LK); afterS4(S5); afterS5(SK);
                afterS3(LK); afterS3(S4); afterS4(SK);
        }
        afterS2(LK); afterS2(S3); afterS3(SK);
}

#else // TC_MINIMIZE_CODE_SIZE

static void LKf (unsigned __int32 *k, unsigned int r, unsigned __int32 *a, unsigned __int32 *b, unsigned __int32 *c, unsigned __int32 *d)
{
        *a = k[r];
        *b = k[r + 1];
        *c = k[r + 2];
        *d = k[r + 3];
}

static void SKf (unsigned __int32 *k, unsigned int r, unsigned __int32 *a, unsigned __int32 *b, unsigned __int32 *c, unsigned __int32 *d)
{
        k[r + 4] = *a;
        k[r + 5] = *b;
        k[r + 6] = *c;
        k[r + 7] = *d;
}

void serpent_set_key(const unsigned __int8 userKey[], int keylen, unsigned __int8 *ks)
{
        unsigned __int32 a,b,c,d,e;
        unsigned __int32 *k = (unsigned __int32 *)ks;
        unsigned __int32 t;
        int i;

        for (i = 0; i < keylen / (int)sizeof(__int32); i++)
                k[i] = LE32(((unsigned __int32*)userKey)[i]);

        if (keylen < 32)
                k[keylen/4] |= (unsigned __int32)1 << ((keylen%4)*8);

        k += 8;
        t = k[-1];
        for (i = 0; i < 132; ++i)
                k[i] = t = rotlFixed(k[i-8] ^ k[i-5] ^ k[i-3] ^ t ^ 0x9e3779b9 ^ i, 11);
        k -= 20;

        for (i=0; i<4; i++)
        {
                LKf (k, 20, &a, &e, &b, &d); S3f (&a, &e, &b, &d, &c); SKf (k, 16, &e, &b, &d, &c);
                LKf (k, 24, &c, &b, &a, &e); S2f (&c, &b, &a, &e, &d); SKf (k, 20, &a, &e, &b, &d);
                LKf (k, 28, &b, &e, &c, &a); S1f (&b, &e, &c, &a, &d); SKf (k, 24, &c, &b, &a, &e);
                LKf (k, 32, &a, &b, &c, &d); S0f (&a, &b, &c, &d, &e); SKf (k, 28, &b, &e, &c, &a);
                k += 8*4;
                LKf (k, 4, &a, &c, &d, &b); S7f (&a, &c, &d, &b, &e); SKf (k, 0, &d, &e, &b, &a);
                LKf (k, 8, &a, &c, &b, &e); S6f (&a, &c, &b, &e, &d); SKf (k, 4, &a, &c, &d, &b);
                LKf (k, 12, &b, &a, &e, &c); S5f (&b, &a, &e, &c, &d); SKf (k, 8, &a, &c, &b, &e);
                LKf (k, 16, &e, &b, &d, &c); S4f (&e, &b, &d, &c, &a); SKf (k, 12, &b, &a, &e, &c);
        }
        LKf (k, 20, &a, &e, &b, &d); S3f (&a, &e, &b, &d, &c); SKf (k, 16, &e, &b, &d, &c);
}

#endif // TC_MINIMIZE_CODE_SIZE


#ifndef TC_MINIMIZE_CODE_SIZE

[COLOR=royalblue][B]__device__[/B] void serpent_encrypt(const unsigned __int8 *inBlock, unsigned __int8 *outBlock, unsigned __int8 *ks)
{
        unsigned __int32 a, b, c, d, e;
        unsigned int i=1;
        const unsigned __int32 *k = (unsigned __int32 *)ks + 8;
        unsigned __int32 *in = (unsigned __int32 *) inBlock;
        unsigned __int32 *out = (unsigned __int32 *) outBlock;

    a = LE32(in[0]);
        b = LE32(in[1]);
        c = LE32(in[2]);
        d = LE32(in[3]);

        do
        {
                beforeS0(KX); beforeS0(S0); afterS0(LT);
                afterS0(KX); afterS0(S1); afterS1(LT);
                afterS1(KX); afterS1(S2); afterS2(LT);
                afterS2(KX); afterS2(S3); afterS3(LT);
                afterS3(KX); afterS3(S4); afterS4(LT);
                afterS4(KX); afterS4(S5); afterS5(LT);
                afterS5(KX); afterS5(S6); afterS6(LT);
                afterS6(KX); afterS6(S7);

                if (i == 4)
                        break;

                ++i;
                c = b;
                b = e;
                e = d;
                d = a;
                a = e;
                k += 32;
                beforeS0(LT);
        }
        while (1);

        afterS7(KX);

    out[0] = LE32(d);
        out[1] = LE32(e);
        out[2] = LE32(b);
        out[3] = LE32(a);
}

#else // TC_MINIMIZE_CODE_SIZE

typedef unsigned __int32 uint32;

static void LTf (uint32 *a, uint32 *b, uint32 *c, uint32 *d)
{
        *a = rotlFixed(*a, 13);
        *c = rotlFixed(*c, 3);
        *d = rotlFixed(*d ^ *c ^ (*a << 3), 7);
        *b = rotlFixed(*b ^ *a ^ *c, 1);
        *a = rotlFixed(*a ^ *b ^ *d, 5);
        *c = rotlFixed(*c ^ *d ^ (*b << 7), 22);
}

[COLOR=royalblue][B]__device__[/B] void serpent_encrypt(const unsigned __int8 *inBlock, unsigned __int8 *outBlock, unsigned __int8 *ks)
{
        unsigned __int32 a, b, c, d, e;
        unsigned int i=1;
        const unsigned __int32 *k = (unsigned __int32 *)ks + 8;
        unsigned __int32 *in = (unsigned __int32 *) inBlock;
        unsigned __int32 *out = (unsigned __int32 *) outBlock;

    a = LE32(in[0]);
        b = LE32(in[1]);
        c = LE32(in[2]);
        d = LE32(in[3]);

        do
        {
                KXf (k, 0, &a, &b, &c, &d); S0f (&a, &b, &c, &d, &e); LTf (&b, &e, &c, &a);
                KXf (k, 4, &b, &e, &c, &a); S1f (&b, &e, &c, &a, &d); LTf (&c, &b, &a, &e);
                KXf (k, 8, &c, &b, &a, &e); S2f (&c, &b, &a, &e, &d); LTf (&a, &e, &b, &d);
                KXf (k, 12, &a, &e, &b, &d); S3f (&a, &e, &b, &d, &c); LTf (&e, &b, &d, &c);
                KXf (k, 16, &e, &b, &d, &c); S4f (&e, &b, &d, &c, &a); LTf (&b, &a, &e, &c);
                KXf (k, 20, &b, &a, &e, &c); S5f (&b, &a, &e, &c, &d); LTf (&a, &c, &b, &e);
                KXf (k, 24, &a, &c, &b, &e); S6f (&a, &c, &b, &e, &d); LTf (&a, &c, &d, &b);
                KXf (k, 28, &a, &c, &d, &b); S7f (&a, &c, &d, &b, &e);

                if (i == 4)
                        break;

                ++i;
                c = b;
                b = e;
                e = d;
                d = a;
                a = e;
                k += 32;
                LTf (&a,&b,&c,&d);
        }
        while (1);

        KXf (k, 32, &d, &e, &b, &a);

    out[0] = LE32(d);
        out[1] = LE32(e);
        out[2] = LE32(b);
        out[3] = LE32(a);
}

#endif // TC_MINIMIZE_CODE_SIZE

#if !defined (TC_MINIMIZE_CODE_SIZE) || defined (TC_WINDOWS_BOOT_SERPENT)

[COLOR=royalblue][B]__device__[/B] void serpent_decrypt(const unsigned __int8 *inBlock, unsigned __int8 *outBlock, unsigned __int8 *ks)
{
        unsigned __int32 a, b, c, d, e;
        const unsigned __int32 *k = (unsigned __int32 *)ks + 104;
        unsigned int i=4;
        unsigned __int32 *in = (unsigned __int32 *) inBlock;
        unsigned __int32 *out = (unsigned __int32 *) outBlock;

    a = LE32(in[0]);
        b = LE32(in[1]);
        c = LE32(in[2]);
        d = LE32(in[3]);

        beforeI7(KX);
        goto start;

        do
        {
                c = b;
                b = d;
                d = e;
                k -= 32;
                beforeI7(ILT);
start:
                beforeI7(I7); afterI7(KX);
                afterI7(ILT); afterI7(I6); afterI6(KX);
                afterI6(ILT); afterI6(I5); afterI5(KX);
                afterI5(ILT); afterI5(I4); afterI4(KX);
                afterI4(ILT); afterI4(I3); afterI3(KX);
                afterI3(ILT); afterI3(I2); afterI2(KX);
                afterI2(ILT); afterI2(I1); afterI1(KX);
                afterI1(ILT); afterI1(I0); afterI0(KX);
        }
        while (--i != 0);

    out[0] = LE32(a);
        out[1] = LE32(d);
        out[2] = LE32(b);
        out[3] = LE32(e);
}

#else // TC_MINIMIZE_CODE_SIZE && !TC_WINDOWS_BOOT_SERPENT

static void ILTf (uint32 *a, uint32 *b, uint32 *c, uint32 *d)
{
        *c = rotrFixed(*c, 22);
        *a = rotrFixed(*a, 5);
        *c ^= *d ^ (*b << 7);
        *a ^= *b ^ *d;
        *b = rotrFixed(*b, 1);
        *d = rotrFixed(*d, 7) ^ *c ^ (*a << 3);
        *b ^= *a ^ *c;
        *c = rotrFixed(*c, 3);
        *a = rotrFixed(*a, 13);
}

[COLOR=royalblue][B]__device__[/B] void serpent_decrypt(const unsigned __int8 *inBlock, unsigned __int8 *outBlock, unsigned __int8 *ks)
{
        unsigned __int32 a, b, c, d, e;
        const unsigned __int32 *k = (unsigned __int32 *)ks + 104;
        unsigned int i=4;
        unsigned __int32 *in = (unsigned __int32 *) inBlock;
        unsigned __int32 *out = (unsigned __int32 *) outBlock;

    a = LE32(in[0]);
        b = LE32(in[1]);
        c = LE32(in[2]);
        d = LE32(in[3]);

        KXf (k, 32, &a, &b, &c, &d);
        goto start;

        do
        {
                c = b;
                b = d;
                d = e;
                k -= 32;
                beforeI7(ILT);
start:
                beforeI7(I7); KXf (k, 28, &d, &a, &b, &e);
                ILTf (&d, &a, &b, &e); afterI7(I6); KXf (k, 24, &a, &b, &c, &e);
                ILTf (&a, &b, &c, &e); afterI6(I5); KXf (k, 20, &b, &d, &e, &c);
                ILTf (&b, &d, &e, &c); afterI5(I4); KXf (k, 16, &b, &c, &e, &a);
                ILTf (&b, &c, &e, &a); afterI4(I3); KXf (k, 12, &a, &b, &e, &c);
                ILTf (&a, &b, &e, &c); afterI3(I2); KXf (k, 8, &b, &d, &e, &c);
                ILTf (&b, &d, &e, &c); afterI2(I1); KXf (k, 4, &a, &b, &c, &e);
                ILTf (&a, &b, &c, &e); afterI1(I0); KXf (k, 0, &a, &d, &b, &e);
        }
        while (--i != 0);

    out[0] = LE32(a);
        out[1] = LE32(d);
        out[2] = LE32(b);
        out[3] = LE32(e);
}

#endif // TC_MINIMIZE_CODE_SIZE && !TC_WINDOWS_BOOT_SERPENT

[COLOR=royalblue][B]__global__ void serpent_enc(const unsigned __int8 *inBlock, unsigned __int8 *outBlock, unsigned __int8 *ks) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    serpent_encrypt(inBlock + 16*b, outBlock + 16*b, ks);
}

__global__ void serpent_dec(const unsigned __int8 *inBlock, unsigned __int8 *outBlock, unsigned __int8 *ks) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    serpent_decrypt(inBlock + 16*b, outBlock + 16*b, ks);
}

inline void HandleErrorImpl(cudaError error, const char* file, int line) {
    if (error != cudaSuccess) {
        printf("%s: %d %s", file, line, cudaGetErrorString(error));
        exit(1);
    }
}[/B]
[COLOR=royalblue][B]int main(void) {
    unsigned ks_var;
    int threads = 1024;
    int blocks = 6400;

    unsigned __int8 *inBlock;
    cudaMalloc(&inBlock, 16*threads*blocks);
    cudaMemcpy(inBlock, 0, 16*threads*blocks, cudaMemcpyHostToDevice);

    unsigned __int8 *outBlock;
    cudaMalloc(&outBlock, 16*threads*blocks);
    [COLOR=seagreen]cudaMemcpy(outBlock, 0, 16*threads*blocks, cudaMemcpyHostToDevice);
    unsigned __int8 *ks;
    cudaMalloc(&ks, sizeof(ks_var));
    cudaMemcpy(ks, &ks_var, sizeof(ks_var), cudaMemcpyHostToDevice);

    cudaEvent_t start, stop;
    HandleError(cudaEventCreate(&start));
    HandleError(cudaEventCreate(&stop));
    HandleError(cudaEventRecord( start, 0 ));

    serpent_enc<<<blocks,threads>>>(inBlock, outBlock, ks);
    serpent_dec<<<blocks,threads>>>(inBlock, outBlock, ks);

    HandleError(cudaEventRecord( stop, 0 ));
    HandleError(cudaEventSynchronize( stop ));
    float elapsedTime;
    HandleError(cudaEventElapsedTime( &elapsedTime, start, stop ));

    printf("Performance: %.f MB/sec\n", 2*((16*threads*blocks)/1048576)/(elapsedTime*1000));

    HandleError(cudaEventDestroy( start ));
    HandleError(cudaEventDestroy( stop ));
    
    cudaFree(inBlock);
    cudaFree(outBlock);
    cudaFree(ks);

    return 0;[/B][COLOR=royalblue][B]}[/B]
```
Serpent.h


```
#ifndef HEADER_Crypto_Serpent
#define HEADER_Crypto_Serpent

#include "Tcdefs.h"

#ifdef __cplusplus
extern "C"
{
#endif

void serpent_set_key(const unsigned __int8 userKey[], int keylen, unsigned __int8 *ks);
[COLOR=royalblue][B]__device__[/B] void serpent_encrypt(const unsigned __int8 *inBlock, unsigned __int8 *outBlock, unsigned __int8 *ks);
[COLOR=royalblue][B]__device__[/B] void serpent_decrypt(const unsigned __int8 *inBlock, unsigned __int8 *outBlock, unsigned __int8 *ks);

#ifdef __cplusplus
}
#endif

#endif // HEADER_Crypto_Serpent
```
Tcdef.h


```
/*
Legal Notice: Some portions of the source code contained in this file were
derived from the source code of Encryption for the Masses 2.02a, which is
Copyright (c) 1998-2000 Paul Le Roux and which is governed by the 'License
Agreement for Encryption for the Masses'. Modifications and additions to
the original source code (contained in this file) and all other portions
of this file are Copyright (c) 2003-2010 TrueCrypt Developers Association
and are governed by the TrueCrypt License 3.0 the full text of which is
contained in the file License.txt included in TrueCrypt binary and source
code distribution packages. */

#ifndef TCDEFS_H
#define TCDEFS_H

#define TC_APP_NAME                                                "TrueCrypt"

// Version displayed to user
#define VERSION_STRING                                        "7.1"

// Version number to compare against driver
#define VERSION_NUM                                                0x0710

// Release date
#define TC_STR_RELEASE_DATE                                "September 1, 2011"
#define TC_RELEASE_DATE_YEAR                        2011
#define TC_RELEASE_DATE_MONTH                        9

#define BYTES_PER_KB 1024LL
#define BYTES_PER_MB 1048576LL
#define BYTES_PER_GB 1073741824LL
#define BYTES_PER_TB 1099511627776LL
#define BYTES_PER_PB 1125899906842624LL

/* GUI/driver errors */

#define WIDE(x) (LPWSTR)L##x

#ifdef _MSC_VER

typedef __int8 int8;
typedef __int16 int16;
typedef __int32 int32;
typedef unsigned __int8 byte;
typedef unsigned __int16 uint16;
typedef unsigned __int32 uint32;

#ifdef TC_NO_COMPILER_INT64
typedef unsigned __int32        TC_LARGEST_COMPILER_UINT;
#else
typedef unsigned __int64        TC_LARGEST_COMPILER_UINT;
typedef __int64 int64;
typedef unsigned __int64 uint64;
#endif

#else // !_MSC_VER

#include <inttypes.h>
#include <limits.h>

typedef int8_t int8;
typedef int16_t int16;
typedef int32_t int32;
typedef int64_t int64;
typedef uint8_t byte;
typedef uint16_t uint16;
typedef uint32_t uint32;
typedef uint64_t uint64;

#if UCHAR_MAX != 0xffU
#error UCHAR_MAX != 0xff
#endif
#define __int8 char

#if USHRT_MAX != 0xffffU
#error USHRT_MAX != 0xffff
#endif
#define __int16 short

#if UINT_MAX != 0xffffffffU
#error UINT_MAX != 0xffffffff
#endif
#define __int32 int

typedef uint64 TC_LARGEST_COMPILER_UINT;

#define BOOL int
#ifndef FALSE
#define FALSE 0
#define TRUE 1
#endif

#endif // !_MSC_VER

#define TC_INT_TYPES_DEFINED

// Integer types required by Cryptolib
typedef unsigned __int8 uint_8t;
typedef unsigned __int16 uint_16t;
typedef unsigned __int32 uint_32t;
#ifndef TC_NO_COMPILER_INT64
typedef uint64 uint_64t;
#endif

typedef union
{
        struct
        {
                unsigned __int32 LowPart;
                unsigned __int32 HighPart;
        };
#ifndef TC_NO_COMPILER_INT64
        uint64 Value;
#endif

} UINT64_STRUCT;

#ifdef TC_WINDOWS_BOOT

#        ifdef __cplusplus
extern "C"
#        endif
void ThrowFatalException (int line);

#        define TC_THROW_FATAL_EXCEPTION        ThrowFatalException (__LINE__)
#elif defined (TC_WINDOWS_DRIVER)
#        define TC_THROW_FATAL_EXCEPTION KeBugCheckEx (SECURITY_SYSTEM, __LINE__, 0, 0, 'TC')
#else
#        define TC_THROW_FATAL_EXCEPTION        *(char *) 0 = 0
#endif

#ifdef TC_WINDOWS_DRIVER

#include <ntifs.h>
#include <ntddk.h>                /* Standard header file for nt drivers */
#include <ntdddisk.h>                /* Standard I/O control codes */

#define TCalloc(size) ((void *) ExAllocatePoolWithTag( NonPagedPool, size, 'MMCT' ))
#define TCfree(memblock) ExFreePoolWithTag( memblock, 'MMCT' )

#define DEVICE_DRIVER

#ifndef BOOL
typedef int BOOL;
#endif

#ifndef TRUE
#define TRUE 1
#endif

#ifndef FALSE
#define FALSE !TRUE
#endif

#else                                /* !TC_WINDOWS_DRIVER */

#define TCalloc malloc
#define TCfree free

#ifdef _WIN32

#ifndef TC_LOCAL_WIN32_WINNT_OVERRIDE
#        undef _WIN32_WINNT
#        define        _WIN32_WINNT 0x0501        /* Does not apply to the driver */
#endif

#include <windows.h>                /* Windows header */
#include <commctrl.h>                /* The common controls */
#include <process.h>                /* Process control */
#include <winioctl.h>
#include <stdio.h>                /* For sprintf */

#endif                                /* _WIN32 */

#endif                                /* !TC_WINDOWS_DRIVER */

#ifndef TC_TO_STRING
#        define TC_TO_STRING2(n) #n
#        define TC_TO_STRING(n) TC_TO_STRING2(n)
#endif

#ifdef DEVICE_DRIVER
#        if defined (DEBUG) || 0
#                if 1 // DbgPrintEx is not available on Windows 2000
#                        define Dump DbgPrint
#                else
#                        define Dump(...) DbgPrintEx (DPFLTR_IHVDRIVER_ID, DPFLTR_ERROR_LEVEL, __VA_ARGS__)
#                endif
#                define DumpMem(...) DumpMemory (__VA_ARGS__)
#        else
#                define Dump(...)
#                define DumpMem(...)
#        endif
#endif

#if !defined (trace_msg) && !defined (TC_WINDOWS_BOOT)
#        ifdef DEBUG
#                ifdef DEVICE_DRIVER
#                        define trace_msg Dump
#                elif defined (_WIN32)
#                        define trace_msg(...) do { char msg[2048]; _snprintf (msg, sizeof (msg), __VA_ARGS__); OutputDebugString (msg); } while (0)
#                endif
#                define trace_point trace_msg (__FUNCTION__ ":" TC_TO_STRING(__LINE__) "\n")
#        else
#                define trace_msg(...)
#                define trace_point
#        endif
#endif

#ifdef DEVICE_DRIVER
#        define TC_EVENT KEVENT
#        define TC_WAIT_EVENT(EVENT) KeWaitForSingleObject (&EVENT, Executive, KernelMode, FALSE, NULL)
#elif defined (_WIN32)
#        define TC_EVENT HANDLE
#        define TC_WAIT_EVENT(EVENT) WaitForSingleObject (EVENT, INFINITE)
#endif

#ifdef _WIN32
#define burn(mem,size) do { volatile char *burnm = (volatile char *)(mem); int burnc = size; RtlSecureZeroMemory (mem, size); while (burnc--) *burnm++ = 0; } while (0)
#else
#define burn(mem,size) do { volatile char *burnm = (volatile char *)(mem); int burnc = size; while (burnc--) *burnm++ = 0; } while (0)
#endif

// The size of the memory area to wipe is in bytes amd it must be a multiple of 8.
#ifndef TC_NO_COMPILER_INT64
#        define FAST_ERASE64(mem,size) do { volatile uint64 *burnm = (volatile uint64 *)(mem); int burnc = size >> 3; while (burnc--) *burnm++ = 0; } while (0)
#else
#        define FAST_ERASE64(mem,size) do { volatile unsigned __int32 *burnm = (volatile unsigned __int32 *)(mem); int burnc = size >> 2; while (burnc--) *burnm++ = 0; } while (0)
#endif

#ifdef TC_WINDOWS_BOOT
#        ifndef max
#                define max(a,b) (((a) > (b)) ? (a) : (b))
#        endif

#        ifdef __cplusplus
extern "C"
#        endif
void EraseMemory (void *memory, int size);

#        undef burn
#        define burn EraseMemory
#endif

#ifdef MAX_PATH
#define TC_MAX_PATH                MAX_PATH
#else
#define TC_MAX_PATH                260        /* Includes the null terminator */
#endif

#define TC_STR_RELEASED_BY "Released by TrueCrypt Foundation on " TC_STR_RELEASE_DATE

#define MAX_URL_LENGTH        2084 /* Internet Explorer limit. Includes the terminating null character. */

#define TC_HOMEPAGE "http://www.truecrypt.org/"
#define TC_APPLINK "http://www.truecrypt.org/applink?version=" VERSION_STRING
#define TC_APPLINK_SECURE "https://www.truecrypt.org/applink?version=" VERSION_STRING

enum
{
        /* WARNING: ADD ANY NEW CODES AT THE END (DO NOT INSERT THEM BETWEEN EXISTING). DO *NOT* DELETE ANY
        EXISTING CODES! Changing these values or their meanings may cause incompatibility with other versions
        (for example, if a new version of the TrueCrypt installer receives an error code from an installed
        driver whose version is lower, it will report and interpret the error incorrectly). */

        ERR_SUCCESS                                                                = 0,
        ERR_OS_ERROR                                                        = 1,
        ERR_OUTOFMEMORY                                                        = 2,
        ERR_PASSWORD_WRONG                                                = 3,
        ERR_VOL_FORMAT_BAD                                                = 4,
        ERR_DRIVE_NOT_FOUND                                                = 5,
        ERR_FILES_OPEN                                                        = 6,
        ERR_VOL_SIZE_WRONG                                                = 7,
        ERR_COMPRESSION_NOT_SUPPORTED                        = 8,
        ERR_PASSWORD_CHANGE_VOL_TYPE                        = 9,
        ERR_PASSWORD_CHANGE_VOL_VERSION                        = 10,
        ERR_VOL_SEEKING                                                        = 11,
        ERR_VOL_WRITING                                                        = 12,
        ERR_FILES_OPEN_LOCK                                                = 13,
        ERR_VOL_READING                                                        = 14,
        ERR_DRIVER_VERSION                                                = 15,
        ERR_NEW_VERSION_REQUIRED                                = 16,
        ERR_CIPHER_INIT_FAILURE                                        = 17,
        ERR_CIPHER_INIT_WEAK_KEY                                = 18,
        ERR_SELF_TESTS_FAILED                                        = 19,
        ERR_SECTOR_SIZE_INCOMPATIBLE                        = 20,
        ERR_VOL_ALREADY_MOUNTED                                        = 21,
        ERR_NO_FREE_DRIVES                                                = 22,
        ERR_FILE_OPEN_FAILED                                        = 23,
        ERR_VOL_MOUNT_FAILED                                        = 24,
        DEPRECATED_ERR_INVALID_DEVICE                        = 25,
        ERR_ACCESS_DENIED                                                = 26,
        ERR_MODE_INIT_FAILED                                        = 27,
        ERR_DONT_REPORT                                                        = 28,
        ERR_ENCRYPTION_NOT_COMPLETED                        = 29,
        ERR_PARAMETER_INCORRECT                                        = 30,
        ERR_SYS_HIDVOL_HEAD_REENC_MODE_WRONG        = 31,
        ERR_NONSYS_INPLACE_ENC_INCOMPLETE                = 32,
        ERR_USER_ABORT                                                        = 33
};

#endif         // #ifndef TCDEFS_H
```
Läuft auch schon ohne errors und warnings durch, was mich sehr freut, und auch die Performance sieht ganz gut aus:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Ich habe zum Serpent-Code vorerst folgende Fragen:

1.) Mich verwirrt der outBlock! Ist schon klar, dass nach der Ver- und Entschlüsselung auch irgendwas rauskommen muss, aber brauche ich in meiner main() die *grüne* Zeile? Ich weiß ja nicht, was nach dem Verschlüsseln herauskommt. Macht daher m. E. nicht viel Sinn, lauter 0er für den outBlock in den VRAM zu kopieren (die dann ohnehin überschrieben werden müssten?!). Es müsste doch schon reichen, einfach für den outBlock einen 100 MB großen Bereich im VRAM zu allokieren, was ja schon in der cudaMalloc-Zeile über der grünen Zeile passiert?! 

2.) Wie kann ich am besten überprüfen, ob der Code korrekt arbeitet und mir nach dem Ver- und Entschlüsseln wieder 100 MB in 0er zurückliefert (ich reserviere ja für inBlock einen 100 MB großen Bereich im VRAM und fülle den mit 0er)? Ich hab's mal geschafft, outBlock in einer for-Schleife mit printf() ausgeben zu lassen und es kamen tatsächlich 16 Werte raus, allerdings waren das irgendwelche (großen) Zahlen (allerdings 16x das gleiche). Jedenfalls nicht 16 0er.
Ich habe nach weiteren Arbeiten am Code probiert, diese (angepasste) for-Schleife ...

```
for (int i=0; i<((16*threads*blocks)/sizeof(unsigned __int8)); i++) {
        printf("%d, ", outBlock[i]);
    }
```
... ganz am Ende der main() über den cudaFree einzufügen, aber wenn ich den Code dann laufen lasse, werden mir keine Werte ausgegeben. So, als gäb's nur das erste printf() mit der Performance.


----------



## sebi707 (30. Dezember 2013)

*AW: [CUDA] RC6 / Serpent*

1) Die grüne Zeile kannst du dir sparen, da outBlock ja dann eh von der Funktion zum verschlüsseln beschrieben wird. Im übrigen ist dort auch noch ein Fehler, denn der zweite Parameter von cudaMemcpy ist 0 was nicht sein darf. Bei den cudaMalloc und cudaMemcpy auch das HandleError drum packen dann solltest du auch eine Fehlermeldung angezeigt kriegen. Du wolltest dort wohl cudaMemset benutzen um alles auf 0 zu setzen aber das brauchste natürlich nur für den inBlock.

2) Um den Code zu prüfen ist es auf jeden fall mal Sinnvoll zu prüfen ob die Daten nach dem ver- und danach wieder entschlüsseln wieder identisch sind. Am besten wäre es auch noch wenn man die verschlüsselten Daten vergleicht mit dem was man im Internet findet. Zu allen bekannten Verschlüsselungen sollte es irgendwo Daten geben was verschlüsselt rauskommen muss wenn man z.B. nur 0 Bytes mit einem bestimmten Schlüssel verschlüsselt. Das Problem beim Anzeigen deiner Daten ist, dass du versuchst Daten von einem GPU Pointer zu lesen. Dabei wird dein Programm unweigerlich abstürzen. Du musst zuerst einen entsprechend großen Bereich im RAM reserivieren und dann mit cudaMemcpy von der GPU in dem RAM kopieren. Dann kannst du alles mit printf ausgeben. Im übrigen musst du die Reihenfolge der Parameter beim decrypt umdrehen. Nach dem verschlüsseln sind ja deine verschlüsselten Daten im outBlock und wenn du diese wieder entschlüsseln willst dann musst du outBlock als Input nehmen.

Wieso bist du eigentlich der Meinung, der Code wäre schon für CUDA? Wenn der wirklich für CUDA gewesen ist dann hättest du eigentlich nicht noch überall __global__ Keywords oder ähnliches einfügen müssen.

Edit: Woher hast du überhaupt unsigned ks_var? Soll das irgendwie den Schlüssel beschreiben? Wenn ja wo wird das initialisiert? Außerdem sicher, dass es wirklich nur ein unsigned ist und nicht größer? 32 Bit für einen Schlüssel scheinen mir recht klein, da könnte man ja einfach alle möglichen Schlüssel durchprobieren. sizeof(unsigned __int8) ist im übrigen auch recht überflüssig, da __int8 für einen Typ mit 8 Bits also genau einem Byte steht. Das ganze ist also sowieso 1 und kann man sich sparen.


----------



## boss3D (30. Dezember 2013)

*AW: [CUDA] RC6 / Serpent*

Also jetzt sieht's erstmal so aus:

```
int main(void) {
    unsigned ks_var;
    int threads = 1024;
    int blocks = 6400;

    unsigned __int8 *inBlock;
    cudaMalloc(&inBlock, 16*threads*blocks);
    cudaMemset(inBlock, 0, 16*threads*blocks);

    unsigned __int8 *outBlock;
    cudaMalloc(&outBlock, 16*threads*blocks);

    unsigned __int8 *ks;
    cudaMalloc(&ks, sizeof(ks_var));
    cudaMemcpy(ks, &ks_var, sizeof(ks_var), cudaMemcpyHostToDevice);

    cudaEvent_t start, stop;
    HandleError(cudaEventCreate(&start));
    HandleError(cudaEventCreate(&stop));
    HandleError(cudaEventRecord( start, 0 ));

    serpent_enc<<<blocks,threads>>>(inBlock, outBlock, ks);
    serpent_dec<<<blocks,threads>>>([COLOR=royalblue][B]outBlock, inBlock[/B], ks);

    HandleError(cudaEventRecord( stop, 0 ));
    HandleError(cudaEventSynchronize( stop ));
    float elapsedTime;
    HandleError(cudaEventElapsedTime( &elapsedTime, start, stop ));

    printf("Performance: %.f MB/sec\n", 2*((16*threads*blocks)/1048576)/(elapsedTime*1000));

    HandleError(cudaEventDestroy( start ));
    HandleError(cudaEventDestroy( stop ));

    [COLOR=royalblue][B]unsigned __int8 *test = (unsigned __int8*)malloc(16*threads*blocks);
    cudaMemcpy(outBlock, &test, sizeof(test), cudaMemcpyDeviceToHost);

    for (int i=0; i<sizeof(test); i++) {
        printf("%d, ", test[i]);
    }[/B]
    [COLOR=royalblue][B]free(test);[/B]
    cudaFree(inBlock);
    cudaFree(outBlock);
    cudaFree(ks);

    return 0;
}
```
outBlock und inBlock habe ich in decrypt vertauscht. Die Schleife gibt mir jetzt immerhin 8 0er aus, aber das müssten doch VIEL mehr sein bei 100 MB?!

Dass es bereits ein CUDA Code war, habe ich angenommen, da ich mir Serpent als .cu File besorgt habe.

ks müsste der Schlüssel sein. ks_var habe ich dann angelegt weil ich ja noch einen Parameter für cudaMemcpy gebraucht habe. Das ist halt wie in RC6 mit s_var für *s, habe ich mir gedacht. Den Schlüssel muss ich jedenfalls noch in der main initialisieren ...

*[Edit]*
Schlüsselinitialisierung habe ich gerade so probiert:


> char* key = "meingeheimespasswort";
> serpent_set_key(key, strlen(key), &ks_var);


^^ argument of type "unsigned int *" is incompatible with parameter of type "unsigned char *" ... --> Eh klar. Muss ich mir wohl für den ersten Parameter noch einen Typcast überlegen?!


----------



## sebi707 (30. Dezember 2013)

*AW: [CUDA] RC6 / Serpent*

Hier hast du die Parameter falsch:

```
cudaMemcpy(outBlock, &test, sizeof(test), cudaMemcpyDeviceToHost);
```
Du kopierst jetzt zwar von der GPU zur CPU, aber der erste Parameter ist immer das Ziel und der zweite die Quelle. Also test nach vorne und outBlock nach hinten. Im übrigen muss es auch test ohne & sein weil du die Daten dahin kopieren willst wohin test zeigt und nicht nach test selbst. Sowas wie sizeof(test) Funktioniert mit Pointern nicht richtig. Du musst hier als größe einfach 16*threads*blocks nehmen. In der for loop auch, dann werden auch mehr als 8 Werte angezeigt. Ich sags nochmal: Um ALLE cuda*** Funktionen ein HandleError(). Auch um cudaMalloc, cudaMemcpy und cudaMemset, damit du die Fehlermeldungen mitkriegst wenn nicht genug Speicher reserviert werden konnte oder Parameter falsch sind.

Bei deinem Key initialisieren sollte ks_var auch ein unsigned __int8 sein. Laut Wikipedia gibt es Serpent als Variante mit 128, 192 oder 256 Bit großen Schlüsseln. Welches davon auf deine Implementierung zutrifft musst du mal gucken. Im Zweifallsfall nehm einfach 32 Bytes (für die 256 Bit) für ks_var.


----------



## boss3D (30. Dezember 2013)

*AW: [CUDA] RC6 / Serpent*

Habe das jetzt noch alles gemacht, allerdings habe ich die for-Schleife auf 16 Werte begrenzt. 16*threads*blocks Werte kann der Laptop nicht mehr vernünftig berechnen/darstellen. Da friert mir vorher das System ein ...

Jedenfalls gibt's scheinbar noch 2 Probleme:

1.) Es kommen irgendwelche Werte am Ende raus, und nicht wieder lauter 0er.




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



2.) In meiner Zeile ...

```
serpent_set_key(key, strlen(key), &ks_var)
```
... kriege ich jetzt den Error _argument of type "char *" is incompatible with parameter of type "const unsigned char *"_

Hier nochmal die ganze main():

```
int main(void) {
    char* key = "meingeheimespasswort";
    unsigned __int8 ks_var;
    int threads = 1024;
    int blocks = 6400;
    serpent_set_key(key, strlen(key), &ks_var);

    unsigned __int8 *inBlock;
    HandleError(cudaMalloc(&inBlock, 16*threads*blocks));
    HandleError(cudaMemset(inBlock, 0, 16*threads*blocks));

    unsigned __int8 *outBlock;
    HandleError(cudaMalloc(&outBlock, 16*threads*blocks));

    unsigned __int8 *ks;
    HandleError(cudaMalloc(&ks, sizeof(ks_var)));
    HandleError(cudaMemcpy(ks, &ks_var, sizeof(ks_var), cudaMemcpyHostToDevice));

    cudaEvent_t start, stop;
    HandleError(cudaEventCreate(&start));
    HandleError(cudaEventCreate(&stop));
    HandleError(cudaEventRecord( start, 0 ));

    serpent_enc<<<blocks,threads>>>(inBlock, outBlock, ks);
    serpent_dec<<<blocks,threads>>>(outBlock, inBlock, ks);

    HandleError(cudaEventRecord( stop, 0 ));
    HandleError(cudaEventSynchronize( stop ));
    float elapsedTime;
    HandleError(cudaEventElapsedTime( &elapsedTime, start, stop ));

    printf("Performance: %.f MB/sec\n", 2*((16*threads*blocks)/1048576)/(elapsedTime*1000));

    HandleError(cudaEventDestroy( start ));
    HandleError(cudaEventDestroy( stop ));

    unsigned __int8 *test = (unsigned __int8*)malloc(16*threads*blocks);
    HandleError(cudaMemcpy(test, outBlock, 16*threads*blocks, cudaMemcpyDeviceToHost));

    for (int i=0; i<16; i++) {
        printf("%d, ", test[i]);
    }

    free(test);

    HandleError(cudaFree(inBlock));
    HandleError(cudaFree(outBlock));
    HandleError(cudaFree(ks));

    return 0;
}
```
*[Edit]*
Auf einmal kommen doch lauter 0er raus. Somit bleibt nur Problem 2) ...

*[Edit2]*
Mit nem Typcast würde ich die Fehlermeldung wegkriegen, aber dafür kommt keine Ausgabe mehr (weder vom einen, noch vom anderen printf()). _*seufz*_

```
serpent_set_key((unsigned char*)key, strlen(key), &ks_var);
```


----------



## sebi707 (31. Dezember 2013)

*AW: [CUDA] RC6 / Serpent*

Kriegst du in deiner Entwicklungsumgebung gar nicht mit wenn das Programm abstürzt? Du hast für ks_var ja auch nur 1 Byte reserviert. Das casten mit (unsigned char*) ist schon in Ordnung, allerdings wird es dann wohl abstürzen weil das Programm versucht mehr als nur ein Byte nach ks_var zu schreiben. Mach ks_var mal zu einem Array mit mindstens 32 Elementen (Also 32 Bytes für maximal 256 Bit Schlüsselgröße).

Das plötzlich lauter 0 rauskommt klingt eher unwahrscheinlich. Du kopierst dir nämlich outBlock in deine test Variable und outBlock sind die verschlüsselten Daten. Nach dem Aufruf von

```
serpent_dec<<<blocks,threads>>>(outBlock, inBlock, ks);
```
sind die unverschlüsselten Daten wieder in inBlock. Also musst du dir auch dieses anzeigen lassen.


----------



## boss3D (31. Dezember 2013)

*AW: [CUDA] RC6 / Serpent*

Ne, in Nsight Eclipse merke ich hier gar nichts! Der führt jeden Mist beinhart aus, egal wie viele Errors drinnen sind ... und wenn am Ende alles rot ist. 

^^ Das ist ja das doofe im Vergleich zum Visual Studio. Hier in meiner IDE erkenne ich Fehler nur daran, dass das Programm nicht das macht, was ich mir erwartet hätte ...
---------
Hab's jetzt so:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Damit ist zwar der Error weg, aber es stürzt vermutlich immer noch ab, weil ich keine Ausgabe kriege?!


----------



## sebi707 (31. Dezember 2013)

*AW: [CUDA] RC6 / Serpent*

Mh ja kann ich so auch nicht beantworten. Kannst du alle Dateien mal irgendwie als Archiv hochladen, damit ich mir das einfach runterladen und bei mir selbst compilieren kann? Ich werde aber frühstens Morgen drüber gucken.


----------



## boss3D (31. Dezember 2013)

*AW: [CUDA] RC6 / Serpent*

Okay. Ich packe dir auch den RC6 dazu. Ich habe nämlich dort jetzt auch wirklich vor ALLE cuda Aufrufe ein HandleError geschrieben und dabei ist noch 1 Fehler in Zeile 150 rausgekommen. Der müsste in RC6 noch weg, und in Serpent eben das Problem mit dem key ...

Bitte verrate mir dann auch deine Grafik-Hardware und deine Performance-Ergebnisse! Würde mich echt interessieren. Langsamer als mein Laptop hier kann's ja nicht mehr sein. 




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.


----------



## sebi707 (31. Dezember 2013)

*AW: [CUDA] RC6 / Serpent*

Also in deinem RC6 Code sind mir noch zwei Fehler aufgefallen. Einmal ist deine Berechnung für den Datendurchsatz falsch. Du hast hinten stehten elapsedTime*1000 aber von Millisekunden zu Sekunden musst du natürlich elapsedTime/1000 rechnen. Außerdem kommt bei "After decryption" nicht wieder überall 0 raus, da du in deiner rc6dec funktion nicht rc6_dec sondern rc6_enc aufrufst. Statt einmal zu verschlüsseln und wieder zu entschlüsseln hast du 2mal verschlüsselt. Wenn ich das änder dann scheint aber alles zu laufen. Performance auf meiner GTX 560 Ti (zufälligerweise genau die Karte in dem System wo du das nacher testen willst) sind 1097MB/s.

Jetzt zu Serpent. In Zeile 326 und 327 fehlt noch das __device__ damit die Warnings weg gehen. Außerdem gleicher Fehler bei der Berechung des Datendurchsatzes. Der andere Fehler warum es abstürzt ist wohl bei der Größe von ks_var. Leider kann ich da grade auch keinen genauen Wert finden wie groß ks_var sein muss aber 1024 Elemente scheint zu reichen. Da werden wohl ähnlich wie bei RC6 mehrere Rundenschlüssel generiert weshalb 32 Byte nicht reichen. Performance ist bei mir 4675 MB/s.


----------



## boss3D (31. Dezember 2013)

*AW: [CUDA] RC6 / Serpent*

Alter Schwede, wenn ich in RC6 noch die beiden von dir genannten Fehler ausbessere, komme ich auf eine völlig utopische Performance:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Da wäre ja meine 9600M GT um Lichtjahre schneller als deine GTX 560 Ti. Da stimmt noch irgendwas nicht?!

Und warnings gibt's nach den beiden Änderungen auch, die ich zuvor nicht hatte:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        


-----------

In Serpent komme ich nach dem Ausbessern der Fehler auf eine ähnlich unrealistische Performance:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        





*[Edit]*
Sehe gerade, dass beide Codes bei mir die exakt selbe, falsche Performance liefern. Also haben wohl beide Codes bei mir noch 1 und den selben Fehler?!

*[Edit2]*
Bei weiteren Durchläufen erscheinen jetzt bei keinem Code mehr warnings, aber die Performance bleibt bei beiden völlig unrealistisch.


----------



## sebi707 (31. Dezember 2013)

*AW: [CUDA] RC6 / Serpent*

Ich vermute es liegt daran, dass deine GPU gar keine 1024 Threads pro Block unterstützt und der Kernel deshalb gar nicht startet. Mich wundert nur, dass es keine Fehlermeldung deshalb gibt. Mach mal ein HandleError(cudaGetLastError()); nach den beiden Kernelaufrufen. Du solltest jedenfalls auch mal mit weniger Threads pro Block probieren.


----------



## boss3D (1. Januar 2014)

*AW: [CUDA] RC6 / Serpent*

Habe jetzt noch bei beiden Codes die zusätzliche HandleError Zeile eingefügt und 512 Threads sowie 12800 Blocks eingestellt. 

Serpent läuft damit scheinbar fehlerfrei durch und liefert folgendes durchaus realistisches Ergebnis:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



RC6 liefert in Zeile 178 folgenden Fehler:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Habe ich da immer noch irgendwelche Daten vergessen in den VRAM zu kopieren, oder was heißt das diesmal?
---------

BTW: Kannst du eigentlich deine Performance-Ergebnisse reproduzieren? Wenn du die Codes jeweils 10 Mal hintereinander laufen lässt, kriegst du dann immer exakt 1097 MB/s bzw. 4675 MB/s raus, oder unterschiedliche aber sehr ähnliche Werte?

Bei mir war's im fehlerhaften RC6 so, dass ich im Bereich von 5 MB/s - 75 MB/s alles mögliche rausgekriegt habe, und jetzt im "fehlerfreien" Serpent immer ganz exakt 22 MB/s rauskriege. RC6 läuft ja jetzt, nach den Korrekturen, noch nicht wieder.


----------



## sebi707 (1. Januar 2014)

*AW: [CUDA] RC6 / Serpent*

Wenn du die beiden Sachen zu RC6 behoben hast und sonst der Code ist wie im Archiv kann es eigentlich nur an der Hardware liegen, die irgendwas nicht unterstützt. Dazu habe ich den Code nochmal auf meinem Laptop mit einer nVidia NVS 3100M (unterstützt Compute Capability 1.2 also noch immer etwas neuer als deine GPU) probiert aber selbst dort läuft alles mit 512 Threads pro Block. Ich kann mir also nicht erklären woher der Fehler kommt. Ich werde aber nochmal versuchen herauszufinden ob sich irgendwas wichtiges zwischen Compute Capability 1.0 und 1.2 geändert hat. Ansonsten musst du dich damit abfinden, dass es auf deinem PC wohl nicht läuft aber dann auf dem späteren Testsystem schon.

Die Performance Ergebnisse sind bei mir ziemlich reproduzierbar. Jetzt auf dem Laptop kriege ich eine Performance von konstant 40MB/s bei RC6 aber wenn ich mir ein paar mehr Nachkommastellen anzeigen lasse sieht man, dass es leicht schwankt:
Performance: 40.271107 MB/sec
Performance: 40.271900 MB/sec
Performance: 40.271191 MB/sec

Edit: Du kannst mal versuchen dein RC6 Programm mit cuda-memcheck zu prüfen. Dazu einfach mit einer Console in den Ordner wechseln wo das fertig compilierte Programm ist und "cuda-memcheck *programm name*" eintippen. Meistens hat unspecified launch failure irgendwas mit fehlerhaften Speicherzugriffen zu tun. Eventuell bietet deine Entwicklungsumgebung auch direkt möglichkeiten an Code zu debuggen. Das wäre in jedem Fall nötig jetzt, da ich den Fehler nicht reproduzieren kann.


----------



## boss3D (1. Januar 2014)

*AW: [CUDA] RC6 / Serpent*

Es geht im Prinzip eh nur darum, dass das dann auf dem Benchmarksystem einwandfrei läuft. Jetzt beim Arbeiten ist es halt blöd, dass ich nur die 9600M GT im Laptop als einzige nVidia Hardware habe und die am untersten Limit werkt ...

Wenn die Ergebnisse bei dir so konstant bleiben, brauche ich mich nicht mehr zu wundern, wenn's bei mir jetzt auch so ist. Mit mehreren Nachkommastellen sieht man auch, dass die 22 MB/sec nur gerundet waren:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Eine einzige Vorgabe des Projekts fehlt uns jetzt noch: Der Rundenschlüssel soll jedes Mal inkrementiert werden.

RC6 läuft defaultmäßig mit 20 Runden. Der erste Schlüssel errechnet sich nach meinem Verständnis aus unserer key-Phrase?! Aber wo enstehen die weiteren Schlüssel? Ich kann ja nicht einfach am Ende von rc6_initl() "key++;" sagen?!

In serpent muss man sich wohl serpent_set_key() anschauen, allerdings habe ich noch nicht durchschaut, mit wie vielen Runden unser Serpent-Code läuft ...


----------



## sebi707 (1. Januar 2014)

*AW: [CUDA] RC6 / Serpent*

Da ich die genaue Aufgabenstellung nicht kenne kann ich nur spekulieren was gemeint ist. Den Schlüssel jedes mal zu ändern ist eigentlich unüblich und vermutlich nicht gemeint. Die Schlüssel für die 20 Runden bei RC6 werden nach eine festen Regel aus dem Key-Phrase generiert. Ist eventuell das hier gemeint?


----------



## boss3D (1. Januar 2014)

*AW: [CUDA] RC6 / Serpent*

^^ Wenn ich das selbst so genau wüsste. Das ist der einzige Teil der Vorgabe, den ich nicht kapiert habe ...
Soweit ich mich ans erste Projektmeeting erinnern kann, ist es NICHT erforderlich, dass wir uns mit den Cipher Modes beschäftigen. Aber ansonsten fällt mir auch nichts ein, was wir mit dem key machen sollen. Ab morgen erreiche ich den Lehrer wieder per email. Heben wir uns das bis zu seiner Antwort auf.

Ich schaue mir jetzt mal vorsichtig Twofish an und melde mich wieder, sobald ich kuriose Ergebnisse kriege, oder wo anstehe.


----------



## boss3D (1. Januar 2014)

*AW: [CUDA] RC6 / Serpent /Twofish*

*Twofish*

Habe mich jetzt für einen anderen Twofish-Code entschieden, als der, den ich mittlerweile aus dem vorigen Posting wieder gelöscht habe. Ich will nicht mit ~20 Files arbeiten müssen, wenn's auch mit 5 geht. Außerdem ist es mir mittlerweile lieber, einen C Code nach CUDA zu portieren, als einen fremden CUDA-Code umzubasteln ...

Jedenfalls läuft das Portieren von Twofish bis jetzt ganz gut. Ich bin nur gerade auf folgendes Problem gestoßen (siehe Errors):




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Kann ich das einfach lösen, indem ich ReverseRoundSubkeys() auch zu einer __device__ Funktion mache?
Was die warnings bedeuten ist eh klar. cipherInstance *cipher und keyInstance *key muss ich noch initialisieren. int inputLen ist hoffentlich richtig initialisiert.

Hier der Code mit meinen Ergänzungen:

```
/***************************************************************************
    TWOFISH2.C    -- Optimized C API calls for TWOFISH AES submission

    Submitters:
        Bruce Schneier, Counterpane Systems
        Doug Whiting,    Hi/fn
        John Kelsey,    Counterpane Systems
        Chris Hall,        Counterpane Systems
        David Wagner,    UC Berkeley

    Code Author:        Doug Whiting,    Hi/fn

    Version  1.00        April 1998

    Copyright 1998, Hi/fn and Counterpane Systems.  All rights reserved.

    Notes:
        *    Optimized version
        *    Tab size is set to 4 characters in this file

***************************************************************************/
#include    "AES.h"
#include    "TABLE.h"

#include    <memory.h>
#include    <assert.h>

[COLOR=royalblue][B]#define HandleError(x) HandleErrorImpl(x, __FILE__, __LINE__)[/B]
#if   defined(min_key)  && !defined(MIN_KEY)
#define    MIN_KEY        1            /* toupper() */
#elif defined(part_key) && !defined(PART_KEY)
#define    PART_KEY    1
#elif defined(zero_key) && !defined(ZERO_KEY)
#define    ZERO_KEY    1
#endif


#ifdef USE_ASM
extern    int    useAsm;                /* ok to use ASM code? */

typedef    int cdecl CipherProc
   (cipherInstance *cipher, keyInstance *key,BYTE *input,int inputLen,BYTE *outBuffer);
typedef int    cdecl KeySetupProc(keyInstance *key);

extern CipherProc    *blockEncrypt_86;    /* ptr to ASM functions */
extern CipherProc    *blockDecrypt_86;
extern KeySetupProc    *reKey_86;
extern DWORD        cdecl TwofishAsmCodeSize(void);
#endif

/*
+*****************************************************************************
*            Constants/Macros/Tables
-****************************************************************************/

#define        CONST                    /* help syntax from C++, NOP here */

CONST        fullSbox MDStab;        /* not actually const.  Initialized ONE time */
int            needToBuildMDS=1;        /* is MDStab initialized yet? */

#define        BIG_TAB        0

#if BIG_TAB
BYTE        bigTab[4][256][256];    /* pre-computed S-box */
#endif

/* number of rounds for various key sizes:  128, 192, 256 */
/* (ignored for now in optimized code!) */
CONST int    numRounds[4]= {0,ROUNDS_128,ROUNDS_192,ROUNDS_256};

#if REENTRANT
#define        _sBox_     key->sBox8x32
#else
static        fullSbox _sBox_;        /* permuted MDStab based on keys */
#endif
#define _sBox8_(N) (((BYTE *) _sBox_) + (N)*256)

/*------- see what level of S-box precomputation we need to do -----*/
#if   defined(ZERO_KEY)
#define    MOD_STRING    "(Zero S-box keying)"
#define    Fe32_128(x,R)    \
    (    MDStab[0][p8(01)[p8(02)[_b(x,R  )]^b0(SKEY[1])]^b0(SKEY[0])] ^    \
        MDStab[1][p8(11)[p8(12)[_b(x,R+1)]^b1(SKEY[1])]^b1(SKEY[0])] ^    \
        MDStab[2][p8(21)[p8(22)[_b(x,R+2)]^b2(SKEY[1])]^b2(SKEY[0])] ^    \
        MDStab[3][p8(31)[p8(32)[_b(x,R+3)]^b3(SKEY[1])]^b3(SKEY[0])] )
#define    Fe32_192(x,R)    \
    (    MDStab[0][p8(01)[p8(02)[p8(03)[_b(x,R  )]^b0(SKEY[2])]^b0(SKEY[1])]^b0(SKEY[0])] ^ \
        MDStab[1][p8(11)[p8(12)[p8(13)[_b(x,R+1)]^b1(SKEY[2])]^b1(SKEY[1])]^b1(SKEY[0])] ^ \
        MDStab[2][p8(21)[p8(22)[p8(23)[_b(x,R+2)]^b2(SKEY[2])]^b2(SKEY[1])]^b2(SKEY[0])] ^ \
        MDStab[3][p8(31)[p8(32)[p8(33)[_b(x,R+3)]^b3(SKEY[2])]^b3(SKEY[1])]^b3(SKEY[0])] )
#define    Fe32_256(x,R)    \
    (    MDStab[0][p8(01)[p8(02)[p8(03)[p8(04)[_b(x,R  )]^b0(SKEY[3])]^b0(SKEY[2])]^b0(SKEY[1])]^b0(SKEY[0])] ^ \
        MDStab[1][p8(11)[p8(12)[p8(13)[p8(14)[_b(x,R+1)]^b1(SKEY[3])]^b1(SKEY[2])]^b1(SKEY[1])]^b1(SKEY[0])] ^ \
        MDStab[2][p8(21)[p8(22)[p8(23)[p8(24)[_b(x,R+2)]^b2(SKEY[3])]^b2(SKEY[2])]^b2(SKEY[1])]^b2(SKEY[0])] ^ \
        MDStab[3][p8(31)[p8(32)[p8(33)[p8(34)[_b(x,R+3)]^b3(SKEY[3])]^b3(SKEY[2])]^b3(SKEY[1])]^b3(SKEY[0])] )

#define    GetSboxKey    DWORD SKEY[4];    /* local copy */ \
                    memcpy(SKEY,key->sboxKeys,sizeof(SKEY));
/*----------------------------------------------------------------*/
#elif defined(MIN_KEY)
#define    MOD_STRING    "(Minimal keying)"
#define    Fe32_(x,R)(MDStab[0][p8(01)[_sBox8_(0)[_b(x,R  )]] ^ b0(SKEY0)] ^ \
                   MDStab[1][p8(11)[_sBox8_(1)[_b(x,R+1)]] ^ b1(SKEY0)] ^ \
                   MDStab[2][p8(21)[_sBox8_(2)[_b(x,R+2)]] ^ b2(SKEY0)] ^ \
                   MDStab[3][p8(31)[_sBox8_(3)[_b(x,R+3)]] ^ b3(SKEY0)])
#define sbSet(N,i,J,v) { _sBox8_(N)[i+J] = v; }
#define    GetSboxKey    DWORD SKEY0    = key->sboxKeys[0]        /* local copy */
/*----------------------------------------------------------------*/
#elif defined(PART_KEY)
#define    MOD_STRING    "(Partial keying)"
#define    Fe32_(x,R)(MDStab[0][_sBox8_(0)[_b(x,R  )]] ^ \
                   MDStab[1][_sBox8_(1)[_b(x,R+1)]] ^ \
                   MDStab[2][_sBox8_(2)[_b(x,R+2)]] ^ \
                   MDStab[3][_sBox8_(3)[_b(x,R+3)]])
#define sbSet(N,i,J,v) { _sBox8_(N)[i+J] = v; }
#define    GetSboxKey
/*----------------------------------------------------------------*/
#else    /* default is FULL_KEY */
#ifndef FULL_KEY
#define    FULL_KEY    1
#endif
#if BIG_TAB
#define    TAB_STR        " (Big table)"
#else
#define    TAB_STR
#endif
#ifdef COMPILE_KEY
#define    MOD_STRING    "(Compiled subkeys)" TAB_STR
#else
#define    MOD_STRING    "(Full keying)" TAB_STR
#endif
/* Fe32_ does a full S-box + MDS lookup.  Need to #define _sBox_ before use.
   Note that we "interleave" 0,1, and 2,3 to avoid cache bank collisions
   in optimized assembly language.
*/
#define    Fe32_(x,R) (_sBox_[0][2*_b(x,R  )] ^ _sBox_[0][2*_b(x,R+1)+1] ^    \
                    _sBox_[2][2*_b(x,R+2)] ^ _sBox_[2][2*_b(x,R+3)+1])
        /* set a single S-box value, given the input byte */
#define sbSet(N,i,J,v) { _sBox_[N&2][2*i+(N&1)+2*J]=MDStab[N][v]; }
#define    GetSboxKey
#endif

CONST        char *moduleDescription    ="Optimized C ";
CONST        char *modeString        =MOD_STRING;


/* macro(s) for debugging help */
#define        CHECK_TABLE        0        /* nonzero --> compare against "slow" table */
#define        VALIDATE_PARMS    0        /* disable for full speed */

#include    "DEBUG.h"                /* debug display macros */

/* end of debug macros */

#ifdef GetCodeSize
extern DWORD Here(DWORD x);            /* return caller's address! */
DWORD TwofishCodeStart(void) { return Here(0); }
#endif

/*
+*****************************************************************************
*
* Function Name:    TableOp
*
* Function:            Handle table use checking
*
* Arguments:        op    =    what to do    (see TAB_* defns in AES.H)
*
* Return:            TRUE --> done (for TAB_QUERY)
*
* Notes: This routine is for use in generating the tables KAT file.
*         For this optimized version, we don't actually track table usage,
*         since it would make the macros incredibly ugly.  Instead we just
*         run for a fixed number of queries and then say we're done.
*
-****************************************************************************/
int TableOp(int op)
    {
    static int queryCnt=0;

    switch (op)
        {
        case TAB_DISABLE:
            break;
        case TAB_ENABLE:
            break;
        case TAB_RESET:
            queryCnt=0;
            break;
        case TAB_QUERY:
            queryCnt++;
            if (queryCnt < TAB_MIN_QUERY)
                return FALSE;
        }
    return TRUE;
    }


/*
+*****************************************************************************
*
* Function Name:    ParseHexDword
*
* Function:            Parse ASCII hex nibbles and fill in key/iv dwords
*
* Arguments:        bit            =    # bits to read
*                    srcTxt        =    ASCII source
*                    d            =    ptr to dwords to fill in
*                    dstTxt        =    where to make a copy of ASCII source
*                                    (NULL ok)
*
* Return:            Zero if no error.  Nonzero --> invalid hex or length
*
* Notes:  Note that the parameter d is a DWORD array, not a byte array.
*    This routine is coded to work both for little-endian and big-endian
*    architectures.  The character stream is interpreted as a LITTLE-ENDIAN
*    byte stream, since that is how the Pentium works, but the conversion
*    happens automatically below.
*
-****************************************************************************/
int ParseHexDword(int bits,CONST char *srcTxt,DWORD *d,char *dstTxt)
    {
    int i;
    char c;
    DWORD b;

    union    /* make sure LittleEndian is defined correctly */
        {
        BYTE  b[4];
        DWORD d[1];
        } v;
    v.d[0]=1;
    if (v.b[0 ^ ADDR_XOR] != 1)
        return BAD_ENDIAN;        /* make sure compile-time switch is set ok */

#if VALIDATE_PARMS
  #if ALIGN32
    if (((int)d) & 3)
        return BAD_ALIGN32;
  #endif
#endif

    for (i=0;i*32<bits;i++)
        d[i]=0;                    /* first, zero the field */

    for (i=0;i*4<bits;i++)        /* parse one nibble at a time */
        {                        /* case out the hexadecimal characters */
        c=srcTxt[i];
        if (dstTxt) dstTxt[i]=c;
        if ((c >= '0') && (c <= '9'))
            b=c-'0';
        else if ((c >= 'a') && (c <= 'f'))
            b=c-'a'+10;
        else if ((c >= 'A') && (c <= 'F'))
            b=c-'A'+10;
        else
            return BAD_KEY_MAT;    /* invalid hex character */
        /* works for big and little endian! */
        d[i/8] |= b << (4*((i^1)&7));
        }

    return 0;                    /* no error */
    }


#if CHECK_TABLE
/*
+*****************************************************************************
*
* Function Name:    f32
*
* Function:            Run four bytes through keyed S-boxes and apply MDS matrix
*
* Arguments:        x            =    input to f function
*                    k32            =    pointer to key dwords
*                    keyLen        =    total key length (k32 --> keyLey/2 bits)
*
* Return:            The output of the keyed permutation applied to x.
*
* Notes:
*    This function is a keyed 32-bit permutation.  It is the major building
*    block for the Twofish round function, including the four keyed 8x8
*    permutations and the 4x4 MDS matrix multiply.  This function is used
*    both for generating round subkeys and within the round function on the
*    block being encrypted.
*
*    This version is fairly slow and pedagogical, although a smartcard would
*    probably perform the operation exactly this way in firmware.   For
*    ultimate performance, the entire operation can be completed with four
*    lookups into four 256x32-bit tables, with three dword xors.
*
*    The MDS matrix is defined in TABLE.H.  To multiply by Mij, just use the
*    macro Mij(x).
*
-****************************************************************************/
DWORD f32(DWORD x,CONST DWORD *k32,int keyLen)
    {
    BYTE  b[4];

    /* Run each byte thru 8x8 S-boxes, xoring with key byte at each stage. */
    /* Note that each byte goes through a different combination of S-boxes.*/

    *((DWORD *)b) = Bswap(x);    /* make b[0] = LSB, b[3] = MSB */
    switch (((keyLen + 63)/64) & 3)
        {
        case 0:        /* 256 bits of key */
            b[0] = p8(04)[b[0]] ^ b0(k32[3]);
            b[1] = p8(14)[b[1]] ^ b1(k32[3]);
            b[2] = p8(24)[b[2]] ^ b2(k32[3]);
            b[3] = p8(34)[b[3]] ^ b3(k32[3]);
            /* fall thru, having pre-processed b[0]..b[3] with k32[3] */
        case 3:        /* 192 bits of key */
            b[0] = p8(03)[b[0]] ^ b0(k32[2]);
            b[1] = p8(13)[b[1]] ^ b1(k32[2]);
            b[2] = p8(23)[b[2]] ^ b2(k32[2]);
            b[3] = p8(33)[b[3]] ^ b3(k32[2]);
            /* fall thru, having pre-processed b[0]..b[3] with k32[2] */
        case 2:        /* 128 bits of key */
            b[0] = p8(00)[p8(01)[p8(02)[b[0]] ^ b0(k32[1])] ^ b0(k32[0])];
            b[1] = p8(10)[p8(11)[p8(12)[b[1]] ^ b1(k32[1])] ^ b1(k32[0])];
            b[2] = p8(20)[p8(21)[p8(22)[b[2]] ^ b2(k32[1])] ^ b2(k32[0])];
            b[3] = p8(30)[p8(31)[p8(32)[b[3]] ^ b3(k32[1])] ^ b3(k32[0])];
        }

    /* Now perform the MDS matrix multiply inline. */
    return    ((M00(b[0]) ^ M01(b[1]) ^ M02(b[2]) ^ M03(b[3]))      ) ^
            ((M10(b[0]) ^ M11(b[1]) ^ M12(b[2]) ^ M13(b[3])) <<  8) ^
            ((M20(b[0]) ^ M21(b[1]) ^ M22(b[2]) ^ M23(b[3])) << 16) ^
            ((M30(b[0]) ^ M31(b[1]) ^ M32(b[2]) ^ M33(b[3])) << 24) ;
    }
#endif    /* CHECK_TABLE */


/*
+*****************************************************************************
*
* Function Name:    RS_MDS_encode
*
* Function:            Use (12,8) Reed-Solomon code over GF(256) to produce
*                    a key S-box dword from two key material dwords.
*
* Arguments:        k0    =    1st dword
*                    k1    =    2nd dword
*
* Return:            Remainder polynomial generated using RS code
*
* Notes:
*    Since this computation is done only once per reKey per 64 bits of key,
*    the performance impact of this routine is imperceptible. The RS code
*    chosen has "simple" coefficients to allow smartcard/hardware implementation
*    without lookup tables.
*
-****************************************************************************/
DWORD RS_MDS_Encode(DWORD k0,DWORD k1)
    {
    int i,j;
    DWORD r;

    for (i=r=0;i<2;i++)
        {
        r ^= (i) ? k0 : k1;            /* merge in 32 more key bits */
        for (j=0;j<4;j++)            /* shift one byte at a time */
            RS_rem(r);
        }
    return r;
    }


/*
+*****************************************************************************
*
* Function Name:    BuildMDS
*
* Function:            Initialize the MDStab array
*
* Arguments:        None.
*
* Return:            None.
*
* Notes:
*    Here we precompute all the fixed MDS table.  This only needs to be done
*    one time at initialization, after which the table is "CONST".
*
-****************************************************************************/
void BuildMDS(void)
    {
    int i;
    DWORD d;
    BYTE m1[2],mX[2],mY[4];

    for (i=0;i<256;i++)
        {
        m1[0]=P8x8[0][i];        /* compute all the matrix elements */
        mX[0]=(BYTE) Mul_X(m1[0]);
        mY[0]=(BYTE) Mul_Y(m1[0]);

        m1[1]=P8x8[1][i];
        mX[1]=(BYTE) Mul_X(m1[1]);
        mY[1]=(BYTE) Mul_Y(m1[1]);

#undef    Mul_1                    /* change what the pre-processor does with Mij */
#undef    Mul_X
#undef    Mul_Y
#define    Mul_1    m1                /* It will now access m01[], m5B[], and mEF[] */
#define    Mul_X    mX
#define    Mul_Y    mY

#define    SetMDS(N)                    \
        b0(d) = M0##N[P_##N##0];    \
        b1(d) = M1##N[P_##N##0];    \
        b2(d) = M2##N[P_##N##0];    \
        b3(d) = M3##N[P_##N##0];    \
        MDStab[N][i] = d;

        SetMDS(0);                /* fill in the matrix with elements computed above */
        SetMDS(1);
        SetMDS(2);
        SetMDS(3);
        }
#undef    Mul_1
#undef    Mul_X
#undef    Mul_Y
#define    Mul_1    Mx_1            /* re-enable true multiply */
#define    Mul_X    Mx_X
#define    Mul_Y    Mx_Y

#if BIG_TAB
    {
    int j,k;
    BYTE *q0,*q1;

    for (i=0;i<4;i++)
        {
        switch (i)
            {
            case 0:    q0=p8(01); q1=p8(02);    break;
            case 1:    q0=p8(11); q1=p8(12);    break;
            case 2:    q0=p8(21); q1=p8(22);    break;
            case 3:    q0=p8(31); q1=p8(32);    break;
            }
        for (j=0;j<256;j++)
            for (k=0;k<256;k++)
                bigTab[i][j][k]=q0[q1[k]^j];
        }
    }
#endif

    needToBuildMDS=0;            /* NEVER modify the table again! */
    }

/*
+*****************************************************************************
*
* Function Name:    ReverseRoundSubkeys
*
* Function:            Reverse order of round subkeys to switch between encrypt/decrypt
*
* Arguments:        key        =    ptr to keyInstance to be reversed
*                    newDir    =    new direction value
*
* Return:            None.
*
* Notes:
*    This optimization allows both blockEncrypt and blockDecrypt to use the same
*    "fallthru" switch statement based on the number of rounds.
*    Note that key->numRounds must be even and >= 2 here.
*
-****************************************************************************/
void ReverseRoundSubkeys(keyInstance *key,BYTE newDir)
    {
    DWORD t0,t1;
    register DWORD *r0=key->subKeys+ROUND_SUBKEYS;
    register DWORD *r1=r0 + 2*key->numRounds - 2;

    for (;r0 < r1;r0+=2,r1-=2)
        {
        t0=r0[0];            /* swap the order */
        t1=r0[1];
        r0[0]=r1[0];        /* but keep relative order within pairs */
        r0[1]=r1[1];
        r1[0]=t0;
        r1[1]=t1;
        }

    key->direction=newDir;
    }

/*
+*****************************************************************************
*
* Function Name:    Xor256
*
* Function:            Copy an 8-bit permutation (256 bytes), xoring with a byte
*
* Arguments:        dst        =    where to put result
*                    src        =    where to get data (can be same asa dst)
*                    b        =    byte to xor
*
* Return:            None
*
* Notes:
*     BorlandC's optimization is terrible!  When we put the code inline,
*    it generates fairly good code in the *following* segment (not in the Xor256
*    code itself).  If the call is made, the code following the call is awful!
*    The penalty is nearly 50%!  So we take the code size hit for inlining for
*    Borland, while Microsoft happily works with a call.
*
-****************************************************************************/
#if defined(__BORLANDC__)    /* do it inline */
#define Xor32(dst,src,i) { ((DWORD *)dst)[i] = ((DWORD *)src)[i] ^ tmpX; }
#define    Xor256(dst,src,b)                \
    {                                    \
    register DWORD tmpX=0x01010101u * b;\
    for (i=0;i<64;i+=4)                    \
        { Xor32(dst,src,i  ); Xor32(dst,src,i+1); Xor32(dst,src,i+2); Xor32(dst,src,i+3); }    \
    }
#else                        /* do it as a function call */
void Xor256(void *dst,void *src,BYTE b)
    {
    register DWORD    x=b*0x01010101u;    /* replicate byte to all four bytes */
    register DWORD *d=(DWORD *)dst;
    register DWORD *s=(DWORD *)src;
#define X_8(N)    { d[N]=s[N] ^ x; d[N+1]=s[N+1] ^ x; }
#define X_32(N)    { X_8(N); X_8(N+2); X_8(N+4); X_8(N+6); }
    X_32(0 ); X_32( 8); X_32(16); X_32(24);    /* all inline */
    d+=32;    /* keep offsets small! */
    s+=32;
    X_32(0 ); X_32( 8); X_32(16); X_32(24);    /* all inline */
    }
#endif

/*
+*****************************************************************************
*
* Function Name:    reKey
*
* Function:            Initialize the Twofish key schedule from key32
*
* Arguments:        key            =    ptr to keyInstance to be initialized
*
* Return:            TRUE on success
*
* Notes:
*    Here we precompute all the round subkeys, although that is not actually
*    required.  For example, on a smartcard, the round subkeys can
*    be generated on-the-fly    using f32()
*
-****************************************************************************/
int reKey(keyInstance *key)
    {
    int        i,j,k64Cnt,keyLen;
    int        subkeyCnt;
    DWORD    A=0,B=0,q;
    DWORD    sKey[MAX_KEY_BITS/64],k32e[MAX_KEY_BITS/64],k32o[MAX_KEY_BITS/64];
    BYTE    L0[256],L1[256];    /* small local 8-bit permutations */

#if VALIDATE_PARMS
  #if ALIGN32
    if (((int)key) & 3)
        return BAD_ALIGN32;
    if ((key->keyLen % 64) || (key->keyLen < MIN_KEY_BITS))
        return BAD_KEY_INSTANCE;
  #endif
#endif

    if (needToBuildMDS)            /* do this one time only */
        BuildMDS();

#define    F32(res,x,k32)    \
    {                                                            \
    DWORD t=x;                                                    \
    switch (k64Cnt & 3)                                            \
        {                                                        \
        case 0:  /* same as 4 */                                \
                    b0(t)   = p8(04)[b0(t)] ^ b0(k32[3]);        \
                    b1(t)   = p8(14)[b1(t)] ^ b1(k32[3]);        \
                    b2(t)   = p8(24)[b2(t)] ^ b2(k32[3]);        \
                    b3(t)   = p8(34)[b3(t)] ^ b3(k32[3]);        \
                 /* fall thru, having pre-processed t */        \
        case 3:        b0(t)   = p8(03)[b0(t)] ^ b0(k32[2]);        \
                    b1(t)   = p8(13)[b1(t)] ^ b1(k32[2]);        \
                    b2(t)   = p8(23)[b2(t)] ^ b2(k32[2]);        \
                    b3(t)   = p8(33)[b3(t)] ^ b3(k32[2]);        \
                 /* fall thru, having pre-processed t */        \
        case 2:     /* 128-bit keys (optimize for this case) */    \
            res=    MDStab[0][p8(01)[p8(02)[b0(t)] ^ b0(k32[1])] ^ b0(k32[0])] ^    \
                    MDStab[1][p8(11)[p8(12)[b1(t)] ^ b1(k32[1])] ^ b1(k32[0])] ^    \
                    MDStab[2][p8(21)[p8(22)[b2(t)] ^ b2(k32[1])] ^ b2(k32[0])] ^    \
                    MDStab[3][p8(31)[p8(32)[b3(t)] ^ b3(k32[1])] ^ b3(k32[0])] ;    \
        }                                                        \
    }


#if !CHECK_TABLE
#if defined(USE_ASM)                /* only do this if not using assember */
if (!(useAsm & 4))
#endif
#endif
    {
    subkeyCnt = ROUND_SUBKEYS + 2*key->numRounds;
    keyLen=key->keyLen;
    k64Cnt=(keyLen+63)/64;            /* number of 64-bit key words */
    for (i=0,j=k64Cnt-1;i<k64Cnt;i++,j--)
        {                            /* split into even/odd key dwords */
        k32e[i]=key->key32[2*i  ];
        k32o[i]=key->key32[2*i+1];
        /* compute S-box keys using (12,8) Reed-Solomon code over GF(256) */
        sKey[j]=key->sboxKeys[j]=RS_MDS_Encode(k32e[i],k32o[i]);    /* reverse order */
        }
    }

#ifdef USE_ASM
if (useAsm & 4)
    {
    #if defined(COMPILE_KEY) && defined(USE_ASM)
        key->keySig        = VALID_SIG;            /* show that we are initialized */
        key->codeSize    = sizeof(key->compiledCode);    /* set size */
    #endif
    reKey_86(key);
    }
else
#endif
    {
    for (i=q=0;i<subkeyCnt/2;i++,q+=SK_STEP)
        {                            /* compute round subkeys for PHT */
        F32(A,q        ,k32e);        /* A uses even key dwords */
        F32(B,q+SK_BUMP,k32o);        /* B uses odd  key dwords */
        B = ROL(B,8);
        key->subKeys[2*i  ] = A+B;    /* combine with a PHT */
        B = A + 2*B;
        key->subKeys[2*i+1] = ROL(B,SK_ROTL);
        }
#if !defined(ZERO_KEY)
    switch (keyLen)    /* case out key length for speed in generating S-boxes */
        {
        case 128:
        #if defined(FULL_KEY) || defined(PART_KEY)
#if BIG_TAB
            #define    one128(N,J)    sbSet(N,i,J,L0[i+J])
            #define    sb128(N) {                        \
                BYTE *qq=bigTab[N][b##N(sKey[1])];    \
                Xor256(L0,qq,b##N(sKey[0]));        \
                for (i=0;i<256;i+=2) { one128(N,0); one128(N,1); } }
#else
            #define    one128(N,J)    sbSet(N,i,J,p8(N##1)[L0[i+J]]^k0)
            #define    sb128(N) {                    \
                Xor256(L0,p8(N##2),b##N(sKey[1]));    \
                { register DWORD k0=b##N(sKey[0]);    \
                for (i=0;i<256;i+=2) { one128(N,0); one128(N,1); } } }
#endif
        #elif defined(MIN_KEY)
            #define    sb128(N) Xor256(_sBox8_(N),p8(N##2),b##N(sKey[1]))
        #endif
            sb128(0); sb128(1); sb128(2); sb128(3);
            break;
        case 192:
        #if defined(FULL_KEY) || defined(PART_KEY)
            #define one192(N,J) sbSet(N,i,J,p8(N##1)[p8(N##2)[L0[i+J]]^k1]^k0)
            #define    sb192(N) {                        \
                Xor256(L0,p8(N##3),b##N(sKey[2]));    \
                { register DWORD k0=b##N(sKey[0]);    \
                  register DWORD k1=b##N(sKey[1]);    \
                  for (i=0;i<256;i+=2) { one192(N,0); one192(N,1); } } }
        #elif defined(MIN_KEY)
            #define one192(N,J) sbSet(N,i,J,p8(N##2)[L0[i+J]]^k1)
            #define    sb192(N) {                        \
                Xor256(L0,p8(N##3),b##N(sKey[2]));    \
                { register DWORD k1=b##N(sKey[1]);    \
                  for (i=0;i<256;i+=2) { one192(N,0); one192(N,1); } } }
        #endif
            sb192(0); sb192(1); sb192(2); sb192(3);
            break;
        case 256:
        #if defined(FULL_KEY) || defined(PART_KEY)
            #define one256(N,J) sbSet(N,i,J,p8(N##1)[p8(N##2)[L0[i+J]]^k1]^k0)
            #define    sb256(N) {                                        \
                Xor256(L1,p8(N##4),b##N(sKey[3]));                    \
                for (i=0;i<256;i+=2) {L0[i  ]=p8(N##3)[L1[i]];        \
                                      L0[i+1]=p8(N##3)[L1[i+1]]; }    \
                Xor256(L0,L0,b##N(sKey[2]));                        \
                { register DWORD k0=b##N(sKey[0]);                    \
                  register DWORD k1=b##N(sKey[1]);                    \
                  for (i=0;i<256;i+=2) { one256(N,0); one256(N,1); } } }
        #elif defined(MIN_KEY)
            #define one256(N,J) sbSet(N,i,J,p8(N##2)[L0[i+J]]^k1)
            #define    sb256(N) {                                        \
                Xor256(L1,p8(N##4),b##N(sKey[3]));                    \
                for (i=0;i<256;i+=2) {L0[i  ]=p8(N##3)[L1[i]];        \
                                      L0[i+1]=p8(N##3)[L1[i+1]]; }    \
                Xor256(L0,L0,b##N(sKey[2]));                        \
                { register DWORD k1=b##N(sKey[1]);                    \
                  for (i=0;i<256;i+=2) { one256(N,0); one256(N,1); } } }
        #endif
            sb256(0); sb256(1);    sb256(2); sb256(3);
            break;
        }
#endif
    }

#if CHECK_TABLE                        /* sanity check  vs. pedagogical code*/
    {
    GetSboxKey;
    for (i=0;i<subkeyCnt/2;i++)
        {
        A = f32(i*SK_STEP        ,k32e,keyLen);    /* A uses even key dwords */
        B = f32(i*SK_STEP+SK_BUMP,k32o,keyLen);    /* B uses odd  key dwords */
        B = ROL(B,8);
        assert(key->subKeys[2*i  ] == A+  B);
        assert(key->subKeys[2*i+1] == ROL(A+2*B,SK_ROTL));
        }
  #if !defined(ZERO_KEY)            /* any S-boxes to check? */
    for (i=q=0;i<256;i++,q+=0x01010101)
        assert(f32(q,key->sboxKeys,keyLen) == Fe32_(q,0));
  #endif
    }
#endif /* CHECK_TABLE */

    DebugDumpKey(key);

    if (key->direction == DIR_ENCRYPT)
        ReverseRoundSubkeys(key,DIR_ENCRYPT);    /* reverse the round subkey order */

    return TRUE;
    }
/*
+*****************************************************************************
*
* Function Name:    makeKey
*
* Function:            Initialize the Twofish key schedule
*
* Arguments:        key            =    ptr to keyInstance to be initialized
*                    direction    =    DIR_ENCRYPT or DIR_DECRYPT
*                    keyLen        =    # bits of key text at *keyMaterial
*                    keyMaterial    =    ptr to hex ASCII chars representing key bits
*
* Return:            TRUE on success
*                    else error code (e.g., BAD_KEY_DIR)
*
* Notes:    This parses the key bits from keyMaterial.  Zeroes out unused key bits
*
-****************************************************************************/
int makeKey(keyInstance *key, BYTE direction, int keyLen,CONST char *keyMaterial)
    {
#if VALIDATE_PARMS                /* first, sanity check on parameters */
    if (key == NULL)
        return BAD_KEY_INSTANCE;/* must have a keyInstance to initialize */
    if ((direction != DIR_ENCRYPT) && (direction != DIR_DECRYPT))
        return BAD_KEY_DIR;        /* must have valid direction */
    if ((keyLen > MAX_KEY_BITS) || (keyLen < 8) || (keyLen & 0x3F))
        return BAD_KEY_MAT;        /* length must be valid */
    key->keySig = VALID_SIG;    /* show that we are initialized */
  #if ALIGN32
    if ((((int)key) & 3) || (((int)key->key32) & 3))
        return BAD_ALIGN32;
  #endif
#endif

    key->direction    = direction;/* set our cipher direction */
    key->keyLen        = (keyLen+63) & ~63;        /* round up to multiple of 64 */
    key->numRounds    = numRounds[(keyLen-1)/64];
    memset(key->key32,0,sizeof(key->key32));    /* zero unused bits */
    key->keyMaterial[MAX_KEY_SIZE]=0;    /* terminate ASCII string */

    if ((keyMaterial == NULL) || (keyMaterial[0]==0))
        return TRUE;            /* allow a "dummy" call */

    if (ParseHexDword(keyLen,keyMaterial,key->key32,key->keyMaterial))
        return BAD_KEY_MAT;

    return reKey(key);            /* generate round subkeys */
    }


/*
+*****************************************************************************
*
* Function Name:    cipherInit
*
* Function:            Initialize the Twofish cipher in a given mode
*
* Arguments:        cipher        =    ptr to cipherInstance to be initialized
*                    mode        =    MODE_ECB, MODE_CBC, or MODE_CFB1
*                    IV            =    ptr to hex ASCII test representing IV bytes
*
* Return:            TRUE on success
*                    else error code (e.g., BAD_CIPHER_MODE)
*
-****************************************************************************/
int cipherInit(cipherInstance *cipher, BYTE mode,CONST char *IV)
    {
    int i;
#if VALIDATE_PARMS                /* first, sanity check on parameters */
    if (cipher == NULL)
        return BAD_PARAMS;        /* must have a cipherInstance to initialize */
    if ((mode != MODE_ECB) && (mode != MODE_CBC) && (mode != MODE_CFB1))
        return BAD_CIPHER_MODE;    /* must have valid cipher mode */
    cipher->cipherSig    =    VALID_SIG;
  #if ALIGN32
    if ((((int)cipher) & 3) || (((int)cipher->IV) & 3) || (((int)cipher->iv32) & 3))
        return BAD_ALIGN32;
  #endif
#endif

    if ((mode != MODE_ECB) && (IV))    /* parse the IV */
        {
        if (ParseHexDword(BLOCK_SIZE,IV,cipher->iv32,NULL))
            return BAD_IV_MAT;
        for (i=0;i<BLOCK_SIZE/32;i++)    /* make byte-oriented copy for CFB1 */
            ((DWORD *)cipher->IV)[i] = Bswap(cipher->iv32[i]);
        }

    cipher->mode        =    mode;

    return TRUE;
    }

/*
+*****************************************************************************
*
* Function Name:    blockEncrypt
*
* Function:            Encrypt block(s) of data using Twofish
*
* Arguments:        cipher        =    ptr to already initialized cipherInstance
*                    key            =    ptr to already initialized keyInstance
*                    input        =    ptr to data blocks to be encrypted
*                    inputLen    =    # bits to encrypt (multiple of blockSize)
*                    outBuffer    =    ptr to where to put encrypted blocks
*
* Return:            # bits ciphered (>= 0)
*                    else error code (e.g., BAD_CIPHER_STATE, BAD_KEY_MATERIAL)
*
* Notes: The only supported block size for ECB/CBC modes is BLOCK_SIZE bits.
*         If inputLen is not a multiple of BLOCK_SIZE bits in those modes,
*         an error BAD_INPUT_LEN is returned.  In CFB1 mode, all block
*         sizes can be supported.
*
-****************************************************************************/
[COLOR=royalblue][B]__device__[/B] int blockEncrypt(cipherInstance *cipher, keyInstance *key,CONST BYTE *input,
                int inputLen, BYTE *outBuffer)
    {
    int   i,n;                        /* loop counters */
    DWORD x[BLOCK_SIZE/32];            /* block being encrypted */
    DWORD t0,t1;                    /* temp variables */
    int      rounds=key->numRounds;    /* number of rounds */
    BYTE  bit,bit0,ctBit,carry;        /* temps for CFB */

    /* make local copies of things for faster access */
    int      mode = cipher->mode;
    DWORD sk[TOTAL_SUBKEYS];
    DWORD IV[BLOCK_SIZE/32];

    GetSboxKey;

#if VALIDATE_PARMS
    if ((cipher == NULL) || (cipher->cipherSig != VALID_SIG))
        return BAD_CIPHER_STATE;
    if ((key == NULL) || (key->keySig != VALID_SIG))
        return BAD_KEY_INSTANCE;
    if ((rounds < 2) || (rounds > MAX_ROUNDS) || (rounds&1))
        return BAD_KEY_INSTANCE;
    if ((mode != MODE_CFB1) && (inputLen % BLOCK_SIZE))
        return BAD_INPUT_LEN;
  #if ALIGN32
    if ( (((int)cipher) & 3) || (((int)key      ) & 3) ||
         (((int)input ) & 3) || (((int)outBuffer) & 3))
        return BAD_ALIGN32;
  #endif
#endif

    if (mode == MODE_CFB1)
        {    /* use recursion here to handle CFB, one block at a time */
        cipher->mode = MODE_ECB;    /* do encryption in ECB */
        for (n=0;n<inputLen;n++)
            {
            blockEncrypt(cipher,key,cipher->IV,BLOCK_SIZE,(BYTE *)x);
            bit0  = 0x80 >> (n & 7);/* which bit position in byte */
            ctBit = (input[n/8] & bit0) ^ ((((BYTE *) x)[0] & 0x80) >> (n&7));
            outBuffer[n/8] = (outBuffer[n/8] & ~ bit0) | ctBit;
            carry = ctBit >> (7 - (n&7));
            for (i=BLOCK_SIZE/8-1;i>=0;i--)
                {
                bit = cipher->IV[i] >> 7;    /* save next "carry" from shift */
                cipher->IV[i] = (cipher->IV[i] << 1) ^ carry;
                carry = bit;
                }
            }
        cipher->mode = MODE_CFB1;    /* restore mode for next time */
        return inputLen;
        }

    /* here for ECB, CBC modes */
    if (key->direction != DIR_ENCRYPT)
        ReverseRoundSubkeys(key,DIR_ENCRYPT);    /* reverse the round subkey order */

#ifdef USE_ASM
    if ((useAsm & 1) && (inputLen))
  #ifdef COMPILE_KEY
        if (key->keySig == VALID_SIG)
            return ((CipherProc *)(key->encryptFuncPtr))(cipher,key,input,inputLen,outBuffer);
  #else
        return (*blockEncrypt_86)(cipher,key,input,inputLen,outBuffer);
  #endif
#endif
    /* make local copy of subkeys for speed */
    memcpy(sk,key->subKeys,sizeof(DWORD)*(ROUND_SUBKEYS+2*rounds));
    if (mode == MODE_CBC) {
        BlockCopy(IV,cipher->iv32);
    } else {
        IV[0]=IV[1]=IV[2]=IV[3]=0;
    }

    for (n=0;n<inputLen;n+=BLOCK_SIZE,input+=BLOCK_SIZE/8,outBuffer+=BLOCK_SIZE/8)
        {
#ifdef DEBUG
        DebugDump(input,"\n",-1,0,0,0,1);
        if (cipher->mode == MODE_CBC)
            DebugDump(cipher->iv32,"",IV_ROUND,0,0,0,0);
#endif
#define    LoadBlockE(N)  x[N]=Bswap(((DWORD *)input)[N]) ^ sk[INPUT_WHITEN+N] ^ IV[N]
        LoadBlockE(0);    LoadBlockE(1);    LoadBlockE(2);    LoadBlockE(3);
        DebugDump(x,"",0,0,0,0,0);
#define    EncryptRound(K,R,id)    \
            t0       = Fe32##id(x[K  ],0);                    \
            t1       = Fe32##id(x[K^1],3);                    \
            x[K^3] = ROL(x[K^3],1);                            \
            x[K^2]^= t0 +   t1 + sk[ROUND_SUBKEYS+2*(R)  ];    \
            x[K^3]^= t0 + 2*t1 + sk[ROUND_SUBKEYS+2*(R)+1];    \
            x[K^2] = ROR(x[K^2],1);                            \
            DebugDump(x,"",rounds-(R),0,0,1,0);
#define        Encrypt2(R,id)    { EncryptRound(0,R+1,id); EncryptRound(2,R,id); }

#if defined(ZERO_KEY)
        switch (key->keyLen)
            {
            case 128:
                for (i=rounds-2;i>=0;i-=2)
                    Encrypt2(i,_128);
                break;
            case 192:
                for (i=rounds-2;i>=0;i-=2)
                    Encrypt2(i,_192);
                break;
            case 256:
                for (i=rounds-2;i>=0;i-=2)
                    Encrypt2(i,_256);
                break;
            }
#else
        Encrypt2(14,_);
        Encrypt2(12,_);
        Encrypt2(10,_);
        Encrypt2( 8,_);
        Encrypt2( 6,_);
        Encrypt2( 4,_);
        Encrypt2( 2,_);
        Encrypt2( 0,_);
#endif

        /* need to do (or undo, depending on your point of view) final swap */
#if LittleEndian
#define    StoreBlockE(N)    ((DWORD *)outBuffer)[N]=x[N^2] ^ sk[OUTPUT_WHITEN+N]
#else
#define    StoreBlockE(N)    { t0=x[N^2] ^ sk[OUTPUT_WHITEN+N]; ((DWORD *)outBuffer)[N]=Bswap(t0); }
#endif
        StoreBlockE(0);    StoreBlockE(1);    StoreBlockE(2);    StoreBlockE(3);
        if (mode == MODE_CBC)
            {
            IV[0]=Bswap(((DWORD *)outBuffer)[0]);
            IV[1]=Bswap(((DWORD *)outBuffer)[1]);
            IV[2]=Bswap(((DWORD *)outBuffer)[2]);
            IV[3]=Bswap(((DWORD *)outBuffer)[3]);
            }
#ifdef DEBUG
        DebugDump(outBuffer,"",rounds+1,0,0,0,1);
        if (cipher->mode == MODE_CBC)
            DebugDump(cipher->iv32,"",IV_ROUND,0,0,0,0);
#endif
        }

    if (mode == MODE_CBC)
        BlockCopy(cipher->iv32,IV);

    return inputLen;
    }

/*
+*****************************************************************************
*
* Function Name:    blockDecrypt
*
* Function:            Decrypt block(s) of data using Twofish
*
* Arguments:        cipher        =    ptr to already initialized cipherInstance
*                    key            =    ptr to already initialized keyInstance
*                    input        =    ptr to data blocks to be decrypted
*                    inputLen    =    # bits to encrypt (multiple of blockSize)
*                    outBuffer    =    ptr to where to put decrypted blocks
*
* Return:            # bits ciphered (>= 0)
*                    else error code (e.g., BAD_CIPHER_STATE, BAD_KEY_MATERIAL)
*
* Notes: The only supported block size for ECB/CBC modes is BLOCK_SIZE bits.
*         If inputLen is not a multiple of BLOCK_SIZE bits in those modes,
*         an error BAD_INPUT_LEN is returned.  In CFB1 mode, all block
*         sizes can be supported.
*
-****************************************************************************/
[COLOR=royalblue][B]__device__[/B] int blockDecrypt(cipherInstance *cipher, keyInstance *key,CONST BYTE *input,
                int inputLen, BYTE *outBuffer)
    {
    int   i,n;                        /* loop counters */
    DWORD x[BLOCK_SIZE/32];            /* block being encrypted */
    DWORD t0,t1;                    /* temp variables */
    int      rounds=key->numRounds;    /* number of rounds */
    BYTE  bit,bit0,ctBit,carry;        /* temps for CFB */

    /* make local copies of things for faster access */
    int      mode = cipher->mode;
    DWORD sk[TOTAL_SUBKEYS];
    DWORD IV[BLOCK_SIZE/32];

    GetSboxKey;

#if VALIDATE_PARMS
    if ((cipher == NULL) || (cipher->cipherSig != VALID_SIG))
        return BAD_CIPHER_STATE;
    if ((key == NULL) || (key->keySig != VALID_SIG))
        return BAD_KEY_INSTANCE;
    if ((rounds < 2) || (rounds > MAX_ROUNDS) || (rounds&1))
        return BAD_KEY_INSTANCE;
    if ((cipher->mode != MODE_CFB1) && (inputLen % BLOCK_SIZE))
        return BAD_INPUT_LEN;
  #if ALIGN32
    if ( (((int)cipher) & 3) || (((int)key      ) & 3) ||
         (((int)input)  & 3) || (((int)outBuffer) & 3))
        return BAD_ALIGN32;
  #endif
#endif

    if (cipher->mode == MODE_CFB1)
        {    /* use blockEncrypt here to handle CFB, one block at a time */
        cipher->mode = MODE_ECB;    /* do encryption in ECB */
        for (n=0;n<inputLen;n++)
            {
            blockEncrypt(cipher,key,cipher->IV,BLOCK_SIZE,(BYTE *)x);
            bit0  = 0x80 >> (n & 7);
            ctBit = input[n/8] & bit0;
            outBuffer[n/8] = (outBuffer[n/8] & ~ bit0) |
                             (ctBit ^ ((((BYTE *) x)[0] & 0x80) >> (n&7)));
            carry = ctBit >> (7 - (n&7));
            for (i=BLOCK_SIZE/8-1;i>=0;i--)
                {
                bit = cipher->IV[i] >> 7;    /* save next "carry" from shift */
                cipher->IV[i] = (cipher->IV[i] << 1) ^ carry;
                carry = bit;
                }
            }
        cipher->mode = MODE_CFB1;    /* restore mode for next time */
        return inputLen;
        }

    /* here for ECB, CBC modes */
    if (key->direction != DIR_DECRYPT)
        ReverseRoundSubkeys(key,DIR_DECRYPT);    /* reverse the round subkey order */
#ifdef USE_ASM
    if ((useAsm & 2) && (inputLen))
  #ifdef COMPILE_KEY
        if (key->keySig == VALID_SIG)
            return ((CipherProc *)(key->decryptFuncPtr))(cipher,key,input,inputLen,outBuffer);
  #else
        return (*blockDecrypt_86)(cipher,key,input,inputLen,outBuffer);
  #endif
#endif
    /* make local copy of subkeys for speed */
    memcpy(sk,key->subKeys,sizeof(DWORD)*(ROUND_SUBKEYS+2*rounds));
    if (mode == MODE_CBC) {
        BlockCopy(IV,cipher->iv32);
    } else {
        IV[0]=IV[1]=IV[2]=IV[3]=0;
    }

    for (n=0;n<inputLen;n+=BLOCK_SIZE,input+=BLOCK_SIZE/8,outBuffer+=BLOCK_SIZE/8)
        {
        DebugDump(input,"\n",rounds+1,0,0,0,1);
#define LoadBlockD(N) x[N^2]=Bswap(((DWORD *)input)[N]) ^ sk[OUTPUT_WHITEN+N]
        LoadBlockD(0);    LoadBlockD(1);    LoadBlockD(2);    LoadBlockD(3);

#define    DecryptRound(K,R,id)                                \
            t0       = Fe32##id(x[K  ],0);                    \
            t1       = Fe32##id(x[K^1],3);                    \
            DebugDump(x,"",(R)+1,0,0,1,0);                    \
            x[K^2] = ROL (x[K^2],1);                        \
            x[K^2]^= t0 +   t1 + sk[ROUND_SUBKEYS+2*(R)  ];    \
            x[K^3]^= t0 + 2*t1 + sk[ROUND_SUBKEYS+2*(R)+1];    \
            x[K^3] = ROR (x[K^3],1);                        \

#define        Decrypt2(R,id)    { DecryptRound(2,R+1,id); DecryptRound(0,R,id); }

#if defined(ZERO_KEY)
        switch (key->keyLen)
            {
            case 128:
                for (i=rounds-2;i>=0;i-=2)
                    Decrypt2(i,_128);
                break;
            case 192:
                for (i=rounds-2;i>=0;i-=2)
                    Decrypt2(i,_192);
                break;
            case 256:
                for (i=rounds-2;i>=0;i-=2)
                    Decrypt2(i,_256);
                break;
            }
#else
        {
        Decrypt2(14,_);
        Decrypt2(12,_);
        Decrypt2(10,_);
        Decrypt2( 8,_);
        Decrypt2( 6,_);
        Decrypt2( 4,_);
        Decrypt2( 2,_);
        Decrypt2( 0,_);
        }
#endif
        DebugDump(x,"",0,0,0,0,0);
        if (cipher->mode == MODE_ECB)
            {
#if LittleEndian
#define    StoreBlockD(N)    ((DWORD *)outBuffer)[N] = x[N] ^ sk[INPUT_WHITEN+N]
#else
#define    StoreBlockD(N)    { t0=x[N]^sk[INPUT_WHITEN+N]; ((DWORD *)outBuffer)[N] = Bswap(t0); }
#endif
            StoreBlockD(0);    StoreBlockD(1);    StoreBlockD(2);    StoreBlockD(3);
#undef  StoreBlockD
            DebugDump(outBuffer,"",-1,0,0,0,1);
            continue;
            }
        else
            {
#define    StoreBlockD(N)    x[N]   ^= sk[INPUT_WHITEN+N] ^ IV[N];    \
                        IV[N]   = Bswap(((DWORD *)input)[N]);    \
                        ((DWORD *)outBuffer)[N] = Bswap(x[N]);
            StoreBlockD(0);    StoreBlockD(1);    StoreBlockD(2);    StoreBlockD(3);
#undef  StoreBlockD
            DebugDump(outBuffer,"",-1,0,0,0,1);
            }
        }
    if (mode == MODE_CBC)    /* restore iv32 to cipher */
        BlockCopy(cipher->iv32,IV);

    return inputLen;
    }

#ifdef GetCodeSize
DWORD TwofishCodeSize(void)
    {
    DWORD x= Here(0);
#ifdef USE_ASM
    if (useAsm & 3)
        return TwofishAsmCodeSize();
#endif
    return x - TwofishCodeStart();
    };
#endif
[COLOR=royalblue][B]
__global__ void encrypt(cipherInstance *cipher, keyInstance *key, CONST BYTE *input, int inputLen, BYTE *outBuffer) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    blockEncrypt(cipher, key, input + 16*b, inputLen, outBuffer);
}

__global__ void decrypt(cipherInstance *cipher, keyInstance *key, CONST BYTE *input, int inputLen, BYTE *outBuffer) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    blockDecrypt(cipher, key, input + 16*b, inputLen, outBuffer);
}

inline void HandleErrorImpl(cudaError error, const char* file, int line) {
    if (error != cudaSuccess) {
        printf("%s: %d %s", file, line, cudaGetErrorString(error));
        exit(1);
    }
}

int main(void) {
    char* initKey = "meingeheimespasswort";
    int threads = 512;
    int blocks = 12800;
    cipherInstance *cipher;
    keyInstance *key;
    int inputLen = 16*threads*blocks;

    CONST BYTE *input;
    HandleError(cudaMalloc(&input, 16*threads*blocks));
    HandleError(cudaMemset(input, 0, 16*threads*blocks));

    BYTE *outBuffer;
    HandleError(cudaMalloc(&outBuffer, 16*threads*blocks));

    char *test1 = (char*)malloc(16*threads*blocks);
    HandleError(cudaMemcpy(test1, input, 16*threads*blocks, cudaMemcpyDeviceToHost));

    printf("First 16 bytes of input data: ");
    for (int i=0; i<16; i++) {
        printf("%d, ", test1[i]);
    }

    cudaEvent_t start, stop;
    HandleError(cudaEventCreate(&start));
    HandleError(cudaEventCreate(&stop));
    HandleError(cudaEventRecord( start, 0 ));

    encrypt<<<blocks,threads>>>(cipher, key, input, inputLen, outBuffer);
    decrypt<<<blocks,threads>>>(cipher, key, outBuffer, inputLen, input);

    HandleError(cudaGetLastError());

    HandleError(cudaEventRecord( stop, 0 ));
    HandleError(cudaEventSynchronize( stop ));
    float elapsedTime;
    HandleError(cudaEventElapsedTime( &elapsedTime, start, stop ));

    printf("\nPerformance: %.6f MB/sec\n", 2*((16*threads*blocks)/1048576)/(elapsedTime/1000));

    HandleError(cudaEventDestroy( start ));
    HandleError(cudaEventDestroy( stop ));

    char *test2 = (char*)malloc(16*threads*blocks);
    HandleError(cudaMemcpy(test2, outBuffer, 16*threads*blocks, cudaMemcpyDeviceToHost));

    printf("After decryption: ");
    for (int i=0; i<16; i++) {
        printf("%d, ", test2[i]);
    }

    free(test1);
    free(test2);

    HandleError(cudaFree(input));
    HandleError(cudaFree(outBuffer));

    return 0;
}[/B]
```



			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



*[Edit]*
Wenn ich ReverseRoundSubkeys() zu einer __host__ __device__ Funktion mache, dann kriege ich folgenden Error:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Kann ich's trotzdem so lassen? Hier meint einer, dass Rekursion auf Hardware ab Compute capability 2.0 unterstützt wird. Kannst du das bitte mal mit deiner GTX 560 Ti testen? Ist halt blöd, dass ich das jetzt wieder nicht testen kann und mit dem Error weiterprogrammieren muss. _*seufz*_


----------



## sebi707 (2. Januar 2014)

*AW: [CUDA] RC6 / Serpent /Twofish*

Der rekursive Teil scheint nur für den CFB Modus benutzt zu werden. Da du den aber eh nicht nutzen willst kannst du den ganzen if-Block mit "if (cipher->mode == MODE_CFB1)" rausnehmen. Dann hast du keine Rekusion mehr aber der Code sieht nicht sonderlich gut aus um nach CUDA portiert zu werden. Die blockDecrypt sind wohl eher dazu gedacht gleich mehr Daten zu ver- und entschlüsseln und du willst eigentlich nur einen Block verarbeiten. Außerdem sehe ich grade noch irgendwelche Debug Outputs und sonstwas das man wohl alles rauswerfen müsste.

Außerdem verstehe ich deine Aussage zu fremden CUDA-Code nicht. Der Serpent Code war definitiv nicht für CUDA sonst hättest du nicht überall __device__ und sonstwas ergänzen müssen. Wenn du fertigen CUDA-Code findest ist schon alles fertig und du musst nur noch deine Kernel schreiben und dich nicht um komische Fehler kümmern weil die Funktionen komische Sachen machen die so auf GPU nicht funktionieren.


----------



## boss3D (2. Januar 2014)

*AW: [CUDA] RC6 / Serpent /Twofish*

Zu Serpent: Was ich gefunden hatte, war ein .cu File, aber ohne irgendwas darin, das auf CUDA hingedeute hätte. Keine __device__, keine __global__, nichts. Ich war mir dann auch nicht sicher, was das war. C Code in einem .cu File?! Egal ...

Zu Twofish: Tja, ich hätte heute Früh einen anderen Code gehabt, der sich aber aus über 20 einzelnen Files zusammengesetzt hatte. Mit sowas wollte ich echt nicht arbeiten. Ich hatte da gar keinen Überblick. Dann habe ich beim Weitersuchen den hier mit 5 Files gefunden. Meinst du, ich solle hier weiterbasteln, oder lieber noch einen anderen Twofish suchen?


----------



## sebi707 (2. Januar 2014)

*AW: [CUDA] RC6 / Serpent /Twofish*

Dieser Code zu Twofish sieht übersichtlich aus (bis auf das alle Zeileumbrüche irgendwie doppelt sind):
https://www.schneier.com/sccd/TWOFISH.ZIP


----------



## boss3D (2. Januar 2014)

*AW: [CUDA] RC6 / Serpent /Twofish*

^^ Hm, ich habe mir den Code jetzt mal angeschaut und auch die ganzen unnötigen Leerzeilen gelöscht, allerdings findet Nsight Eclipse 83 Error und im Code selber werden zumindest 2 Dinge rot unterwellt:

```
/* This is an independent implementation of the encryption algorithm:   */
/*                                                                      */
/*         Twofish by Bruce Schneier and colleagues                     */
/*                                                                      */
/* which is a candidate algorithm in the Advanced Encryption Standard   */
/* programme of the US National Institute of Standards and Technology.  */
/*                                                                      */
/* Copyright in this implementation is held by Dr B R Gladman but I     */
/* hereby give permission for its free direct or derivative use subject */
/* to acknowledgment of its origin and compliance with any conditions   */
/* that the originators of t he algorithm place on its exploitation.     */
/*                                                                      */
/* My thanks to Doug Whiting and Niels Ferguson for comments that led   */
/* to improvements in this implementation.                              */
/*                                                                      */
/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */

/* Timing data for Twofish (twofish.c)

128 bit key:
Key Setup:    8414 cycles
Encrypt:       376 cycles =    68.1 mbits/sec
Decrypt:       374 cycles =    68.4 mbits/sec
Mean:          375 cycles =    68.3 mbits/sec

192 bit key:
Key Setup:   11628 cycles
Encrypt:       376 cycles =    68.1 mbits/sec
Decrypt:       374 cycles =    68.4 mbits/sec
Mean:          375 cycles =    68.3 mbits/sec

256 bit key:
Key Setup:   15457 cycles
Encrypt:       381 cycles =    67.2 mbits/sec
Decrypt:       374 cycles =    68.4 mbits/sec
Mean:          378 cycles =    67.8 mbits/sec

*/

#include "std_defs.h"
#include <stdio.h>

#define Q_TABLES
#define M_TABLE
#define MK_TABLE
#define ONE_STEP

static char *alg_name[] = { "twofish", "twofish.c", "twofish" };

char **cipher_name()
{
    [COLOR=red][B]return alg_name;[/B]}

u4byte  k_len;
u4byte  l_key[40];
u4byte  s_key[4];

/* finite field arithmetic for GF(2**8) with the modular    */
/* polynomial x^8 + x^6 + x^5 + x^3 + 1 (0x169)             */

#define G_M 0x0169

u1byte  tab_5b[4] = { 0, G_M >> 2, G_M >> 1, (G_M >> 1) ^ (G_M >> 2) };
u1byte  tab_ef[4] = { 0, (G_M >> 1) ^ (G_M >> 2), G_M >> 1, G_M >> 2 };

#define ffm_01(x)    (x)
#define ffm_5b(x)   ((x) ^ ((x) >> 2) ^ tab_5b[(x) & 3])
#define ffm_ef(x)   ((x) ^ ((x) >> 1) ^ ((x) >> 2) ^ tab_ef[(x) & 3])

u1byte ror4[16] = { 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 };
u1byte ashx[16] = { 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 5, 14, 7 };

u1byte qt0[2][16] =
{   { 8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4 },
    { 2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5 }
};

u1byte qt1[2][16] =
{   { 14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13 },
    { 1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8 }
};

u1byte qt2[2][16] =
{   { 11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1 },
    { 4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15 }
};

u1byte qt3[2][16] =
{   { 13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10 },
    { 11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10 }
};

u1byte qp(const u4byte n, const u1byte x)
{   u1byte  a0, a1, a2, a3, a4, b0, b1, b2, b3, b4;

    a0 = x >> 4; b0 = x & 15;
    a1 = a0 ^ b0; b1 = ror4[b0] ^ ashx[a0];
    a2 = qt0[n][a1]; b2 = qt1[n][b1];
    a3 = a2 ^ b2; b3 = ror4[b2] ^ ashx[a2];
    a4 = qt2[n][a3]; b4 = qt3[n][b3];

    return (b4 << 4) | a4;
};

#ifdef  Q_TABLES

u4byte  qt_gen = 0;
u1byte  q_tab[2][256];

#define q(n,x)  q_tab[n][x]

void gen_qtab(void)
{   u4byte  i;

    for(i = 0; i < 256; ++i)
    {
        q(0,i) = qp(0, (u1byte)i);
        q(1,i) = qp(1, (u1byte)i);
    }
};

#else
#define q(n,x)  qp(n, x)
#endif

#ifdef  M_TABLE

u4byte  mt_gen = 0;
u4byte  m_tab[4][256];

void gen_mtab(void)
{   u4byte  i, f01, f5b, fef;

    for(i = 0; i < 256; ++i)
    {
        f01 = q(1,i); f5b = ffm_5b(f01); fef = ffm_ef(f01);
        m_tab[0][i] = f01 + (f5b << 8) + (fef << 16) + (fef << 24);
        m_tab[2][i] = f5b + (fef << 8) + (f01 << 16) + (fef << 24);

        f01 = q(0,i); f5b = ffm_5b(f01); fef = ffm_ef(f01);
        m_tab[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24);
        m_tab[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24);
    }
};

#define mds(n,x)    m_tab[n][x]

#else

#define fm_00   ffm_01
#define fm_10   ffm_5b
#define fm_20   ffm_ef
#define fm_30   ffm_ef

#define q_0(x)  q(1,x)

#define fm_01   ffm_ef
#define fm_11   ffm_ef
#define fm_21   ffm_5b
#define fm_31   ffm_01

#define q_1(x)  q(0,x)

#define fm_02   ffm_5b
#define fm_12   ffm_ef
#define fm_22   ffm_01
#define fm_32   ffm_ef

#define q_2(x)  q(1,x)

#define fm_03   ffm_5b
#define fm_13   ffm_01
#define fm_23   ffm_e
#define fm_33   ffm_5b

#define q_3(x)  q(0,x)

#define f_0(n,x)    ((u4byte)fm_0##n(x))
#define f_1(n,x)    ((u4byte)fm_1##n(x) << 8)
#define f_2(n,x)    ((u4byte)fm_2##n(x) << 16)
#define f_3(n,x)    ((u4byte)fm_3##n(x) << 24)

#define mds(n,x)    f_0(n,q_##n(x)) ^ f_1(n,q_##n(x)) ^ f_2(n,q_##n(x)) ^ f_3(n,q_##n(x))

#endif

u4byte h_fun(const u4byte x, const u4byte key[])
{   u4byte  b0, b1, b2, b3;

#ifndef M_TABLE
    u4byte  m5b_b0, m5b_b1, m5b_b2, m5b_b3;
    u4byte  mef_b0, mef_b1, mef_b2, mef_b3;
#endif

    b0 = byte(x, 0); b1 = byte(x, 1); b2 = byte(x, 2); b3 = byte(x, 3);

    switch(k_len)
    {
    case 4: b0 = q(1, b0) ^ byte(key[3],0);
            b1 = q(0, b1) ^ byte(key[3],1);
            b2 = q(0, b2) ^ byte(key[3],2);
            b3 = q(1, b3) ^ byte(key[3],3);

    case 3: b0 = q(1, b0) ^ byte(key[2],0);
            b1 = q(1, b1) ^ byte(key[2],1);
            b2 = q(0, b2) ^ byte(key[2],2);
            b3 = q(0, b3) ^ byte(key[2],3);

    case 2: b0 = q(0,q(0,b0) ^ byte(key[1],0)) ^ byte(key[0],0);
            b1 = q(0,q(1,b1) ^ byte(key[1],1)) ^ byte(key[0],1);
            b2 = q(1,q(0,b2) ^ byte(key[1],2)) ^ byte(key[0],2);
            b3 = q(1,q(1,b3) ^ byte(key[1],3)) ^ byte(key[0],3);
    }

#ifdef  M_TABLE

    return  mds(0, b0) ^ mds(1, b1) ^ mds(2, b2) ^ mds(3, b3);

#else

    b0 = q(1, b0); b1 = q(0, b1); b2 = q(1, b2); b3 = q(0, b3);
    m5b_b0 = ffm_5b(b0); m5b_b1 = ffm_5b(b1); m5b_b2 = ffm_5b(b2); m5b_b3 = ffm_5b(b3);
    mef_b0 = ffm_ef(b0); mef_b1 = ffm_ef(b1); mef_b2 = ffm_ef(b2); mef_b3 = ffm_ef(b3);
    b0 ^= mef_b1 ^ m5b_b2 ^ m5b_b3; b3 ^= m5b_b0 ^ mef_b1 ^ mef_b2;
    b2 ^= mef_b0 ^ m5b_b1 ^ mef_b3; b1 ^= mef_b0 ^ mef_b2 ^ m5b_b3;

    return b0 | (b3 << 8) | (b2 << 16) | (b1 << 24);

#endif
};

#ifdef  MK_TABLE

#ifdef  ONE_STEP

u4byte  mk_tab[4][256];

#else

u1byte  sb[4][256];

#endif

#define q20(x)  q(0,q(0,x) ^ byte(key[1],0)) ^ byte(key[0],0)
#define q21(x)  q(0,q(1,x) ^ byte(key[1],1)) ^ byte(key[0],1)
#define q22(x)  q(1,q(0,x) ^ byte(key[1],2)) ^ byte(key[0],2)
#define q23(x)  q(1,q(1,x) ^ byte(key[1],3)) ^ byte(key[0],3)

#define q30(x)  q(0,q(0,q(1, x) ^ byte(key[2],0)) ^ byte(key[1],0)) ^ byte(key[0],0)
#define q31(x)  q(0,q(1,q(1, x) ^ byte(key[2],1)) ^ byte(key[1],1)) ^ byte(key[0],1)
#define q32(x)  q(1,q(0,q(0, x) ^ byte(key[2],2)) ^ byte(key[1],2)) ^ byte(key[0],2)
#define q33(x)  q(1,q(1,q(0, x) ^ byte(key[2],3)) ^ byte(key[1],3)) ^ byte(key[0],3)

#define q40(x)  q(0,q(0,q(1, q(1, x) ^ byte(key[3],0)) ^ byte(key[2],0)) ^ byte(key[1],0)) ^ byte(key[0],0)
#define q41(x)  q(0,q(1,q(1, q(0, x) ^ byte(key[3],1)) ^ byte(key[2],1)) ^ byte(key[1],1)) ^ byte(key[0],1)
#define q42(x)  q(1,q(0,q(0, q(0, x) ^ byte(key[3],2)) ^ byte(key[2],2)) ^ byte(key[1],2)) ^ byte(key[0],2)
#define q43(x)  q(1,q(1,q(0, q(1, x) ^ byte(key[3],3)) ^ byte(key[2],3)) ^ byte(key[1],3)) ^ byte(key[0],3)

[COLOR=red][B]gen_mk_tab(u4byte key[])[/B]{   u4byte  i;
    u1byte  by;

    switch(k_len)
    {
    case 2: for(i = 0; i < 256; ++i)
            {
                by = (u1byte)i;

#ifdef ONE_STEP

                mk_tab[0][i] = mds(0, q20(by)); mk_tab[1][i] = mds(1, q21(by));
                mk_tab[2][i] = mds(2, q22(by)); mk_tab[3][i] = mds(3, q23(by));

#else

                sb[0][i] = q20(by); sb[1][i] = q21(by);
                sb[2][i] = q22(by); sb[3][i] = q23(by);

#endif
            }
            break;

    case 3: for(i = 0; i < 256; ++i)
            {
                by = (u1byte)i;

#ifdef ONE_STEP

                mk_tab[0][i] = mds(0, q30(by)); mk_tab[1][i] = mds(1, q31(by));
                mk_tab[2][i] = mds(2, q32(by)); mk_tab[3][i] = mds(3, q33(by));

#else

                sb[0][i] = q30(by); sb[1][i] = q31(by);
                sb[2][i] = q32(by); sb[3][i] = q33(by);

#endif
            }
            break;

    case 4: for(i = 0; i < 256; ++i)
            {
                by = (u1byte)i;

#ifdef ONE_STEP

                mk_tab[0][i] = mds(0, q40(by)); mk_tab[1][i] = mds(1, q41(by));
                mk_tab[2][i] = mds(2, q42(by)); mk_tab[3][i] = mds(3, q43(by));

#else

                sb[0][i] = q40(by); sb[1][i] = q41(by);
                sb[2][i] = q42(by); sb[3][i] = q43(by);

#endif
            }
    }
};

#  ifdef ONE_STEP
#    define g0_fun(x) ( mk_tab[0][byte(x,0)] ^ mk_tab[1][byte(x,1)] \
                      ^ mk_tab[2][byte(x,2)] ^ mk_tab[3][byte(x,3)] )
#    define g1_fun(x) ( mk_tab[0][byte(x,3)] ^ mk_tab[1][byte(x,0)] \
                      ^ mk_tab[2][byte(x,1)] ^ mk_tab[3][byte(x,2)] )
#  else
#    define g0_fun(x) ( mds(0, sb[0][byte(x,0)]) ^ mds(1, sb[1][byte(x,1)]) \
                      ^ mds(2, sb[2][byte(x,2)]) ^ mds(3, sb[3][byte(x,3)]) )
#    define g1_fun(x) ( mds(0, sb[0][byte(x,3)]) ^ mds(1, sb[1][byte(x,0)]) \
                      ^ mds(2, sb[2][byte(x,1)]) ^ mds(3, sb[3][byte(x,2)]) )
#  endif

#else

#define g0_fun(x)   h_fun(x,s_key)
#define g1_fun(x)   h_fun(rotl(x,8),s_key)

#endif

/* The (12,8) Reed Soloman code has the generator polynomial
  g(x) = x^4 + (a + 1/a) * x^3 + a * x^2 + (a + 1/a) * x + 1

where the coefficients are in the finite field GF(2^8) with a
modular polynomial a^8 + a^6 + a^3 + a^2 + 1. To generate the
remainder we have to start with a 12th order polynomial with our
eight input bytes as the coefficients of the 4th to 11th terms.
That is:

  m[7] * x^11 + m[6] * x^10 ... + m[0] * x^4 + 0 * x^3 +... + 0

We then multiply the generator polynomial by m[7] * x^7 and subtract
it - xor in GF(2^8) - from the above to eliminate the x^7 term (the
artihmetic on the coefficients is done in GF(2^8). We then multiply
the generator polynomial by x^6 * coeff(x^10) and use this to remove
the x^10 term. We carry on in this way until the x^4 term is removed
so that we are left with:

  r[3] * x^3 + r[2] * x^2 + r[1] 8 x^1 + r[0]

which give the resulting 4 bytes of the remainder. This is equivalent
to the matrix multiplication in the Twofish description but much faster
to implement.

*/

#define G_MOD   0x0000014d

u4byte mds_rem(u4byte p0, u4byte p1)
{   u4byte  i, t, u;

    for(i = 0; i < 8; ++i)
    {
        t = p1 >> 24;   // get most significant coefficient
        p1 = (p1 << 8) | (p0 >> 24); p0 <<= 8;  // shift others up

        // multiply t by a (the primitive element - i.e. left shift)

        u = (t << 1);

        if(t & 0x80)            // subtract modular polynomial on overflow
            u ^= G_MOD;

        p1 ^= t ^ (u << 16);    // remove t * (a * x^2 + 1)
        u ^= (t >> 1);          // form u = a * t + t / a = t * (a + 1 / a);

        if(t & 0x01)            // add the modular polynomial on underflow
            u ^= G_MOD >> 1;

        p1 ^= (u << 24) | (u << 8); // remove t * (a + 1/a) * (x^3 + x)
    }

    return p1;

};

/* initialise the key schedule from the user supplied key   */

u4byte *set_key(const u4byte in_key[], const u4byte key_len)
{   u4byte  i, a, b, me_key[4], mo_key[4];

#ifdef Q_TABLES

    if(!qt_gen)
    {
        gen_qtab(); qt_gen = 1;
    }

#endif

#ifdef M_TABLE

    if(!mt_gen)
    {
        gen_mtab(); mt_gen = 1;
    }

#endif

    k_len = key_len / 64;   /* 2, 3 or 4 */

    for(i = 0; i < k_len; ++i)
    {
        a = in_key[i + i];     me_key[i] = a;
        b = in_key[i + i + 1]; mo_key[i] = b;
        s_key[k_len - i - 1] = mds_rem(a, b);
    }

    for(i = 0; i < 40; i += 2)
    {
        a = 0x01010101 * i; b = a + 0x01010101;
        a = h_fun(a, me_key);
        b = rotl(h_fun(b, mo_key), 8);
        l_key[i] = a + b;
        l_key[i + 1] = rotl(a + 2 * b, 9);
    }

#ifdef MK_TABLE

    gen_mk_tab(s_key);

#endif

    return l_key;

};

/* encrypt a block of text  */

#define f_rnd(i)                                                    \
    t1 = g1_fun(blk[1]); t0 = g0_fun(blk[0]);                       \
    blk[2] = rotr(blk[2] ^ (t0 + t1 + l_key[4 * (i) + 8]), 1);      \
    blk[3] = rotl(blk[3], 1) ^ (t0 + 2 * t1 + l_key[4 * (i) + 9]);  \
    t1 = g1_fun(blk[3]); t0 = g0_fun(blk[2]);                       \
    blk[0] = rotr(blk[0] ^ (t0 + t1 + l_key[4 * (i) + 10]), 1);     \
    blk[1] = rotl(blk[1], 1) ^ (t0 + 2 * t1 + l_key[4 * (i) + 11])

void encrypt(const u4byte in_blk[4], u4byte out_blk[])
{   u4byte  t0, t1, blk[4];

    blk[0] = in_blk[0] ^ l_key[0];
    blk[1] = in_blk[1] ^ l_key[1];
    blk[2] = in_blk[2] ^ l_key[2];
    blk[3] = in_blk[3] ^ l_key[3];

    f_rnd(0); f_rnd(1); f_rnd(2); f_rnd(3);
    f_rnd(4); f_rnd(5); f_rnd(6); f_rnd(7);

    out_blk[0] = blk[2] ^ l_key[4];
    out_blk[1] = blk[3] ^ l_key[5];
    out_blk[2] = blk[0] ^ l_key[6];
    out_blk[3] = blk[1] ^ l_key[7];
};

/* decrypt a block of text  */

#define i_rnd(i)                                                        \
        t1 = g1_fun(blk[1]); t0 = g0_fun(blk[0]);                       \
        blk[2] = rotl(blk[2], 1) ^ (t0 + t1 + l_key[4 * (i) + 10]);     \
        blk[3] = rotr(blk[3] ^ (t0 + 2 * t1 + l_key[4 * (i) + 11]), 1); \
        t1 = g1_fun(blk[3]); t0 = g0_fun(blk[2]);                       \
        blk[0] = rotl(blk[0], 1) ^ (t0 + t1 + l_key[4 * (i) +  8]);     \
        blk[1] = rotr(blk[1] ^ (t0 + 2 * t1 + l_key[4 * (i) +  9]), 1)

void decrypt(const u4byte in_blk[4], u4byte out_blk[4])
{   u4byte  t0, t1, blk[4];

    blk[0] = in_blk[0] ^ l_key[4];
    blk[1] = in_blk[1] ^ l_key[5];
    blk[2] = in_blk[2] ^ l_key[6];
    blk[3] = in_blk[3] ^ l_key[7];

    i_rnd(7); i_rnd(6); i_rnd(5); i_rnd(4);
    i_rnd(3); i_rnd(2); i_rnd(1); i_rnd(0);

    out_blk[0] = blk[2] ^ l_key[0];
    out_blk[1] = blk[3] ^ l_key[1];
    out_blk[2] = blk[0] ^ l_key[2];
    out_blk[3] = blk[1] ^ l_key[3];
};

int main(void) {

    printf("Hallo!\n");

    return 0;
}
```


```
/* 1. Standard types for AES cryptography source code               */

typedef unsigned char   u1byte; /* an 8 bit unsigned character type */
typedef unsigned short  u2byte; /* a 16 bit unsigned integer type   */
typedef unsigned long   u4byte; /* a 32 bit unsigned integer type   */
typedef signed char     s1byte; /* an 8 bit signed character type   */
typedef signed short    s2byte; /* a 16 bit signed integer type     */
typedef signed long     s4byte; /* a 32 bit signed integer type     */

/* 2. Standard interface for AES cryptographic routines             */
/* These are all based on 32 bit unsigned values and will therefore */
/* require endian conversions for big-endian architectures          */

#ifdef  __cplusplus
    extern "C"
    {
#endif

    char **cipher_name(void);
    u4byte *set_key(const u4byte in_key[], const u4byte key_len);
    void encrypt(const u4byte in_blk[4], u4byte out_blk[4]);
    void decrypt(const u4byte in_blk[4], u4byte out_blk[4]);

#ifdef  __cplusplus
    };
#endif

/* 3. Basic macros for speeding up generic operations               */
/* Circular rotate of 32 bit values                                 */

#ifdef _MSC_VER

#  include <stdlib.h>

#  pragma intrinsic(_lrotr,_lrotl)
#  define rotr(x,n) _lrotr(x,n)
#  define rotl(x,n) _lrotl(x,n)

#else

#define rotr(x,n)   (((x) >> ((int)(n))) | ((x) << (32 - (int)(n))))
#define rotl(x,n)   (((x) << ((int)(n))) | ((x) >> (32 - (int)(n))))

#endif

/* Invert byte order in a 32 bit variable                           */
#define bswap(x)    (rotl(x, 8) & 0x00ff00ff | rotr(x, 8) & 0xff00ff00)

/* Extract byte from a 32 bit quantity (little endian notation)     */
#define byte(x,n)   ((u1byte)((x) >> (8 * n)))

/* For inverting byte order in input/output 32 bit words if needed  */
#ifdef  BLOCK_SWAP
#define BYTE_SWAP
#define WORD_SWAP
#endif

#ifdef  BYTE_SWAP
#define io_swap(x)  bswap(x)
#else
#define io_swap(x)  (x)
#endif

/* For inverting the byte order of input/output blocks if needed    */
#ifdef  WORD_SWAP
#define get_block(x)                            \
    ((u4byte*)(x))[0] = io_swap(in_blk[3]);     \
    ((u4byte*)(x))[1] = io_swap(in_blk[2]);     \
    ((u4byte*)(x))[2] = io_swap(in_blk[1]);     \
    ((u4byte*)(x))[3] = io_swap(in_blk[0])

#define put_block(x)                            \
    out_blk[3] = io_swap(((u4byte*)(x))[0]);    \
    out_blk[2] = io_swap(((u4byte*)(x))[1]);    \
    out_blk[1] = io_swap(((u4byte*)(x))[2]);    \
    out_blk[0] = io_swap(((u4byte*)(x))[3])

#define get_key(x,len)                          \
    ((u4byte*)(x))[4] = ((u4byte*)(x))[5] =     \
    ((u4byte*)(x))[6] = ((u4byte*)(x))[7] = 0;  \
    switch((((len) + 63) / 64)) {                  \

    case 2:                                     \
    ((u4byte*)(x))[0] = io_swap(in_key[3]);     \
    ((u4byte*)(x))[1] = io_swap(in_key[2]);     \
    ((u4byte*)(x))[2] = io_swap(in_key[1]);     \
    ((u4byte*)(x))[3] = io_swap(in_key[0]);     \
    break;                                      \

    case 3:                                     \
    ((u4byte*)(x))[0] = io_swap(in_key[5]);     \
    ((u4byte*)(x))[1] = io_swap(in_key[4]);     \
    ((u4byte*)(x))[2] = io_swap(in_key[3]);     \
    ((u4byte*)(x))[3] = io_swap(in_key[2]);     \
    ((u4byte*)(x))[4] = io_swap(in_key[1]);     \
    ((u4byte*)(x))[5] = io_swap(in_key[0]);     \
    break;                                      \

    case 4:                                     \
    ((u4byte*)(x))[0] = io_swap(in_key[7]);     \
    ((u4byte*)(x))[1] = io_swap(in_key[6]);     \
    ((u4byte*)(x))[2] = io_swap(in_key[5]);     \
    ((u4byte*)(x))[3] = io_swap(in_key[4]);     \
    ((u4byte*)(x))[4] = io_swap(in_key[3]);     \
    ((u4byte*)(x))[5] = io_swap(in_key[2]);     \
    ((u4byte*)(x))[6] = io_swap(in_key[1]);     \
    ((u4byte*)(x))[7] = io_swap(in_key[0]);     \
    }

#else

#define get_block(x)                            \
    ((u4byte*)(x))[0] = io_swap(in_blk[0]);     \
    ((u4byte*)(x))[1] = io_swap(in_blk[1]);     \
    ((u4byte*)(x))[2] = io_swap(in_blk[2]);     \
    ((u4byte*)(x))[3] = io_swap(in_blk[3])

#define put_block(x)                            \
    out_blk[0] = io_swap(((u4byte*)(x))[0]);    \
    out_blk[1] = io_swap(((u4byte*)(x))[1]);    \
    out_blk[2] = io_swap(((u4byte*)(x))[2]);    \
    out_blk[3] = io_swap(((u4byte*)(x))[3])

#define get_key(x,len)                          \
    ((u4byte*)(x))[4] = ((u4byte*)(x))[5] =     \
    ((u4byte*)(x))[6] = ((u4byte*)(x))[7] = 0;  \

   [COLOR=red][B] switch((((len) + 63) / 64)) {   [/B]            \
    case 4:                                     \
    ((u4byte*)(x))[6] = io_swap(in_key[6]);     \
    ((u4byte*)(x))[7] = io_swap(in_key[7]);     \

    case 3:                                     \
    ((u4byte*)(x))[4] = io_swap(in_key[4]);     \
    ((u4byte*)(x))[5] = io_swap(in_key[5]);     \

    case 2:                                     \
    ((u4byte*)(x))[0] = io_swap(in_key[0]);     \
    ((u4byte*)(x))[1] = io_swap(in_key[1]);     \
    ((u4byte*)(x))[2] = io_swap(in_key[2]);     \
    ((u4byte*)(x))[3] = io_swap(in_key[3]);     \
    }

#endif
```
Im .cu File heißt's beim ersten roten: identifier alg_name is undefined
Beim zweiten roten: explicit type is missing ("int" assumed) --> könnte ich mit int oder void lösen. Was nehmen?

Im .h File heißt's beim switch: expected a declaration.
Was soll ich denn einfügen? Ist eh alles da?! Habe auch schon die Klammern abgezählt; müsste stimmen?!

Und jedes Mal, wenn ich den Code ausführen will, sehe ich das hier:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



*[Edit]*
Im .cu File scheint der Compiler nicht über Zeile 48 hinauszukommen. Da kommt ne Meldung von wegen "previous syntax error", aber vor Zeile 48 gibt's doch noch fast nichts, wo was falsch sein könnte. Ich sehe davor keinen Fehler.

*[Edit2]*
Zeile 40 scheint das Problem zu sein. Wenn ich statt _#include "std_defs.h"_ sage: _#include "../std_defs.h"_, dann verschwinden in beiden Files die Errors, aber das .h File wird vom .cu File verständlicherweise nicht mehr gefunden.


----------



## sebi707 (2. Januar 2014)

*AW: [CUDA] RC6 / Serpent /Twofish*

Bitte sag mir, dass du nicht die ganzen doppelten Zeilenumbrüche von Hand weggemacht hast? In der _std_defs.h_, bei dem switch ist nämlich eine falsche Leerzeile, die nicht mit \ endet und damit das Makro beendet. Hier 


			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        

 mal die von mir bereinigte Version. Der einzige Fehler neben den doppelten Zeilenumbrüchen war ein fehlendes "void" bei der Funktion "gen_mk_tab(u4byte key[])". So compiliert aber wenigstens alles ohne Fehler oder Warnungen.


----------



## boss3D (2. Januar 2014)

*AW: [CUDA] RC6 / Serpent /Twofish*

Okay, danke. Abgesehen von zig warnings habe ich's bis auf 2 Errors hingekriegt:

```
/* This is an independent implementation of the encryption algorithm:   */
/*                                                                      */
/*         Twofish by Bruce Schneier and colleagues                     */
/*                                                                      */
/* which is a candidate algorithm in the Advanced Encryption Standard   */
/* programme of the US National Institute of Standards and Technology.  */
/*                                                                      */
/* Copyright in this implementation is held by Dr B R Gladman but I     */
/* hereby give permission for its free direct or derivative use subject */
/* to acknowledgment of its origin and compliance with any conditions   */
/* that the originators of t he algorithm place on its exploitation.    */
/*                                                                      */
/* My thanks to Doug Whiting and Niels Ferguson for comments that led   */
/* to improvements in this implementation.                              */
/*                                                                      */
/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */

/* Timing data for Twofish (twofish.c)

128 bit key:
Key Setup:    8414 cycles
Encrypt:       376 cycles =    68.1 mbits/sec
Decrypt:       374 cycles =    68.4 mbits/sec
Mean:          375 cycles =    68.3 mbits/sec

192 bit key:
Key Setup:   11628 cycles
Encrypt:       376 cycles =    68.1 mbits/sec
Decrypt:       374 cycles =    68.4 mbits/sec
Mean:          375 cycles =    68.3 mbits/sec

256 bit key:
Key Setup:   15457 cycles
Encrypt:       381 cycles =    67.2 mbits/sec
Decrypt:       374 cycles =    68.4 mbits/sec
Mean:          378 cycles =    67.8 mbits/sec

*/

#include "std_defs.h"
[COLOR=royalblue][B]#include <stdio.h>[/B]
#define Q_TABLES
#define M_TABLE
#define MK_TABLE
#define ONE_STEP

[COLOR=royalblue][B]#define HandleError(x) HandleErrorImpl(x, __FILE__, __LINE__)[/B]
static char *alg_name[] = { "twofish", "twofish.c", "twofish" };

char **cipher_name()
{
    return alg_name;
}

u4byte  k_len;
u4byte  l_key[40];
u4byte  s_key[4];

/* finite field arithmetic for GF(2**8) with the modular    */
/* polynomial x^8 + x^6 + x^5 + x^3 + 1 (0x169)             */

#define G_M 0x0169

u1byte  tab_5b[4] = { 0, G_M >> 2, G_M >> 1, (G_M >> 1) ^ (G_M >> 2) };
u1byte  tab_ef[4] = { 0, (G_M >> 1) ^ (G_M >> 2), G_M >> 1, G_M >> 2 };

#define ffm_01(x)    (x)
#define ffm_5b(x)   ((x) ^ ((x) >> 2) ^ tab_5b[(x) & 3])
#define ffm_ef(x)   ((x) ^ ((x) >> 1) ^ ((x) >> 2) ^ tab_ef[(x) & 3])

u1byte ror4[16] = { 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 };
u1byte ashx[16] = { 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 5, 14, 7 };

u1byte qt0[2][16] =
{   { 8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4 },
    { 2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5 }
};

u1byte qt1[2][16] =
{   { 14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13 },
    { 1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8 }
};

u1byte qt2[2][16] =
{   { 11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1 },
    { 4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15 }
};

u1byte qt3[2][16] =
{   { 13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10 },
    { 11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10 }
};

u1byte qp(const u4byte n, const u1byte x)
{   u1byte  a0, a1, a2, a3, a4, b0, b1, b2, b3, b4;

    a0 = x >> 4; b0 = x & 15;
    a1 = a0 ^ b0; b1 = ror4[b0] ^ ashx[a0];
    a2 = qt0[n][a1]; b2 = qt1[n][b1];
    a3 = a2 ^ b2; b3 = ror4[b2] ^ ashx[a2];
    a4 = qt2[n][a3]; b4 = qt3[n][b3];
    return (b4 << 4) | a4;
};

#ifdef  Q_TABLES

u4byte  qt_gen = 0;
u1byte  q_tab[2][256];

#define q(n,x)  q_tab[n][x]

void gen_qtab(void)
{   u4byte  i;

    for(i = 0; i < 256; ++i)
    {
        q(0,i) = qp(0, (u1byte)i);
        q(1,i) = qp(1, (u1byte)i);
    }
};

#else

#define q(n,x)  qp(n, x)

#endif

#ifdef  M_TABLE

u4byte  mt_gen = 0;
u4byte  m_tab[4][256];

void gen_mtab(void)
{   u4byte  i, f01, f5b, fef;

    for(i = 0; i < 256; ++i)
    {
        f01 = q(1,i); f5b = ffm_5b(f01); fef = ffm_ef(f01);
        m_tab[0][i] = f01 + (f5b << 8) + (fef << 16) + (fef << 24);
        m_tab[2][i] = f5b + (fef << 8) + (f01 << 16) + (fef << 24);

        f01 = q(0,i); f5b = ffm_5b(f01); fef = ffm_ef(f01);
        m_tab[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24);
        m_tab[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24);
    }
};

#define mds(n,x)    m_tab[n][x]

#else

#define fm_00   ffm_01
#define fm_10   ffm_5b
#define fm_20   ffm_ef
#define fm_30   ffm_ef
#define q_0(x)  q(1,x)

#define fm_01   ffm_ef
#define fm_11   ffm_ef
#define fm_21   ffm_5b
#define fm_31   ffm_01
#define q_1(x)  q(0,x)

#define fm_02   ffm_5b
#define fm_12   ffm_ef
#define fm_22   ffm_01
#define fm_32   ffm_ef
#define q_2(x)  q(1,x)

#define fm_03   ffm_5b
#define fm_13   ffm_01
#define fm_23   ffm_ef
#define fm_33   ffm_5b
#define q_3(x)  q(0,x)

#define f_0(n,x)    ((u4byte)fm_0##n(x))
#define f_1(n,x)    ((u4byte)fm_1##n(x) << 8)
#define f_2(n,x)    ((u4byte)fm_2##n(x) << 16)
#define f_3(n,x)    ((u4byte)fm_3##n(x) << 24)

#define mds(n,x)    f_0(n,q_##n(x)) ^ f_1(n,q_##n(x)) ^ f_2(n,q_##n(x)) ^ f_3(n,q_##n(x))

#endif

u4byte h_fun(const u4byte x, const u4byte key[])
{   u4byte  b0, b1, b2, b3;

#ifndef M_TABLE
    u4byte  m5b_b0, m5b_b1, m5b_b2, m5b_b3;
    u4byte  mef_b0, mef_b1, mef_b2, mef_b3;
#endif

    b0 = byte(x, 0); b1 = byte(x, 1); b2 = byte(x, 2); b3 = byte(x, 3);

    switch(k_len)
    {
    case 4: b0 = q(1, b0) ^ byte(key[3],0);
            b1 = q(0, b1) ^ byte(key[3],1);
            b2 = q(0, b2) ^ byte(key[3],2);
            b3 = q(1, b3) ^ byte(key[3],3);
    case 3: b0 = q(1, b0) ^ byte(key[2],0);
            b1 = q(1, b1) ^ byte(key[2],1);
            b2 = q(0, b2) ^ byte(key[2],2);
            b3 = q(0, b3) ^ byte(key[2],3);
    case 2: b0 = q(0,q(0,b0) ^ byte(key[1],0)) ^ byte(key[0],0);
            b1 = q(0,q(1,b1) ^ byte(key[1],1)) ^ byte(key[0],1);
            b2 = q(1,q(0,b2) ^ byte(key[1],2)) ^ byte(key[0],2);
            b3 = q(1,q(1,b3) ^ byte(key[1],3)) ^ byte(key[0],3);
    }
#ifdef  M_TABLE

    return  mds(0, b0) ^ mds(1, b1) ^ mds(2, b2) ^ mds(3, b3);

#else

    b0 = q(1, b0); b1 = q(0, b1); b2 = q(1, b2); b3 = q(0, b3);
    m5b_b0 = ffm_5b(b0); m5b_b1 = ffm_5b(b1); m5b_b2 = ffm_5b(b2); m5b_b3 = ffm_5b(b3);
    mef_b0 = ffm_ef(b0); mef_b1 = ffm_ef(b1); mef_b2 = ffm_ef(b2); mef_b3 = ffm_ef(b3);
    b0 ^= mef_b1 ^ m5b_b2 ^ m5b_b3; b3 ^= m5b_b0 ^ mef_b1 ^ mef_b2;
    b2 ^= mef_b0 ^ m5b_b1 ^ mef_b3; b1 ^= mef_b0 ^ mef_b2 ^ m5b_b3;

    return b0 | (b3 << 8) | (b2 << 16) | (b1 << 24);

#endif
};

#ifdef  MK_TABLE

#ifdef  ONE_STEP
u4byte  mk_tab[4][256];
#else
u1byte  sb[4][256];
#endif

#define q20(x)  q(0,q(0,x) ^ byte(key[1],0)) ^ byte(key[0],0)
#define q21(x)  q(0,q(1,x) ^ byte(key[1],1)) ^ byte(key[0],1)
#define q22(x)  q(1,q(0,x) ^ byte(key[1],2)) ^ byte(key[0],2)
#define q23(x)  q(1,q(1,x) ^ byte(key[1],3)) ^ byte(key[0],3)

#define q30(x)  q(0,q(0,q(1, x) ^ byte(key[2],0)) ^ byte(key[1],0)) ^ byte(key[0],0)
#define q31(x)  q(0,q(1,q(1, x) ^ byte(key[2],1)) ^ byte(key[1],1)) ^ byte(key[0],1)
#define q32(x)  q(1,q(0,q(0, x) ^ byte(key[2],2)) ^ byte(key[1],2)) ^ byte(key[0],2)
#define q33(x)  q(1,q(1,q(0, x) ^ byte(key[2],3)) ^ byte(key[1],3)) ^ byte(key[0],3)

#define q40(x)  q(0,q(0,q(1, q(1, x) ^ byte(key[3],0)) ^ byte(key[2],0)) ^ byte(key[1],0)) ^ byte(key[0],0)
#define q41(x)  q(0,q(1,q(1, q(0, x) ^ byte(key[3],1)) ^ byte(key[2],1)) ^ byte(key[1],1)) ^ byte(key[0],1)
#define q42(x)  q(1,q(0,q(0, q(0, x) ^ byte(key[3],2)) ^ byte(key[2],2)) ^ byte(key[1],2)) ^ byte(key[0],2)
#define q43(x)  q(1,q(1,q(0, q(1, x) ^ byte(key[3],3)) ^ byte(key[2],3)) ^ byte(key[1],3)) ^ byte(key[0],3)

void gen_mk_tab(u4byte key[])
{   u4byte  i;
    u1byte  by;

    switch(k_len)
    {
    case 2: for(i = 0; i < 256; ++i)
            {
                by = (u1byte)i;
#ifdef ONE_STEP
                mk_tab[0][i] = mds(0, q20(by)); mk_tab[1][i] = mds(1, q21(by));
                mk_tab[2][i] = mds(2, q22(by)); mk_tab[3][i] = mds(3, q23(by));
#else
                sb[0][i] = q20(by); sb[1][i] = q21(by);
                sb[2][i] = q22(by); sb[3][i] = q23(by);
#endif
            }
            break;

    case 3: for(i = 0; i < 256; ++i)
            {
                by = (u1byte)i;
#ifdef ONE_STEP
                mk_tab[0][i] = mds(0, q30(by)); mk_tab[1][i] = mds(1, q31(by));
                mk_tab[2][i] = mds(2, q32(by)); mk_tab[3][i] = mds(3, q33(by));
#else
                sb[0][i] = q30(by); sb[1][i] = q31(by);
                sb[2][i] = q32(by); sb[3][i] = q33(by);
#endif
            }
            break;

    case 4: for(i = 0; i < 256; ++i)
            {
                by = (u1byte)i;
#ifdef ONE_STEP
                mk_tab[0][i] = mds(0, q40(by)); mk_tab[1][i] = mds(1, q41(by));
                mk_tab[2][i] = mds(2, q42(by)); mk_tab[3][i] = mds(3, q43(by));
#else
                sb[0][i] = q40(by); sb[1][i] = q41(by);
                sb[2][i] = q42(by); sb[3][i] = q43(by);
#endif
            }
    }
};

#  ifdef ONE_STEP
#    define g0_fun(x) ( mk_tab[0][byte(x,0)] ^ mk_tab[1][byte(x,1)] \
                      ^ mk_tab[2][byte(x,2)] ^ mk_tab[3][byte(x,3)] )
#    define g1_fun(x) ( mk_tab[0][byte(x,3)] ^ mk_tab[1][byte(x,0)] \
                      ^ mk_tab[2][byte(x,1)] ^ mk_tab[3][byte(x,2)] )
#  else
#    define g0_fun(x) ( mds(0, sb[0][byte(x,0)]) ^ mds(1, sb[1][byte(x,1)]) \
                      ^ mds(2, sb[2][byte(x,2)]) ^ mds(3, sb[3][byte(x,3)]) )
#    define g1_fun(x) ( mds(0, sb[0][byte(x,3)]) ^ mds(1, sb[1][byte(x,0)]) \
                      ^ mds(2, sb[2][byte(x,1)]) ^ mds(3, sb[3][byte(x,2)]) )
#  endif

#else

#define g0_fun(x)   h_fun(x,s_key)
#define g1_fun(x)   h_fun(rotl(x,8),s_key)

#endif

/* The (12,8) Reed Soloman code has the generator polynomial

  g(x) = x^4 + (a + 1/a) * x^3 + a * x^2 + (a + 1/a) * x + 1

where the coefficients are in the finite field GF(2^8) with a
modular polynomial a^8 + a^6 + a^3 + a^2 + 1. To generate the
remainder we have to start with a 12th order polynomial with our
eight input bytes as the coefficients of the 4th to 11th terms.
That is:

  m[7] * x^11 + m[6] * x^10 ... + m[0] * x^4 + 0 * x^3 +... + 0

We then multiply the generator polynomial by m[7] * x^7 and subtract
it - xor in GF(2^8) - from the above to eliminate the x^7 term (the
artihmetic on the coefficients is done in GF(2^8). We then multiply
the generator polynomial by x^6 * coeff(x^10) and use this to remove
the x^10 term. We carry on in this way until the x^4 term is removed
so that we are left with:

  r[3] * x^3 + r[2] * x^2 + r[1] 8 x^1 + r[0]

which give the resulting 4 bytes of the remainder. This is equivalent
to the matrix multiplication in the Twofish description but much faster
to implement.

*/

#define G_MOD   0x0000014d

u4byte mds_rem(u4byte p0, u4byte p1)
{   u4byte  i, t, u;

    for(i = 0; i < 8; ++i)
    {
        t = p1 >> 24;   // get most significant coefficient

        p1 = (p1 << 8) | (p0 >> 24); p0 <<= 8;  // shift others up

        // multiply t by a (the primitive element - i.e. left shift)

        u = (t << 1);

        if(t & 0x80)            // subtract modular polynomial on overflow

            u ^= G_MOD;

        p1 ^= t ^ (u << 16);    // remove t * (a * x^2 + 1)

        u ^= (t >> 1);          // form u = a * t + t / a = t * (a + 1 / a);

        if(t & 0x01)            // add the modular polynomial on underflow

            u ^= G_MOD >> 1;

        p1 ^= (u << 24) | (u << 8); // remove t * (a + 1/a) * (x^3 + x)
    }

    return p1;
};

/* initialise the key schedule from the user supplied key   */

u4byte *set_key(const u4byte in_key[], const u4byte key_len)
{   u4byte  i, a, b, me_key[4], mo_key[4];

#ifdef Q_TABLES
    if(!qt_gen)
    {
        gen_qtab(); qt_gen = 1;
    }
#endif

#ifdef M_TABLE
    if(!mt_gen)
    {
        gen_mtab(); mt_gen = 1;
    }
#endif

    k_len = key_len / 64;   /* 2, 3 or 4 */

    for(i = 0; i < k_len; ++i)
    {
        a = in_key[i + i];     me_key[i] = a;
        b = in_key[i + i + 1]; mo_key[i] = b;
        s_key[k_len - i - 1] = mds_rem(a, b);
    }

    for(i = 0; i < 40; i += 2)
    {
        a = 0x01010101 * i; b = a + 0x01010101;
        a = h_fun(a, me_key);
        b = rotl(h_fun(b, mo_key), 8);
        l_key[i] = a + b;
        l_key[i + 1] = rotl(a + 2 * b, 9);
    }

#ifdef MK_TABLE
    gen_mk_tab(s_key);
#endif

    return l_key;
};

/* encrypt a block of text  */

#define f_rnd(i)                                                    \
    t1 = g1_fun(blk[1]); t0 = g0_fun(blk[0]);                       \
    blk[2] = rotr(blk[2] ^ (t0 + t1 + l_key[4 * (i) + 8]), 1);      \
    blk[3] = rotl(blk[3], 1) ^ (t0 + 2 * t1 + l_key[4 * (i) + 9]);  \
    t1 = g1_fun(blk[3]); t0 = g0_fun(blk[2]);                       \
    blk[0] = rotr(blk[0] ^ (t0 + t1 + l_key[4 * (i) + 10]), 1);     \
    blk[1] = rotl(blk[1], 1) ^ (t0 + 2 * t1 + l_key[4 * (i) + 11])

[COLOR=royalblue][B]__device__[/B] void encrypt(const u4byte in_blk[4], u4byte out_blk[4])
{   u4byte  t0, t1, blk[4];

    blk[0] = in_blk[0] ^ l_key[0];
    blk[1] = in_blk[1] ^ l_key[1];
    blk[2] = in_blk[2] ^ l_key[2];
    blk[3] = in_blk[3] ^ l_key[3];

    f_rnd(0); f_rnd(1); f_rnd(2); f_rnd(3);
    f_rnd(4); f_rnd(5); f_rnd(6); f_rnd(7);

    out_blk[0] = blk[2] ^ l_key[4];
    out_blk[1] = blk[3] ^ l_key[5];
    out_blk[2] = blk[0] ^ l_key[6];
    out_blk[3] = blk[1] ^ l_key[7];
};

/* decrypt a block of text  */

#define i_rnd(i)                                                        \
        t1 = g1_fun(blk[1]); t0 = g0_fun(blk[0]);                       \
        blk[2] = rotl(blk[2], 1) ^ (t0 + t1 + l_key[4 * (i) + 10]);     \
        blk[3] = rotr(blk[3] ^ (t0 + 2 * t1 + l_key[4 * (i) + 11]), 1); \
        t1 = g1_fun(blk[3]); t0 = g0_fun(blk[2]);                       \
        blk[0] = rotl(blk[0], 1) ^ (t0 + t1 + l_key[4 * (i) +  8]);     \
        blk[1] = rotr(blk[1] ^ (t0 + 2 * t1 + l_key[4 * (i) +  9]), 1)

[COLOR=royalblue][B]__device__ [/B]void decrypt(const u4byte in_blk[4], u4byte out_blk[4])
{   u4byte  t0, t1, blk[4];

    blk[0] = in_blk[0] ^ l_key[4];
    blk[1] = in_blk[1] ^ l_key[5];
    blk[2] = in_blk[2] ^ l_key[6];
    blk[3] = in_blk[3] ^ l_key[7];

    i_rnd(7); i_rnd(6); i_rnd(5); i_rnd(4);
    i_rnd(3); i_rnd(2); i_rnd(1); i_rnd(0);

    out_blk[0] = blk[2] ^ l_key[0];
    out_blk[1] = blk[3] ^ l_key[1];
    out_blk[2] = blk[0] ^ l_key[2];
    out_blk[3] = blk[1] ^ l_key[3];
};
[COLOR=royalblue][B]
__global__ void twofish_enc(const u4byte in_blk[4], u4byte out_blk[4]) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    encrypt(in_blk[4] + 16*b, out_blk[4] + 16*b);
}

__global__ void twofish_dec(const u4byte in_blk[4], u4byte out_blk[4]) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    decrypt(in_blk[4] + 16*b, out_blk[4] + 16*b);
}

inline void HandleErrorImpl(cudaError error, const char* file, int line) {
    if (error != cudaSuccess) {
        printf("%s: %d %s", file, line, cudaGetErrorString(error));
        exit(1);
    }
}

int main(void) {
    char* key = "meingeheimespasswort";
    int threads = 512;
    int blocks = 12800;

    u4byte* in_blk[4];
    HandleError(cudaMalloc(&in_blk[4], 16*threads*blocks));
    HandleError(cudaMemset(in_blk[4], 0, 16*threads*blocks));

    u4byte* out_blk[4];
    HandleError(cudaMalloc(&out_blk[4], 16*threads*blocks));

    char *test1 = (char*)malloc(16*threads*blocks);
    HandleError(cudaMemcpy(test1, in_blk[4], 16*threads*blocks, cudaMemcpyDeviceToHost));

    printf("First 16 bytes of input data: ");
    for (int i=0; i<16; i++) {
        printf("%d, ", test1[i]);
    }

    cudaEvent_t start, stop;
    HandleError(cudaEventCreate(&start));
    HandleError(cudaEventCreate(&stop));
    HandleError(cudaEventRecord( start, 0 ));

    twofish_enc<<<blocks,threads>>>(in_blk[4], out_blk[4]);
    twofish_dec<<<blocks,threads>>>(out_blk[4], in_blk[4]);

    HandleError(cudaGetLastError());

    HandleError(cudaEventRecord( stop, 0 ));
    HandleError(cudaEventSynchronize( stop ));
    float elapsedTime;
    HandleError(cudaEventElapsedTime( &elapsedTime, start, stop ));

    printf("\nPerformance: %.6f MB/sec\n", 2*((16*threads*blocks)/1048576)/(elapsedTime/1000));

    HandleError(cudaEventDestroy( start ));
    HandleError(cudaEventDestroy( stop ));

    char *test2 = (char*)malloc(16*threads*blocks);
    HandleError(cudaMemcpy(test2, in_blk[4], 16*threads*blocks, cudaMemcpyDeviceToHost));

    printf("After decryption: ");
    for (int i=0; i<16; i++) {
        printf("%d, ", test2[i]);
    }

    free(test1);
    free(test2);

    HandleError(cudaFree(in_blk[4]));
    HandleError(cudaFree(out_blk[4]));

    return 0;
}[/B]
```



			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Wenn wir die noch wegbringen, fehlt in Twofish m. E. nur noch die Schlüsselinitialisierung ...

*[Edit]*
Key-Initialisierung habe ich in der main gerade noch so gelöst:

```
set_key((const u4byte*)key, strlen(key));
```
Scheint zu funktionieren.


----------



## sebi707 (2. Januar 2014)

*AW: [CUDA] RC6 / Serpent /Twofish*

Du kannst nicht einfach überall das mit dem Array so stehen lassen. Deine twofish_enc/dec Funktionen sollten als Parameter nur ein Pointer auf ein u4byte haben. Außerdem muss dann die Berechnung der Positionen etwas angepasst werden. In Twofish ist ein Block scheinbar auch 16 Bytes aber du arbeitest hier schon mit 4 Byte großen Typen also musst du pro Block nur 4 Werte weiter gehen. So würde denn etwa die twofish_enc Funktion aussehen:

```
__global__ void twofish_enc(const u4byte* in_blk, u4byte* out_blk) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    encrypt(in_blk + 4*b, out_blk + 4*b);
}
```
Gleiche Sache in der main Funktion. Du willst kein Array mit vier u4byte Pointern drin sondern nur ein Pointer auf u4byte. So etwa

```
u4byte* in_blk;
    HandleError(cudaMalloc(&in_blk, 16*threads*blocks));
    HandleError(cudaMemset(in_blk, 0, 16*threads*blocks));
```
Die Sache mit der Schlüsselinitialisierung scheint wieder etwas fummeliger zu sein, da der Schlüssel nicht an die Funktionen übergeben wird sondern als globale Variable vorliegt (twofish.cu Zeile 55-57). Ich würde sagen das einfachste ist diese 3 Variablen mit __device__ zu markieren und die set_key Funktion auch zu einer device Funktion zu machen.

Edit: Irgendwie scheint diese Implementierung doch nicht so besonders gut geeignet zu sein nach CUDA portiert zu werden, da es viele globale Variablen gibt.


----------



## boss3D (2. Januar 2014)

*AW: [CUDA] RC6 / Serpent /Twofish*

So, das hat jetzt die alten Errors weg gebracht, aber neue mit sich gebracht ... _*seufz*_

```
/* This is an independent implementation of the encryption algorithm:   */
/*                                                                      */
/*         Twofish by Bruce Schneier and colleagues                     */
/*                                                                      */
/* which is a candidate algorithm in the Advanced Encryption Standard   */
/* programme of the US National Institute of Standards and Technology.  */
/*                                                                      */
/* Copyright in this implementation is held by Dr B R Gladman but I     */
/* hereby give permission for its free direct or derivative use subject */
/* to acknowledgment of its origin and compliance with any conditions   */
/* that the originators of t he algorithm place on its exploitation.    */
/*                                                                      */
/* My thanks to Doug Whiting and Niels Ferguson for comments that led   */
/* to improvements in this implementation.                              */
/*                                                                      */
/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */

/* Timing data for Twofish (twofish.c)

128 bit key:
Key Setup:    8414 cycles
Encrypt:       376 cycles =    68.1 mbits/sec
Decrypt:       374 cycles =    68.4 mbits/sec
Mean:          375 cycles =    68.3 mbits/sec

192 bit key:
Key Setup:   11628 cycles
Encrypt:       376 cycles =    68.1 mbits/sec
Decrypt:       374 cycles =    68.4 mbits/sec
Mean:          375 cycles =    68.3 mbits/sec

256 bit key:
Key Setup:   15457 cycles
Encrypt:       381 cycles =    67.2 mbits/sec
Decrypt:       374 cycles =    68.4 mbits/sec
Mean:          378 cycles =    67.8 mbits/sec

*/

#include "std_defs.h"
#include <stdio.h>

#define Q_TABLES
#define M_TABLE
#define MK_TABLE
#define ONE_STEP

#define HandleError(x) HandleErrorImpl(x, __FILE__, __LINE__)

static char *alg_name[] = { "twofish", "twofish.c", "twofish" };

char **cipher_name()
{
    return alg_name;
}

__device__ u4byte  k_len;
__device__ u4byte  l_key[40];
__device__ u4byte  s_key[4];

/* finite field arithmetic for GF(2**8) with the modular    */
/* polynomial x^8 + x^6 + x^5 + x^3 + 1 (0x169)             */

#define G_M 0x0169

u1byte  tab_5b[4] = { 0, G_M >> 2, G_M >> 1, (G_M >> 1) ^ (G_M >> 2) };
u1byte  tab_ef[4] = { 0, (G_M >> 1) ^ (G_M >> 2), G_M >> 1, G_M >> 2 };

#define ffm_01(x)    (x)
#define ffm_5b(x)   ((x) ^ ((x) >> 2) ^ tab_5b[(x) & 3])
#define ffm_ef(x)   ((x) ^ ((x) >> 1) ^ ((x) >> 2) ^ tab_ef[(x) & 3])

u1byte ror4[16] = { 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 };
u1byte ashx[16] = { 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 5, 14, 7 };

u1byte qt0[2][16] =
{   { 8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4 },
    { 2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5 }
};

u1byte qt1[2][16] =
{   { 14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13 },
    { 1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8 }
};

u1byte qt2[2][16] =
{   { 11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1 },
    { 4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15 }
};

u1byte qt3[2][16] =
{   { 13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10 },
    { 11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10 }
};

u1byte qp(const u4byte n, const u1byte x)
{   u1byte  a0, a1, a2, a3, a4, b0, b1, b2, b3, b4;

    a0 = x >> 4; b0 = x & 15;
    a1 = a0 ^ b0; b1 = ror4[b0] ^ ashx[a0];
    a2 = qt0[n][a1]; b2 = qt1[n][b1];
    a3 = a2 ^ b2; b3 = ror4[b2] ^ ashx[a2];
    a4 = qt2[n][a3]; b4 = qt3[n][b3];
    return (b4 << 4) | a4;
};

#ifdef  Q_TABLES

u4byte  qt_gen = 0;
u1byte  q_tab[2][256];

#define q(n,x)  q_tab[n][x]

void gen_qtab(void)
{   u4byte  i;

    for(i = 0; i < 256; ++i)
    {
        q(0,i) = qp(0, (u1byte)i);
        q(1,i) = qp(1, (u1byte)i);
    }
};

#else

#define q(n,x)  qp(n, x)

#endif

#ifdef  M_TABLE

u4byte  mt_gen = 0;
u4byte  m_tab[4][256];

void gen_mtab(void)
{   u4byte  i, f01, f5b, fef;

    for(i = 0; i < 256; ++i)
    {
        f01 = q(1,i); f5b = ffm_5b(f01); fef = ffm_ef(f01);
        m_tab[0][i] = f01 + (f5b << 8) + (fef << 16) + (fef << 24);
        m_tab[2][i] = f5b + (fef << 8) + (f01 << 16) + (fef << 24);

        f01 = q(0,i); f5b = ffm_5b(f01); fef = ffm_ef(f01);
        m_tab[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24);
        m_tab[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24);
    }
};

#define mds(n,x)    m_tab[n][x]

#else

#define fm_00   ffm_01
#define fm_10   ffm_5b
#define fm_20   ffm_ef
#define fm_30   ffm_ef
#define q_0(x)  q(1,x)

#define fm_01   ffm_ef
#define fm_11   ffm_ef
#define fm_21   ffm_5b
#define fm_31   ffm_01
#define q_1(x)  q(0,x)

#define fm_02   ffm_5b
#define fm_12   ffm_ef
#define fm_22   ffm_01
#define fm_32   ffm_ef
#define q_2(x)  q(1,x)

#define fm_03   ffm_5b
#define fm_13   ffm_01
#define fm_23   ffm_ef
#define fm_33   ffm_5b
#define q_3(x)  q(0,x)

#define f_0(n,x)    ((u4byte)fm_0##n(x))
#define f_1(n,x)    ((u4byte)fm_1##n(x) << 8)
#define f_2(n,x)    ((u4byte)fm_2##n(x) << 16)
#define f_3(n,x)    ((u4byte)fm_3##n(x) << 24)

#define mds(n,x)    f_0(n,q_##n(x)) ^ f_1(n,q_##n(x)) ^ f_2(n,q_##n(x)) ^ f_3(n,q_##n(x))

#endif

u4byte h_fun(const u4byte x, const u4byte key[])
{   u4byte  b0, b1, b2, b3;

#ifndef M_TABLE
    u4byte  m5b_b0, m5b_b1, m5b_b2, m5b_b3;
    u4byte  mef_b0, mef_b1, mef_b2, mef_b3;
#endif

    b0 = byte(x, 0); b1 = byte(x, 1); b2 = byte(x, 2); b3 = byte(x, 3);

    switch(k_len)
    {
    case 4: b0 = q(1, b0) ^ byte(key[3],0);
            b1 = q(0, b1) ^ byte(key[3],1);
            b2 = q(0, b2) ^ byte(key[3],2);
            b3 = q(1, b3) ^ byte(key[3],3);
    case 3: b0 = q(1, b0) ^ byte(key[2],0);
            b1 = q(1, b1) ^ byte(key[2],1);
            b2 = q(0, b2) ^ byte(key[2],2);
            b3 = q(0, b3) ^ byte(key[2],3);
    case 2: b0 = q(0,q(0,b0) ^ byte(key[1],0)) ^ byte(key[0],0);
            b1 = q(0,q(1,b1) ^ byte(key[1],1)) ^ byte(key[0],1);
            b2 = q(1,q(0,b2) ^ byte(key[1],2)) ^ byte(key[0],2);
            b3 = q(1,q(1,b3) ^ byte(key[1],3)) ^ byte(key[0],3);
    }
#ifdef  M_TABLE

    return  mds(0, b0) ^ mds(1, b1) ^ mds(2, b2) ^ mds(3, b3);

#else

    b0 = q(1, b0); b1 = q(0, b1); b2 = q(1, b2); b3 = q(0, b3);
    m5b_b0 = ffm_5b(b0); m5b_b1 = ffm_5b(b1); m5b_b2 = ffm_5b(b2); m5b_b3 = ffm_5b(b3);
    mef_b0 = ffm_ef(b0); mef_b1 = ffm_ef(b1); mef_b2 = ffm_ef(b2); mef_b3 = ffm_ef(b3);
    b0 ^= mef_b1 ^ m5b_b2 ^ m5b_b3; b3 ^= m5b_b0 ^ mef_b1 ^ mef_b2;
    b2 ^= mef_b0 ^ m5b_b1 ^ mef_b3; b1 ^= mef_b0 ^ mef_b2 ^ m5b_b3;

    return b0 | (b3 << 8) | (b2 << 16) | (b1 << 24);

#endif
};

#ifdef  MK_TABLE

#ifdef  ONE_STEP
u4byte  mk_tab[4][256];
#else
u1byte  sb[4][256];
#endif

#define q20(x)  q(0,q(0,x) ^ byte(key[1],0)) ^ byte(key[0],0)
#define q21(x)  q(0,q(1,x) ^ byte(key[1],1)) ^ byte(key[0],1)
#define q22(x)  q(1,q(0,x) ^ byte(key[1],2)) ^ byte(key[0],2)
#define q23(x)  q(1,q(1,x) ^ byte(key[1],3)) ^ byte(key[0],3)

#define q30(x)  q(0,q(0,q(1, x) ^ byte(key[2],0)) ^ byte(key[1],0)) ^ byte(key[0],0)
#define q31(x)  q(0,q(1,q(1, x) ^ byte(key[2],1)) ^ byte(key[1],1)) ^ byte(key[0],1)
#define q32(x)  q(1,q(0,q(0, x) ^ byte(key[2],2)) ^ byte(key[1],2)) ^ byte(key[0],2)
#define q33(x)  q(1,q(1,q(0, x) ^ byte(key[2],3)) ^ byte(key[1],3)) ^ byte(key[0],3)

#define q40(x)  q(0,q(0,q(1, q(1, x) ^ byte(key[3],0)) ^ byte(key[2],0)) ^ byte(key[1],0)) ^ byte(key[0],0)
#define q41(x)  q(0,q(1,q(1, q(0, x) ^ byte(key[3],1)) ^ byte(key[2],1)) ^ byte(key[1],1)) ^ byte(key[0],1)
#define q42(x)  q(1,q(0,q(0, q(0, x) ^ byte(key[3],2)) ^ byte(key[2],2)) ^ byte(key[1],2)) ^ byte(key[0],2)
#define q43(x)  q(1,q(1,q(0, q(1, x) ^ byte(key[3],3)) ^ byte(key[2],3)) ^ byte(key[1],3)) ^ byte(key[0],3)

void gen_mk_tab(u4byte key[])
{   u4byte  i;
    u1byte  by;

    switch(k_len)
    {
    case 2: for(i = 0; i < 256; ++i)
            {
                by = (u1byte)i;
#ifdef ONE_STEP
                mk_tab[0][i] = mds(0, q20(by)); mk_tab[1][i] = mds(1, q21(by));
                mk_tab[2][i] = mds(2, q22(by)); mk_tab[3][i] = mds(3, q23(by));
#else
                sb[0][i] = q20(by); sb[1][i] = q21(by);
                sb[2][i] = q22(by); sb[3][i] = q23(by);
#endif
            }
            break;

    case 3: for(i = 0; i < 256; ++i)
            {
                by = (u1byte)i;
#ifdef ONE_STEP
                mk_tab[0][i] = mds(0, q30(by)); mk_tab[1][i] = mds(1, q31(by));
                mk_tab[2][i] = mds(2, q32(by)); mk_tab[3][i] = mds(3, q33(by));
#else
                sb[0][i] = q30(by); sb[1][i] = q31(by);
                sb[2][i] = q32(by); sb[3][i] = q33(by);
#endif
            }
            break;

    case 4: for(i = 0; i < 256; ++i)
            {
                by = (u1byte)i;
#ifdef ONE_STEP
                mk_tab[0][i] = mds(0, q40(by)); mk_tab[1][i] = mds(1, q41(by));
                mk_tab[2][i] = mds(2, q42(by)); mk_tab[3][i] = mds(3, q43(by));
#else
                sb[0][i] = q40(by); sb[1][i] = q41(by);
                sb[2][i] = q42(by); sb[3][i] = q43(by);
#endif
            }
    }
};

#  ifdef ONE_STEP
#    define g0_fun(x) ( mk_tab[0][byte(x,0)] ^ mk_tab[1][byte(x,1)] \
                      ^ mk_tab[2][byte(x,2)] ^ mk_tab[3][byte(x,3)] )
#    define g1_fun(x) ( mk_tab[0][byte(x,3)] ^ mk_tab[1][byte(x,0)] \
                      ^ mk_tab[2][byte(x,1)] ^ mk_tab[3][byte(x,2)] )
#  else
#    define g0_fun(x) ( mds(0, sb[0][byte(x,0)]) ^ mds(1, sb[1][byte(x,1)]) \
                      ^ mds(2, sb[2][byte(x,2)]) ^ mds(3, sb[3][byte(x,3)]) )
#    define g1_fun(x) ( mds(0, sb[0][byte(x,3)]) ^ mds(1, sb[1][byte(x,0)]) \
                      ^ mds(2, sb[2][byte(x,1)]) ^ mds(3, sb[3][byte(x,2)]) )
#  endif

#else

#define g0_fun(x)   h_fun(x,s_key)
#define g1_fun(x)   h_fun(rotl(x,8),s_key)

#endif

/* The (12,8) Reed Soloman code has the generator polynomial

  g(x) = x^4 + (a + 1/a) * x^3 + a * x^2 + (a + 1/a) * x + 1

where the coefficients are in the finite field GF(2^8) with a
modular polynomial a^8 + a^6 + a^3 + a^2 + 1. To generate the
remainder we have to start with a 12th order polynomial with our
eight input bytes as the coefficients of the 4th to 11th terms.
That is:

  m[7] * x^11 + m[6] * x^10 ... + m[0] * x^4 + 0 * x^3 +... + 0

We then multiply the generator polynomial by m[7] * x^7 and subtract
it - xor in GF(2^8) - from the above to eliminate the x^7 term (the
artihmetic on the coefficients is done in GF(2^8). We then multiply
the generator polynomial by x^6 * coeff(x^10) and use this to remove
the x^10 term. We carry on in this way until the x^4 term is removed
so that we are left with:

  r[3] * x^3 + r[2] * x^2 + r[1] 8 x^1 + r[0]

which give the resulting 4 bytes of the remainder. This is equivalent
to the matrix multiplication in the Twofish description but much faster
to implement.

*/

#define G_MOD   0x0000014d

u4byte mds_rem(u4byte p0, u4byte p1)
{   u4byte  i, t, u;

    for(i = 0; i < 8; ++i)
    {
        t = p1 >> 24;   // get most significant coefficient

        p1 = (p1 << 8) | (p0 >> 24); p0 <<= 8;  // shift others up

        // multiply t by a (the primitive element - i.e. left shift)

        u = (t << 1);

        if(t & 0x80)            // subtract modular polynomial on overflow

            u ^= G_MOD;

        p1 ^= t ^ (u << 16);    // remove t * (a * x^2 + 1)

        u ^= (t >> 1);          // form u = a * t + t / a = t * (a + 1 / a);

        if(t & 0x01)            // add the modular polynomial on underflow

            u ^= G_MOD >> 1;

        p1 ^= (u << 24) | (u << 8); // remove t * (a + 1/a) * (x^3 + x)
    }

    return p1;
};

/* initialise the key schedule from the user supplied key   */

__device__ u4byte *set_key(const u4byte in_key[], const u4byte key_len)
{   u4byte  i, a, b, me_key[4], mo_key[4];

#ifdef Q_TABLES
    [COLOR=red][B]if(!qt_gen)[/B]    {
        gen_qtab(); qt_gen = 1;
    }
#endif

#ifdef M_TABLE
    [COLOR=red][B]if(!mt_gen)[/B]    {
        gen_mtab(); mt_gen = 1;
    }
#endif

    k_len = key_len / 64;   /* 2, 3 or 4 */

    for(i = 0; i < k_len; ++i)
    {
        a = in_key[i + i];     me_key[i] = a;
        b = in_key[i + i + 1]; mo_key[i] = b;
        s_key[k_len - i - 1] = mds_rem(a, b);
    }

    for(i = 0; i < 40; i += 2)
    {
        a = 0x01010101 * i; b = a + 0x01010101;
        a = h_fun(a, me_key);
        b = rotl(h_fun(b, mo_key), 8);
        l_key[i] = a + b;
        l_key[i + 1] = rotl(a + 2 * b, 9);
    }

#ifdef MK_TABLE
    gen_mk_tab(s_key);
#endif

    return l_key;
};

/* encrypt a block of text  */

#define f_rnd(i)                                                    \
    t1 = g1_fun(blk[1]); t0 = g0_fun(blk[0]);                       \
    blk[2] = rotr(blk[2] ^ (t0 + t1 + l_key[4 * (i) + 8]), 1);      \
    blk[3] = rotl(blk[3], 1) ^ (t0 + 2 * t1 + l_key[4 * (i) + 9]);  \
    t1 = g1_fun(blk[3]); t0 = g0_fun(blk[2]);                       \
    blk[0] = rotr(blk[0] ^ (t0 + t1 + l_key[4 * (i) + 10]), 1);     \
    blk[1] = rotl(blk[1], 1) ^ (t0 + 2 * t1 + l_key[4 * (i) + 11])

__device__ void encrypt(const u4byte in_blk[4], u4byte out_blk[4])
{   u4byte  t0, t1, blk[4];

    blk[0] = in_blk[0] ^ l_key[0];
    blk[1] = in_blk[1] ^ l_key[1];
    blk[2] = in_blk[2] ^ l_key[2];
    blk[3] = in_blk[3] ^ l_key[3];

    [COLOR=red][B]f_rnd(0); f_rnd(1); f_rnd(2); f_rnd(3);[/B]    f_rnd(4); f_rnd(5); f_rnd(6); f_rnd(7);

    out_blk[0] = blk[2] ^ l_key[4];
    out_blk[1] = blk[3] ^ l_key[5];
    out_blk[2] = blk[0] ^ l_key[6];
    out_blk[3] = blk[1] ^ l_key[7];
};

/* decrypt a block of text  */

#define i_rnd(i)                                                        \
        t1 = g1_fun(blk[1]); t0 = g0_fun(blk[0]);                       \
        blk[2] = rotl(blk[2], 1) ^ (t0 + t1 + l_key[4 * (i) + 10]);     \
        blk[3] = rotr(blk[3] ^ (t0 + 2 * t1 + l_key[4 * (i) + 11]), 1); \
        t1 = g1_fun(blk[3]); t0 = g0_fun(blk[2]);                       \
        blk[0] = rotl(blk[0], 1) ^ (t0 + t1 + l_key[4 * (i) +  8]);     \
        blk[1] = rotr(blk[1] ^ (t0 + 2 * t1 + l_key[4 * (i) +  9]), 1)

__device__ void decrypt(const u4byte in_blk[4], u4byte out_blk[4])
{   u4byte  t0, t1, blk[4];

    blk[0] = in_blk[0] ^ l_key[4];
    blk[1] = in_blk[1] ^ l_key[5];
    blk[2] = in_blk[2] ^ l_key[6];
    blk[3] = in_blk[3] ^ l_key[7];

   [COLOR=red][B] i_rnd(7); i_rnd(6); i_rnd(5); i_rnd(4);[/B]    i_rnd(3); i_rnd(2); i_rnd(1); i_rnd(0);

    out_blk[0] = blk[2] ^ l_key[0];
    out_blk[1] = blk[3] ^ l_key[1];
    out_blk[2] = blk[0] ^ l_key[2];
    out_blk[3] = blk[1] ^ l_key[3];
};

__global__ void twofish_enc(const u4byte in_blk[4], u4byte out_blk[4]) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    encrypt(in_blk + 4*b, out_blk + 4*b);
}

__global__ void twofish_dec(const u4byte in_blk[4], u4byte out_blk[4]) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    decrypt(in_blk + 4*b, out_blk + 4*b);
}

inline void HandleErrorImpl(cudaError error, const char* file, int line) {
    if (error != cudaSuccess) {
        printf("%s: %d %s", file, line, cudaGetErrorString(error));
        exit(1);
    }
}

int main(void) {
    char* key = "meingeheimespasswort";
    int threads = 512;
    int blocks = 12800;
    set_key((const u4byte*)key, strlen(key));

    u4byte* in_blk;
    HandleError(cudaMalloc(&in_blk, 16*threads*blocks));
    HandleError(cudaMemset(in_blk, 0, 16*threads*blocks));

    u4byte* out_blk;
    HandleError(cudaMalloc(&out_blk, 16*threads*blocks));

    char *test1 = (char*)malloc(16*threads*blocks);
    HandleError(cudaMemcpy(test1, in_blk, 16*threads*blocks, cudaMemcpyDeviceToHost));

    printf("First 16 bytes of input data: ");
    for (int i=0; i<16; i++) {
        printf("%d, ", test1[i]);
    }

    cudaEvent_t start, stop;
    HandleError(cudaEventCreate(&start));
    HandleError(cudaEventCreate(&stop));
    HandleError(cudaEventRecord( start, 0 ));

    twofish_enc<<<blocks,threads>>>(in_blk, out_blk);
    twofish_dec<<<blocks,threads>>>(out_blk, in_blk);

    HandleError(cudaGetLastError());

    HandleError(cudaEventRecord( stop, 0 ));
    HandleError(cudaEventSynchronize( stop ));
    float elapsedTime;
    HandleError(cudaEventElapsedTime( &elapsedTime, start, stop ));

    printf("\nPerformance: %.6f MB/sec\n", 2*((16*threads*blocks)/1048576)/(elapsedTime/1000));

    HandleError(cudaEventDestroy( start ));
    HandleError(cudaEventDestroy( stop ));

    char *test2 = (char*)malloc(16*threads*blocks);
    HandleError(cudaMemcpy(test2, in_blk, 16*threads*blocks, cudaMemcpyDeviceToHost));

    printf("After decryption: ");
    for (int i=0; i<16; i++) {
        printf("%d, ", test2[i]);
    }

    free(test1);
    free(test2);

    HandleError(cudaFree(in_blk));
    HandleError(cudaFree(out_blk));

    return 0;
}
```
^^ In den 4 roten Zeilen heißt's jetzt, dass die jeweiligen identifier in device code undefined sind ...


----------



## sebi707 (2. Januar 2014)

*AW: [CUDA] RC6 / Serpent /Twofish*

Ja musste mal die Datei durchgehen und an alle globalen Variablen ein __device__ klatschen und hoffen, dass es geht.


----------



## boss3D (2. Januar 2014)

*AW: [CUDA] RC6 / Serpent /Twofish*

Ich hoffe, ich habe alles richtig erwischt, aber bis auf zig warnings schaut's jetzt ganz gut aus:

```
/* This is an independent implementation of the encryption algorithm:   */
/*                                                                      */
/*         Twofish by Bruce Schneier and colleagues                     */
/*                                                                      */
/* which is a candidate algorithm in the Advanced Encryption Standard   */
/* programme of the US National Institute of Standards and Technology.  */
/*                                                                      */
/* Copyright in this implementation is held by Dr B R Gladman but I     */
/* hereby give permission for its free direct or derivative use subject */
/* to acknowledgment of its origin and compliance with any conditions   */
/* that the originators of t he algorithm place on its exploitation.    */
/*                                                                      */
/* My thanks to Doug Whiting and Niels Ferguson for comments that led   */
/* to improvements in this implementation.                              */
/*                                                                      */
/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */

/* Timing data for Twofish (twofish.c)

128 bit key:
Key Setup:    8414 cycles
Encrypt:       376 cycles =    68.1 mbits/sec
Decrypt:       374 cycles =    68.4 mbits/sec
Mean:          375 cycles =    68.3 mbits/sec

192 bit key:
Key Setup:   11628 cycles
Encrypt:       376 cycles =    68.1 mbits/sec
Decrypt:       374 cycles =    68.4 mbits/sec
Mean:          375 cycles =    68.3 mbits/sec

256 bit key:
Key Setup:   15457 cycles
Encrypt:       381 cycles =    67.2 mbits/sec
Decrypt:       374 cycles =    68.4 mbits/sec
Mean:          378 cycles =    67.8 mbits/sec

*/

#include "std_defs.h"
#include <stdio.h>

#define Q_TABLES
#define M_TABLE
#define MK_TABLE
#define ONE_STEP

#define HandleError(x) HandleErrorImpl(x, __FILE__, __LINE__)

static char *alg_name[] = { "twofish", "twofish.c", "twofish" };

char **cipher_name()
{
    return alg_name;
}

__device__ u4byte  k_len;
__device__ u4byte  l_key[40];
__device__ u4byte  s_key[4];

/* finite field arithmetic for GF(2**8) with the modular    */
/* polynomial x^8 + x^6 + x^5 + x^3 + 1 (0x169)             */

#define G_M 0x0169

__device__ u1byte  tab_5b[4] = { 0, G_M >> 2, G_M >> 1, (G_M >> 1) ^ (G_M >> 2) };
__device__ u1byte  tab_ef[4] = { 0, (G_M >> 1) ^ (G_M >> 2), G_M >> 1, G_M >> 2 };

#define ffm_01(x)    (x)
#define ffm_5b(x)   ((x) ^ ((x) >> 2) ^ tab_5b[(x) & 3])
#define ffm_ef(x)   ((x) ^ ((x) >> 1) ^ ((x) >> 2) ^ tab_ef[(x) & 3])

__device__ u1byte ror4[16] = { 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 };
__device__ u1byte ashx[16] = { 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, 5, 14, 7 };

__device__ u1byte qt0[2][16] =
{   { 8, 1, 7, 13, 6, 15, 3, 2, 0, 11, 5, 9, 14, 12, 10, 4 },
    { 2, 8, 11, 13, 15, 7, 6, 14, 3, 1, 9, 4, 0, 10, 12, 5 }
};

__device__ u1byte qt1[2][16] =
{   { 14, 12, 11, 8, 1, 2, 3, 5, 15, 4, 10, 6, 7, 0, 9, 13 },
    { 1, 14, 2, 11, 4, 12, 3, 7, 6, 13, 10, 5, 15, 9, 0, 8 }
};

__device__ u1byte qt2[2][16] =
{   { 11, 10, 5, 14, 6, 13, 9, 0, 12, 8, 15, 3, 2, 4, 7, 1 },
    { 4, 12, 7, 5, 1, 6, 9, 10, 0, 14, 13, 8, 2, 11, 3, 15 }
};

__device__ u1byte qt3[2][16] =
{   { 13, 7, 15, 4, 1, 2, 6, 14, 9, 11, 3, 0, 8, 5, 12, 10 },
    { 11, 9, 5, 1, 12, 3, 13, 14, 6, 4, 7, 15, 2, 0, 8, 10 }
};

u1byte qp(const u4byte n, const u1byte x)
{   u1byte  a0, a1, a2, a3, a4, b0, b1, b2, b3, b4;

    a0 = x >> 4; b0 = x & 15;
    a1 = a0 ^ b0; b1 = ror4[b0] ^ ashx[a0];
    a2 = qt0[n][a1]; b2 = qt1[n][b1];
    a3 = a2 ^ b2; b3 = ror4[b2] ^ ashx[a2];
    a4 = qt2[n][a3]; b4 = qt3[n][b3];
    return (b4 << 4) | a4;
};

#ifdef  Q_TABLES

__device__ u4byte  qt_gen = 0;
__device__ u1byte  q_tab[2][256];

#define q(n,x)  q_tab[n][x]

void gen_qtab(void)
{   u4byte  i;

    for(i = 0; i < 256; ++i)
    {
        q(0,i) = qp(0, (u1byte)i);
        q(1,i) = qp(1, (u1byte)i);
    }
};

#else

#define q(n,x)  qp(n, x)

#endif

#ifdef  M_TABLE

__device__ u4byte  mt_gen = 0;
__device__ u4byte  m_tab[4][256];

void gen_mtab(void)
{   u4byte  i, f01, f5b, fef;

    for(i = 0; i < 256; ++i)
    {
        f01 = q(1,i); f5b = ffm_5b(f01); fef = ffm_ef(f01);
        m_tab[0][i] = f01 + (f5b << 8) + (fef << 16) + (fef << 24);
        m_tab[2][i] = f5b + (fef << 8) + (f01 << 16) + (fef << 24);

        f01 = q(0,i); f5b = ffm_5b(f01); fef = ffm_ef(f01);
        m_tab[1][i] = fef + (fef << 8) + (f5b << 16) + (f01 << 24);
        m_tab[3][i] = f5b + (f01 << 8) + (fef << 16) + (f5b << 24);
    }
};

#define mds(n,x)    m_tab[n][x]

#else

#define fm_00   ffm_01
#define fm_10   ffm_5b
#define fm_20   ffm_ef
#define fm_30   ffm_ef
#define q_0(x)  q(1,x)

#define fm_01   ffm_ef
#define fm_11   ffm_ef
#define fm_21   ffm_5b
#define fm_31   ffm_01
#define q_1(x)  q(0,x)

#define fm_02   ffm_5b
#define fm_12   ffm_ef
#define fm_22   ffm_01
#define fm_32   ffm_ef
#define q_2(x)  q(1,x)

#define fm_03   ffm_5b
#define fm_13   ffm_01
#define fm_23   ffm_ef
#define fm_33   ffm_5b
#define q_3(x)  q(0,x)

#define f_0(n,x)    ((u4byte)fm_0##n(x))
#define f_1(n,x)    ((u4byte)fm_1##n(x) << 8)
#define f_2(n,x)    ((u4byte)fm_2##n(x) << 16)
#define f_3(n,x)    ((u4byte)fm_3##n(x) << 24)

#define mds(n,x)    f_0(n,q_##n(x)) ^ f_1(n,q_##n(x)) ^ f_2(n,q_##n(x)) ^ f_3(n,q_##n(x))

#endif

u4byte h_fun(const u4byte x, const u4byte key[])
{   u4byte  b0, b1, b2, b3;

#ifndef M_TABLE
    u4byte  m5b_b0, m5b_b1, m5b_b2, m5b_b3;
    u4byte  mef_b0, mef_b1, mef_b2, mef_b3;
#endif

    b0 = byte(x, 0); b1 = byte(x, 1); b2 = byte(x, 2); b3 = byte(x, 3);

    switch(k_len)
    {
    case 4: b0 = q(1, b0) ^ byte(key[3],0);
            b1 = q(0, b1) ^ byte(key[3],1);
            b2 = q(0, b2) ^ byte(key[3],2);
            b3 = q(1, b3) ^ byte(key[3],3);
    case 3: b0 = q(1, b0) ^ byte(key[2],0);
            b1 = q(1, b1) ^ byte(key[2],1);
            b2 = q(0, b2) ^ byte(key[2],2);
            b3 = q(0, b3) ^ byte(key[2],3);
    case 2: b0 = q(0,q(0,b0) ^ byte(key[1],0)) ^ byte(key[0],0);
            b1 = q(0,q(1,b1) ^ byte(key[1],1)) ^ byte(key[0],1);
            b2 = q(1,q(0,b2) ^ byte(key[1],2)) ^ byte(key[0],2);
            b3 = q(1,q(1,b3) ^ byte(key[1],3)) ^ byte(key[0],3);
    }
#ifdef  M_TABLE

    return  mds(0, b0) ^ mds(1, b1) ^ mds(2, b2) ^ mds(3, b3);

#else

    b0 = q(1, b0); b1 = q(0, b1); b2 = q(1, b2); b3 = q(0, b3);
    m5b_b0 = ffm_5b(b0); m5b_b1 = ffm_5b(b1); m5b_b2 = ffm_5b(b2); m5b_b3 = ffm_5b(b3);
    mef_b0 = ffm_ef(b0); mef_b1 = ffm_ef(b1); mef_b2 = ffm_ef(b2); mef_b3 = ffm_ef(b3);
    b0 ^= mef_b1 ^ m5b_b2 ^ m5b_b3; b3 ^= m5b_b0 ^ mef_b1 ^ mef_b2;
    b2 ^= mef_b0 ^ m5b_b1 ^ mef_b3; b1 ^= mef_b0 ^ mef_b2 ^ m5b_b3;

    return b0 | (b3 << 8) | (b2 << 16) | (b1 << 24);

#endif
};

#ifdef  MK_TABLE

#ifdef  ONE_STEP
__device__ u4byte  mk_tab[4][256];
#else
__device__ u1byte  sb[4][256];
#endif

#define q20(x)  q(0,q(0,x) ^ byte(key[1],0)) ^ byte(key[0],0)
#define q21(x)  q(0,q(1,x) ^ byte(key[1],1)) ^ byte(key[0],1)
#define q22(x)  q(1,q(0,x) ^ byte(key[1],2)) ^ byte(key[0],2)
#define q23(x)  q(1,q(1,x) ^ byte(key[1],3)) ^ byte(key[0],3)

#define q30(x)  q(0,q(0,q(1, x) ^ byte(key[2],0)) ^ byte(key[1],0)) ^ byte(key[0],0)
#define q31(x)  q(0,q(1,q(1, x) ^ byte(key[2],1)) ^ byte(key[1],1)) ^ byte(key[0],1)
#define q32(x)  q(1,q(0,q(0, x) ^ byte(key[2],2)) ^ byte(key[1],2)) ^ byte(key[0],2)
#define q33(x)  q(1,q(1,q(0, x) ^ byte(key[2],3)) ^ byte(key[1],3)) ^ byte(key[0],3)

#define q40(x)  q(0,q(0,q(1, q(1, x) ^ byte(key[3],0)) ^ byte(key[2],0)) ^ byte(key[1],0)) ^ byte(key[0],0)
#define q41(x)  q(0,q(1,q(1, q(0, x) ^ byte(key[3],1)) ^ byte(key[2],1)) ^ byte(key[1],1)) ^ byte(key[0],1)
#define q42(x)  q(1,q(0,q(0, q(0, x) ^ byte(key[3],2)) ^ byte(key[2],2)) ^ byte(key[1],2)) ^ byte(key[0],2)
#define q43(x)  q(1,q(1,q(0, q(1, x) ^ byte(key[3],3)) ^ byte(key[2],3)) ^ byte(key[1],3)) ^ byte(key[0],3)

void gen_mk_tab(u4byte key[])
{   u4byte  i;
    u1byte  by;

    switch(k_len)
    {
    case 2: for(i = 0; i < 256; ++i)
            {
                by = (u1byte)i;
#ifdef ONE_STEP
                mk_tab[0][i] = mds(0, q20(by)); mk_tab[1][i] = mds(1, q21(by));
                mk_tab[2][i] = mds(2, q22(by)); mk_tab[3][i] = mds(3, q23(by));
#else
                sb[0][i] = q20(by); sb[1][i] = q21(by);
                sb[2][i] = q22(by); sb[3][i] = q23(by);
#endif
            }
            break;

    case 3: for(i = 0; i < 256; ++i)
            {
                by = (u1byte)i;
#ifdef ONE_STEP
                mk_tab[0][i] = mds(0, q30(by)); mk_tab[1][i] = mds(1, q31(by));
                mk_tab[2][i] = mds(2, q32(by)); mk_tab[3][i] = mds(3, q33(by));
#else
                sb[0][i] = q30(by); sb[1][i] = q31(by);
                sb[2][i] = q32(by); sb[3][i] = q33(by);
#endif
            }
            break;

    case 4: for(i = 0; i < 256; ++i)
            {
                by = (u1byte)i;
#ifdef ONE_STEP
                mk_tab[0][i] = mds(0, q40(by)); mk_tab[1][i] = mds(1, q41(by));
                mk_tab[2][i] = mds(2, q42(by)); mk_tab[3][i] = mds(3, q43(by));
#else
                sb[0][i] = q40(by); sb[1][i] = q41(by);
                sb[2][i] = q42(by); sb[3][i] = q43(by);
#endif
            }
    }
};

#  ifdef ONE_STEP
#    define g0_fun(x) ( mk_tab[0][byte(x,0)] ^ mk_tab[1][byte(x,1)] \
                      ^ mk_tab[2][byte(x,2)] ^ mk_tab[3][byte(x,3)] )
#    define g1_fun(x) ( mk_tab[0][byte(x,3)] ^ mk_tab[1][byte(x,0)] \
                      ^ mk_tab[2][byte(x,1)] ^ mk_tab[3][byte(x,2)] )
#  else
#    define g0_fun(x) ( mds(0, sb[0][byte(x,0)]) ^ mds(1, sb[1][byte(x,1)]) \
                      ^ mds(2, sb[2][byte(x,2)]) ^ mds(3, sb[3][byte(x,3)]) )
#    define g1_fun(x) ( mds(0, sb[0][byte(x,3)]) ^ mds(1, sb[1][byte(x,0)]) \
                      ^ mds(2, sb[2][byte(x,1)]) ^ mds(3, sb[3][byte(x,2)]) )
#  endif

#else

#define g0_fun(x)   h_fun(x,s_key)
#define g1_fun(x)   h_fun(rotl(x,8),s_key)

#endif

/* The (12,8) Reed Soloman code has the generator polynomial

  g(x) = x^4 + (a + 1/a) * x^3 + a * x^2 + (a + 1/a) * x + 1

where the coefficients are in the finite field GF(2^8) with a
modular polynomial a^8 + a^6 + a^3 + a^2 + 1. To generate the
remainder we have to start with a 12th order polynomial with our
eight input bytes as the coefficients of the 4th to 11th terms.
That is:

  m[7] * x^11 + m[6] * x^10 ... + m[0] * x^4 + 0 * x^3 +... + 0

We then multiply the generator polynomial by m[7] * x^7 and subtract
it - xor in GF(2^8) - from the above to eliminate the x^7 term (the
artihmetic on the coefficients is done in GF(2^8). We then multiply
the generator polynomial by x^6 * coeff(x^10) and use this to remove
the x^10 term. We carry on in this way until the x^4 term is removed
so that we are left with:

  r[3] * x^3 + r[2] * x^2 + r[1] 8 x^1 + r[0]

which give the resulting 4 bytes of the remainder. This is equivalent
to the matrix multiplication in the Twofish description but much faster
to implement.

*/

#define G_MOD   0x0000014d

u4byte mds_rem(u4byte p0, u4byte p1)
{   u4byte  i, t, u;

    for(i = 0; i < 8; ++i)
    {
        t = p1 >> 24;   // get most significant coefficient

        p1 = (p1 << 8) | (p0 >> 24); p0 <<= 8;  // shift others up

        // multiply t by a (the primitive element - i.e. left shift)

        u = (t << 1);

        if(t & 0x80)            // subtract modular polynomial on overflow

            u ^= G_MOD;

        p1 ^= t ^ (u << 16);    // remove t * (a * x^2 + 1)

        u ^= (t >> 1);          // form u = a * t + t / a = t * (a + 1 / a);

        if(t & 0x01)            // add the modular polynomial on underflow

            u ^= G_MOD >> 1;

        p1 ^= (u << 24) | (u << 8); // remove t * (a + 1/a) * (x^3 + x)
    }

    return p1;
};

/* initialise the key schedule from the user supplied key   */

u4byte *set_key(const u4byte in_key[], const u4byte key_len)
{   u4byte  i, a, b, me_key[4], mo_key[4];

#ifdef Q_TABLES
    if(!qt_gen)
    {
        gen_qtab(); qt_gen = 1;
    }
#endif

#ifdef M_TABLE
    if(!mt_gen)
    {
        gen_mtab(); mt_gen = 1;
    }
#endif

    k_len = key_len / 64;   /* 2, 3 or 4 */

    for(i = 0; i < k_len; ++i)
    {
        a = in_key[i + i];     me_key[i] = a;
        b = in_key[i + i + 1]; mo_key[i] = b;
        s_key[k_len - i - 1] = mds_rem(a, b);
    }

    for(i = 0; i < 40; i += 2)
    {
        a = 0x01010101 * i; b = a + 0x01010101;
        a = h_fun(a, me_key);
        b = rotl(h_fun(b, mo_key), 8);
        l_key[i] = a + b;
        l_key[i + 1] = rotl(a + 2 * b, 9);
    }

#ifdef MK_TABLE
    gen_mk_tab(s_key);
#endif

    return l_key;
};

/* encrypt a block of text  */

#define f_rnd(i)                                                    \
    t1 = g1_fun(blk[1]); t0 = g0_fun(blk[0]);                       \
    blk[2] = rotr(blk[2] ^ (t0 + t1 + l_key[4 * (i) + 8]), 1);      \
    blk[3] = rotl(blk[3], 1) ^ (t0 + 2 * t1 + l_key[4 * (i) + 9]);  \
    t1 = g1_fun(blk[3]); t0 = g0_fun(blk[2]);                       \
    blk[0] = rotr(blk[0] ^ (t0 + t1 + l_key[4 * (i) + 10]), 1);     \
    blk[1] = rotl(blk[1], 1) ^ (t0 + 2 * t1 + l_key[4 * (i) + 11])

__device__ void encrypt(const u4byte in_blk[4], u4byte out_blk[4])
{   u4byte  t0, t1, blk[4];

    blk[0] = in_blk[0] ^ l_key[0];
    blk[1] = in_blk[1] ^ l_key[1];
    blk[2] = in_blk[2] ^ l_key[2];
    blk[3] = in_blk[3] ^ l_key[3];

    f_rnd(0); f_rnd(1); f_rnd(2); f_rnd(3);
    f_rnd(4); f_rnd(5); f_rnd(6); f_rnd(7);

    out_blk[0] = blk[2] ^ l_key[4];
    out_blk[1] = blk[3] ^ l_key[5];
    out_blk[2] = blk[0] ^ l_key[6];
    out_blk[3] = blk[1] ^ l_key[7];
};

/* decrypt a block of text  */

#define i_rnd(i)                                                        \
        t1 = g1_fun(blk[1]); t0 = g0_fun(blk[0]);                       \
        blk[2] = rotl(blk[2], 1) ^ (t0 + t1 + l_key[4 * (i) + 10]);     \
        blk[3] = rotr(blk[3] ^ (t0 + 2 * t1 + l_key[4 * (i) + 11]), 1); \
        t1 = g1_fun(blk[3]); t0 = g0_fun(blk[2]);                       \
        blk[0] = rotl(blk[0], 1) ^ (t0 + t1 + l_key[4 * (i) +  8]);     \
        blk[1] = rotr(blk[1] ^ (t0 + 2 * t1 + l_key[4 * (i) +  9]), 1)

__device__ void decrypt(const u4byte in_blk[4], u4byte out_blk[4])
{   u4byte  t0, t1, blk[4];

    blk[0] = in_blk[0] ^ l_key[4];
    blk[1] = in_blk[1] ^ l_key[5];
    blk[2] = in_blk[2] ^ l_key[6];
    blk[3] = in_blk[3] ^ l_key[7];

    i_rnd(7); i_rnd(6); i_rnd(5); i_rnd(4);
    i_rnd(3); i_rnd(2); i_rnd(1); i_rnd(0);

    out_blk[0] = blk[2] ^ l_key[0];
    out_blk[1] = blk[3] ^ l_key[1];
    out_blk[2] = blk[0] ^ l_key[2];
    out_blk[3] = blk[1] ^ l_key[3];
};

__global__ void twofish_enc(const u4byte in_blk[4], u4byte out_blk[4]) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    encrypt(in_blk + 4*b, out_blk + 4*b);
}

__global__ void twofish_dec(const u4byte in_blk[4], u4byte out_blk[4]) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    decrypt(in_blk + 4*b, out_blk + 4*b);
}

inline void HandleErrorImpl(cudaError error, const char* file, int line) {
    if (error != cudaSuccess) {
        printf("%s: %d %s", file, line, cudaGetErrorString(error));
        exit(1);
    }
}

int main(void) {
    char* key = "meingeheimespasswort";
    int threads = 512;
    int blocks = 12800;
    set_key((const u4byte*)key, strlen(key));

    u4byte* in_blk;
    HandleError(cudaMalloc(&in_blk, 16*threads*blocks));
    HandleError(cudaMemset(in_blk, 0, 16*threads*blocks));

    u4byte* out_blk;
    HandleError(cudaMalloc(&out_blk, 16*threads*blocks));

    char *test1 = (char*)malloc(16*threads*blocks);
    HandleError(cudaMemcpy(test1, in_blk, 16*threads*blocks, cudaMemcpyDeviceToHost));

    printf("First 16 bytes of input data: ");
    for (int i=0; i<16; i++) {
        printf("%d, ", test1[i]);
    }

    cudaEvent_t start, stop;
    HandleError(cudaEventCreate(&start));
    HandleError(cudaEventCreate(&stop));
    HandleError(cudaEventRecord( start, 0 ));

    twofish_enc<<<blocks,threads>>>(in_blk, out_blk);
    twofish_dec<<<blocks,threads>>>(out_blk, in_blk);

    HandleError(cudaGetLastError());

    HandleError(cudaEventRecord( stop, 0 ));
    HandleError(cudaEventSynchronize( stop ));
    float elapsedTime;
    HandleError(cudaEventElapsedTime( &elapsedTime, start, stop ));

    printf("\nPerformance: %.6f MB/sec\n", 2*((16*threads*blocks)/1048576)/(elapsedTime/1000));

    HandleError(cudaEventDestroy( start ));
    HandleError(cudaEventDestroy( stop ));

    char *test2 = (char*)malloc(16*threads*blocks);
    HandleError(cudaMemcpy(test2, in_blk, 16*threads*blocks, cudaMemcpyDeviceToHost));

    printf("After decryption: ");
    for (int i=0; i<16; i++) {
        printf("%d, ", test2[i]);
    }

    free(test1);
    free(test2);

    HandleError(cudaFree(in_blk));
    HandleError(cudaFree(out_blk));

    return 0;
}
```
Brauche ich die Schlüssel-Initialisierung in der main jetzt noch in der Form, wie ich es habe?

Und in der Ausgabe kriege ich in Zeile 521 noch einen Fehler:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



_"Too many resources requested for launch"
_
*[Edit]*
Habe beim googlen noch rausgefunden, dass wir scheinbar zu viele Register und/oder zu viel shared memory ansprechen wollen. ???


----------



## sebi707 (3. Januar 2014)

*AW: [CUDA] RC6 / Serpent / Twofish*

Es ist wohl leider ziemlich nervig, dass deine Hardware nicht besonders viel her gibt. Kannst du nicht schon Zugriff auf das Testsystem haben oder irgendwas anderes das nicht an der untersten Grenze von den Möglichkeiten ist? Da wir kein Shared-Memory benutzen ist wohl die Anzahl der Register erschöpft. Versuch mal mit der Anzahl Threads pro Block runter zu gehen ob es dann startet.


----------



## boss3D (3. Januar 2014)

*AW: [CUDA] RC6 / Serpent / Twofish*

Das Benchmarksystem steht in einem Rechen-Cluster auf der FH und ich hätte schon seit knapp zwei Wochen via VPN/VNC Zugriff, allerdings ist das System vor 1 Woche beim simplen Abrufen von emails (!) eingefroren und seitdem sehe ich im VNC Viewer nur noch ein schwarzes Fenster. Ich kann mich erst nach den Weihnachtsferien, wenn ich wieder auf der FH bin, darum kümmern, dass die zuständigen Leute von der Technik einen Hardreset machen. Ich selbst habe als Student auch auf der FH keinen Zutritt zu dem Raum. Und von zuhause aus kann ich schon gar nichts machen. Auf ein gesendetes Strg-Alt-Entf reagiert das System auch nicht mehr ...

Trotzdem vermute ich, dass unser aktuellstes Problem ausnahmsweise nicht an meiner 9600M GT liegt, weil man beim googeln Beiträge von Leuten mit weitaus potenterer Grafikhardware aber dem exakt selben Fehler findet. Oder läuft Twofish bei dir auf deiner GTX 560 Ti einwandfrei?

In ca. 1 h habe ich jedenfalls Zeit, am Code weiterzuarbeiten und mit der Anzahl der Threads/Blöcke herumzuprobieren. Ich melde mich dann nochmals, falls es was bewirkt.


----------



## sebi707 (3. Januar 2014)

*AW: [CUDA] RC6 / Serpent / Twofish*

Hab grade mal geguckt wie das ganze auf meiner GTX 560 Ti läuft und dort kriege ich nur einen "unspecified launch failure". Also Resourcen scheint die GPU genug zu haben nur mit den Pointern passt noch nicht alles. Ich habe mir auch mal ausgeben lassen wie viele Register die Funktionen brauchen und bin bei 28 Registern für die decrypt und 27 Registern für die encrypt Funktion. Bei 512 Threads pro Block macht das 14336 Register und laut der CUDA Programming Guide gibts bei Compute Capability 1.0 nur 8K Register pro Multiprocessor. Also kann auf deiner GPU der Multiprocessor keinen einzigen Block aufnehmen weil du das Limit an registern schon überschritten hast. Bei 256 Threads pro Block wärst du bei 7168 Registern pro Block was knapp unter den 8K liegt und damit laufen sollte.

Edit: Zum Vergleich haben RC6 und Serpent beide maximal 13 Register und 13*512 = 6656 und das ist auch unter 8K.


----------



## boss3D (3. Januar 2014)

*AW: [CUDA] RC6 / Serpent / Twofish*

Habe eben mit 256 Threads / 25600 Blocks (um immer noch auf die 100 MB zu kommen) getestet und damit komme ich jetzt auf den vermutlich von dir gemeinten launch failure ...




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Das heißt wohl wieder, dass irgendwelche Daten, die die GPU braucht, noch nicht zuvor (korrekt) in den VRAM geschrieben werden?! Ich schau mir die ganzen mallocs nochmal an.


----------



## boss3D (4. Januar 2014)

*AW: [CUDA] RC6 / Serpent / Twofish / AES*

*AES*

Ich habe gestern auch noch AES portiert, was soweit ganz gut geklappt hat, nur kriege ich da jetzt auch noch diesen blöden launch failure (und jede Menge warnings) ... 

```
/********************************
** Advanced Encryption Standard
** Author: B-Con (b-con@b-con.us)
** Copyright/Restrictions: GNU GPL
** Disclaimer: This code is presented "as is" without any garuentees; said author holds
               liability for no problems rendered by the use of this code.
** Details: This code is the implementation of the AES algorithm, as specified by the
            NIST in in publication FIPS PUB 197, availible on the NIST website at
            http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf .
******************************************/

[COLOR=royalblue][B]#include <stdio.h>[/B]
#define uchar unsigned char // 8-bit byte
#define uint unsigned long // 32-bit word

[COLOR=royalblue][B]#define HandleError(x) HandleErrorImpl(x, __FILE__, __LINE__)[/B]
// This is the specified AES SBox. To look up a substitution value, put the first
// nibble in the first index (row) and the second nibble in the second index (column).
[COLOR=royalblue][B]__device__[/B] const uchar aes_sbox[16][16] = {
   0x63,0x7C,0x77,0x7B,0xF2,0x6B,0x6F,0xC5,0x30,0x01,0x67,0x2B,0xFE,0xD7,0xAB,0x76,
   0xCA,0x82,0xC9,0x7D,0xFA,0x59,0x47,0xF0,0xAD,0xD4,0xA2,0xAF,0x9C,0xA4,0x72,0xC0,
   0xB7,0xFD,0x93,0x26,0x36,0x3F,0xF7,0xCC,0x34,0xA5,0xE5,0xF1,0x71,0xD8,0x31,0x15,
   0x04,0xC7,0x23,0xC3,0x18,0x96,0x05,0x9A,0x07,0x12,0x80,0xE2,0xEB,0x27,0xB2,0x75,
   0x09,0x83,0x2C,0x1A,0x1B,0x6E,0x5A,0xA0,0x52,0x3B,0xD6,0xB3,0x29,0xE3,0x2F,0x84,
   0x53,0xD1,0x00,0xED,0x20,0xFC,0xB1,0x5B,0x6A,0xCB,0xBE,0x39,0x4A,0x4C,0x58,0xCF,
   0xD0,0xEF,0xAA,0xFB,0x43,0x4D,0x33,0x85,0x45,0xF9,0x02,0x7F,0x50,0x3C,0x9F,0xA8,
   0x51,0xA3,0x40,0x8F,0x92,0x9D,0x38,0xF5,0xBC,0xB6,0xDA,0x21,0x10,0xFF,0xF3,0xD2,
   0xCD,0x0C,0x13,0xEC,0x5F,0x97,0x44,0x17,0xC4,0xA7,0x7E,0x3D,0x64,0x5D,0x19,0x73,
   0x60,0x81,0x4F,0xDC,0x22,0x2A,0x90,0x88,0x46,0xEE,0xB8,0x14,0xDE,0x5E,0x0B,0xDB,
   0xE0,0x32,0x3A,0x0A,0x49,0x06,0x24,0x5C,0xC2,0xD3,0xAC,0x62,0x91,0x95,0xE4,0x79,
   0xE7,0xC8,0x37,0x6D,0x8D,0xD5,0x4E,0xA9,0x6C,0x56,0xF4,0xEA,0x65,0x7A,0xAE,0x08,
   0xBA,0x78,0x25,0x2E,0x1C,0xA6,0xB4,0xC6,0xE8,0xDD,0x74,0x1F,0x4B,0xBD,0x8B,0x8A,
   0x70,0x3E,0xB5,0x66,0x48,0x03,0xF6,0x0E,0x61,0x35,0x57,0xB9,0x86,0xC1,0x1D,0x9E,
   0xE1,0xF8,0x98,0x11,0x69,0xD9,0x8E,0x94,0x9B,0x1E,0x87,0xE9,0xCE,0x55,0x28,0xDF,
   0x8C,0xA1,0x89,0x0D,0xBF,0xE6,0x42,0x68,0x41,0x99,0x2D,0x0F,0xB0,0x54,0xBB,0x16
};

[COLOR=royalblue][B]__device__[/B] const uchar aes_invsbox[16][16] = {
   0x52,0x09,0x6A,0xD5,0x30,0x36,0xA5,0x38,0xBF,0x40,0xA3,0x9E,0x81,0xF3,0xD7,0xFB,
   0x7C,0xE3,0x39,0x82,0x9B,0x2F,0xFF,0x87,0x34,0x8E,0x43,0x44,0xC4,0xDE,0xE9,0xCB,
   0x54,0x7B,0x94,0x32,0xA6,0xC2,0x23,0x3D,0xEE,0x4C,0x95,0x0B,0x42,0xFA,0xC3,0x4E,
   0x08,0x2E,0xA1,0x66,0x28,0xD9,0x24,0xB2,0x76,0x5B,0xA2,0x49,0x6D,0x8B,0xD1,0x25,
   0x72,0xF8,0xF6,0x64,0x86,0x68,0x98,0x16,0xD4,0xA4,0x5C,0xCC,0x5D,0x65,0xB6,0x92,
   0x6C,0x70,0x48,0x50,0xFD,0xED,0xB9,0xDA,0x5E,0x15,0x46,0x57,0xA7,0x8D,0x9D,0x84,
   0x90,0xD8,0xAB,0x00,0x8C,0xBC,0xD3,0x0A,0xF7,0xE4,0x58,0x05,0xB8,0xB3,0x45,0x06,
   0xD0,0x2C,0x1E,0x8F,0xCA,0x3F,0x0F,0x02,0xC1,0xAF,0xBD,0x03,0x01,0x13,0x8A,0x6B,
   0x3A,0x91,0x11,0x41,0x4F,0x67,0xDC,0xEA,0x97,0xF2,0xCF,0xCE,0xF0,0xB4,0xE6,0x73,
   0x96,0xAC,0x74,0x22,0xE7,0xAD,0x35,0x85,0xE2,0xF9,0x37,0xE8,0x1C,0x75,0xDF,0x6E,
   0x47,0xF1,0x1A,0x71,0x1D,0x29,0xC5,0x89,0x6F,0xB7,0x62,0x0E,0xAA,0x18,0xBE,0x1B,
   0xFC,0x56,0x3E,0x4B,0xC6,0xD2,0x79,0x20,0x9A,0xDB,0xC0,0xFE,0x78,0xCD,0x5A,0xF4,
   0x1F,0xDD,0xA8,0x33,0x88,0x07,0xC7,0x31,0xB1,0x12,0x10,0x59,0x27,0x80,0xEC,0x5F,
   0x60,0x51,0x7F,0xA9,0x19,0xB5,0x4A,0x0D,0x2D,0xE5,0x7A,0x9F,0x93,0xC9,0x9C,0xEF,
   0xA0,0xE0,0x3B,0x4D,0xAE,0x2A,0xF5,0xB0,0xC8,0xEB,0xBB,0x3C,0x83,0x53,0x99,0x61,
   0x17,0x2B,0x04,0x7E,0xBA,0x77,0xD6,0x26,0xE1,0x69,0x14,0x63,0x55,0x21,0x0C,0x7D
};

// - This table stores pre-calculated values for all possible GF(2^8) calculations.This
// table is only used by the (Inv)MixColumns steps.
// USAGE: The second index (column) is the coefficient of multiplication. Only 7 different
// coefficients are used: 0x01, 0x02, 0x03, 0x09, 0x0b, 0x0d, 0x0e, but multiplication by
// 1 is negligible leaving only 6 coefficients. Each column of the table is devoted to one
// of these coefficients, in the ascending order of value, from values 0x00 to 0xFF.
// (Columns are listed double-wide to conserve vertical space.)
[COLOR=royalblue][B]__device__[/B] uchar gf_mul[256][6] = {
   {0x00,0x00,0x00,0x00,0x00,0x00},{0x02,0x03,0x09,0x0b,0x0d,0x0e},
   {0x04,0x06,0x12,0x16,0x1a,0x1c},{0x06,0x05,0x1b,0x1d,0x17,0x12},
   {0x08,0x0c,0x24,0x2c,0x34,0x38},{0x0a,0x0f,0x2d,0x27,0x39,0x36},
   {0x0c,0x0a,0x36,0x3a,0x2e,0x24},{0x0e,0x09,0x3f,0x31,0x23,0x2a},
   {0x10,0x18,0x48,0x58,0x68,0x70},{0x12,0x1b,0x41,0x53,0x65,0x7e},
   {0x14,0x1e,0x5a,0x4e,0x72,0x6c},{0x16,0x1d,0x53,0x45,0x7f,0x62},
   {0x18,0x14,0x6c,0x74,0x5c,0x48},{0x1a,0x17,0x65,0x7f,0x51,0x46},
   {0x1c,0x12,0x7e,0x62,0x46,0x54},{0x1e,0x11,0x77,0x69,0x4b,0x5a},
   {0x20,0x30,0x90,0xb0,0xd0,0xe0},{0x22,0x33,0x99,0xbb,0xdd,0xee},
   {0x24,0x36,0x82,0xa6,0xca,0xfc},{0x26,0x35,0x8b,0xad,0xc7,0xf2},
   {0x28,0x3c,0xb4,0x9c,0xe4,0xd8},{0x2a,0x3f,0xbd,0x97,0xe9,0xd6},
   {0x2c,0x3a,0xa6,0x8a,0xfe,0xc4},{0x2e,0x39,0xaf,0x81,0xf3,0xca},
   {0x30,0x28,0xd8,0xe8,0xb8,0x90},{0x32,0x2b,0xd1,0xe3,0xb5,0x9e},
   {0x34,0x2e,0xca,0xfe,0xa2,0x8c},{0x36,0x2d,0xc3,0xf5,0xaf,0x82},
   {0x38,0x24,0xfc,0xc4,0x8c,0xa8},{0x3a,0x27,0xf5,0xcf,0x81,0xa6},
   {0x3c,0x22,0xee,0xd2,0x96,0xb4},{0x3e,0x21,0xe7,0xd9,0x9b,0xba},
   {0x40,0x60,0x3b,0x7b,0xbb,0xdb},{0x42,0x63,0x32,0x70,0xb6,0xd5},
   {0x44,0x66,0x29,0x6d,0xa1,0xc7},{0x46,0x65,0x20,0x66,0xac,0xc9},
   {0x48,0x6c,0x1f,0x57,0x8f,0xe3},{0x4a,0x6f,0x16,0x5c,0x82,0xed},
   {0x4c,0x6a,0x0d,0x41,0x95,0xff},{0x4e,0x69,0x04,0x4a,0x98,0xf1},
   {0x50,0x78,0x73,0x23,0xd3,0xab},{0x52,0x7b,0x7a,0x28,0xde,0xa5},
   {0x54,0x7e,0x61,0x35,0xc9,0xb7},{0x56,0x7d,0x68,0x3e,0xc4,0xb9},
   {0x58,0x74,0x57,0x0f,0xe7,0x93},{0x5a,0x77,0x5e,0x04,0xea,0x9d},
   {0x5c,0x72,0x45,0x19,0xfd,0x8f},{0x5e,0x71,0x4c,0x12,0xf0,0x81},
   {0x60,0x50,0xab,0xcb,0x6b,0x3b},{0x62,0x53,0xa2,0xc0,0x66,0x35},
   {0x64,0x56,0xb9,0xdd,0x71,0x27},{0x66,0x55,0xb0,0xd6,0x7c,0x29},
   {0x68,0x5c,0x8f,0xe7,0x5f,0x03},{0x6a,0x5f,0x86,0xec,0x52,0x0d},
   {0x6c,0x5a,0x9d,0xf1,0x45,0x1f},{0x6e,0x59,0x94,0xfa,0x48,0x11},
   {0x70,0x48,0xe3,0x93,0x03,0x4b},{0x72,0x4b,0xea,0x98,0x0e,0x45},
   {0x74,0x4e,0xf1,0x85,0x19,0x57},{0x76,0x4d,0xf8,0x8e,0x14,0x59},
   {0x78,0x44,0xc7,0xbf,0x37,0x73},{0x7a,0x47,0xce,0xb4,0x3a,0x7d},
   {0x7c,0x42,0xd5,0xa9,0x2d,0x6f},{0x7e,0x41,0xdc,0xa2,0x20,0x61},
   {0x80,0xc0,0x76,0xf6,0x6d,0xad},{0x82,0xc3,0x7f,0xfd,0x60,0xa3},
   {0x84,0xc6,0x64,0xe0,0x77,0xb1},{0x86,0xc5,0x6d,0xeb,0x7a,0xbf},
   {0x88,0xcc,0x52,0xda,0x59,0x95},{0x8a,0xcf,0x5b,0xd1,0x54,0x9b},
   {0x8c,0xca,0x40,0xcc,0x43,0x89},{0x8e,0xc9,0x49,0xc7,0x4e,0x87},
   {0x90,0xd8,0x3e,0xae,0x05,0xdd},{0x92,0xdb,0x37,0xa5,0x08,0xd3},
   {0x94,0xde,0x2c,0xb8,0x1f,0xc1},{0x96,0xdd,0x25,0xb3,0x12,0xcf},
   {0x98,0xd4,0x1a,0x82,0x31,0xe5},{0x9a,0xd7,0x13,0x89,0x3c,0xeb},
   {0x9c,0xd2,0x08,0x94,0x2b,0xf9},{0x9e,0xd1,0x01,0x9f,0x26,0xf7},
   {0xa0,0xf0,0xe6,0x46,0xbd,0x4d},{0xa2,0xf3,0xef,0x4d,0xb0,0x43},
   {0xa4,0xf6,0xf4,0x50,0xa7,0x51},{0xa6,0xf5,0xfd,0x5b,0xaa,0x5f},
   {0xa8,0xfc,0xc2,0x6a,0x89,0x75},{0xaa,0xff,0xcb,0x61,0x84,0x7b},
   {0xac,0xfa,0xd0,0x7c,0x93,0x69},{0xae,0xf9,0xd9,0x77,0x9e,0x67},
   {0xb0,0xe8,0xae,0x1e,0xd5,0x3d},{0xb2,0xeb,0xa7,0x15,0xd8,0x33},
   {0xb4,0xee,0xbc,0x08,0xcf,0x21},{0xb6,0xed,0xb5,0x03,0xc2,0x2f},
   {0xb8,0xe4,0x8a,0x32,0xe1,0x05},{0xba,0xe7,0x83,0x39,0xec,0x0b},
   {0xbc,0xe2,0x98,0x24,0xfb,0x19},{0xbe,0xe1,0x91,0x2f,0xf6,0x17},
   {0xc0,0xa0,0x4d,0x8d,0xd6,0x76},{0xc2,0xa3,0x44,0x86,0xdb,0x78},
   {0xc4,0xa6,0x5f,0x9b,0xcc,0x6a},{0xc6,0xa5,0x56,0x90,0xc1,0x64},
   {0xc8,0xac,0x69,0xa1,0xe2,0x4e},{0xca,0xaf,0x60,0xaa,0xef,0x40},
   {0xcc,0xaa,0x7b,0xb7,0xf8,0x52},{0xce,0xa9,0x72,0xbc,0xf5,0x5c},
   {0xd0,0xb8,0x05,0xd5,0xbe,0x06},{0xd2,0xbb,0x0c,0xde,0xb3,0x08},
   {0xd4,0xbe,0x17,0xc3,0xa4,0x1a},{0xd6,0xbd,0x1e,0xc8,0xa9,0x14},
   {0xd8,0xb4,0x21,0xf9,0x8a,0x3e},{0xda,0xb7,0x28,0xf2,0x87,0x30},
   {0xdc,0xb2,0x33,0xef,0x90,0x22},{0xde,0xb1,0x3a,0xe4,0x9d,0x2c},
   {0xe0,0x90,0xdd,0x3d,0x06,0x96},{0xe2,0x93,0xd4,0x36,0x0b,0x98},
   {0xe4,0x96,0xcf,0x2b,0x1c,0x8a},{0xe6,0x95,0xc6,0x20,0x11,0x84},
   {0xe8,0x9c,0xf9,0x11,0x32,0xae},{0xea,0x9f,0xf0,0x1a,0x3f,0xa0},
   {0xec,0x9a,0xeb,0x07,0x28,0xb2},{0xee,0x99,0xe2,0x0c,0x25,0xbc},
   {0xf0,0x88,0x95,0x65,0x6e,0xe6},{0xf2,0x8b,0x9c,0x6e,0x63,0xe8},
   {0xf4,0x8e,0x87,0x73,0x74,0xfa},{0xf6,0x8d,0x8e,0x78,0x79,0xf4},
   {0xf8,0x84,0xb1,0x49,0x5a,0xde},{0xfa,0x87,0xb8,0x42,0x57,0xd0},
   {0xfc,0x82,0xa3,0x5f,0x40,0xc2},{0xfe,0x81,0xaa,0x54,0x4d,0xcc},
   {0x1b,0x9b,0xec,0xf7,0xda,0x41},{0x19,0x98,0xe5,0xfc,0xd7,0x4f},
   {0x1f,0x9d,0xfe,0xe1,0xc0,0x5d},{0x1d,0x9e,0xf7,0xea,0xcd,0x53},
   {0x13,0x97,0xc8,0xdb,0xee,0x79},{0x11,0x94,0xc1,0xd0,0xe3,0x77},
   {0x17,0x91,0xda,0xcd,0xf4,0x65},{0x15,0x92,0xd3,0xc6,0xf9,0x6b},
   {0x0b,0x83,0xa4,0xaf,0xb2,0x31},{0x09,0x80,0xad,0xa4,0xbf,0x3f},
   {0x0f,0x85,0xb6,0xb9,0xa8,0x2d},{0x0d,0x86,0xbf,0xb2,0xa5,0x23},
   {0x03,0x8f,0x80,0x83,0x86,0x09},{0x01,0x8c,0x89,0x88,0x8b,0x07},
   {0x07,0x89,0x92,0x95,0x9c,0x15},{0x05,0x8a,0x9b,0x9e,0x91,0x1b},
   {0x3b,0xab,0x7c,0x47,0x0a,0xa1},{0x39,0xa8,0x75,0x4c,0x07,0xaf},
   {0x3f,0xad,0x6e,0x51,0x10,0xbd},{0x3d,0xae,0x67,0x5a,0x1d,0xb3},
   {0x33,0xa7,0x58,0x6b,0x3e,0x99},{0x31,0xa4,0x51,0x60,0x33,0x97},
   {0x37,0xa1,0x4a,0x7d,0x24,0x85},{0x35,0xa2,0x43,0x76,0x29,0x8b},
   {0x2b,0xb3,0x34,0x1f,0x62,0xd1},{0x29,0xb0,0x3d,0x14,0x6f,0xdf},
   {0x2f,0xb5,0x26,0x09,0x78,0xcd},{0x2d,0xb6,0x2f,0x02,0x75,0xc3},
   {0x23,0xbf,0x10,0x33,0x56,0xe9},{0x21,0xbc,0x19,0x38,0x5b,0xe7},
   {0x27,0xb9,0x02,0x25,0x4c,0xf5},{0x25,0xba,0x0b,0x2e,0x41,0xfb},
   {0x5b,0xfb,0xd7,0x8c,0x61,0x9a},{0x59,0xf8,0xde,0x87,0x6c,0x94},
   {0x5f,0xfd,0xc5,0x9a,0x7b,0x86},{0x5d,0xfe,0xcc,0x91,0x76,0x88},
   {0x53,0xf7,0xf3,0xa0,0x55,0xa2},{0x51,0xf4,0xfa,0xab,0x58,0xac},
   {0x57,0xf1,0xe1,0xb6,0x4f,0xbe},{0x55,0xf2,0xe8,0xbd,0x42,0xb0},
   {0x4b,0xe3,0x9f,0xd4,0x09,0xea},{0x49,0xe0,0x96,0xdf,0x04,0xe4},
   {0x4f,0xe5,0x8d,0xc2,0x13,0xf6},{0x4d,0xe6,0x84,0xc9,0x1e,0xf8},
   {0x43,0xef,0xbb,0xf8,0x3d,0xd2},{0x41,0xec,0xb2,0xf3,0x30,0xdc},
   {0x47,0xe9,0xa9,0xee,0x27,0xce},{0x45,0xea,0xa0,0xe5,0x2a,0xc0},
   {0x7b,0xcb,0x47,0x3c,0xb1,0x7a},{0x79,0xc8,0x4e,0x37,0xbc,0x74},
   {0x7f,0xcd,0x55,0x2a,0xab,0x66},{0x7d,0xce,0x5c,0x21,0xa6,0x68},
   {0x73,0xc7,0x63,0x10,0x85,0x42},{0x71,0xc4,0x6a,0x1b,0x88,0x4c},
   {0x77,0xc1,0x71,0x06,0x9f,0x5e},{0x75,0xc2,0x78,0x0d,0x92,0x50},
   {0x6b,0xd3,0x0f,0x64,0xd9,0x0a},{0x69,0xd0,0x06,0x6f,0xd4,0x04},
   {0x6f,0xd5,0x1d,0x72,0xc3,0x16},{0x6d,0xd6,0x14,0x79,0xce,0x18},
   {0x63,0xdf,0x2b,0x48,0xed,0x32},{0x61,0xdc,0x22,0x43,0xe0,0x3c},
   {0x67,0xd9,0x39,0x5e,0xf7,0x2e},{0x65,0xda,0x30,0x55,0xfa,0x20},
   {0x9b,0x5b,0x9a,0x01,0xb7,0xec},{0x99,0x58,0x93,0x0a,0xba,0xe2},
   {0x9f,0x5d,0x88,0x17,0xad,0xf0},{0x9d,0x5e,0x81,0x1c,0xa0,0xfe},
   {0x93,0x57,0xbe,0x2d,0x83,0xd4},{0x91,0x54,0xb7,0x26,0x8e,0xda},
   {0x97,0x51,0xac,0x3b,0x99,0xc8},{0x95,0x52,0xa5,0x30,0x94,0xc6},
   {0x8b,0x43,0xd2,0x59,0xdf,0x9c},{0x89,0x40,0xdb,0x52,0xd2,0x92},
   {0x8f,0x45,0xc0,0x4f,0xc5,0x80},{0x8d,0x46,0xc9,0x44,0xc8,0x8e},
   {0x83,0x4f,0xf6,0x75,0xeb,0xa4},{0x81,0x4c,0xff,0x7e,0xe6,0xaa},
   {0x87,0x49,0xe4,0x63,0xf1,0xb8},{0x85,0x4a,0xed,0x68,0xfc,0xb6},
   {0xbb,0x6b,0x0a,0xb1,0x67,0x0c},{0xb9,0x68,0x03,0xba,0x6a,0x02},
   {0xbf,0x6d,0x18,0xa7,0x7d,0x10},{0xbd,0x6e,0x11,0xac,0x70,0x1e},
   {0xb3,0x67,0x2e,0x9d,0x53,0x34},{0xb1,0x64,0x27,0x96,0x5e,0x3a},
   {0xb7,0x61,0x3c,0x8b,0x49,0x28},{0xb5,0x62,0x35,0x80,0x44,0x26},
   {0xab,0x73,0x42,0xe9,0x0f,0x7c},{0xa9,0x70,0x4b,0xe2,0x02,0x72},
   {0xaf,0x75,0x50,0xff,0x15,0x60},{0xad,0x76,0x59,0xf4,0x18,0x6e},
   {0xa3,0x7f,0x66,0xc5,0x3b,0x44},{0xa1,0x7c,0x6f,0xce,0x36,0x4a},
   {0xa7,0x79,0x74,0xd3,0x21,0x58},{0xa5,0x7a,0x7d,0xd8,0x2c,0x56},
   {0xdb,0x3b,0xa1,0x7a,0x0c,0x37},{0xd9,0x38,0xa8,0x71,0x01,0x39},
   {0xdf,0x3d,0xb3,0x6c,0x16,0x2b},{0xdd,0x3e,0xba,0x67,0x1b,0x25},
   {0xd3,0x37,0x85,0x56,0x38,0x0f},{0xd1,0x34,0x8c,0x5d,0x35,0x01},
   {0xd7,0x31,0x97,0x40,0x22,0x13},{0xd5,0x32,0x9e,0x4b,0x2f,0x1d},
   {0xcb,0x23,0xe9,0x22,0x64,0x47},{0xc9,0x20,0xe0,0x29,0x69,0x49},
   {0xcf,0x25,0xfb,0x34,0x7e,0x5b},{0xcd,0x26,0xf2,0x3f,0x73,0x55},
   {0xc3,0x2f,0xcd,0x0e,0x50,0x7f},{0xc1,0x2c,0xc4,0x05,0x5d,0x71},
   {0xc7,0x29,0xdf,0x18,0x4a,0x63},{0xc5,0x2a,0xd6,0x13,0x47,0x6d},
   {0xfb,0x0b,0x31,0xca,0xdc,0xd7},{0xf9,0x08,0x38,0xc1,0xd1,0xd9},
   {0xff,0x0d,0x23,0xdc,0xc6,0xcb},{0xfd,0x0e,0x2a,0xd7,0xcb,0xc5},
   {0xf3,0x07,0x15,0xe6,0xe8,0xef},{0xf1,0x04,0x1c,0xed,0xe5,0xe1},
   {0xf7,0x01,0x07,0xf0,0xf2,0xf3},{0xf5,0x02,0x0e,0xfb,0xff,0xfd},
   {0xeb,0x13,0x79,0x92,0xb4,0xa7},{0xe9,0x10,0x70,0x99,0xb9,0xa9},
   {0xef,0x15,0x6b,0x84,0xae,0xbb},{0xed,0x16,0x62,0x8f,0xa3,0xb5},
   {0xe3,0x1f,0x5d,0xbe,0x80,0x9f},{0xe1,0x1c,0x54,0xb5,0x8d,0x91},
   {0xe7,0x19,0x4f,0xa8,0x9a,0x83},{0xe5,0x1a,0x46,0xa3,0x97,0x8d}
};

/********************
** ADD ROUND KEY
********************/

// Performs the AddRoundKey step. Each round has its own pre-generated 16-byte key in the
// form of 4 integers (the "w" array). Each integer is XOR'd by one column of the state.
// Also performs the job of InvAddRoundKey(); since the function is a simple XOR process,
// it is its own inverse.
[COLOR=royalblue][B]__host__ __device__[/B] void AddRoundKey(uchar state[][4], uint w[])
{
   uchar subkey[4];
   // memcpy(subkey,&w[idx],4); // Not accurate for big endian machines
   // Subkey 1
   subkey[0] = w[0] >> 24;
   subkey[1] = w[0] >> 16;
   subkey[2] = w[0] >> 8;
   subkey[3] = w[0];
   state[0][0] ^= subkey[0];
   state[1][0] ^= subkey[1];
   state[2][0] ^= subkey[2];
   state[3][0] ^= subkey[3];
   // Subkey 2
   subkey[0] = w[1] >> 24;
   subkey[1] = w[1] >> 16;
   subkey[2] = w[1] >> 8;
   subkey[3] = w[1];
   state[0][1] ^= subkey[0];
   state[1][1] ^= subkey[1];
   state[2][1] ^= subkey[2];
   state[3][1] ^= subkey[3];
   // Subkey 3
   subkey[0] = w[2] >> 24;
   subkey[1] = w[2] >> 16;
   subkey[2] = w[2] >> 8;
   subkey[3] = w[2];
   state[0][2] ^= subkey[0];
   state[1][2] ^= subkey[1];
   state[2][2] ^= subkey[2];
   state[3][2] ^= subkey[3];
   // Subkey 4
   subkey[0] = w[3] >> 24;
   subkey[1] = w[3] >> 16;
   subkey[2] = w[3] >> 8;
   subkey[3] = w[3];
   state[0][3] ^= subkey[0];
   state[1][3] ^= subkey[1];
   state[2][3] ^= subkey[2];
   state[3][3] ^= subkey[3];
}

/********************
** (Inv)SubBytes
********************/

// Performs the SubBytes step. All bytes in the state are substituted with a
// pre-calculated value from a lookup table.
[COLOR=royalblue][B]__host__ __device__[/B] void SubBytes(uchar state[][4])
{
   state[0][0] = aes_sbox[state[0][0] >> 4][state[0][0] & 0x0F];
   state[0][1] = aes_sbox[state[0][1] >> 4][state[0][1] & 0x0F];
   state[0][2] = aes_sbox[state[0][2] >> 4][state[0][2] & 0x0F];
   state[0][3] = aes_sbox[state[0][3] >> 4][state[0][3] & 0x0F];
   state[1][0] = aes_sbox[state[1][0] >> 4][state[1][0] & 0x0F];
   state[1][1] = aes_sbox[state[1][1] >> 4][state[1][1] & 0x0F];
   state[1][2] = aes_sbox[state[1][2] >> 4][state[1][2] & 0x0F];
   state[1][3] = aes_sbox[state[1][3] >> 4][state[1][3] & 0x0F];
   state[2][0] = aes_sbox[state[2][0] >> 4][state[2][0] & 0x0F];
   state[2][1] = aes_sbox[state[2][1] >> 4][state[2][1] & 0x0F];
   state[2][2] = aes_sbox[state[2][2] >> 4][state[2][2] & 0x0F];
   state[2][3] = aes_sbox[state[2][3] >> 4][state[2][3] & 0x0F];
   state[3][0] = aes_sbox[state[3][0] >> 4][state[3][0] & 0x0F];
   state[3][1] = aes_sbox[state[3][1] >> 4][state[3][1] & 0x0F];
   state[3][2] = aes_sbox[state[3][2] >> 4][state[3][2] & 0x0F];
   state[3][3] = aes_sbox[state[3][3] >> 4][state[3][3] & 0x0F];
}

[COLOR=royalblue][B]__host__ __device__[/B] void InvSubBytes(uchar state[][4])
{
   state[0][0] = aes_invsbox[state[0][0] >> 4][state[0][0] & 0x0F];
   state[0][1] = aes_invsbox[state[0][1] >> 4][state[0][1] & 0x0F];
   state[0][2] = aes_invsbox[state[0][2] >> 4][state[0][2] & 0x0F];
   state[0][3] = aes_invsbox[state[0][3] >> 4][state[0][3] & 0x0F];
   state[1][0] = aes_invsbox[state[1][0] >> 4][state[1][0] & 0x0F];
   state[1][1] = aes_invsbox[state[1][1] >> 4][state[1][1] & 0x0F];
   state[1][2] = aes_invsbox[state[1][2] >> 4][state[1][2] & 0x0F];
   state[1][3] = aes_invsbox[state[1][3] >> 4][state[1][3] & 0x0F];
   state[2][0] = aes_invsbox[state[2][0] >> 4][state[2][0] & 0x0F];
   state[2][1] = aes_invsbox[state[2][1] >> 4][state[2][1] & 0x0F];
   state[2][2] = aes_invsbox[state[2][2] >> 4][state[2][2] & 0x0F];
   state[2][3] = aes_invsbox[state[2][3] >> 4][state[2][3] & 0x0F];
   state[3][0] = aes_invsbox[state[3][0] >> 4][state[3][0] & 0x0F];
   state[3][1] = aes_invsbox[state[3][1] >> 4][state[3][1] & 0x0F];
   state[3][2] = aes_invsbox[state[3][2] >> 4][state[3][2] & 0x0F];
   state[3][3] = aes_invsbox[state[3][3] >> 4][state[3][3] & 0x0F];
}

/********************
** (Inv)ShiftRows
********************/

// Performs the ShiftRows step. All rows are shifted cylindrically to the left.
[COLOR=royalblue][B]__host__ __device__[/B] void ShiftRows(uchar state[][4])
{
   int t;
   // Shift left by 1
   t = state[1][0];
   state[1][0] = state[1][1];
   state[1][1] = state[1][2];
   state[1][2] = state[1][3];
   state[1][3] = t;
   // Shift left by 2
   t = state[2][0];
   state[2][0] = state[2][2];
   state[2][2] = t;
   t = state[2][1];
   state[2][1] = state[2][3];
   state[2][3] = t;
   // Shift left by 3
   t = state[3][0];
   state[3][0] = state[3][3];
   state[3][3] = state[3][2];
   state[3][2] = state[3][1];
   state[3][1] = t;
}

// All rows are shifted cylindrically to the right.
[COLOR=royalblue][B]__host__ __device__[/B] void InvShiftRows(uchar state[][4])
{
   int t;
   // Shift right by 1
   t = state[1][3];
   state[1][3] = state[1][2];
   state[1][2] = state[1][1];
   state[1][1] = state[1][0];
   state[1][0] = t;
   // Shift right by 2
   t = state[2][3];
   state[2][3] = state[2][1];
   state[2][1] = t;
   t = state[2][2];
   state[2][2] = state[2][0];
   state[2][0] = t;
   // Shift right by 3
   t = state[3][3];
   state[3][3] = state[3][0];
   state[3][0] = state[3][1];
   state[3][1] = state[3][2];
   state[3][2] = t;
}

/********************
** (Inv)MixColumns
********************/

// Performs the MixColums step. The state is multiplied by itself using matrix
// multiplication in a Galios Field 2^8. All multiplication is pre-computed in a table.
// Addition is equivilent to XOR. (Must always make a copy of the column as the original
// values will be destoyed.)
[COLOR=royalblue][B]__host__ __device__[/B] void MixColumns(uchar state[][4])
{
   uchar col[4];
   // Column 1
   col[0] = state[0][0];
   col[1] = state[1][0];
   col[2] = state[2][0];
   col[3] = state[3][0];
   state[0][0] = gf_mul[col[0]][0];
   state[0][0] ^= gf_mul[col[1]][1];
   state[0][0] ^= col[2];
   state[0][0] ^= col[3];
   state[1][0] = col[0];
   state[1][0] ^= gf_mul[col[1]][0];
   state[1][0] ^= gf_mul[col[2]][1];
   state[1][0] ^= col[3];
   state[2][0] = col[0];
   state[2][0] ^= col[1];
   state[2][0] ^= gf_mul[col[2]][0];
   state[2][0] ^= gf_mul[col[3]][1];
   state[3][0] = gf_mul[col[0]][1];
   state[3][0] ^= col[1];
   state[3][0] ^= col[2];
   state[3][0] ^= gf_mul[col[3]][0];
   // Column 2
   col[0] = state[0][1];
   col[1] = state[1][1];
   col[2] = state[2][1];
   col[3] = state[3][1];
   state[0][1] = gf_mul[col[0]][0];
   state[0][1] ^= gf_mul[col[1]][1];
   state[0][1] ^= col[2];
   state[0][1] ^= col[3];
   state[1][1] = col[0];
   state[1][1] ^= gf_mul[col[1]][0];
   state[1][1] ^= gf_mul[col[2]][1];
   state[1][1] ^= col[3];
   state[2][1] = col[0];
   state[2][1] ^= col[1];
   state[2][1] ^= gf_mul[col[2]][0];
   state[2][1] ^= gf_mul[col[3]][1];
   state[3][1] = gf_mul[col[0]][1];
   state[3][1] ^= col[1];
   state[3][1] ^= col[2];
   state[3][1] ^= gf_mul[col[3]][0];
   // Column 3
   col[0] = state[0][2];
   col[1] = state[1][2];
   col[2] = state[2][2];
   col[3] = state[3][2];
   state[0][2] = gf_mul[col[0]][0];
   state[0][2] ^= gf_mul[col[1]][1];
   state[0][2] ^= col[2];
   state[0][2] ^= col[3];
   state[1][2] = col[0];
   state[1][2] ^= gf_mul[col[1]][0];
   state[1][2] ^= gf_mul[col[2]][1];
   state[1][2] ^= col[3];
   state[2][2] = col[0];
   state[2][2] ^= col[1];
   state[2][2] ^= gf_mul[col[2]][0];
   state[2][2] ^= gf_mul[col[3]][1];
   state[3][2] = gf_mul[col[0]][1];
   state[3][2] ^= col[1];
   state[3][2] ^= col[2];
   state[3][2] ^= gf_mul[col[3]][0];
   // Column 4
   col[0] = state[0][3];
   col[1] = state[1][3];
   col[2] = state[2][3];
   col[3] = state[3][3];
   state[0][3] = gf_mul[col[0]][0];
   state[0][3] ^= gf_mul[col[1]][1];
   state[0][3] ^= col[2];
   state[0][3] ^= col[3];
   state[1][3] = col[0];
   state[1][3] ^= gf_mul[col[1]][0];
   state[1][3] ^= gf_mul[col[2]][1];
   state[1][3] ^= col[3];
   state[2][3] = col[0];
   state[2][3] ^= col[1];
   state[2][3] ^= gf_mul[col[2]][0];
   state[2][3] ^= gf_mul[col[3]][1];
   state[3][3] = gf_mul[col[0]][1];
   state[3][3] ^= col[1];
   state[3][3] ^= col[2];
   state[3][3] ^= gf_mul[col[3]][0];
}

[COLOR=royalblue][B]__host__ __device__[/B] void InvMixColumns(uchar state[][4])
{
   int idx;
   uchar col[4],t;
   // Column 1
   col[0] = state[0][0];
   col[1] = state[1][0];
   col[2] = state[2][0];
   col[3] = state[3][0];
   state[0][0] = gf_mul[col[0]][5];
   state[0][0] ^= gf_mul[col[1]][3];
   state[0][0] ^= gf_mul[col[2]][4];
   state[0][0] ^= gf_mul[col[3]][2];
   state[1][0] = gf_mul[col[0]][2];
   state[1][0] ^= gf_mul[col[1]][5];
   state[1][0] ^= gf_mul[col[2]][3];
   state[1][0] ^= gf_mul[col[3]][4];
   state[2][0] = gf_mul[col[0]][4];
   state[2][0] ^= gf_mul[col[1]][2];
   state[2][0] ^= gf_mul[col[2]][5];
   state[2][0] ^= gf_mul[col[3]][3];
   state[3][0] = gf_mul[col[0]][3];
   state[3][0] ^= gf_mul[col[1]][4];
   state[3][0] ^= gf_mul[col[2]][2];
   state[3][0] ^= gf_mul[col[3]][5];
   // Column 2
   col[0] = state[0][1];
   col[1] = state[1][1];
   col[2] = state[2][1];
   col[3] = state[3][1];
   state[0][1] = gf_mul[col[0]][5];
   state[0][1] ^= gf_mul[col[1]][3];
   state[0][1] ^= gf_mul[col[2]][4];
   state[0][1] ^= gf_mul[col[3]][2];
   state[1][1] = gf_mul[col[0]][2];
   state[1][1] ^= gf_mul[col[1]][5];
   state[1][1] ^= gf_mul[col[2]][3];
   state[1][1] ^= gf_mul[col[3]][4];
   state[2][1] = gf_mul[col[0]][4];
   state[2][1] ^= gf_mul[col[1]][2];
   state[2][1] ^= gf_mul[col[2]][5];
   state[2][1] ^= gf_mul[col[3]][3];
   state[3][1] = gf_mul[col[0]][3];
   state[3][1] ^= gf_mul[col[1]][4];
   state[3][1] ^= gf_mul[col[2]][2];
   state[3][1] ^= gf_mul[col[3]][5];
   // Column 3
   col[0] = state[0][2];
   col[1] = state[1][2];
   col[2] = state[2][2];
   col[3] = state[3][2];
   state[0][2] = gf_mul[col[0]][5];
   state[0][2] ^= gf_mul[col[1]][3];
   state[0][2] ^= gf_mul[col[2]][4];
   state[0][2] ^= gf_mul[col[3]][2];
   state[1][2] = gf_mul[col[0]][2];
   state[1][2] ^= gf_mul[col[1]][5];
   state[1][2] ^= gf_mul[col[2]][3];
   state[1][2] ^= gf_mul[col[3]][4];
   state[2][2] = gf_mul[col[0]][4];
   state[2][2] ^= gf_mul[col[1]][2];
   state[2][2] ^= gf_mul[col[2]][5];
   state[2][2] ^= gf_mul[col[3]][3];
   state[3][2] = gf_mul[col[0]][3];
   state[3][2] ^= gf_mul[col[1]][4];
   state[3][2] ^= gf_mul[col[2]][2];
   state[3][2] ^= gf_mul[col[3]][5];
   // Column 4
   col[0] = state[0][3];
   col[1] = state[1][3];
   col[2] = state[2][3];
   col[3] = state[3][3];
   state[0][3] = gf_mul[col[0]][5];
   state[0][3] ^= gf_mul[col[1]][3];
   state[0][3] ^= gf_mul[col[2]][4];
   state[0][3] ^= gf_mul[col[3]][2];
   state[1][3] = gf_mul[col[0]][2];
   state[1][3] ^= gf_mul[col[1]][5];
   state[1][3] ^= gf_mul[col[2]][3];
   state[1][3] ^= gf_mul[col[3]][4];
   state[2][3] = gf_mul[col[0]][4];
   state[2][3] ^= gf_mul[col[1]][2];
   state[2][3] ^= gf_mul[col[2]][5];
   state[2][3] ^= gf_mul[col[3]][3];
   state[3][3] = gf_mul[col[0]][3];
   state[3][3] ^= gf_mul[col[1]][4];
   state[3][3] ^= gf_mul[col[2]][2];
   state[3][3] ^= gf_mul[col[3]][5];
}

/********************
** DEBUGGING FUNCTIONS
********************/

// This prints the "state" grid as a linear hex string
void printstate(uchar state[][4])
{
   int idx,idx2;
   for (idx=0; idx < 4; idx++)
      for (idx2=0; idx2 < 4; idx2++)
         printf("%02x",state[idx2][idx]);
   puts("");
}

// This prints the key (4 consecutive ints) used for a given round as a linear hex string.
void print_rnd_key(uint key[])
{
   int idx;
   for (idx=0; idx < 4; idx++)
      printf("%08x",key[idx]);
   puts("");
}

/********************
** KEY EXPANSION
********************/

// Performs the SubWord substitution for KeyExpansion. Each byte in the supplied integer
// is looked up in the substitution box and replaced by its corresponding value.
uint SubWord(uint word)
{
   unsigned int result;

   result = (int)aes_sbox[(word >> 4) & 0x0000000F][word & 0x0000000F];
   result += (int)aes_sbox[(word >> 12) & 0x0000000F][(word >> 8) & 0x0000000F] << 8;
   result += (int)aes_sbox[(word >> 20) & 0x0000000F][(word >> 16) & 0x0000000F] << 16;
   result += (int)aes_sbox[(word >> 28) & 0x0000000F][(word >> 24) & 0x0000000F] << 24;
   return(result);
}

// Performs the RotWord function for KeyExpansion. The first byte in the integer is rotated
// to the end.
#define KE_ROTWORD(x) ( ((x) << 8) | ((x) >> 24) )

// Performs the action of generating the keys that will be used in every round of
// encryption. "key" is the user-supplied input key, "w" is the output key schedule,
// "keysize" is the length in bits of "key", must be 128, 192, or 256.
void KeyExpansion(uchar key[], uint w[], int keysize)
{
   int Nb=4,Nr,Nk,idx;
   uint temp,Rcon[]={0x01000000,0x02000000,0x04000000,0x08000000,0x10000000,0x20000000,
                     0x40000000,0x80000000,0x1b000000,0x36000000,0x6c000000,0xd8000000,
                     0xab000000,0x4d000000,0x9a000000};
   switch (keysize) {
      case 128: Nr = 10; Nk = 4; break;
      case 192: Nr = 12; Nk = 6; break;
      case 256: Nr = 14; Nk = 8; break;
      default: return;
   }

   for (idx=0; idx < Nk; ++idx) {
      w[idx] = ((key[4 * idx]) << 24) | ((key[4 * idx + 1]) << 16) |
               ((key[4 * idx + 2]) << 8) | ((key[4 * idx + 3]));
   }

   for (idx = Nk; idx < Nb * (Nr+1); ++idx) {
      temp = w[idx - 1];
      if ((idx % Nk) == 0)
         temp = SubWord(KE_ROTWORD(temp)) ^ Rcon[(idx-1)/Nk];
      else if (Nk > 6 && (idx % Nk) == 4)
         temp = SubWord(temp);
      w[idx] = w[idx-Nk] ^ temp;
   }
}

/********************
** AES (En/De)Crypt
********************/

// "in" is the block of 16 sequencial bytes that is to be encrypted. "out" is the encrypted
// sequencial output. "key" is an array consisting of the KEY value that was generated
// using KeySchedule() previously. "keysize" MUST be 128, 192, 256 in size.
[COLOR=royalblue][B]__device__[/B] void aes_encrypt(uchar in[], uchar out[], uint key[], int keysize)
{
   uchar state[4][4];
   // Copy input array (should be 16 bytes long) to a matrix (sequential bytes are ordered
   // by row, not col) called "state" for processing.
   // *** Implementation note: The official AES documentation references the state by
   // column, then row. Accessing an element in C requires row then column. Thus, all state
   // references in AES must have the column and row indexes reversed for C implementation.
   state[0][0] = in[0];
   state[1][0] = in[1];
   state[2][0] = in[2];
   state[3][0] = in[3];
   state[0][1] = in[4];
   state[1][1] = in[5];
   state[2][1] = in[6];
   state[3][1] = in[7];
   state[0][2] = in[8];
   state[1][2] = in[9];
   state[2][2] = in[10];
   state[3][2] = in[11];
   state[0][3] = in[12];
   state[1][3] = in[13];
   state[2][3] = in[14];
   state[3][3] = in[15];

   // Perform the necessary number of rounds. The round key is added first.
   // The last round does not perform the MixColumns step.
   AddRoundKey(state,&key[0]);
   SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[4]);
   SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[8]);
   SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[12]);
   SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[16]);
   SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[20]);
   SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[24]);
   SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[28]);
   SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[32]);
   SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[36]);
   if (keysize != 128) {
      SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[40]);
      SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[44]);
      if (keysize != 192) {
         SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[48]);
         SubBytes(state); ShiftRows(state); MixColumns(state); AddRoundKey(state,&key[52]);
         SubBytes(state); ShiftRows(state); AddRoundKey(state,&key[56]);
      }
      else {
         SubBytes(state); ShiftRows(state); AddRoundKey(state,&key[48]);
      }
   }
   else {
      SubBytes(state); ShiftRows(state); AddRoundKey(state,&key[40]);
   }

   // Copy the state to the output array
   out[0] = state[0][0];
   out[1] = state[1][0];
   out[2] = state[2][0];
   out[3] = state[3][0];
   out[4] = state[0][1];
   out[5] = state[1][1];
   out[6] = state[2][1];
   out[7] = state[3][1];
   out[8] = state[0][2];
   out[9] = state[1][2];
   out[10] = state[2][2];
   out[11] = state[3][2];
   out[12] = state[0][3];
   out[13] = state[1][3];
   out[14] = state[2][3];
   out[15] = state[3][3];
}

[COLOR=royalblue][B]__device__[/B] void aes_decrypt(uchar in[], uchar out[], uint key[], int keysize)
{
   uchar state[4][4];
   // Copy the input to the state.
   state[0][0] = in[0];
   state[1][0] = in[1];
   state[2][0] = in[2];
   state[3][0] = in[3];
   state[0][1] = in[4];
   state[1][1] = in[5];
   state[2][1] = in[6];
   state[3][1] = in[7];
   state[0][2] = in[8];
   state[1][2] = in[9];
   state[2][2] = in[10];
   state[3][2] = in[11];
   state[0][3] = in[12];
   state[1][3] = in[13];
   state[2][3] = in[14];
   state[3][3] = in[15];

   // Perform the necessary number of rounds. The round key is added first.
   // The last round does not perform the MixColumns step.
   if (keysize > 128) {
      if (keysize > 192) {
         AddRoundKey(state,&key[56]);
         InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[52]);InvMixColumns(state);
         InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[48]);InvMixColumns(state);
      }
      else {
         AddRoundKey(state,&key[48]);
      }
      InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[44]);InvMixColumns(state);
      InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[40]);InvMixColumns(state);
   }
   else {
      AddRoundKey(state,&key[40]);
   }
   InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[36]);InvMixColumns(state);
   InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[32]);InvMixColumns(state);
   InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[28]);InvMixColumns(state);
   InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[24]);InvMixColumns(state);
   InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[20]);InvMixColumns(state);
   InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[16]);InvMixColumns(state);
   InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[12]);InvMixColumns(state);
   InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[8]);InvMixColumns(state);
   InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[4]);InvMixColumns(state);
   InvShiftRows(state);InvSubBytes(state);AddRoundKey(state,&key[0]);

   // Copy the state to the output array
   out[0] = state[0][0];
   out[1] = state[1][0];
   out[2] = state[2][0];
   out[3] = state[3][0];
   out[4] = state[0][1];
   out[5] = state[1][1];
   out[6] = state[2][1];
   out[7] = state[3][1];
   out[8] = state[0][2];
   out[9] = state[1][2];
   out[10] = state[2][2];
   out[11] = state[3][2];
   out[12] = state[0][3];
   out[13] = state[1][3];
   out[14] = state[2][3];
   out[15] = state[3][3];
}

[COLOR=royalblue][B]__global__ void aes_enc(uchar in[], uchar out[], uint key[], int keysize) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    aes_encrypt(in + 16*b, out + 16*b, key, keysize);
}

__global__ void aes_dec(uchar in[], uchar out[], uint key[], int keysize) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    aes_decrypt(in + 16*b, out + 16*b, key, keysize);
}

inline void HandleErrorImpl(cudaError error, const char* file, int line) {
    if (error != cudaSuccess) {
        printf("%s: %d %s", file, line, cudaGetErrorString(error));
        exit(1);
    }
}

int main(void) {
    char *key = "meingeheimespasswort";
    int threads = 256;
    int blocks = 25600;
    int keysize = strlen(key);

    uchar *in;
    HandleError(cudaMalloc(&in, 16*threads*blocks));
    HandleError(cudaMemset(in, 0, 16*threads*blocks));

    uchar *out;
    HandleError(cudaMalloc(&out, 16*threads*blocks));

    char *test1 = (char*)malloc(16*threads*blocks);
    HandleError(cudaMemcpy(test1, in, 16*threads*blocks, cudaMemcpyDeviceToHost));

    printf("First 16 bytes of input data: ");
    for (int i=0; i<16; i++) {
        printf("%d, ", test1[i]);
    }

    cudaEvent_t start, stop;
    HandleError(cudaEventCreate(&start));
    HandleError(cudaEventCreate(&stop));
    HandleError(cudaEventRecord( start, 0 ));

    aes_enc<<<blocks,threads>>>(in, out, (uint*)key, keysize);
    aes_dec<<<blocks,threads>>>(out, in, (uint*)key, keysize);

    HandleError(cudaGetLastError());

    HandleError(cudaEventRecord( stop, 0 ));
    HandleError(cudaEventSynchronize( stop ));
    float elapsedTime;
    HandleError(cudaEventElapsedTime( &elapsedTime, start, stop ));

    printf("\nPerformance: %.6f MB/sec\n", 2*((16*threads*blocks)/1048576)/(elapsedTime/1000));

    HandleError(cudaEventDestroy( start ));
    HandleError(cudaEventDestroy( stop ));

    char *test2 = (char*)malloc(16*threads*blocks);
    HandleError(cudaMemcpy(test2, out, 16*threads*blocks, cudaMemcpyDeviceToHost));

    printf("After decryption: ");
    for (int i=0; i<16; i++) {
        printf("%d, ", test2[i]);
    }

    free(test1);
    free(test2);

    HandleError(cudaFree(in));
    HandleError(cudaFree(out));

    return 0;
}[/B]
```
^^ Stimmen meine ganzen eingefügten __host__ __device__? Ich musste die alle einfügen, damit der Code überhaupt ohne Errors startet, aber mir kommt das dennoch leicht komisch vor.

Jetzt müsste ich nur noch bei Twofish und AES die launch failure wegkriegen. Läuft AES, so wie er hier ist, auf deiner GTX 560 Ti?


----------



## boss3D (5. Januar 2014)

*MARS*

Habe jetzt zu guter letzt auch noch einen MARS C Code nach CUDA portiert, ganz nach unserem Schema:

```
/* This is an independent implementation of the encryption algorithm:   */

/*                                                                      */

/*         MARS by a team at IBM,                                        */

/*                                                                      */

/* which is a candidate algorithm in the Advanced Encryption Standard   */

/* programme of the US National Institute of Standards and Technology.  */

/* Copyright in this implementation is held by Dr B R Gladman. The MARS */

/* algorithm is covered by a pending patent application owned by IBM,   */

/* who intend to offer a royalty free license under any issued patent   */

/* that results from such application if MARS is selected as the AES    */

/* algorithm.  In the interim, you may evaluate the MARS algorithm for  */

/* your personal, lawful, non-profit purposes as an end user.           */

/*                                                                      */

/* The header above modified on June 6th 1999.                          */

/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */



/* Timing data for MARS (mars.c)



128 bit key:

Key Setup:    4316 cycles

Encrypt:       369 cycles =    69.4 mbits/sec

Decrypt:       376 cycles =    68.1 mbits/sec

Mean:          373 cycles =    68.7 mbits/sec



192 bit key:

Key Setup:    4377 cycles

Encrypt:       373 cycles =    68.6 mbits/sec

Decrypt:       379 cycles =    67.5 mbits/sec

Mean:          376 cycles =    68.1 mbits/sec



256 bit key:

Key Setup:    4340 cycles

Encrypt:       369 cycles =    69.4 mbits/sec

Decrypt:       376 cycles =    68.1 mbits/sec

Mean:          373 cycles =    68.7 mbits/sec



*/



#include "std_defs.h"
[COLOR=royalblue][B]#include <stdio.h>[/B]


static char *alg_name[] = { "mars", "mars.c", "mars" };



char **cipher_name()

{

    return alg_name;

}


[COLOR=royalblue][B]
__device__[/B] static u4byte s_box[] =

{

    0x09d0c479, 0x28c8ffe0, 0x84aa6c39, 0x9dad7287, /* 0x000    */

    0x7dff9be3, 0xd4268361, 0xc96da1d4, 0x7974cc93,

    0x85d0582e, 0x2a4b5705, 0x1ca16a62, 0xc3bd279d,

    0x0f1f25e5, 0x5160372f, 0xc695c1fb, 0x4d7ff1e4,

    0xae5f6bf4, 0x0d72ee46, 0xff23de8a, 0xb1cf8e83, /* 0x010    */

    0xf14902e2, 0x3e981e42, 0x8bf53eb6, 0x7f4bf8ac,

    0x83631f83, 0x25970205, 0x76afe784, 0x3a7931d4,

    0x4f846450, 0x5c64c3f6, 0x210a5f18, 0xc6986a26,

    0x28f4e826, 0x3a60a81c, 0xd340a664, 0x7ea820c4, /* 0x020    */

    0x526687c5, 0x7eddd12b, 0x32a11d1d, 0x9c9ef086,

    0x80f6e831, 0xab6f04ad, 0x56fb9b53, 0x8b2e095c,

    0xb68556ae, 0xd2250b0d, 0x294a7721, 0xe21fb253,

    0xae136749, 0xe82aae86, 0x93365104, 0x99404a66, /* 0x030    */

    0x78a784dc, 0xb69ba84b, 0x04046793, 0x23db5c1e,

    0x46cae1d6, 0x2fe28134, 0x5a223942, 0x1863cd5b,

    0xc190c6e3, 0x07dfb846, 0x6eb88816, 0x2d0dcc4a,

    0xa4ccae59, 0x3798670d, 0xcbfa9493, 0x4f481d45, /* 0x040    */

    0xeafc8ca8, 0xdb1129d6, 0xb0449e20, 0x0f5407fb,

    0x6167d9a8, 0xd1f45763, 0x4daa96c3, 0x3bec5958,

    0xababa014, 0xb6ccd201, 0x38d6279f, 0x02682215,

    0x8f376cd5, 0x092c237e, 0xbfc56593, 0x32889d2c, /* 0x050    */

    0x854b3e95, 0x05bb9b43, 0x7dcd5dcd, 0xa02e926c,

    0xfae527e5, 0x36a1c330, 0x3412e1ae, 0xf257f462,

    0x3c4f1d71, 0x30a2e809, 0x68e5f551, 0x9c61ba44,

    0x5ded0ab8, 0x75ce09c8, 0x9654f93e, 0x698c0cca, /* 0x060    */

    0x243cb3e4, 0x2b062b97, 0x0f3b8d9e, 0x00e050df,

    0xfc5d6166, 0xe35f9288, 0xc079550d, 0x0591aee8,

    0x8e531e74, 0x75fe3578, 0x2f6d829a, 0xf60b21ae,

    0x95e8eb8d, 0x6699486b, 0x901d7d9b, 0xfd6d6e31, /* 0x070    */

    0x1090acef, 0xe0670dd8, 0xdab2e692, 0xcd6d4365,

    0xe5393514, 0x3af345f0, 0x6241fc4d, 0x460da3a3,

    0x7bcf3729, 0x8bf1d1e0, 0x14aac070, 0x1587ed55,

    0x3afd7d3e, 0xd2f29e01, 0x29a9d1f6, 0xefb10c53, /* 0x080    */

    0xcf3b870f, 0xb414935c, 0x664465ed, 0x024acac7,

    0x59a744c1, 0x1d2936a7, 0xdc580aa6, 0xcf574ca8,

    0x040a7a10, 0x6cd81807, 0x8a98be4c, 0xaccea063,

    0xc33e92b5, 0xd1e0e03d, 0xb322517e, 0x2092bd13, /* 0x090    */

    0x386b2c4a, 0x52e8dd58, 0x58656dfb, 0x50820371,

    0x41811896, 0xe337ef7e, 0xd39fb119, 0xc97f0df6,

    0x68fea01b, 0xa150a6e5, 0x55258962, 0xeb6ff41b,

    0xd7c9cd7a, 0xa619cd9e, 0xbcf09576, 0x2672c073, /* 0x0a0    */

    0xf003fb3c, 0x4ab7a50b, 0x1484126a, 0x487ba9b1,

    0xa64fc9c6, 0xf6957d49, 0x38b06a75, 0xdd805fcd,

    0x63d094cf, 0xf51c999e, 0x1aa4d343, 0xb8495294,

    0xce9f8e99, 0xbffcd770, 0xc7c275cc, 0x378453a7, /* 0x0b0    */

    0x7b21be33, 0x397f41bd, 0x4e94d131, 0x92cc1f98,

    0x5915ea51, 0x99f861b7, 0xc9980a88, 0x1d74fd5f,

    0xb0a495f8, 0x614deed0, 0xb5778eea, 0x5941792d,

    0xfa90c1f8, 0x33f824b4, 0xc4965372, 0x3ff6d550, /* 0x0c0    */

    0x4ca5fec0, 0x8630e964, 0x5b3fbbd6, 0x7da26a48,

    0xb203231a, 0x04297514, 0x2d639306, 0x2eb13149,

    0x16a45272, 0x532459a0, 0x8e5f4872, 0xf966c7d9,

    0x07128dc0, 0x0d44db62, 0xafc8d52d, 0x06316131, /* 0x0d0    */

    0xd838e7ce, 0x1bc41d00, 0x3a2e8c0f, 0xea83837e,

    0xb984737d, 0x13ba4891, 0xc4f8b949, 0xa6d6acb3,

    0xa215cdce, 0x8359838b, 0x6bd1aa31, 0xf579dd52,

    0x21b93f93, 0xf5176781, 0x187dfdde, 0xe94aeb76, /* 0x0e0    */

    0x2b38fd54, 0x431de1da, 0xab394825, 0x9ad3048f,

    0xdfea32aa, 0x659473e3, 0x623f7863, 0xf3346c59,

    0xab3ab685, 0x3346a90b, 0x6b56443e, 0xc6de01f8,

    0x8d421fc0, 0x9b0ed10c, 0x88f1a1e9, 0x54c1f029, /* 0x0f0    */

    0x7dead57b, 0x8d7ba426, 0x4cf5178a, 0x551a7cca,

    0x1a9a5f08, 0xfcd651b9, 0x25605182, 0xe11fc6c3,

    0xb6fd9676, 0x337b3027, 0xb7c8eb14, 0x9e5fd030,



    0x6b57e354, 0xad913cf7, 0x7e16688d, 0x58872a69, /* 0x100    */

    0x2c2fc7df, 0xe389ccc6, 0x30738df1, 0x0824a734,

    0xe1797a8b, 0xa4a8d57b, 0x5b5d193b, 0xc8a8309b,

    0x73f9a978, 0x73398d32, 0x0f59573e, 0xe9df2b03,

    0xe8a5b6c8, 0x848d0704, 0x98df93c2, 0x720a1dc3, /* 0x110    */

    0x684f259a, 0x943ba848, 0xa6370152, 0x863b5ea3,

    0xd17b978b, 0x6d9b58ef, 0x0a700dd4, 0xa73d36bf,

    0x8e6a0829, 0x8695bc14, 0xe35b3447, 0x933ac568,

    0x8894b022, 0x2f511c27, 0xddfbcc3c, 0x006662b6, /* 0x120    */

    0x117c83fe, 0x4e12b414, 0xc2bca766, 0x3a2fec10,

    0xf4562420, 0x55792e2a, 0x46f5d857, 0xceda25ce,

    0xc3601d3b, 0x6c00ab46, 0xefac9c28, 0xb3c35047,

    0x611dfee3, 0x257c3207, 0xfdd58482, 0x3b14d84f, /* 0x130    */

    0x23becb64, 0xa075f3a3, 0x088f8ead, 0x07adf158,

    0x7796943c, 0xfacabf3d, 0xc09730cd, 0xf7679969,

    0xda44e9ed, 0x2c854c12, 0x35935fa3, 0x2f057d9f,

    0x690624f8, 0x1cb0bafd, 0x7b0dbdc6, 0x810f23bb, /* 0x140    */

    0xfa929a1a, 0x6d969a17, 0x6742979b, 0x74ac7d05,

    0x010e65c4, 0x86a3d963, 0xf907b5a0, 0xd0042bd3,

    0x158d7d03, 0x287a8255, 0xbba8366f, 0x096edc33,

    0x21916a7b, 0x77b56b86, 0x951622f9, 0xa6c5e650, /* 0x150    */

    0x8cea17d1, 0xcd8c62bc, 0xa3d63433, 0x358a68fd,

    0x0f9b9d3c, 0xd6aa295b, 0xfe33384a, 0xc000738e,

    0xcd67eb2f, 0xe2eb6dc2, 0x97338b02, 0x06c9f246,

    0x419cf1ad, 0x2b83c045, 0x3723f18a, 0xcb5b3089, /* 0x160    */

    0x160bead7, 0x5d494656, 0x35f8a74b, 0x1e4e6c9e,

    0x000399bd, 0x67466880, 0xb4174831, 0xacf423b2,

    0xca815ab3, 0x5a6395e7, 0x302a67c5, 0x8bdb446b,

    0x108f8fa4, 0x10223eda, 0x92b8b48b, 0x7f38d0ee, /* 0x170    */

    0xab2701d4, 0x0262d415, 0xaf224a30, 0xb3d88aba,

    0xf8b2c3af, 0xdaf7ef70, 0xcc97d3b7, 0xe9614b6c,

    0x2baebff4, 0x70f687cf, 0x386c9156, 0xce092ee5,

    0x01e87da6, 0x6ce91e6a, 0xbb7bcc84, 0xc7922c20, /* 0x180    */

    0x9d3b71fd, 0x060e41c6, 0xd7590f15, 0x4e03bb47,

    0x183c198e, 0x63eeb240, 0x2ddbf49a, 0x6d5cba54,

    0x923750af, 0xf9e14236, 0x7838162b, 0x59726c72,

    0x81b66760, 0xbb2926c1, 0x48a0ce0d, 0xa6c0496d, /* 0x190    */

    0xad43507b, 0x718d496a, 0x9df057af, 0x44b1bde6,

    0x054356dc, 0xde7ced35, 0xd51a138b, 0x62088cc9,

    0x35830311, 0xc96efca2, 0x686f86ec, 0x8e77cb68,

    0x63e1d6b8, 0xc80f9778, 0x79c491fd, 0x1b4c67f2, /* 0x1a0    */

    0x72698d7d, 0x5e368c31, 0xf7d95e2e, 0xa1d3493f,

    0xdcd9433e, 0x896f1552, 0x4bc4ca7a, 0xa6d1baf4,

    0xa5a96dcc, 0x0bef8b46, 0xa169fda7, 0x74df40b7,

    0x4e208804, 0x9a756607, 0x038e87c8, 0x20211e44, /* 0x1b0    */

    0x8b7ad4bf, 0xc6403f35, 0x1848e36d, 0x80bdb038,

    0x1e62891c, 0x643d2107, 0xbf04d6f8, 0x21092c8c,

    0xf644f389, 0x0778404e, 0x7b78adb8, 0xa2c52d53,

    0x42157abe, 0xa2253e2e, 0x7bf3f4ae, 0x80f594f9, /* 0x1c0    */

    0x953194e7, 0x77eb92ed, 0xb3816930, 0xda8d9336,

    0xbf447469, 0xf26d9483, 0xee6faed5, 0x71371235,

    0xde425f73, 0xb4e59f43, 0x7dbe2d4e, 0x2d37b185,

    0x49dc9a63, 0x98c39d98, 0x1301c9a2, 0x389b1bbf, /* 0x1d0    */

    0x0c18588d, 0xa421c1ba, 0x7aa3865c, 0x71e08558,

    0x3c5cfcaa, 0x7d239ca4, 0x0297d9dd, 0xd7dc2830,

    0x4b37802b, 0x7428ab54, 0xaeee0347, 0x4b3fbb85,

    0x692f2f08, 0x134e578e, 0x36d9e0bf, 0xae8b5fcf, /* 0x1e0    */

    0xedb93ecf, 0x2b27248e, 0x170eb1ef, 0x7dc57fd6,

    0x1e760f16, 0xb1136601, 0x864e1b9b, 0xd7ea7319,

    0x3ab871bd, 0xcfa4d76f, 0xe31bd782, 0x0dbeb469,

    0xabb96061, 0x5370f85d, 0xffb07e37, 0xda30d0fb, /* 0x1f0    */

    0xebc977b6, 0x0b98b40f, 0x3a4d0fe6, 0xdf4fc26b,

    0x159cf22a, 0xc298d6e2, 0x2b78ef6a, 0x61a94ac0,

    0xab561187, 0x14eea0f0, 0xdf0d4164, 0x19af70ee

};



static u4byte vk[47] =

{

    0x09d0c479, 0x28c8ffe0, 0x84aa6c39, 0x9dad7287, 0x7dff9be3, 0xd4268361,

    0xc96da1d4

};



[COLOR=royalblue][B]__device__[/B] static u4byte   l_key[40];
[COLOR=royalblue][B]
#define HandleError(x) HandleErrorImpl(x, __FILE__, __LINE__)[/B]
#define f_mix(a,b,c,d)                  \
        r = rotr(a, 8);                 \
        b ^= s_box[a & 255];            \
        b += s_box[(r & 255) + 256];    \
        r = rotr(a, 16);                \
        a  = rotr(a, 24);               \
        c += s_box[r & 255];            \
        d ^= s_box[(a & 255) + 256];



#define b_mix(a,b,c,d)                  \
        r = rotl(a, 8);                 \
        b ^= s_box[(a & 255) + 256];    \
        c -= s_box[r & 255];            \
        r = rotl(a, 16);                \
        a  = rotl(a, 24);               \
        d -= s_box[(r & 255) + 256];    \
        d ^= s_box[a & 255];



#define f_ktr(a,b,c,d,i)    \
    m = a + l_key[i];       \
    a = rotl(a, 13);        \
    r = a * l_key[i + 1];   \
    l = s_box[m & 511];     \
    r = rotl(r, 5);         \
    c += rotl(m, r);        \
    l ^= r;                 \
    r = rotl(r, 5);         \
    l ^= r;                 \
    d ^= r;                 \
    b += rotl(l, r);



#define r_ktr(a,b,c,d,i)    \
    r = a * l_key[i + 1];   \
    a = rotr(a, 13);        \
    m = a + l_key[i];       \
    l = s_box[m & 511];     \
    r = rotl(r, 5);         \
    l ^= r;                 \
    c -= rotl(m, r);        \
    r = rotl(r, 5);         \
    l ^= r;                 \
    d ^= r;                 \
    b -= rotl(l, r);



/* For a 32 bit word (x) generate a mask (m) such that a bit in */

/* m is set to 1 if and only if the corresponding bit in x is:  */

/*                                                              */

/* 1. in a sequence of 10 or more adjacent '0' bits             */

/* 2. in a sequence of 10 or more adjacent '1' bits             */

/* 3. but is not either endpoint of such a sequence unless such */

/*    an endpoint is at the top bit (bit 31) of a word and is   */

/*    in a sequence of '0' bits.                                */

/*                                                              */

/* The only situation in which a sequence endpoint is included  */

/* in the mask is hence when the endpoint is at bit 31 and is   */

/* the endpoint of a sequence of '0' bits. My thanks go to Shai */

/* Halevi of IBM for the neat trick (which I missed) of finding */

/* the '0' and '1' sequences at the same time.                  */



u4byte gen_mask(u4byte x)

{   u4byte  m;



    /* if m{bn} stands for bit number bn of m, set m{bn} = 1 if */

    /* x{bn} == x{bn+1} for 0 <= bn <= 30.  That is, set a bit  */

    /* in m if the corresponding bit and the next higher bit in */

    /* x are equal in value (set m{31} = 0).                    */



    m = (~x ^ (x >> 1)) & 0x7fffffff;



    /* Sequences of 9 '1' bits in m now correspond to sequences */

    /* of 10 '0's or 10 '1' bits in x.  Shift and 'and' bits in */

    /* m to find sequences of 9 or more '1' bits.   As a result */

    /* bits in m are set if they are at the bottom of sequences */

    /* of 10 adjacent '0's or 10 adjacent '1's in x.            */



    m &= (m >> 1) & (m >> 2); m &= (m >> 3) & (m >> 6);



    if(!m)  /* return if mask is empty - no key fixing needed   */

            /* is this early return worthwhile?                 */

        return 0;



    /* We need the internal bits in each continuous sequence of */

    /* matching bits (that is the bits less the two endpoints). */

    /* We thus propagate each set bit into the 8 internal bits  */

    /* that it represents, starting 1 left and finsihing 8 left */

    /* of its position.                                         */



    m <<= 1; m |= (m << 1); m |= (m << 2); m |= (m << 4);



    /* m is now correct except for the odd behaviour of bit 31, */

    /* that is, it will be set if it is in a sequence of 10 or  */

    /* more '0's and clear otherwise.                           */



    m |= (m << 1) & ~x & 0x80000000;



    return m & 0xfffffffc;

};



/* My thanks to Louis Granboulan for spotting an error in the   */

/* previous version of set_key.                                 */



u4byte *set_key(const u4byte in_key[], const u4byte key_len)

{   u4byte  i, j, m, w;



    m = key_len / 32 - 1;



    for(i = j = 0; i < 39; ++i)

    {

      vk[i + 7] = rotl(vk[i] ^ vk[i + 5], 3) ^ in_key[j] ^ i;



      j = (j == m ? 0 : j + 1);

    }



    vk[46] = key_len / 32;



    for(j = 0; j < 7; ++j)

    {

         for(i = 1; i < 40; ++i)



            vk[i + 7] = rotl(vk[i + 7] + s_box[vk[i + 6] & 511], 9);



        vk[7] = rotl(vk[7] + s_box[vk[46] & 511], 9);

    }



    for(i = j = 0; i < 40; ++i)

    {

        l_key[j] = vk[i + 7];



        j = (j < 33 ? j + 7 : j - 33);

    }



    for(i = 5; i < 37; i += 2)

    {

        w = l_key[i] | 3;



        if(m = gen_mask(w))



            w ^= (rotl(s_box[265 + (l_key[i] & 3)], l_key[i + 3] & 31) & m);



        l_key[i] = w;

    }



    return l_key;

};



[COLOR=royalblue][B]__device__[/B] void encrypt(const u4byte in_blk[4], u4byte out_blk[4])

{   u4byte  a, b, c, d, l, m, r;



    a = in_blk[0] + l_key[0]; b = in_blk[1] + l_key[1];

    c = in_blk[2] + l_key[2]; d = in_blk[3] + l_key[3];



    f_mix(a,b,c,d); a += d;

    f_mix(b,c,d,a); b += c;

    f_mix(c,d,a,b);

    f_mix(d,a,b,c);

    f_mix(a,b,c,d); a += d;

    f_mix(b,c,d,a); b += c;

    f_mix(c,d,a,b);

    f_mix(d,a,b,c);



    f_ktr(a,b,c,d, 4); f_ktr(b,c,d,a, 6); f_ktr(c,d,a,b, 8); f_ktr(d,a,b,c,10);

    f_ktr(a,b,c,d,12); f_ktr(b,c,d,a,14); f_ktr(c,d,a,b,16); f_ktr(d,a,b,c,18);

    f_ktr(a,d,c,b,20); f_ktr(b,a,d,c,22); f_ktr(c,b,a,d,24); f_ktr(d,c,b,a,26);

    f_ktr(a,d,c,b,28); f_ktr(b,a,d,c,30); f_ktr(c,b,a,d,32); f_ktr(d,c,b,a,34);



    b_mix(a,b,c,d);

    b_mix(b,c,d,a); c -= b;

    b_mix(c,d,a,b); d -= a;

    b_mix(d,a,b,c);

    b_mix(a,b,c,d);

    b_mix(b,c,d,a); c -= b;

    b_mix(c,d,a,b); d -= a;

    b_mix(d,a,b,c);



    out_blk[0] = a - l_key[36]; out_blk[1] = b - l_key[37];

    out_blk[2] = c - l_key[38]; out_blk[3] = d - l_key[39];

};



[COLOR=royalblue][B]__device__[/B] void decrypt(const u4byte in_blk[4], u4byte out_blk[4])

{   u4byte  a, b, c, d, l, m, r;



    d = in_blk[0] + l_key[36]; c = in_blk[1] + l_key[37];

    b = in_blk[2] + l_key[38]; a = in_blk[3] + l_key[39];



    f_mix(a,b,c,d); a += d;

    f_mix(b,c,d,a); b += c;

    f_mix(c,d,a,b);

    f_mix(d,a,b,c);

    f_mix(a,b,c,d); a += d;

    f_mix(b,c,d,a); b += c;

    f_mix(c,d,a,b);

    f_mix(d,a,b,c);



    r_ktr(a,b,c,d,34); r_ktr(b,c,d,a,32); r_ktr(c,d,a,b,30); r_ktr(d,a,b,c,28);

    r_ktr(a,b,c,d,26); r_ktr(b,c,d,a,24); r_ktr(c,d,a,b,22); r_ktr(d,a,b,c,20);

    r_ktr(a,d,c,b,18); r_ktr(b,a,d,c,16); r_ktr(c,b,a,d,14); r_ktr(d,c,b,a,12);

    r_ktr(a,d,c,b,10); r_ktr(b,a,d,c, 8); r_ktr(c,b,a,d, 6); r_ktr(d,c,b,a, 4);



    b_mix(a,b,c,d);

    b_mix(b,c,d,a); c -= b;

    b_mix(c,d,a,b); d -= a;

    b_mix(d,a,b,c);

    b_mix(a,b,c,d);

    b_mix(b,c,d,a); c -= b;

    b_mix(c,d,a,b); d -= a;

    b_mix(d,a,b,c);



    out_blk[0] = d - l_key[0]; out_blk[1] = c - l_key[1];

    out_blk[2] = b - l_key[2]; out_blk[3] = a - l_key[3];

}
[COLOR=royalblue][B]
__global__ void mars_enc(const u4byte in_blk[4], u4byte out_blk[4]) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    encrypt(in_blk + 4*b, out_blk + 4*b);
}

__global__ void mars_dec(const u4byte in_blk[4], u4byte out_blk[4]) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    decrypt(in_blk + 4*b, out_blk + 4*b);
}

inline void HandleErrorImpl(cudaError error, const char* file, int line) {
    if (error != cudaSuccess) {
        printf("%s: %d %s", file, line, cudaGetErrorString(error));
        exit(1);
    }
}

int main(void) {
    char* key = "meingeheimespasswort";
    int threads = 256;
    int blocks = 25600;
    set_key((const u4byte*)key, strlen(key));

    u4byte* in_blk;
    HandleError(cudaMalloc(&in_blk, 16*threads*blocks));
    HandleError(cudaMemset(in_blk, 0, 16*threads*blocks));

    u4byte* out_blk;
    HandleError(cudaMalloc(&out_blk, 16*threads*blocks));

    char *test1 = (char*)malloc(16*threads*blocks);
    HandleError(cudaMemcpy(test1, in_blk, 16*threads*blocks, cudaMemcpyDeviceToHost));

    printf("First 16 bytes of input data: ");
    for (int i=0; i<16; i++) {
        printf("%d, ", test1[i]);
    }

    cudaEvent_t start, stop;
    HandleError(cudaEventCreate(&start));
    HandleError(cudaEventCreate(&stop));
    HandleError(cudaEventRecord( start, 0 ));

    mars_enc<<<blocks,threads>>>(in_blk, out_blk);
    mars_dec<<<blocks,threads>>>(out_blk, in_blk);

    HandleError(cudaGetLastError());

    HandleError(cudaEventRecord( stop, 0 ));
    HandleError(cudaEventSynchronize( stop ));
    float elapsedTime;
    HandleError(cudaEventElapsedTime( &elapsedTime, start, stop ));

    printf("\nPerformance: %.6f MB/sec\n", 2*((16*threads*blocks)/1048576)/(elapsedTime/1000));

    HandleError(cudaEventDestroy( start ));
    HandleError(cudaEventDestroy( stop ));

    char *test2 = (char*)malloc(16*threads*blocks);
    HandleError(cudaMemcpy(test2, in_blk, 16*threads*blocks, cudaMemcpyDeviceToHost));

    printf("After decryption: ");
    for (int i=0; i<16; i++) {
        printf("%d, ", test2[i]);
    }

    free(test1);
    free(test2);

    HandleError(cudaFree(in_blk));
    HandleError(cudaFree(out_blk));

    return 0;
}[/B]
```
Da der Original-Code von den selben Autoren zu sein schien wie Twofish, konnte ich nahezu alles fast 1:1 kopieren. Allerdings kriege ich auch in MARS den selben Fehler:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Habe ich also den Pointer-Fehler mitkopiert. Wenn wir ihn aber in einem der drei Codes finden, dürfte sich das ganze auch ganz leicht in den anderen beiden beheben lassen, weil's in Twofish, AES, und MARS wirklich der exakt selbe Fehler sein dürfte?!


----------



## boss3D (5. Januar 2014)

Nachdem ich den Fehler bei zeilenweisem Durchschauen des/der Codes nicht finden konnte, habe ich jetzt angefangen, Code-Teile auszukommentieren, solange, bis der launch Fehler nicht mehr auftrat. Dabei habe ich festgestellt, dass es am Ende reicht, die enc und dec Funktionen auszukommentieren. Darin muss also der Fehler liegen. Sind die "weg", kriege ich eine Ausgabe:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



*[Edit]*
Ich habe die Fehlerquelle für den launch error gefunden. Das "4*b" in den Aufrufen der Funktionen. Wenn das weg ist, wird zwar falsch ver- und entschlüsselt, aber der Code läuft ganz normal durch:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Wenn ich jetzt bloß noch wüsste, was genau an der Berechnug mit den 4*b falsch ist, und wie ich das beheben könnte ...


----------



## sebi707 (5. Januar 2014)

So habe mir grade mal den Code zu Twofish angeguckt und hab schon an meinem eigenen Verstand gezweifelt bis es mir endlich aufgefallen ist. Neben mehreren fehlenden __device__ an den Funktionen und der nicht richtigen Schlüsselinitialisierung war der Fehler für "Unspecified launch failure" im std_defs.h Header zu suchen. Dort wird unsigned long als 4 Byte Typ verkauft, allerdings unter Linux x64 ist unsigned long meistens 8 Byte. Ich hab die Typen einfach mit den entsprechenden Varianten aus stdint.h ersetzt und jetzt scheint es zu funktionieren. Hab dir hier 


			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        

 mal den Code hochgeladen.

Edit: Und der AES Code funktioniert jetzt auch. Schlüsselinitialisierung ist fummelig und wieder komisches define für unsigned long. Code hier: 


			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Bei MARS lass ich dich erstmal noch ein bisschen probieren. Dort ist auch garantiert das typedef wieder mit unsigned long. Ansonsten hoffe ich, dass du dir meinen Code nicht einfach übernimmst sondern dir auch anguckst was ich verändert habe und verstehst wieso.


----------



## Crysis nerd (5. Januar 2014)

Yo boss3D, bekomms ja nur am Rand mit, aber du schuldest sebi was, weil er dir dauernd hilft. Ich würd ihm ja mal nen billiges Steamspiel kaufen oder nen selbstgebackenes Schokoeis per Post schicken... Wäre zumindest eine Geste des Dankes 
(ne ich will mich hier nich einmischen, aber ich dachte, es schreibt mal ein anderer als ihr beide in diesen thread  )


----------



## boss3D (5. Januar 2014)

Twofish läuft bei mir in deiner Version, bei AES habe ich nur folgende beiden Zeilen hinzugefügt ...

```
HandleError(cudaFree(key_device));
HandleError(cudaFree(key_w));
```
... aber AES liefert mir immer noch unspecified launch failure. Wenn's aber bei dir auf der GTX 560 Ti läuft, schiebe ich das auf meine unzureichende 9600M GT. 

Zum Verständnis: Einfach nur übernehmen kann ich die Codes alleine schon deswegen nicht, weil ich sie vor Lehrern und "Fachpublikum" erklären können muss. 

Deswegen habe ich auch folgende Fragen:
- Wofür genau hast du bei Twofish jetzt Speicher im VRAM für den Schlüssel (key_device) allokiert? Weil du set_key() zu einer __device__ Funktion gemacht hast, das als kernel aufrufst, und die Daten somit im VRAM sein müssen?!
- ^^ War das nötig, und wenn ja, warum? Warum genau läuft's jetzt, und vorher nicht, als der Schlüssel von der CPU berechnet wurde?
- Zu strlen(blabla) zählst du jetzt immer +1 dazu wegen '\0'? Dann muss ich das ja auch in RC6 und Serpent noch ergänzen, oder?
- Bei AES erklärt sich das ganze genau gleich, oder?
- Die Zeitmessung soll wirklich in jedem Algorithmus ausschließlich (!) die Dauer (bzw. bei uns die Performance) des Ver- und Entschlüsselns ermitteln. Dass der Schlüssel jetzt in Twofish und AES auch von der GPU berechnet wird, hat darauf eh keinen Einfluss?! Immerhin hast du den kernel ja außerhalb der cudaEvents aufgerufen. Oder müsste ich den Schlüssel jetzt in allen 5 Codes von der GPU berechnen lassen?

MARS schaue ich mir nochmal an. Wieder mal VIELEN DANK bis hier her!!! 

*[Edit]*
MARS habe ich jetzt folgendermaßen:

```
/* This is an independent implementation of the encryption algorithm:   */

/*                                                                      */

/*         MARS by a team at IBM,                                        */

/*                                                                      */

/* which is a candidate algorithm in the Advanced Encryption Standard   */

/* programme of the US National Institute of Standards and Technology.  */

/* Copyright in this implementation is held by Dr B R Gladman. The MARS */

/* algorithm is covered by a pending patent application owned by IBM,   */

/* who intend to offer a royalty free license under any issued patent   */

/* that results from such application if MARS is selected as the AES    */

/* algorithm.  In the interim, you may evaluate the MARS algorithm for  */

/* your personal, lawful, non-profit purposes as an end user.           */

/*                                                                      */

/* The header above modified on June 6th 1999.                          */

/* Dr Brian Gladman (gladman@seven77.demon.co.uk) 14th January 1999     */



/* Timing data for MARS (mars.c)



128 bit key:

Key Setup:    4316 cycles

Encrypt:       369 cycles =    69.4 mbits/sec

Decrypt:       376 cycles =    68.1 mbits/sec

Mean:          373 cycles =    68.7 mbits/sec



192 bit key:

Key Setup:    4377 cycles

Encrypt:       373 cycles =    68.6 mbits/sec

Decrypt:       379 cycles =    67.5 mbits/sec

Mean:          376 cycles =    68.1 mbits/sec



256 bit key:

Key Setup:    4340 cycles

Encrypt:       369 cycles =    69.4 mbits/sec

Decrypt:       376 cycles =    68.1 mbits/sec

Mean:          373 cycles =    68.7 mbits/sec



*/



#include "std_defs.h"
#include <stdio.h>



static char *alg_name[] = { "mars", "mars.c", "mars" };



char **cipher_name()

{

    return alg_name;

}



__device__ static u4byte s_box[] =

{

    0x09d0c479, 0x28c8ffe0, 0x84aa6c39, 0x9dad7287, /* 0x000    */

    0x7dff9be3, 0xd4268361, 0xc96da1d4, 0x7974cc93,

    0x85d0582e, 0x2a4b5705, 0x1ca16a62, 0xc3bd279d,

    0x0f1f25e5, 0x5160372f, 0xc695c1fb, 0x4d7ff1e4,

    0xae5f6bf4, 0x0d72ee46, 0xff23de8a, 0xb1cf8e83, /* 0x010    */

    0xf14902e2, 0x3e981e42, 0x8bf53eb6, 0x7f4bf8ac,

    0x83631f83, 0x25970205, 0x76afe784, 0x3a7931d4,

    0x4f846450, 0x5c64c3f6, 0x210a5f18, 0xc6986a26,

    0x28f4e826, 0x3a60a81c, 0xd340a664, 0x7ea820c4, /* 0x020    */

    0x526687c5, 0x7eddd12b, 0x32a11d1d, 0x9c9ef086,

    0x80f6e831, 0xab6f04ad, 0x56fb9b53, 0x8b2e095c,

    0xb68556ae, 0xd2250b0d, 0x294a7721, 0xe21fb253,

    0xae136749, 0xe82aae86, 0x93365104, 0x99404a66, /* 0x030    */

    0x78a784dc, 0xb69ba84b, 0x04046793, 0x23db5c1e,

    0x46cae1d6, 0x2fe28134, 0x5a223942, 0x1863cd5b,

    0xc190c6e3, 0x07dfb846, 0x6eb88816, 0x2d0dcc4a,

    0xa4ccae59, 0x3798670d, 0xcbfa9493, 0x4f481d45, /* 0x040    */

    0xeafc8ca8, 0xdb1129d6, 0xb0449e20, 0x0f5407fb,

    0x6167d9a8, 0xd1f45763, 0x4daa96c3, 0x3bec5958,

    0xababa014, 0xb6ccd201, 0x38d6279f, 0x02682215,

    0x8f376cd5, 0x092c237e, 0xbfc56593, 0x32889d2c, /* 0x050    */

    0x854b3e95, 0x05bb9b43, 0x7dcd5dcd, 0xa02e926c,

    0xfae527e5, 0x36a1c330, 0x3412e1ae, 0xf257f462,

    0x3c4f1d71, 0x30a2e809, 0x68e5f551, 0x9c61ba44,

    0x5ded0ab8, 0x75ce09c8, 0x9654f93e, 0x698c0cca, /* 0x060    */

    0x243cb3e4, 0x2b062b97, 0x0f3b8d9e, 0x00e050df,

    0xfc5d6166, 0xe35f9288, 0xc079550d, 0x0591aee8,

    0x8e531e74, 0x75fe3578, 0x2f6d829a, 0xf60b21ae,

    0x95e8eb8d, 0x6699486b, 0x901d7d9b, 0xfd6d6e31, /* 0x070    */

    0x1090acef, 0xe0670dd8, 0xdab2e692, 0xcd6d4365,

    0xe5393514, 0x3af345f0, 0x6241fc4d, 0x460da3a3,

    0x7bcf3729, 0x8bf1d1e0, 0x14aac070, 0x1587ed55,

    0x3afd7d3e, 0xd2f29e01, 0x29a9d1f6, 0xefb10c53, /* 0x080    */

    0xcf3b870f, 0xb414935c, 0x664465ed, 0x024acac7,

    0x59a744c1, 0x1d2936a7, 0xdc580aa6, 0xcf574ca8,

    0x040a7a10, 0x6cd81807, 0x8a98be4c, 0xaccea063,

    0xc33e92b5, 0xd1e0e03d, 0xb322517e, 0x2092bd13, /* 0x090    */

    0x386b2c4a, 0x52e8dd58, 0x58656dfb, 0x50820371,

    0x41811896, 0xe337ef7e, 0xd39fb119, 0xc97f0df6,

    0x68fea01b, 0xa150a6e5, 0x55258962, 0xeb6ff41b,

    0xd7c9cd7a, 0xa619cd9e, 0xbcf09576, 0x2672c073, /* 0x0a0    */

    0xf003fb3c, 0x4ab7a50b, 0x1484126a, 0x487ba9b1,

    0xa64fc9c6, 0xf6957d49, 0x38b06a75, 0xdd805fcd,

    0x63d094cf, 0xf51c999e, 0x1aa4d343, 0xb8495294,

    0xce9f8e99, 0xbffcd770, 0xc7c275cc, 0x378453a7, /* 0x0b0    */

    0x7b21be33, 0x397f41bd, 0x4e94d131, 0x92cc1f98,

    0x5915ea51, 0x99f861b7, 0xc9980a88, 0x1d74fd5f,

    0xb0a495f8, 0x614deed0, 0xb5778eea, 0x5941792d,

    0xfa90c1f8, 0x33f824b4, 0xc4965372, 0x3ff6d550, /* 0x0c0    */

    0x4ca5fec0, 0x8630e964, 0x5b3fbbd6, 0x7da26a48,

    0xb203231a, 0x04297514, 0x2d639306, 0x2eb13149,

    0x16a45272, 0x532459a0, 0x8e5f4872, 0xf966c7d9,

    0x07128dc0, 0x0d44db62, 0xafc8d52d, 0x06316131, /* 0x0d0    */

    0xd838e7ce, 0x1bc41d00, 0x3a2e8c0f, 0xea83837e,

    0xb984737d, 0x13ba4891, 0xc4f8b949, 0xa6d6acb3,

    0xa215cdce, 0x8359838b, 0x6bd1aa31, 0xf579dd52,

    0x21b93f93, 0xf5176781, 0x187dfdde, 0xe94aeb76, /* 0x0e0    */

    0x2b38fd54, 0x431de1da, 0xab394825, 0x9ad3048f,

    0xdfea32aa, 0x659473e3, 0x623f7863, 0xf3346c59,

    0xab3ab685, 0x3346a90b, 0x6b56443e, 0xc6de01f8,

    0x8d421fc0, 0x9b0ed10c, 0x88f1a1e9, 0x54c1f029, /* 0x0f0    */

    0x7dead57b, 0x8d7ba426, 0x4cf5178a, 0x551a7cca,

    0x1a9a5f08, 0xfcd651b9, 0x25605182, 0xe11fc6c3,

    0xb6fd9676, 0x337b3027, 0xb7c8eb14, 0x9e5fd030,



    0x6b57e354, 0xad913cf7, 0x7e16688d, 0x58872a69, /* 0x100    */

    0x2c2fc7df, 0xe389ccc6, 0x30738df1, 0x0824a734,

    0xe1797a8b, 0xa4a8d57b, 0x5b5d193b, 0xc8a8309b,

    0x73f9a978, 0x73398d32, 0x0f59573e, 0xe9df2b03,

    0xe8a5b6c8, 0x848d0704, 0x98df93c2, 0x720a1dc3, /* 0x110    */

    0x684f259a, 0x943ba848, 0xa6370152, 0x863b5ea3,

    0xd17b978b, 0x6d9b58ef, 0x0a700dd4, 0xa73d36bf,

    0x8e6a0829, 0x8695bc14, 0xe35b3447, 0x933ac568,

    0x8894b022, 0x2f511c27, 0xddfbcc3c, 0x006662b6, /* 0x120    */

    0x117c83fe, 0x4e12b414, 0xc2bca766, 0x3a2fec10,

    0xf4562420, 0x55792e2a, 0x46f5d857, 0xceda25ce,

    0xc3601d3b, 0x6c00ab46, 0xefac9c28, 0xb3c35047,

    0x611dfee3, 0x257c3207, 0xfdd58482, 0x3b14d84f, /* 0x130    */

    0x23becb64, 0xa075f3a3, 0x088f8ead, 0x07adf158,

    0x7796943c, 0xfacabf3d, 0xc09730cd, 0xf7679969,

    0xda44e9ed, 0x2c854c12, 0x35935fa3, 0x2f057d9f,

    0x690624f8, 0x1cb0bafd, 0x7b0dbdc6, 0x810f23bb, /* 0x140    */

    0xfa929a1a, 0x6d969a17, 0x6742979b, 0x74ac7d05,

    0x010e65c4, 0x86a3d963, 0xf907b5a0, 0xd0042bd3,

    0x158d7d03, 0x287a8255, 0xbba8366f, 0x096edc33,

    0x21916a7b, 0x77b56b86, 0x951622f9, 0xa6c5e650, /* 0x150    */

    0x8cea17d1, 0xcd8c62bc, 0xa3d63433, 0x358a68fd,

    0x0f9b9d3c, 0xd6aa295b, 0xfe33384a, 0xc000738e,

    0xcd67eb2f, 0xe2eb6dc2, 0x97338b02, 0x06c9f246,

    0x419cf1ad, 0x2b83c045, 0x3723f18a, 0xcb5b3089, /* 0x160    */

    0x160bead7, 0x5d494656, 0x35f8a74b, 0x1e4e6c9e,

    0x000399bd, 0x67466880, 0xb4174831, 0xacf423b2,

    0xca815ab3, 0x5a6395e7, 0x302a67c5, 0x8bdb446b,

    0x108f8fa4, 0x10223eda, 0x92b8b48b, 0x7f38d0ee, /* 0x170    */

    0xab2701d4, 0x0262d415, 0xaf224a30, 0xb3d88aba,

    0xf8b2c3af, 0xdaf7ef70, 0xcc97d3b7, 0xe9614b6c,

    0x2baebff4, 0x70f687cf, 0x386c9156, 0xce092ee5,

    0x01e87da6, 0x6ce91e6a, 0xbb7bcc84, 0xc7922c20, /* 0x180    */

    0x9d3b71fd, 0x060e41c6, 0xd7590f15, 0x4e03bb47,

    0x183c198e, 0x63eeb240, 0x2ddbf49a, 0x6d5cba54,

    0x923750af, 0xf9e14236, 0x7838162b, 0x59726c72,

    0x81b66760, 0xbb2926c1, 0x48a0ce0d, 0xa6c0496d, /* 0x190    */

    0xad43507b, 0x718d496a, 0x9df057af, 0x44b1bde6,

    0x054356dc, 0xde7ced35, 0xd51a138b, 0x62088cc9,

    0x35830311, 0xc96efca2, 0x686f86ec, 0x8e77cb68,

    0x63e1d6b8, 0xc80f9778, 0x79c491fd, 0x1b4c67f2, /* 0x1a0    */

    0x72698d7d, 0x5e368c31, 0xf7d95e2e, 0xa1d3493f,

    0xdcd9433e, 0x896f1552, 0x4bc4ca7a, 0xa6d1baf4,

    0xa5a96dcc, 0x0bef8b46, 0xa169fda7, 0x74df40b7,

    0x4e208804, 0x9a756607, 0x038e87c8, 0x20211e44, /* 0x1b0    */

    0x8b7ad4bf, 0xc6403f35, 0x1848e36d, 0x80bdb038,

    0x1e62891c, 0x643d2107, 0xbf04d6f8, 0x21092c8c,

    0xf644f389, 0x0778404e, 0x7b78adb8, 0xa2c52d53,

    0x42157abe, 0xa2253e2e, 0x7bf3f4ae, 0x80f594f9, /* 0x1c0    */

    0x953194e7, 0x77eb92ed, 0xb3816930, 0xda8d9336,

    0xbf447469, 0xf26d9483, 0xee6faed5, 0x71371235,

    0xde425f73, 0xb4e59f43, 0x7dbe2d4e, 0x2d37b185,

    0x49dc9a63, 0x98c39d98, 0x1301c9a2, 0x389b1bbf, /* 0x1d0    */

    0x0c18588d, 0xa421c1ba, 0x7aa3865c, 0x71e08558,

    0x3c5cfcaa, 0x7d239ca4, 0x0297d9dd, 0xd7dc2830,

    0x4b37802b, 0x7428ab54, 0xaeee0347, 0x4b3fbb85,

    0x692f2f08, 0x134e578e, 0x36d9e0bf, 0xae8b5fcf, /* 0x1e0    */

    0xedb93ecf, 0x2b27248e, 0x170eb1ef, 0x7dc57fd6,

    0x1e760f16, 0xb1136601, 0x864e1b9b, 0xd7ea7319,

    0x3ab871bd, 0xcfa4d76f, 0xe31bd782, 0x0dbeb469,

    0xabb96061, 0x5370f85d, 0xffb07e37, 0xda30d0fb, /* 0x1f0    */

    0xebc977b6, 0x0b98b40f, 0x3a4d0fe6, 0xdf4fc26b,

    0x159cf22a, 0xc298d6e2, 0x2b78ef6a, 0x61a94ac0,

    0xab561187, 0x14eea0f0, 0xdf0d4164, 0x19af70ee

};



__device__ static u4byte vk[47] =

{

    0x09d0c479, 0x28c8ffe0, 0x84aa6c39, 0x9dad7287, 0x7dff9be3, 0xd4268361,

    0xc96da1d4

};



__device__ static u4byte   l_key[40];

#define HandleError(x) HandleErrorImpl(x, __FILE__, __LINE__)

#define f_mix(a,b,c,d)                  \
        r = rotr(a, 8);                 \
        b ^= s_box[a & 255];            \
        b += s_box[(r & 255) + 256];    \
        r = rotr(a, 16);                \
        a  = rotr(a, 24);               \
        c += s_box[r & 255];            \
        d ^= s_box[(a & 255) + 256];



#define b_mix(a,b,c,d)                  \
        r = rotl(a, 8);                 \
        b ^= s_box[(a & 255) + 256];    \
        c -= s_box[r & 255];            \
        r = rotl(a, 16);                \
        a  = rotl(a, 24);               \
        d -= s_box[(r & 255) + 256];    \
        d ^= s_box[a & 255];



#define f_ktr(a,b,c,d,i)    \
    m = a + l_key[i];       \
    a = rotl(a, 13);        \
    r = a * l_key[i + 1];   \
    l = s_box[m & 511];     \
    r = rotl(r, 5);         \
    c += rotl(m, r);        \
    l ^= r;                 \
    r = rotl(r, 5);         \
    l ^= r;                 \
    d ^= r;                 \
    b += rotl(l, r);



#define r_ktr(a,b,c,d,i)    \
    r = a * l_key[i + 1];   \
    a = rotr(a, 13);        \
    m = a + l_key[i];       \
    l = s_box[m & 511];     \
    r = rotl(r, 5);         \
    l ^= r;                 \
    c -= rotl(m, r);        \
    r = rotl(r, 5);         \
    l ^= r;                 \
    d ^= r;                 \
    b -= rotl(l, r);



/* For a 32 bit word (x) generate a mask (m) such that a bit in */

/* m is set to 1 if and only if the corresponding bit in x is:  */

/*                                                              */

/* 1. in a sequence of 10 or more adjacent '0' bits             */

/* 2. in a sequence of 10 or more adjacent '1' bits             */

/* 3. but is not either endpoint of such a sequence unless such */

/*    an endpoint is at the top bit (bit 31) of a word and is   */

/*    in a sequence of '0' bits.                                */

/*                                                              */

/* The only situation in which a sequence endpoint is included  */

/* in the mask is hence when the endpoint is at bit 31 and is   */

/* the endpoint of a sequence of '0' bits. My thanks go to Shai */

/* Halevi of IBM for the neat trick (which I missed) of finding */

/* the '0' and '1' sequences at the same time.                  */



__device__ u4byte gen_mask(u4byte x)

{   u4byte  m;



    /* if m{bn} stands for bit number bn of m, set m{bn} = 1 if */

    /* x{bn} == x{bn+1} for 0 <= bn <= 30.  That is, set a bit  */

    /* in m if the corresponding bit and the next higher bit in */

    /* x are equal in value (set m{31} = 0).                    */



    m = (~x ^ (x >> 1)) & 0x7fffffff;



    /* Sequences of 9 '1' bits in m now correspond to sequences */

    /* of 10 '0's or 10 '1' bits in x.  Shift and 'and' bits in */

    /* m to find sequences of 9 or more '1' bits.   As a result */

    /* bits in m are set if they are at the bottom of sequences */

    /* of 10 adjacent '0's or 10 adjacent '1's in x.            */



    m &= (m >> 1) & (m >> 2); m &= (m >> 3) & (m >> 6);



    if(!m)  /* return if mask is empty - no key fixing needed   */

            /* is this early return worthwhile?                 */

        return 0;



    /* We need the internal bits in each continuous sequence of */

    /* matching bits (that is the bits less the two endpoints). */

    /* We thus propagate each set bit into the 8 internal bits  */

    /* that it represents, starting 1 left and finsihing 8 left */

    /* of its position.                                         */



    m <<= 1; m |= (m << 1); m |= (m << 2); m |= (m << 4);



    /* m is now correct except for the odd behaviour of bit 31, */

    /* that is, it will be set if it is in a sequence of 10 or  */

    /* more '0's and clear otherwise.                           */



    m |= (m << 1) & ~x & 0x80000000;



    return m & 0xfffffffc;

};



/* My thanks to Louis Granboulan for spotting an error in the   */

/* previous version of set_key.                                 */



__global__ void set_key(const u4byte in_key[], const u4byte key_len)

{   u4byte  i, j, m, w;



    m = key_len / 32 - 1;



    for(i = j = 0; i < 39; ++i)

    {

      vk[i + 7] = rotl(vk[i] ^ vk[i + 5], 3) ^ in_key[j] ^ i;



      j = (j == m ? 0 : j + 1);

    }



    vk[46] = key_len / 32;



    for(j = 0; j < 7; ++j)

    {

         for(i = 1; i < 40; ++i)



            vk[i + 7] = rotl(vk[i + 7] + s_box[vk[i + 6] & 511], 9);



        vk[7] = rotl(vk[7] + s_box[vk[46] & 511], 9);

    }



    for(i = j = 0; i < 40; ++i)

    {

        l_key[j] = vk[i + 7];



        j = (j < 33 ? j + 7 : j - 33);

    }



    for(i = 5; i < 37; i += 2)

    {

        w = l_key[i] | 3;



        if(m = gen_mask(w))



            w ^= (rotl(s_box[265 + (l_key[i] & 3)], l_key[i + 3] & 31) & m);



        l_key[i] = w;

    }


};



__device__ void encrypt(const u4byte in_blk[4], u4byte out_blk[4])

{   u4byte  a, b, c, d, l, m, r;



    a = in_blk[0] + l_key[0]; b = in_blk[1] + l_key[1];

    c = in_blk[2] + l_key[2]; d = in_blk[3] + l_key[3];



    f_mix(a,b,c,d); a += d;

    f_mix(b,c,d,a); b += c;

    f_mix(c,d,a,b);

    f_mix(d,a,b,c);

    f_mix(a,b,c,d); a += d;

    f_mix(b,c,d,a); b += c;

    f_mix(c,d,a,b);

    f_mix(d,a,b,c);



    f_ktr(a,b,c,d, 4); f_ktr(b,c,d,a, 6); f_ktr(c,d,a,b, 8); f_ktr(d,a,b,c,10);

    f_ktr(a,b,c,d,12); f_ktr(b,c,d,a,14); f_ktr(c,d,a,b,16); f_ktr(d,a,b,c,18);

    f_ktr(a,d,c,b,20); f_ktr(b,a,d,c,22); f_ktr(c,b,a,d,24); f_ktr(d,c,b,a,26);

    f_ktr(a,d,c,b,28); f_ktr(b,a,d,c,30); f_ktr(c,b,a,d,32); f_ktr(d,c,b,a,34);



    b_mix(a,b,c,d);

    b_mix(b,c,d,a); c -= b;

    b_mix(c,d,a,b); d -= a;

    b_mix(d,a,b,c);

    b_mix(a,b,c,d);

    b_mix(b,c,d,a); c -= b;

    b_mix(c,d,a,b); d -= a;

    b_mix(d,a,b,c);



    out_blk[0] = a - l_key[36]; out_blk[1] = b - l_key[37];

    out_blk[2] = c - l_key[38]; out_blk[3] = d - l_key[39];

};



__device__ void decrypt(const u4byte in_blk[4], u4byte out_blk[4])

{   u4byte  a, b, c, d, l, m, r;



    d = in_blk[0] + l_key[36]; c = in_blk[1] + l_key[37];

    b = in_blk[2] + l_key[38]; a = in_blk[3] + l_key[39];



    f_mix(a,b,c,d); a += d;

    f_mix(b,c,d,a); b += c;

    f_mix(c,d,a,b);

    f_mix(d,a,b,c);

    f_mix(a,b,c,d); a += d;

    f_mix(b,c,d,a); b += c;

    f_mix(c,d,a,b);

    f_mix(d,a,b,c);



    r_ktr(a,b,c,d,34); r_ktr(b,c,d,a,32); r_ktr(c,d,a,b,30); r_ktr(d,a,b,c,28);

    r_ktr(a,b,c,d,26); r_ktr(b,c,d,a,24); r_ktr(c,d,a,b,22); r_ktr(d,a,b,c,20);

    r_ktr(a,d,c,b,18); r_ktr(b,a,d,c,16); r_ktr(c,b,a,d,14); r_ktr(d,c,b,a,12);

    r_ktr(a,d,c,b,10); r_ktr(b,a,d,c, 8); r_ktr(c,b,a,d, 6); r_ktr(d,c,b,a, 4);



    b_mix(a,b,c,d);

    b_mix(b,c,d,a); c -= b;

    b_mix(c,d,a,b); d -= a;

    b_mix(d,a,b,c);

    b_mix(a,b,c,d);

    b_mix(b,c,d,a); c -= b;

    b_mix(c,d,a,b); d -= a;

    b_mix(d,a,b,c);



    out_blk[0] = d - l_key[0]; out_blk[1] = c - l_key[1];

    out_blk[2] = b - l_key[2]; out_blk[3] = a - l_key[3];

}

__global__ void mars_enc(const u4byte in_blk[4], u4byte out_blk[4]) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    encrypt(in_blk + 4*b, out_blk + 4*b);
}

__global__ void mars_dec(const u4byte in_blk[4], u4byte out_blk[4]) {
    int b = blockIdx.x*blockDim.x + threadIdx.x;
    decrypt(in_blk + 4*b, out_blk + 4*b);
}

inline void HandleErrorImpl(cudaError error, const char* file, int line) {
    if (error != cudaSuccess) {
        printf("%s: %d %s", file, line, cudaGetErrorString(error));
        exit(1);
    }
}

int main(void) {
    int threads = 256;
    int blocks = 25600;

    char* key = "meingeheimespasswort";
    char* key_device;
    HandleError(cudaMalloc(&key_device, strlen(key)+1));
    HandleError(cudaMemcpy(key_device, key, strlen(key)+1, cudaMemcpyHostToDevice));
    set_key<<<1,1>>>((const u4byte*)key, strlen(key));
    HandleError(cudaGetLastError());

    u4byte* in_blk;
    HandleError(cudaMalloc(&in_blk, 16*threads*blocks));
    HandleError(cudaMemset(in_blk, 0, 16*threads*blocks));

    u4byte* out_blk;
    HandleError(cudaMalloc(&out_blk, 16*threads*blocks));

    char *test1 = (char*)malloc(16*threads*blocks);
    HandleError(cudaMemcpy(test1, in_blk, 16*threads*blocks, cudaMemcpyDeviceToHost));

    printf("First 16 bytes of input data: ");
    for (int i=0; i<16; i++) {
        printf("%d, ", test1[i]);
    }

    cudaEvent_t start, stop;
    HandleError(cudaEventCreate(&start));
    HandleError(cudaEventCreate(&stop));
    HandleError(cudaEventRecord( start, 0 ));

    mars_enc<<<blocks,threads>>>(in_blk, out_blk);
    mars_dec<<<blocks,threads>>>(out_blk, in_blk);

    HandleError(cudaGetLastError());

    HandleError(cudaEventRecord( stop, 0 ));
    HandleError(cudaEventSynchronize( stop ));
    float elapsedTime;
    HandleError(cudaEventElapsedTime( &elapsedTime, start, stop ));

    printf("\nPerformance: %.6f MB/sec\n", 2*((16*threads*blocks)/1048576)/(elapsedTime/1000));

    HandleError(cudaEventDestroy( start ));
    HandleError(cudaEventDestroy( stop ));

    char *test2 = (char*)malloc(16*threads*blocks);
    HandleError(cudaMemcpy(test2, in_blk, 16*threads*blocks, cudaMemcpyDeviceToHost));

    printf("After decryption: ");
    for (int i=0; i<16; i++) {
        printf("%d, ", test2[i]);
    }

    free(test1);
    free(test2);

    HandleError(cudaFree(in_blk));
    HandleError(cudaFree(out_blk));
    HandleError(cudaFree(key_device));

    return 0;
}
```
^^ im Code selbst werden jetzt auch keine Fehler mehr angezeigt, allerdings komme ich beim Ausführen wieder auf den altbekannten unspecified launch failure. Angeblich soll er von Zeile 795 verursacht werden:

```
HandleError(cudaMemcpy(test1, in_blk, 16*threads*blocks, cudaMemcpyDeviceToHost));
```
Twofish und AES liefern jetzt bei weiteren Durchläufen auch nur noch diesen unspecified launch failure. Aber ich vertraue jetzt ganz darauf, dass die Codes bei dir auf der GTX 560 Ti wirklich einwandfrei laufen und ich den Fehler nur wegen meiner zu schwachen 9600M GT kriege ...

Was sollte es denn sonst sein, wenn wir idente Twofish und AES haben?


----------



## sebi707 (5. Januar 2014)

Also die Twofish Implementierung unterscheiden sich von denen davor dadurch, dass Schlüssel und alles in globalen Variablen liegen. Statt also ein struct das den Schlüssel enthält in den VRAM zu kopieren macht es eher Sinn alle Funktionen als __device__ Funktionen zu deklarieren und die Daten für den Schlüssel einfach auch von der GPU erstellen zu lassen. Da Strings in C aber auch nur Pointer auf char sind muss man das ganze wieder in den VRAM kopieren vorm Aufruf. Das war jedenfalls der Teil für die erfolgreiche Schlüsselinitialisierung.

Der Zeit der mich vorhin viel mehr Zeit gekostet hat war, wegen dem falschen typedef. Ich hatte ja schon geschrieben, dass aufgrund eines Fehlers im Header der Typ u4byte tatsächlich 8 Byte groß war. Das führt dann zu massiv Problemen bei sowas wie "in_blk + 4*b" Wo wir eigentlich 16 Byte weiter wollten um mit jedem b einen neuen Block zu erwischen. Denn statt 4*4Byte vorwärts zu gehen werden jetzt 4*8Byte übersprungen. Daher kam also der "Unspecified launch failure" weil wir Speicher gelesen und geschrieben haben der weit außerhalb des reservierten Bereichs lieg.

Ja ich mache dort strlen()+1 weil ich das abschließende '\0' mitkopieren möchte. Wenn du genau guckst dann mache ich das aber nur beim reservieren des Speichers und kopieren der Daten aber nicht beim übergeben an die Funktion set_key. Du brauchst das also bei RC6 und Serpent nicht zu machen.

Ob die Schlüssel jetzt von der CPU berechnet werden und anschließend auf die GPU kopiert werden oder direkt auf der GPU generiert werden hat auf die spätere Geschwindigkeit des Algorithmus keinen Einfluss. Muss man eben nur sehen, dass Start und Stop-Event nur die Ver- und Entschlüsselung enthält.

Das du immer noch einen "Unspecified launch failure" bei Twofish und AES erhälst wundert mich. Eigentlich sollte das so auch auf deiner Hardware laufen. Wenn du weiterhin unspecified launch failure kriegst empfehle ich dir nochmals cuda-memcheck. Das Tool ist sehr leicht zu bedienen (verglichen mit gdb oder cuda-gdb). Du musst nur "cuda-memcheck *progname*" in der Console eintippen und schon sollte dir das Programm alle Speicherfehler reportieren.

Abschließend noch ein Fehler der mir vorhin aufgefallen ist. Twofish und MARS die set_key Funktion erwartet als Länge nicht die des Schlüssels in Bytes sondern Bits. Also beim Übergeben noch ein *8 ergänzen. Bei MARS führt ein falscher Wert dort auch zu Speicherfehlern.


----------



## boss3D (6. Januar 2014)

Okay, strlen(key)*8 habe ich jetzt in Twofish und MARS auch noch drinnen. Bei mir sieht's jetzt nach den letzten Fehlerkorrekturen so aus:

AES: the launch timed out and was terminated (Zeile 816)
MARS: unspecified launch failure (Zeile 795)
RC6: the launch timed out and was terminated (Zeile 178)
Serpent: funktioniert (22 MB/s)
Twofish: funktioniert (18 MB/s)

^^ Ich schaue mir das jetzt mal mit cuda-memcheck an ...

*[Edit]*
Jetzt muss ich nur noch rausfinden, was das alles bedeutet:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        

 


			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        

 


			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



*[Edit2]*
Fehler in MARS ist behoben; war nur ein blöder "Schlampigkeitsfehler". Ich hatte in set_key() nur "key" statt "key_device" angegeben. Der Test fällt jedenfalls beeindruckend aus! MARS ist von meinen 3 funktionierenden bis jetzt der mit Abstand performanteste Algorithmus:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Beiben noch AES und RC6 ...

*[Edit3]*
RC6 funktioniert, wenn ich wenige Threads (256) und Blöcke (12800) einstelle. Also liegt das Problem wohl wirklich nur an meiner zu schwachen 9600M GT. Die schwache Performance sagt jetzt im Vergleich mit den anderen, deutlich besser parallelisierten Algorithmen natürlich nichts aus. Das wird dann erst auf dem GTX 560 Ti SLI mit selber Thread-/Blockanzahl interessant:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



Bleibt nur noch AES ...*

[Edit4]*
AES hatte das ganz gleiche Problem wie RC6. Die GPU packte es einfach nicht. Jetzt mit 128 Threads / 6400 Blöcken funktioniert AES. Das wird wohl auch erst am Benchmarksystem interessant:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Damit funktionieren jetzt endlich auch alle Codes bei mir! 
----------------

Übrigens weiß ich jetzt auch, wie das mit den Rundenschlüsseln gemeint war.:

_Beginnend beim Schlüssel 0x00000000..00 einfach die Schlüssel  0x00000000..01, 0x00000000..02 usw. probieren. Mit key++ weiterspringen._

Aber ich denke, das lassen wir vorerst. Wenn wir jetzt alle Codes auf das umschreiben, bringen wir wahrscheinlich nur wieder Fehler rein, die wir dann wieder in stundenlanger Arbeit suchen müssten. Oder wüsstest du sofort und mit Sicherheit, wie das ginge?


----------



## sebi707 (6. Januar 2014)

Mir ist immer noch nicht ganz klar welcher Schlüssel gemeint ist. Die Passphrase oder das was die einzelnen Algos daraus generieren? In jedem Fall wäre das überhaupt nicht einfach zu implementieren. Zumindest nicht schön parallel, da man nach jedem Block nochmal neu set_key oder ähnliches aufrufen müsste, was die ganze Sache extremst verlangsamen würde.

Noch eine Sache die mir aufgefallen ist. AES und einige andere verschlüsselungen gibt es als verschiedene Varianten mit unterschliedlich großen Keys. Bei AES z.b. gibts 128, 192 und 256 Bit als Keysize. Die Varianten kann man einfach durch setzten der keysize Variablen in der main() Funktion ändern. Momentan ist die 256 Bit Variante eingestellt die wohl auch die langsamste Variante ist. Ich würde also AES in allen 3 Versionen benchmarken. Einige andere Verschlüsselungen haben das vermutlich auch. Musste mal bei Wikipedia gucken bei welchen das der Fall ist und wie man das umschalten kann (falls das bei der Implementierung überhaupt umzuschalten geht).


----------



## boss3D (6. Januar 2014)

So, wie ich das jetzt verstehe, sollte 0x00000000...0 unsere Passphrase ersetzen, und die Schlüsselberechnungsfunktionen sollten dann nichts anderes machen als key++. Aber wenn wir die Codes jetzt darauf umbasteln kommen sicher wieder 100 Errors. Das will ich mir nicht mehr antun. Außerdem müsste das ganze bis morgen 10:30 fertig sein. Das wäre eh schon zu knapp.

Ja, das mit den Schlüsseln kann ich dann beim Benchmarken durchaus berücksichtigen. Wenn's möglich ist, alle Algorithmen mit allen möglichen (aber immer der jeweils gleichen) Schlüssel-Längen zu benchmarken ...

*[Edit]*
Außerdem denke ich mir auch, dass das mit 0x00000000...0, 0x00000000...1, 0x00000000...2, etc. doch auch total einfach zu bruteforcen sein muss?! Jedenfalls ist das sicher leichter zu erraten als eine x-beliebige Passphrase?!


----------



## sebi707 (6. Januar 2014)

Hab grade mal geguckt. Alle 5 Verschlüsselungen unterstützen tatsächlich die gleichen Schlüsselllängen von 128, 192 und 256 Bit. Ich glaube aber eher nicht, dass man bei allen Implementation das umstellen kann. Ich würde daher bei denen wo man es umstellen kann alle 3 Varianten in der Benchmark Liste als z.B. AES-128, AES-192 und AES-256 aufnehmen und da wo man es nicht umstellen kann rausfinden welche der 3 Varianten benutzt wird und dann die Bitzahl auch dahinter schreiben.


----------



## boss3D (6. Januar 2014)

Außer bei AES kann man es eh bei keinem unserer anderen 4 Algorithmen einfach so umstellen. Und ich traue mich nicht so recht, da jetzt herumbasteln zu probieren, bevor am Ende wieder alle Codes nur failures und errors liefern. 

Mich verwirrt das auch, was du da bei AES reingebaut hast. Dieses key_device. Wozu brauchen wir denn überhaupt noch unsere key Passphrase, wenn wir eh key_device in der Größe des Schlüssel (128, 192, oder 256) haben?


----------



## sebi707 (6. Januar 2014)

Mir ist grade noch ein kleiner Fehler in AES aufgefallen. Eigentlich sollte key_device nur keysize/8 groß sein, da keysize in Bits ist. Also bei dem cudaMalloc und cudaMemset sollte keysize/8 stehen.

Die KeyExpansion Funktion von AES erwartet, dass key_device mindstens so viele Bits groß ist wie man in keysize angibt. Daher setze ich zuerst alles auf 0 und kopiere dann unseren Passphrase drüber. Aus dem 256 Bit key_device werden dann die Rundenschlüssel abgeleitet und in key_w gespeichert.


----------



## Crymes (8. Januar 2014)

Hey,
find ich ein interessantes Projekt.
Du machst das alles mit Eclipse cdt ?
Kanst du vll. kurz sagen wie viel schneller Aes in Cuda läuft ? Ich hab mir jetzt nicht den mompletten Thread durchgelesen


----------



## boss3D (8. Januar 2014)

Hi!

Ich arbeite mit der von nVidia zum Download angebotenen Nsight Edition von Eclipse unter Kubuntu 13.10. Ich hatte das Projekt unter Windows 7 mit Visual Studio 2010 Nsight begonnen, war dann aber "so schlau", auf Visual Studio 2013 upzugraden ohne mich vorher darüber zu informieren, dass das noch nicht von CUDA 5.5 unterstützt wird. Da ich aber nicht wieder stundenlange downgraden wollte, blieb mir eben nur Linux/Eclipse (war am Ende aber kein Problem) ...

AES-256 ist auf GPU dank Parallelisierung in folgendem Ausmaß performanter, als ohne: 
9600M GT, 1 Thread / 1 Block: 0.000000 MB/sec
9600M GT, 128 Threads / 200 Blocks: 0.000000 MB/sec
9600M GT, 128 Threads / 800 Blocks: 1.513634 MB/sec
9600M GT, 128 Threads / 6400 Blocks: 2.256983 MB/sec
("vernünftige" Werte auf potenter Hardware folgen noch)
^^ Die ersten beiden Ergebnisse haben mich selbst überrascht, aber scheinbar "muss" AES parallelisiert sein, um auf dieser extremst schwachen GPU überhaupt vernünftige Datenmengen verarbeiten zu können?! Wobei die Blockanzahl interessanter zu sein scheint, als die Threadanzahl.

Im Moment bin ich damit beschäftigt, die Präsentation des Projekts für die Messe auf der FH vorzubereiten, falls sich wer wundert, warum ich hier (vorerst) nichts mehr zu den Codes schreibe.


----------



## Crymes (8. Januar 2014)

Cool, ich hab gerade ein Projekt über Wegfindung am Laufen, werde es nach der Präsentation in einem Thread hier veröffentlichen. Hab auch schon über Parallelisierung nachgedacht, da das mit Java Aparapi ziemlich komfortabel funktionieren soll.
Das Problem ist nur dass meine Tiefensuche nur aus Rekursion besteht ;( ,
mal schauen ob ich die Breitensuche parallel bekomme.
Jetzt hab ich aber erstmal die Arbeit drüber zu schreiben, 9 Seiten Text sind schon fertig  .

Ich mache das auch alles unter Kubuntu 13.10 mit Eclipse, läuft echt prima auf meinem Netbook.


----------



## boss3D (12. Januar 2014)

Ich habe gerade mal testweise RC6 am Benchmarksystem (2x GTX 560 Ti SLI) laufen lassen:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^  Nachdem das Ergebnis sehr ähnlich zu dem von Sebi's GTX 560 Ti ist,  gehe ich davon aus, dass die Codes auch am Benchmarksystem wohl nicht  mit SLI laufen. Ist jetzt aber auch keine Tragik. Interessant wär's halt  gewesen. Meint ihr, ich könnte (rein gedanklich) die Performance für  SLI x2 rechnen? Oder wäre das auch hier eher so wie in Spielen, dass  sich die durch die zweite Grake eher um 20 - 80 % erhöhen würde, aber sicher  nicht verdoppeln?

Weitere Ergebnisse von den anderen Codes werde ich noch hier posten ...


----------



## bingo88 (12. Januar 2014)

SLI funktioniert generell nicht mit CUDA, du musst mehrere GPUs explizit über deinen Code ansprechen. Einfach so "verdoppeln" geht übrigens in der Regel auch nicht, das hängt davon ab, wie gut dein Problem skaliert (z.B. strong vs. weak scaling)


----------



## sebi707 (14. Januar 2014)

Ich würde schon sagen, dass sich die Leistung einfach verdoppeln wird. Da du eh nur die Leistung des Algos selbst misst und nicht das Kopieren zur Grafikkarte und zurück. Außerdem können beide Grafikkarten unabhängig voneinander rechnen und müssen nich untereinander Daten austauschen. Die Performance wird also meiner Meinung nach ziemlich exakt das doppelte betragen.


----------



## boss3D (14. Januar 2014)

^^ Im Moment kämpfen wir (mein Projektteam und ich) sehr damit, die Codes unter Windows (Visual Studio) zum Laufen zu kriegen. In RC6, Serpent, AES-256 und AES-192 ist mir das durch das Hinzufügen einiger Bibliotheken (u. a. cuda_runtime_api.h, device_launch_parameters.h, etc.) gelungen, aber Twofish/MARS (beide mit dem selben std_defs.h Header File) melden irgendwas von wegen lrotr Host-Funktion kann nicht von Device aus aufgerufen werden. Schön und gut, der Fehler ist ein alter bekannter, aber diese Funktion gibt's weder im Twofish- noch im MARS-Code. Und im std_defs.h File kriege ich nen Systax Error, wenn ich da __device__ vor die genannte Funktion schreibe, weil die schon einen Bezeichner hat ... 

Aber das kurioseste ist AES-128! 1:1 der selbe Code, wie seine "großen Brüder" (habe zur Sicherheit sogar extra copy-gepastet), nur eben mit dem klitzekleinen Unterschied, dass key = 128 da steht. Und trotzdem geht der als einziger von den dreien unter Windows nicht. 

Zur Not müssen wir dann bei der Präsentation am PC (Show-PC wird dann über eine GTX 460 verfügen) eine Linux-Live-CD verwenden ...
Außer, hier kann mir bitte noch jemand helfen, die Codes auch unter Windows zum Laufen zu kriegen.


----------



## sebi707 (14. Januar 2014)

Was heißt der AES-128 Code geht unter Windows nicht? Compiliert nicht? Fehlermeldung von CUDA wenn man es startet? Das mit Live-CD könnte auch ein Spaß werden, da zumindest ich nicht wüsste wie man der CD beibringt direkt mit dem richtigen CUDA Treiber von NVidia zu starten.


----------



## boss3D (14. Januar 2014)

Leider ist das Benchmark-System (via VPN/VNC) mal wieder nicht erreichbar, weil "Java unavailable" (habe jetzt ne halbe Stunde herumprobiert, und Java ist in v7 Update 51 definitiv am aktuellen Stand). Mir reicht's langsam damit! Ich weiß die genaue Fehlermeldung nicht mehr auswendig, nur, dass es mich extrem irritiert hatte, dass bei IDENTEM Code nur die 128er Version nicht ging ...

Das WE von 17. - 19. kann/muss ich mich nochmal richtig ins Benchmarking reinhängen, um dann auch alles für die Präsentation auf der Messe am 24. vorzubereiten. Wenn ich in den nächsten Tagen nochmal das Benchmarksystem benutzen kann, poste ich, was genau bei AES-128 als Error kommt. Compiliert hat's sogar, wenn ich mich richtig erinnere.

Das mit der Live-CD habe ich gestern probehalber mit einem 8 GB USB Stick ausprobiert, allerdings war das anscheinend schon zu wenig Platz für Ubuntu + CUDA?! Jedenfalls hat sich CUDA nicht installieren lassen und bei allen von mir durchprobierten Ordnern/Verzeichnissen hieß es entweder, 'nicht groß genug' oder 'keine Schreibrechte'. Das wird wirklich noch ein "Spaß".


----------



## sebi707 (15. Januar 2014)

Mit USB Stick könnte das ganze schon eher was werden. Aber das ist ja dann keine Live-CD mehr sondern einfach eine Installation auf den USB-Stick. Oder was hast du da probiert? Wenn du nur den USB-Stick ansteckst und die Live-CD startest dann läuft alles vom RAM aus und wird wohl tatsächlich nicht genug Platz haben um CUDA zu installieren.

Edit: Warum brauchst du überhaupt Java auf dem Benchmark System? Eigentlich doch nur für Eclipse aber das compilieren kann man zur Not auch über die Shell (ins Verzeichnis mit den *.cu Dateien wechseln und 'nvcc *alle .cu Dateien mit Leerzeichen getrennt hier*' eintippen) oder auf einem anderen PC machen.


----------



## boss3D (15. Januar 2014)

Eigentlich hatte ich eine richtige Installation am USB-Stick vorgehabt, und bin auch davon ausgegangen, dass der Linux Live USB Creator das auch machen würde ... aber als ich dann am Laptop von dem Stick Ubuntu gestartet habe, wurde ich gleich gefragt, ob ich es (am Laptop) installieren oder einfach nur als Live Version ausprobieren wolle.
Das muss ich mir nochmal anschauen, wie ich das wirklich fix am USB-Stick installieren kann ...

Jave bräuchte ich nicht am Benchmarksystem, sondern hier auf meinem lokalen für den browserbasierten Aufbau der VPN-Verbindung:




			Dieser Inhalt steht nur eingeloggten Mitgliedern zur Verfügung.
        



^^ Hier scheitert's (seit ca. 3 Tagen). Dabei habe ich extra erst gestern Java auf's aktuelle Update 51 geupdatet. 
Aber eine laufende Verbindung zum Benchmarksystem herzustellen war eh immer schon mehr Glück als sonst was ... _*seufz*_


----------

