الترميز بالأعداد الأولية

في أكتوبر/تشرين الأول 1999، أطلقت مجموعة بقيادة النرويجي جون ليخ يوهانسن، البالغ من العمر آنذاك 16 عامًا، برنامج DeCSS للتحايل على نظام تشفير المحتوى (CSS) لحماية تشغيل أقراص DVD. كان نظام CSS يستخدم تشفيرًا من 40 بت، وُزِّعت مفاتيحه على الشركات المصنعة المرخصة، لتقييد تشغيل أقراص DVD. ولأن توزيع الشفرة يندرج تحت قانون الألفية الرقمية لحقوق المؤلف (DMCA) الأمريكي، وكان محظورًا قانونًا، سعى النشطاء إلى إيجاد طرق لإخفاء الشفرة في صورة كيان رياضي.


ثم قام فيل كارمودي بإنشاء عدد أولي، والذي عند تفسيره ثنائيًا بعد فك ضغط gzip، يحتوي على الشفرة المصدرية الكاملة لخوارزمية DeCSS. يمكن تنفيذ جوهر خوارزمية DeCSS بلغة TypeScript كما يلي، حيث تُطابق عمليات البت منطق فك تشفير القطاعات مباشرةً.:

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

يقوم مبدأ الأعداد الأولية على تفسير كامل شفرة المصدر كعدد صحيح واحد. ولأن أي ملف لا يُمثل عددًا أوليًا، يُضاف إلى هذا العدد بايتات إضافية (حشو). تُزاد هذه البايتات في حلقة تكرارية حتى يُؤكد اختبار أولية، مثل اختبار ميلر-رابين، أن العدد أولي. يستخدم المُولِّد التالي شفرة DeCSS المذكورة أعلاه ويبحث عن تمثيل عددي أولي مُناسب.:

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

لم تكن خدعة الأعداد الأولية موضوعًا لقضية منفصلة، ولم تكن هناك حاجة لذلك. فرغم أن العدد الأولي الأصلي الذي ابتكره كارمودي كان يتألف من 1401 رقمًا، إلا أنه كان صغيرًا جدًا ليُدرج ضمن قوائم أكبر الأعداد الأولية في ذلك الوقت. لاحقًا، ابتكر نسخةً تتألف من 1905 رقمًا، مُضخّمة اصطناعيًا ببايتات فارغة، ليحقق المركز العاشر في تصنيف ECPP . أثبت هذا النجاح استحالة فرض رقابة على الرياضيات البحتة، إذ استحق العدد مكانه في القائمة استنادًا إلى خصائصه الرياضية فقط.

عودة