/* ===========================================================================
 *  demo.c - Beispielquellcode zur CitadelCore-Vorfuehrung
 *  AetherSec, Stand 14.10.2026
 * ===========================================================================
 *
 *  WAS DIESE DATEI IST
 *  Lehrmaterial. Drei kleine Funktionen, an denen sich zeigen laesst, welche
 *  Programmteile man mit CitadelCore gezielt haerten kann. Die Datei ist
 *  bewusst kurz und uebersetzt sich mit jedem Standard-C-Compiler.
 *
 *  WAS DIESE DATEI NICHT IST
 *  Kein CitadelCore-Produktquellcode. Compiler, LLVM-Passes und Laufzeit-
 *  bibliothek von CitadelCore sind hier nicht enthalten. Auch keine
 *  empfohlene Lizenzarchitektur fuer ein Produkt: eine echte Lizenzpruefung
 *  gehoert nicht so aufgebaut, wie es hier zur Anschauung geschieht.
 *
 *  ALLE WERTE SIND OEFFENTLICHE TESTDATEN
 *  Die Konstanten unten stehen offen in dieser Datei und sind deshalb kein
 *  Geheimnis. Sie dienen nur dazu, dass der Ablauf nachvollziehbar und das
 *  Ergebnis reproduzierbar ist.
 *
 *  REFERENZ-BUILD (ohne Haertung)
 *      clang -O1 -fno-inline -o demo.exe demo.c
 *
 *  BUILD MIT CITADELCORE (Windows)
 *      citadel --compile demo.c -o demo.exe --level max --report
 *
 *  Ohne CitadelCore bleiben die Annotationen unten wirkungslos: der Compiler
 *  ignoriert sie, das Programm verhaelt sich identisch.
 * ======================================================================== */

#include <stdio.h>
#include <string.h>

/* Die Annotationen sind clang-spezifisch. Mit jedem anderen Compiler
 * entfalten sie keine Wirkung, und die Datei uebersetzt sich unveraendert. */
#if defined(__clang__)
#define CC_VIRTUALIZE __attribute__((annotate("citadel_virtualize")))
#define CC_PROTECT    __attribute__((annotate("citadel_protect")))
#define CC_PUBLIC     __attribute__((annotate("citadel_public")))
#else
#define CC_VIRTUALIZE
#define CC_PROTECT
#define CC_PUBLIC
#endif

/* ---------------------------------------------------------------------------
 *  1) check_demo_license - demonstrative Pruefentscheidung
 * ---------------------------------------------------------------------------
 *  Reine Ganzzahlarithmetik, keine Aufrufe, kein Speicherzugriff. Damit
 *  erfuellt die Funktion die dokumentierten Bedingungen des Virtualisierungs-
 *  passes (siehe WINDOWS.md, Abschnitt "Code-Virtualisierung").
 *
 *  Oeffentliche Testdaten:
 *      check_demo_license(4660, 22136, 123)  ->  1   (angenommen)
 *      check_demo_license(4660, 22136, 124)  ->  0   (abgelehnt)
 *      check_demo_license(0, 0, 0)           ->  0   (abgelehnt)
 *
 *  Gerechnet wird in unsigned int. Der Ueberlauf ist dort definiert
 *  (Modulo 2^32), es gibt also kein undefiniertes Verhalten.
 *  Eingaben werden auf 0..65535 begrenzt.
 * ------------------------------------------------------------------------ */
CC_VIRTUALIZE
int check_demo_license(int group_a, int group_b, int group_c)
{
    unsigned a = (unsigned)(group_a & 0xFFFF);
    unsigned b = (unsigned)(group_b & 0xFFFF);
    unsigned c = (unsigned)(group_c & 0xFFFF);
    unsigned state = 0x2F1E3D4Cu;
    int round;

    for (round = 0; round < 8; round++) {
        state = state * 16777619u;          /* FNV-Primzahl, oeffentlich */
        state = state ^ a;
        state = (state << 7) | (state >> 25);
        state = state + b;
        state = state ^ (state >> 11);
        state = state + c;
    }

    /* 0xB9C1F07E ist der oeffentliche Sollwert dieser Vorfuehrung. */
    return (state == 0xB9C1F07Eu) ? 1 : 0;
}

