Codice in numeri primi

Nell'ottobre del 1999, un gruppo guidato dall'allora sedicenne norvegese Jon Lech Johansen rilasciò il programma DeCSS per aggirare il sistema di protezione CSS (Content Scramble System) utilizzato per la riproduzione dei DVD. Il CSS si basava su una crittografia a 40 bit, le cui chiavi venivano distribuite ai produttori autorizzati, per limitare la riproduzione dei DVD. Poiché la distribuzione del codice era soggetta al DMCA statunitense ed era quindi illegale, gli attivisti cercarono un modo per camuffare il codice sotto forma di entità matematica.


Phil Carmody ha quindi costruito un numero primo che, una volta interpretato in binario dopo la decompressione gzip, contiene il codice sorgente completo di DeCSS. Il nucleo dell'algoritmo DeCSS può essere implementato in TypeScript come segue, dove le operazioni sui bit mappano direttamente la logica di decrittazione del settore.:

function CSSdescramble(sec: Uint8Array, key: Uint8Array): void {
    let t1: number, t2: number, t3: number, t4: number, t5: number, t6: number;
    const end = 0x800;

    t1 = (key[0] ^ sec[0x54]) | 0x100;
    t2 = key[1] ^ sec[0x55];

    const keyView = new DataView(key.buffer, key.byteOffset);
    const secView = new DataView(sec.buffer, sec.byteOffset);

    t3 = (keyView.getUint32(2, true) ^ secView.getUint32(0x56, true)) >>> 0;
    t4 = t3 & 7;
    t3 = (t3 * 2 + 8 - t4) >>> 0;

    let offset = 0x80;
    t5 = 0;

    while (offset < end) {
        t4 = CSStab2[t2] ^ CSStab3[t1];
        t2 = t1 >>> 1;
        t1 = ((t1 & 1) << 8) ^ t4;
        t4 = CSStab5[t4];
        t6 = (((((((t3 >>> 3) ^ t3) >>> 1) ^ t3) >>> 8) ^ t3) >>> 5) & 0xff;
        t3 = (((t3 << 8) >>> 0) | t6) >>> 0;
        t6 = CSStab4[t6];
        t5 += t6 + t4;

        sec[offset] = CSStab1[sec[offset]] ^ (t5 & 0xff);
        t5 >>>= 8;
        offset++;
    }
}

Il principio alla base dei numeri primi è quello di interpretare l'intero codice sorgente come un singolo numero intero. Poiché nessun file dato è mai un numero primo, il numero viene artificialmente incrementato con byte aggiuntivi (padding). Questo padding viene incrementato in un ciclo finché un test di primalità, come il test di Miller-Rabin, non conferma che il numero è primo. Il seguente generatore utilizza il codice DeCSS descritto sopra e cerca una rappresentazione corrispondente di un numero primo.:

import { isPrime } from 'crypto-utils-lib'; // Hypothetical library for primality testing

async function generateIllegalPrime(code: string): Promise<bigint | null> {
    const encoder = new TextEncoder();
    const bytes = encoder.encode(code);

    let hexBase = Array.from(bytes)
        .map(b => b.toString(16).padStart(2, '0'))
        .join('');

    // Start bei 1, da 0x00 immer gerade und damit keine Primzahl ist
    for (let i = 1; i < 256; i++) {
        const candidateHex = hexBase + i.toString(16).padStart(2, '0');
        const candidateInt = BigInt('0x' + candidateHex);

        if (await isPrime(candidateInt)) {
            return candidateInt;
        }
    }
    return null;
}

const source = `void CSSdescramble(unsigned char *sec, unsigned char *key) { ... }`;
generateIllegalPrime(source).then(p => console.log(p));

Il trucco del numero primo non fu mai oggetto di un processo separato, né ce n'era bisogno. Sebbene il numero primo originale di Carmody avesse 1401 cifre, era troppo piccolo per le classifiche dei numeri primi più grandi dell'epoca. In seguito, creò una versione di 1905 cifre, artificialmente gonfiata con byte nulli, per raggiungere il decimo posto nella classifica ECPP . Questo successo dimostrò l'impossibilità di censurare la matematica pura, poiché il numero si guadagnò il suo posto nella lista esclusivamente in base alle sue proprietà matematiche.

Indietro