/* ---------------------------------------------------------------------------
 *  2) calculate_quote - kleine deterministische Ganzzahlberechnung
 * ---------------------------------------------------------------------------
 *  Preis einer Bestellung in Cent. Bewusst ohne Gleitkomma, damit das
 *  Ergebnis auf jeder Maschine gleich ist.
 *
 *  Definierte Wertebereiche (ausserhalb wird geklemmt, nie ueberlaufen):
 *      units            1 .. 10000
 *      unit_price_cents 1 .. 1000000
 *      discount_percent 0 .. 90
 *
 *  Groesstmoegliches Zwischenergebnis: 10000 * 1000000 = 10^10. Das passt
 *  nicht in 32 Bit, deshalb rechnet die Funktion in long long und gibt den
 *  auf 2.000.000.000 begrenzten Betrag als int zurueck.
 *
 *  Oeffentliche Testdaten:
 *      calculate_quote(10, 4999, 0)   ->  49990
 *      calculate_quote(10, 4999, 10)  ->  44991
 *      calculate_quote(3, 7499, 25)   ->  16873
 * ------------------------------------------------------------------------ */
CC_PROTECT
int calculate_quote(int units, int unit_price_cents, int discount_percent)
{
    long long gross;
    long long net;

    if (units < 1) units = 1;
    if (units > 10000) units = 10000;
    if (unit_price_cents < 1) unit_price_cents = 1;
    if (unit_price_cents > 1000000) unit_price_cents = 1000000;
    if (discount_percent < 0) discount_percent = 0;
    if (discount_percent > 90) discount_percent = 90;

    gross = (long long)units * (long long)unit_price_cents;
    net = gross - (gross * (long long)discount_percent) / 100;

    if (net > 2000000000LL) net = 2000000000LL;
    return (int)net;
}

/* ---------------------------------------------------------------------------
 *  3) get_demo_message - unkritische Beispiel-Zeichenkette
 * ---------------------------------------------------------------------------
 *  Gibt einen von drei festen Texten zurueck. Diese Texte sind mit
 *  citadel_public markiert: sie sollen auch dann lesbar bleiben, wenn mit
 *  einem Freischaltgeheimnis gebaut wurde und dieses noch nicht gesetzt ist.
 *  Ohne die Markierung wuerde CitadelCore auch sie verschluesseln.
 *
 *  Die Funktion gibt einen Zeiger zurueck und wird deshalb nicht
 *  virtualisiert - Speicherzugriffe lehnt der Virtualisierungspass
 *  ausdruecklich ab, statt sie still falsch zu uebersetzen.
 * ------------------------------------------------------------------------ */
static CC_PUBLIC const char k_msg_ok[]      = "Demo-Pruefung angenommen.\n";
static CC_PUBLIC const char k_msg_denied[]  = "Demo-Pruefung abgelehnt.\n";
static CC_PUBLIC const char k_msg_usage[]   =
    "Aufruf: demo GRUPPE_A GRUPPE_B GRUPPE_C\n"
    "Beispiel: demo 4660 22136 123\n";

const char *get_demo_message(int code)
{
    if (code == 1) return k_msg_ok;
    if (code == 0) return k_msg_denied;
    return k_msg_usage;
}

/* ------------------------------------------------------------------------ */

static int parse_int(const char *text, int fallback)
{
    int value = 0;
    int digits = 0;
    size_t i;

    if (text == NULL) return fallback;
    for (i = 0; text[i] != '\0' && i < 9; i++) {
        if (text[i] < '0' || text[i] > '9') return fallback;
        value = value * 10 + (text[i] - '0');
        digits++;
    }
    return digits > 0 ? value : fallback;
}

int main(int argc, char **argv)
{
    int a, b, c, verdict, quote;

    if (argc < 4) {
        fputs(get_demo_message(-1), stdout);
        return 2;
    }

    a = parse_int(argv[1], 0);
    b = parse_int(argv[2], 0);
    c = parse_int(argv[3], 0);

    verdict = check_demo_license(a, b, c);
    fputs(get_demo_message(verdict), stdout);

    quote = calculate_quote(10, 4999, verdict ? 10 : 0);
    printf("Angebot: %d Cent\n", quote);

    return verdict ? 0 : 1;
}
