C: निरंतर समय कोड द्वारा AES FIPS -197 उप-तालिकाएँ प्रतिस्थापित करता है


17

में FIPS-197 ( उन्नत एन्क्रिप्शन स्टैंडर्ड , एईएस के रूप में जाना जाता है), यह का भारी इस्तेमाल किया जाता है SubBytes, जो के रूप में लागू किया जा सकता

unsigned char SubBytes(unsigned char x) {
static const unsigned char t[256] = {
  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};
return t[x];}

यह कार्य मनमाना नहीं है; यह एक प्रतिवर्ती मानचित्रण है, जिसमें एक गैल्वेन फील्ड में एक उलटफेर शामिल है, जिसके बाद एक परिशोधन परिवर्तन होता है। सभी विवरण FIPS -197 खंड 5.1.1 या यहां खंड 4.2.1 (थोड़ा अलग नाम के तहत) में हैं।

तालिका के रूप में कार्यान्वयन के साथ एक समस्या यह है कि यह तथाकथित कैश-टाइमिंग हमलों के लिए खुलता है ।

इस प्रकार आपका मिशन उपरोक्त SubBytes()कार्य के लिए एक सटीक प्रतिस्थापन तैयार करना है , जो निरंतर समय के व्यवहार को प्रदर्शित करता है; हम मान लेंगे कि ऐसा मामला है जब इनपुट xके आधार पर कुछ भी SubBytesउपयोग नहीं किया जाता है:

  • एक सरणी सूचकांक के रूप में,
  • नियंत्रण से आपरेण्ड के रूप में if, while, for, case, या ऑपरेटर ?:;
  • ऑपरेटरों के किसी भी संकार्य के रूप में &&, ||, !, ==, !=, <,> , <=,>= , *, /, %,
  • ऑपरेटरों की सही संकार्य के रूप में >>, <<, *=,/= , %=,<<= , >>=

जीतने वाली प्रविष्टि सबसे कम लागत के साथ एक होगी, जो इनपुट-निर्भर डेटा पथ में निष्पादित ऑपरेटरों की संख्या से प्राप्त होती है, जो कि गैर-संचालक के लिए 5 वजन के साथ -और ~साथ ही साथ<<1 , >>1, +1, -1, अन्य सभी संचालकों के लिए 7 का वजन, अन्य गणनाओं के साथ बदलाव, या अन्य स्थिरांक के प्रकार / जोड़ (प्रकार कास्ट और पदोन्नति मुफ्त हैं)। सिद्धांत रूप से, उस लागत को अनियंत्रित छोरों (यदि कोई हो), और इनपुट से स्वतंत्र द्वारा अपरिवर्तित किया जाता है x। टाई-ब्रेकर के रूप में, व्हाट्सएप और टिप्पणियों को हटाने के बाद सबसे छोटे कोड के साथ उत्तर जीतता है।

मैं वर्ष 2013, यूटीसी में जितनी जल्दी हो सके उत्तर के रूप में एक प्रविष्टि नामित करने की योजना बना रहा हूं। मैं उन भाषाओं के उत्तरों पर विचार करूंगा जिनके बारे में मुझे कुछ ज्ञान है, उन्हें सी के लिए सीधे अनुवाद के रूप में रैंकिंग करना आकार के लिए अनुकूलित नहीं है।

मुक्त कलाकारों और प्रोन्नति, और आकार की रैंकिंग के प्रारंभिक चूक के लिए +1और -1इष्ट ऑपरेटरों में माफी । ध्यान दें कि *दोनों जब एकात्मक, और गुणा के रूप में निषिद्ध हैं।


1
यह देखते हुए कि लुकअप निशुल्क है क्योंकि आप उन्हें स्थिरांक के रूप में इनलाइन कर सकते हैं।
पीटर टेलर

"वर्ष 2013 की शुरुआत में, UTC" - क्या यह समय क्षेत्र से अधिक दिलचस्प नहीं होगा?
पाओलो एबरमन

@ Pa @loEbermann: मेरा इरादा अब स्पष्ट होना चाहिए।
fgrieu

जवाबों:


13

स्कोर: 940 933 926 910, फील्ड टॉवर दृष्टिकोण

public class SBox2
{
    public static void main(String[] args)
    {
        for (int i = 0; i < 256; i++) {
            int s = SubBytes(i);
            System.out.format("%02x  ", s);
            if (i % 16 == 15) System.out.println();
        }
    }

    private static int SubBytes(int x) {
        int fwd;
        fwd  = 0x010001 & -(x & 1); x >>= 1; //   7+5+7+5+ | 24+
        fwd ^= 0x1d010f & -(x & 1); x >>= 1; // 7+7+5+7+5+ | 31+
        fwd ^= 0x4f020b & -(x & 1); x >>= 1; // 7+7+5+7+5+ | 31+
        fwd ^= 0x450201 & -(x & 1); x >>= 1; // 7+7+5+7+5+ | 31+
        fwd ^= 0xce080d & -(x & 1); x >>= 1; // 7+7+5+7+5+ | 31+
        fwd ^= 0xa20f0f & -(x & 1); x >>= 1; // 7+7+5+7+5+ | 31+
        fwd ^= 0xc60805 & -(x & 1); x >>= 1; // 7+7+5+7+5+ | 31+
        fwd ^= 0x60070e & -x;                // 7+7+5+     | 19+

        // Running total so far: 229

        int p1;
        {
            int ma = fwd;
            int mb = fwd >> 16;         // 7+         | 7+
            p1  = ma & -(mb&1); ma<<=1; //   7+5+7+5+ | 24+
            p1 ^= ma & -(mb&2); ma<<=1; // 7+7+5+7+5+ | 31+
            p1 ^= ma & -(mb&4); ma<<=1; // 7+7+5+7+5+ | 31+
            p1 ^= ma & -(mb&8);         // 7+7+5+7+   | 26+
            int t = p1 >> 3;            // 7+         | 7+
            p1 ^= (t >> 1) ^ (t & 0xe); // 7+5+7+7+   | 26+
        }

        // Running total so far: 229 + 152 = 381

        int y3, y2, y1, y0;
        {
            int Kinv = (fwd >> 20) ^ p1;     // 7+7+
            int w0 = Kinv & 1; Kinv >>= 1;   // 7+5+
            int w1 = Kinv & 1; Kinv >>= 1;   // 7+5+
            int w2 = Kinv & 1; Kinv >>= 1;   // 7+5+
            int w3 = Kinv & 1;               // 7+

            int t0 = w1 ^ w0 ^ (w2 & w3);      // 7+7+7+
            int t1 = w2 ^ (w0 | w3);           // 7+7+
            int t2 = t0 ^ t1;                  // 7+

            y3 = t2 ^ (t1 & (w1 & w3));        // 7+7+7+
            y2 = t0 ^ (w0 | t2);               // 7+7+
            y1 = w0 ^ w3 ^ (t1 & t0);          // 7+7+7+
            y0 = w3 ^ (t0 | (w1 ^ (w0 | w2))); // 7+7+7+7


        }

        // Running total so far: 381 + 24*7 + 3*5 = 564

        int p2;
        {
            int ma = fwd;
            p2  = ma & -y0; ma<<=1;       //   7+5+5+ | 17+
            p2 ^= ma & -y1; ma<<=1;       // 7+7+5+5+ | 24+
            p2 ^= ma & -y2; ma<<=1;       // 7+7+5+5+ | 24+
            p2 ^= ma & -y3;               // 7+7+5+   | 19+
            int t = p2 >> 3;              // 7+       | 7+
            p2 ^= (t >> 1) ^ (t & 0xe0e); // 7+5+7+7+ | 26
        }

        // Running total so far: 564 + 117 = 681

        int inv8;
        inv8  =  31 & -(p2 & 1);           //   7+5+7+   | 19+
        inv8 ^= 178 & -(p2 & 2); p2 >>= 2; // 7+7+5+7+7+ | 33+
        inv8 ^= 171 & -(p2 & 1);           // 7+7+5+7+   | 26+
        inv8 ^=  54 & -(p2 & 2); p2 >>= 6; // 7+7+5+7+7+ | 33+
        inv8 ^= 188 & -(p2 & 1);           // 7+7+5+7+   | 26+
        inv8 ^=  76 & -(p2 & 2); p2 >>= 2; // 7+7+5+7+7+ | 33+
        inv8 ^= 127 & -(p2 & 1);           // 7+7+5+7+   | 26+
        inv8 ^= 222 & -(p2 & 2);           // 7+7+5+7    | 26+

        return inv8 ^ 0x63;                // 7+         | 7+

        // Grand total: 681 + 229 = 910
    }
}

संरचना अनिवार्य रूप से बोयार और पेराल्टा के कार्यान्वयन के समान है - GF (2 ^ 8) में उलटा को कम करने के लिए GF (2 ^ 4) में उलटा करें, इसे एक रैखिक प्रस्तावना, एक गैर-रेखीय निकाय और एक रेखीय विचलन में तोड़ दें, और फिर उन्हें अलग से छोटा करें। मैं बिट निष्कर्षण के लिए कुछ दंड का भुगतान करता हूं, लेकिन मैं समानांतर रूप से संचालन करने में सक्षम हूं (बिट्स के कुछ विवेकपूर्ण पैडिंग के साथ)fwd )। विस्तृत रूप में...

पृष्ठभूमि

जैसा कि समस्या वर्णन में उल्लेख किया गया है, एस-बॉक्स में गैल्वेन फ़ील्ड GF (2 ^ 8) के एक विशेष कार्यान्वयन में एक व्युत्क्रम शामिल है, जिसके बाद एक परिशोधन परिवर्तन होता है। यदि आप जानते हैं कि उन दोनों का क्या मतलब है, तो इस अनुभाग को छोड़ दें।

एक चक्कर (या रैखिक) परिवर्तन एक फ़ंक्शन है f(x)जो सम्मान करता है f(x + y) = f(x) + f(y)और f(a*x) = a*f(x)

एक फ़ील्ड Fदो विशेष तत्वों के साथ तत्वों का एक समूह है, जिसे हम कॉल करेंगे 0और 1, और दो ऑपरेटर, जिसे हम कॉल करेंगे +और *, जो विभिन्न गुणों का सम्मान करता है। इस खंड में, मान लेते हैं कि x, y, और zके तत्व हैंF

  • के तत्वों Fके तहत प्रपत्र एक अबेलियन समूह +के साथ 0पहचान के रूप में: यानी x + yका एक तत्व है F; x + 0 = 0 + x = x; प्रत्येक xमें एक समान है -xकि x + (-x) = (-x) + x = 0; x + (y + z) = (x + y) + z; और x + y= y + x
  • के तत्वों Fके अलावा अन्य 0के तहत प्रपत्र एक अबेलियन समूह *के साथ 1पहचान के रूप में।
  • गुणन इसके अलावा अधिक वितरित करता है x * (y + z) = (x * y) + (x * z):।

यह पता चला है कि परिमित क्षेत्रों पर कुछ काफी गंभीर सीमाएँ हैं:

  • उनके पास कई ऐसे तत्व होने चाहिए जो एक प्रमुख शक्ति है।
  • वे एक ही आकार के अन्य सभी परिमित क्षेत्रों के साथ आइसोमोर्फिक हैं (अर्थात किसी दिए गए आकार का वास्तव में केवल एक परिमित क्षेत्र है, और कोई भी अन्य बस रिलेबिलिंग हैं; उस फ़ील्ड को कॉल करें GF (p ^ k) जहां pप्रधान है;k शक्ति है) ।
  • बहुसांस्कृतिक समूह के F\{0}तहत *चक्रीय है; यानी कम से कम एक तत्व gऐसा है कि हर तत्व एक शक्ति हैg
  • 1 से अधिक शक्तियों kके लिए प्राइम ऑर्डर के क्षेत्र के क्रम के यूनीवेट बहुपद के रूप में एक प्रतिनिधित्व है । Eg GF (2 ^ 8) का xGF (2) से अधिक के बहुपदों के संदर्भ में प्रतिनिधित्व है । वास्तव में आमतौर पर एक से अधिक प्रतिनिधित्व होते हैं। x^7 * xजीएफ में विचार करें (2 ^ 8); यह कुछ क्रम -7 बहुपद के बराबर होना चाहिए, लेकिन कौन सा? बहुत सारे विकल्प हैं जो सही संरचना देते हैं; एईएस बनाने का विकल्प चुनता है x^8 = x^4 + x^3 + x + 1(लेक्सिकोग्राफिक रूप से सबसे छोटा बहुपद जो काम करता है)।

तो हम GF के उस विशेष प्रतिनिधित्व में एक व्युत्क्रम की गणना कैसे करते हैं (2 ^ 8)? सीधे तौर पर निपटना एक समस्या है, इसलिए हमें इसे तोड़ने की जरूरत है।

फील्ड टॉवर: GF के संदर्भ में GF (2 ^ 8) का प्रतिनिधित्व करते हुए (2 ^ 4)

GF (2 ^ 8) का प्रतिनिधित्व करने के बजाय GF (2) पर 8 शब्दों के बहुपद के साथ हम इसे GF (2 ^ 4) के 2 शब्दों के बहुपद के साथ प्रतिनिधित्व कर सकते हैं। इस बार हमें एक रैखिक बहुपद चुनने की आवश्यकता है x^2। मान लीजिए हम चुनते हैं x^2 = px + q। फिर(ax + b) * (cx + d) = (ad + bc + acp)x + (bd + acq)

क्या इस प्रतिनिधित्व में विलोम खोजना आसान है? अगर (cx + d) = (ax + b)^-1हमें एक साथ समीकरण मिलते हैं

  • ad + (b + ap)c = 0
  • bd + (aq)c = 1

चलो D = [b(b+ap) + a^2 q]और सेट c = a * D^-1;d = (b + ap) * D^-1। इसलिए हम GF (2 ^ 4) में रूपांतरण की लागत के लिए GF (2 ^ 8), उलटा और GF (2 ^ 4) में कुछ जोड़ और गुणा, और एक रूपांतरण वापस कर सकते हैं। भले ही हम उलटा किसी तालिका के माध्यम से करते हैं, हमने तालिका का आकार 256 से घटाकर 16 कर दिया है।

कार्यान्वयन का विवरण

GF (4) का प्रतिनिधित्व करने के लिए हम तीन बहुपदों को कम करने के लिए चुन सकते हैं x^4:

  • x^4 = x + 1
  • x^4 = x^3 + 1
  • x^4 = x^3 + x^2 + x + 1

गुणन के कार्यान्वयन में सबसे महत्वपूर्ण अंतर है। तीन में से किसी के लिए (जो poly3, 9, एफ के अनुरूप है ) निम्नलिखित काम करेगा:

// 14x &, 7x unary -, 3x <<1, 3x >>1, 3x >>3, 6x ^ gives score 226
int mul(int a, int b) {
    // Call current values a = a0, b = b0
    int p = a & -(b & 1);
    a = ((a << 1) ^ (poly & -(a >> 3))) & 15;
    b >>= 1;
    // Now p = a0 * (b0 mod x); a = a0 x; b = b0 div x

    p ^= a & -(b & 1);
    a = ((a << 1) ^ (poly & -(a >> 3))) & 15;
    b >>= 1;
    // Now p = a0 * (b0 mod x^2); a = a0 x^2; b = b0 div x^2

    p ^= a & -(b & 1);
    a = ((a << 1) ^ (poly & -(a >> 3))) & 15;
    b >>= 1;
    // Now p = a0 * (b0 mod x^3); a = a0 x^3; b = b0 div x^3

    p ^= a & -(b & 1);
    // p = a0 * b0

    return p;
}

हालाँकि, अगर हम चुनते हैं कि हम poly = 3अतिप्रवाह को अधिक कुशलता से संभाल सकते हैं क्योंकि इसकी एक अच्छी संरचना है: कोई डबल-ओवरफ़्लो नहीं है, क्योंकि दोनों इनपुट घन हैं और x^6 = x^2 (x + 1)घन भी हैं। इसके अलावा, हम इनकी शिफ्ट को बचा सकते हैं b: चूंकि हम ओवरफ्लो को अंतिम तक छोड़ रहे हैं, इसलिए इसमें 1 या 1 के a0 x^2समान कोई सेट बिट नहीं है xऔर इसलिए हम इसे -1 के बजाय -4 के साथ मास्क कर सकते हैं। परिणाम है

// 10x &, 4x unary -, 3x <<1, 1x >>1, 1x >>3, 5x ^ gives score 152
int mul(int a, int b) {
    int p;
    p  = a & -(b & 1); a <<= 1;
    p ^= a & -(b & 2); a <<= 1;
    p ^= a & -(b & 4); a <<= 1;
    p ^= a & -(b & 8);
    // Here p = a0 * b0 but with overflow, which we need to bring back down.

    int t = p >> 3;
    p ^= (t >> 1) ^ (t & 0xe);
    return p & 15;
}

हमें अभी भी pऔर के मूल्यों को चुनने की आवश्यकता हैq GF से अधिक GF (2 ^ 8) के प्रतिनिधित्व (2 ^ 4) के लिए है, लेकिन हम उन पर कई बाधाओं जरूरत नहीं है। एक बात जो मायने रखती है वह यह है कि हम अपने मूल प्रतिनिधित्व के बिट्स से काम करने वाले प्रतिनिधित्व के बिट्स तक एक रैखिक कार्य कर सकते हैं। यह दो कारणों से मायने रखता है: सबसे पहले, रैखिक परिवर्तन करना आसान है, जबकि एक गैर-रैखिक परिवर्तन को पूरे एस-बॉक्स को अनुकूलित करने के लिए कठिनाई में अनुकूलन के बराबर अनुकूलन की आवश्यकता होगी; दूसरी बात, क्योंकि हम कुछ साइड लाभ प्राप्त कर सकते हैं। संरचना को फिर से बनाने के लिए:

GF256 SubBytes(GF256 x) {
    GF16 a, b, t, D, Dinv, c, d;

    (a, b) = f(x); // f is linear

    t = b + a * p;
    D = b * t + a * a * q;
    Dinv = inverse_GF16(D);
    c = a * Dinv;
    d = t * Dinv;

    return finv(c, d); // finv is also linear
}

यदि बिट्स xहैं x7 x6 ... x0तो चूंकि परिवर्तन रैखिक है, इसलिए हमें मिलता है a = f({x7}0000000 + 0{x6}000000 + ... + 0000000{x0}) = f({x7}0000000) + f(0{x6}000000) + ... + f(0000000{x0})। इसे स्क्वायर करें और हमें वह स्थान मिलता है a^2 = f({x7}0000000)^2 + f(0{x6}000000)^2 + ... + f(0000000{x0})^2जहां क्रॉस-शब्द रद्द हो जाते हैं (क्योंकि GF (2) में 1 + 1 = 0)। तो a^2एक रैखिक समारोह के रूप में भी गणना की जा सकती है x। हम प्राप्त करने के लिए आगे रैखिक परिवर्तन को बढ़ा सकते हैं:

GF256 SubBytes(GF256 x) {
    GF16 a, b, t, a2q, D, Dinv, c, d;

    (a, b, t, a2q) = faug(x);

    D = b * t + a2q;
    Dinv = inverse_GF16(D);
    c = a * Dinv;
    d = t * Dinv;

    return finv(c, d);
}

और हम तीन गुणा और एक जोड़ के नीचे हैं। हम गुणन कोड को दो गुणा करने के लिए बढ़ा सकते हैंDinvसमानांतर में । तो हमारी कुल लागत एक आगे रैखिक परिवर्तन, एक जोड़, दो गुणा, GF में एक व्युत्क्रम (2 ^ 4), और एक पीछे रैखिक परिवर्तन है। हम एस-बॉक्स के उलटा रैखिक परिवर्तन में रोल कर सकते हैं और अनिवार्य रूप से मुफ्त में प्राप्त कर सकते हैं।

रेखीय परिवर्तनों के लिए गुणांक की गणना बहुत दिलचस्प नहीं है, और न ही यहां एक मुखौटा और एक पारी को बचाने के लिए सूक्ष्म अनुकूलन है। शेष दिलचस्प भाग का अनुकूलन हैinverse_GF16। 4 बिट्स से 4 बिट्स तक 2 ^ 64 अलग-अलग फ़ंक्शन हैं, इसलिए प्रत्यक्ष अनुकूलन के लिए बहुत मेमोरी और समय की आवश्यकता होती है। मैंने जो किया है वह 4 बिट्स से 1 बिट तक 4 कार्यों पर विचार करने के लिए है, किसी भी एक फ़ंक्शन के लिए अनुमत कुल लागत पर एक कैप रखें (63 प्रति फ़ंक्शन की अधिकतम लागत के साथ मैं एक मिनट के तहत सभी उपयुक्त अभिव्यक्तियों की गणना कर सकता हूं), और कार्यों के प्रत्येक tuple के लिए सामान्य उपसंचाई उन्मूलन करते हैं। 25 मिनट की क्रंचिंग के बाद, मुझे पता चला कि उस कैप के साथ सबसे अच्छा उलटा संभव है जिसकी कुल लागत 133 (आउटपुट का औसत 33.25 प्रति बिट है, जो यह देखते हुए बुरा नहीं है कि किसी भी व्यक्तिगत बिट के लिए सबसे सस्ती अभिव्यक्ति 35 है) ।

मैं अभी भी GF (2 ^ 4) में व्युत्क्रम को कम करने के लिए अन्य तरीकों के साथ प्रयोग कर रहा हूं, और एक दृष्टिकोण जो टॉप-डाउन के बजाय नीचे-अप बनाता है, 133 से 126 तक सुधार हुआ है।


बहुत खुबस! मैं यह काम करता है की पुष्टि! एक विवरण: 8 वें & 1छंटनी की जा सकती है (esp। यदि xहै unsigned char; CHAR_BITकोडगोल्फ में 8 है)।
fgrieu

@fgrieu, अच्छी बात है।
पीटर टेलर

8

स्कोर: 980 = 7 * 5 + 115 * 7 + 7 * 5 + 15 * 7, बोयार और पेराल्टा की न्यूनतम

मुझे जोआन बोयार और रेने पेराल्टा द्वारा क्रिप्टोलॉजी के अनुप्रयोगों के साथ एक नया संयोजन तर्क कम करने की तकनीक मिली , जो (सी औपचारिकता के लिए बचाओ) वह है जो आवश्यक है। उनके समीकरण प्राप्त करने के लिए प्रयोग किया जाता तकनीक है पेटेंट संयुक्त राज्य अमेरिका की तुलना में कम है। मैंने उनके समीकरणों का सीधा C अनुवाद किया , कृपया यहाँ से जुड़े ।

unsigned char SubBytes_Boyar_Peralta(unsigned char x7){
  unsigned char 
  x6=x7>>1,x5=x6>>1,x4=x5>>1,x3=x4>>1,x2=x3>>1,x1=x2>>1,x0=x1>>1,
  y14=x3^x5,y13=x0^x6,y9=x0^x3,y8=x0^x5,t0=x1^x2,y1=t0^x7,y4=y1^x3,y12=y13^y14,y2=y1^x0,
  y5=y1^x6,y3=y5^y8,t1=x4^y12,y15=t1^x5,y20=t1^x1,y6=y15^x7,y10=y15^t0,y11=y20^y9,y7=x7^y11,
  y17=y10^y11,y19=y10^y8,y16=t0^y11,y21=y13^y16,y18=x0^y16,t2=y12&y15,t3=y3&y6,t4=t3^t2,
  t5=y4&x7,t6=t5^t2,t7=y13&y16,t8=y5&y1,t9=t8^t7,t10=y2&y7,t11=t10^t7,t12=y9&y11,
  t13=y14&y17,t14=t13^t12,t15=y8&y10,t16=t15^t12,t17=t4^t14,t18=t6^t16,t19=t9^t14,
  t20=t11^t16,t21=t17^y20,t22=t18^y19,t23=t19^y21,t24=t20^y18,t25=t21^t22,t26=t21&t23,
  t27=t24^t26,t28=t25&t27,t29=t28^t22,t30=t23^t24,t31=t22^t26,t32=t31&t30,t33=t32^t24,
  t34=t23^t33,t35=t27^t33,t36=t24&t35,t37=t36^t34,t38=t27^t36,t39=t29&t38,t40=t25^t39,
  t41=t40^t37,t42=t29^t33,t43=t29^t40,t44=t33^t37,t45=t42^t41,z0=t44&y15,z1=t37&y6,
  z2=t33&x7,z3=t43&y16,z4=t40&y1,z5=t29&y7,z6=t42&y11,z7=t45&y17,z8=t41&y10,z9=t44&y12,
  z10=t37&y3,z11=t33&y4,z12=t43&y13,z13=t40&y5,z14=t29&y2,z15=t42&y9,z16=t45&y14,z17=t41&y8,
  t46=z15^z16,t47=z10^z11,t48=z5^z13,t49=z9^z10,t50=z2^z12,t51=z2^z5,t52=z7^z8,t53=z0^z3,
  t54=z6^z7,t55=z16^z17,t56=z12^t48,t57=t50^t53,t58=z4^t46,t59=z3^t54,t60=t46^t57,
  t61=z14^t57,t62=t52^t58,t63=t49^t58,t64=z4^t59,t65=t61^t62,t66=z1^t63,s0=t59^t63,
  s6=t56^t62,s7=t48^t60,t67=t64^t65,s3=t53^t66,s4=t51^t66,s5=t47^t65,s1=t64^s3,s2=t55^t67;
  return (((((((s0<<1|s1&1)<<1|s2&1)<<1|s3&1)<<1|s4&1)<<1|s5&1)<<1|s6&1)<<1|s7&1)^0x63;}

वाह, वास्तव में काम करता है, और वास्तव में सस्ता है। जब disassembling होती है, तो यह वास्तव में 144 निर्देश है, जिसमें प्रस्तावना, उपसंहार और चाल निर्देश को छोड़कर।
बदसूरत

5

स्कोर: 10965

यह सरणी लुक को अनरोल करने के समान सिद्धांत का उपयोग करता है। अतिरिक्त जातियों की आवश्यकता हो सकती है।

कैसे सुधार करने के लिए इंगित करने के लिए बदसूरत करने के लिए धन्यवाद is_zero

// Cost: 255 * (5+7+24+7) = 10965
unsigned char SubBytes(unsigned char x) {
    unsigned char r = 0x63;
    char c = (char)x;
    c--; r ^= is_zero(c) & (0x63^0x7c); // 5+7+24+7 inlining the final xor
    c--; r ^= is_zero(c) & (0x63^0x77); // 5+7+24+7
    // ...
    c--; r ^= is_zero(c) & (0x63^0x16); // 5+7+24+7
    return r;
}

// Cost: 24
// Returns (unsigned char)-1 when input is 0 and 0 otherwise
unsigned char is_zero(char c) {
    // Shifting a signed number right is unspecified, so use unsigned
    unsigned char u;
    c |= -c;               // 7+5+
    u = (unsigned char)c;
    u >>= (CHAR_BITS - 1); // 7+
    c = (char)u;
    // c is 0 if we want -1 and 1 otherwise.
    c--;                   // 5
    return (unsigned char)c;
}

2
पूर्णांक c के लिए, (c|-c)>>310 के लिए 0 और -1 है अन्यथा।
ugoren

@ युगीन, समझदार भाषाओं में, हाँ। सी में, एक अहस्ताक्षरित प्रकार को शिफ्ट करना अनिर्दिष्ट है।
पीटर टेलर

1
मुझे लगता है कि आप पर हस्ताक्षर किए गए मतलब है। लेकिन यह साइट वास्तव में सख्त मानक अनुपालन के लिए प्रसिद्ध नहीं है। इसके अलावा, आपका c >> 4लगता है मुझ पर हस्ताक्षरित राइट शिफ्ट। और अगर आप वास्तव में जोर देते हैं - ((unsigned int)(c|-c))>>31है c?1:0
ugoren

@ यूगोरेन, आप सही कह रहे हैं, मेरा मतलब है हस्ताक्षर किए। c >>4साथ या संकेत विस्तार के बिना काम करता है। लेकिन अहस्ताक्षरित पारी का उपयोग करने पर अच्छी पकड़: जब मैं घर पहुंचूंगा और फोन के बजाय एक उचित कंप्यूटर का उपयोग कर सकता हूं। धन्यवाद।
पीटर टेलर

3

स्कोर: 9109, बीजीय दृष्टिकोण

यदि कोई इसे बहुत सुधार सकता है, तो मैं लुकअप दृष्टिकोण छोड़ दूंगा, लेकिन यह पता चलता है कि एक अच्छा बीजीय दृष्टिकोण संभव है। यह कार्यान्वयन यूक्लिड के एल्गोरिथ्म का उपयोग करते हुए गुणात्मक व्युत्क्रम पाता है । मैंने इसे जावा में लिखा है, लेकिन सिद्धांत रूप में इसे सी में पोर्ट किया जा सकता है - मैंने उन हिस्सों पर टिप्पणी की है जो केवल 8-बिट प्रकारों का उपयोग करके इसे फिर से बनाना चाहते हैं।

is_nonzeroमेरे अन्य उत्तर पर टिप्पणी में चेक को छोटा करने का संकेत देने के लिए बदसूरत होने के लिए धन्यवाद ।

public class SBox
{
    public static void main(String[] args)
    {
        for (int i = 0; i < 256; i++) {
            int s = SubBytes(i);
            System.out.format("%02x  ", s);
            if (i % 16 == 15) System.out.println();
        }
    }

    // Total cost: 9109
    public static int SubBytes(int x)
    {
        x = inv_euclid(x); // 9041
        x = affine(x);     // 68
        return x;
    }

    // Total cost: 68
    private static int affine(int s0) {
        int s = s0;
        s ^= (s0 << 1) ^ (s0 >> 7); // 5 + 7
        s ^= (s0 << 2) ^ (s0 >> 6); // 7 + 7
        s ^= (s0 << 3) ^ (s0 >> 5); // 7 + 7
        s ^= (s0 << 4) ^ (s0 >> 4); // 7 + 7
        return (s ^ 0x63) & 0xff;   // 7 + 7
    }

    // Does the inverse in the Galois field for a total cost of 24 + 9010 + 7 = 9041
    private static int inv_euclid(int s) {
        // The first part of handling the special case: cost of 24
        int zeromask = is_nonzero(s);

        // NB the special value of r would complicate the unrolling slightly with unsigned bytes
        int r = 0x11b, a = 0, b = 1;

        // Total cost of loop: 7*(29+233+566+503+28) - 503 = 9010
        for (int depth = 0; depth < 7; depth++) { // 7*(
            // Calculate mask to fake out when we're looping further than necessary: cost 29
            int mask = is_nonzero(s >> 1);

            // Cost: 233
            int ord = polynomial_order(s);

            // This next block does div/rem at a total cost of 6*(24+49) + 69 + 59 = 566
            int quot = 0, rem = r;
            for (int i = 7; i > 1; i--) {                   // 6*(
                int divmask = is_nonzero(ord & (rem >> i)); // 24+7+7
                quot ^= (1 << i) & divmask;                 // 7+0+7+ since 1<<i is inlined on unrolling
                rem ^= (s << i) & divmask;                  // 7+7+7) +
            }
            int divmask1 = is_nonzero(ord & (rem >> 1));    // 24+7+5
            quot ^= 2 & divmask1;                           // 7+7+
            rem ^= (s << 1) & divmask1;                     // 7+5+7+
            int divmask0 = is_nonzero(ord & rem);           // 24+7
            quot ^= 1 & divmask0;                           // 7+7+
            rem ^= s & divmask0;                            // 7+7

            // This next block does the rest for the cost of a mul (503) plus 28
            // When depth = 0, b = 1 so we can skip the mul on unrolling
            r = s;
            s = rem;
            quot = mul(quot, b) ^ a;
            a = b;
            b ^= (quot ^ b) & mask;
        }

        // The rest of handling the special case: cost 7
        return b & zeromask;
    }

    // Gets the highest set bit in the input. Assumes that it's always at least 1<<1
    // Cost: 233
    private static int polynomial_order(int s) {
        int ord = 2;
        ord ^= 6 & -((s >> 2) & 1);           // 7+7+5+7+7 = 33 +
        ord ^= (ord ^ 8) & -((s >> 3) & 1);   // 7+7+7+5+7+7 = 40 +
        ord ^= (ord ^ 16) & -((s >> 4) & 1);  // 40 +
        ord ^= (ord ^ 32) & -((s >> 5) & 1);  // 40 +
        ord ^= (ord ^ 64) & -((s >> 6) & 1);  // 40 +
        ord ^= (ord ^ 128) & -((s >> 7) & 1); // 40
        return ord;
    }

    // Returns 0 if c is 0 and -1 otherwise
    // Cost: 24
    private static int is_nonzero(int c) {
        c |= -c;   // 7+5+
        c >>>= 31; // 7+ (simulating a cast to unsigned and right shift by CHAR_BIT)
        c = -c;    // 5+ (could be saved assuming a particular implementation of signed right shift)
        return c;
    }

    // Performs a multiplication in the Rijndael finite field
    // Cost: 503 (496 if working with unsigned bytes)
    private static int mul(int a, int b) {
        int p = 0;
        for (int counter = 0; counter < 8; counter++) { // 8*(_+_
            p ^= a & -(b & 1);                          // +7+7+5+7
            a = (a << 1) ^ (0x1b & -(a >> 7));          // +5+7+7+5+7
            b >>= 1;                                    // +5)
        }
        p &= 0xff;                                      // +7 avoidable with unsigned bytes
        return p;
    }
}

2

स्कोर: 256 * (7+ (8 * (7 + 7 + 7) - (2 + 2)) + 5 + 7 + 7) = 48640 (लूप को अनियंत्रित मानकर)

unsigned char SubBytes(unsigned char x) {
static const unsigned char t[256] = {
  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};

unsigned char ret_val = 0;
int i,j;
for(i=0;i<256;i++) {
  unsigned char is_index = (x ^ ((unsigned char) i));
  for(j=0;j<8;j++) {
   is_index |= (is_index << (1 << j)) | (is_index >> (1 << j));
  }
  is_index = ~is_index;
  ret_val |= is_index & t[i];
}

return ret_val;}

स्पष्टीकरण:

अनिवार्य रूप से एक सरणी लुकअप को बिटवाइज़ ऑपरेटरों का उपयोग करके और हमेशा पूरे सरणी को संसाधित करते हुए पुन: कार्यान्वित किया जाता है। हम xप्रत्येक अनुक्रमणिका के साथ सरणी, और xor के माध्यम से लूप करते हैं, फिर परिणाम को नकारात्मक रूप से नकारने के लिए बिटवाइज़ ऑपरेटर्स का उपयोग करते हैं, इसलिए हम 255 प्राप्त करते हैं x=iऔर 0 अन्यथा। हम सरणी-मान के साथ बिटवाइज़-और यह करते हैं, ताकि चुना हुआ मूल्य अपरिवर्तित हो और अन्य 0. हो जाएं। फिर हम इस सरणी के बिटवाइज़-या लेते हैं, जिससे केवल चुने गए मान बाहर निकलते हैं।

दो 1 << jसंचालन लूप को अनियंत्रित करने के भाग के रूप में चले जाएंगे, उन्हें 2 की शक्तियों के साथ 1 से 128 तक बदल दिया जाएगा।


अब यह देखना है कि बिटवाइज़ ऑपरेटरों का उपयोग करके वास्तव में गणित करना संभव है या नहीं।
हिस्टोक्रैट

यहाँ एल्गोरिथ्म के माध्यम से देखते हुए , मुझे संदेह है कि बहुपद-समय के कुछ चरणों के विकल्प के रूप में कम से कम एक बार सभी बाइट्स पर लूपिंग के बिना बहुपद व्युत्क्रम को लागू करना संभव होगा। तो यह अच्छी तरह से किसी भी "स्मार्ट" समाधान को हरा सकता है। मुझे संदेह है कि यह निरंतर-समय सरणी लुकिंग एक अधिक आशाजनक एवेन्यू है।
हिस्टोक्रेट

अच्छा लगा। Anes.c में फ़ंक्शन rj_sbox यहां प्रेरणा दे सकता है (हालांकि, जैसा है, यह प्रश्न से मेल नहीं खाता है)।
fgrieu

-(2+2)आपकी स्कोरिंग गणना कहां से आती है? संपादित करें: आह, inlining एक <<1और एक बनाता है >>1
पीटर टेलर 15

0

लुकिंग टेबल का उपयोग करके स्कोर 1968 1692

ध्यान दें: यह समाधान की वजह से मानदंड पर खरे उतर नहीं है, w >> b

लुकअप टेबल का उपयोग करना, लेकिन एक बार में 8 बाइट पढ़ना।
3 * 7 + 32 * (6 * 7 + 2 * 5) + 7 = 692

unsigned char SubBytes(unsigned char x){

static const unsigned char t[256] = {
  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};

  unsigned long long *t2 = (unsigned long long *)t;
  int a = x>>3, b=(x&7)<<3;                       // 7+7+7
  int i;
  int ret = 0;
  for (i=0;i<256/8;i++) {                         // 32 *
      unsigned long long w = t2[i];
      int badi = ((unsigned int)(a|-a))>>31;      // 7+7+5
      w &= (badi-1);                              // +7+7
      a--;                                        // +5
      ret |= w >> b;                              // +7+7
  }
  return ret & 0xff;                              // +7
}

मुझे नहीं लगता कि यह प्रश्न में निरंतर समय की परिभाषा को पूरा करता है, क्योंकि w>>bआरएचएस से गणना की गई हैx
पीटर टेलर

कई उल्लंघन हैं: w >> bजहां bइनपुट पर निर्भर करता है; भी x/8, x%8और *= (1-badi)। पहले वाले को विशेष रूप से कम-अंत सीपीयू पर एक समय निर्भरता में गिरावट की संभावना है। हालांकि, व्यापक चर का उपयोग करने के विचार में निश्चित रूप से क्षमता है।
fgrieu

मैंने निर्देशों को ध्यान से नहीं पढ़ा। मैं ज्यादातर समस्याओं को ठीक कर सकता हूं, लेकिन w >> bयह बहुत आवश्यक है (मुझे यह देखने की आवश्यकता है कि क्या यह सब कुछ फिर से
लिखे

0

टेबल लुकअप और मास्क, स्कोर = 256 * (5 * 7 + 1 * 5) = 10240

केवल हम जो परिणाम चाहते हैं उसे बाहर निकालने के लिए मास्क के साथ टेबल लुकअप का उपयोग करता है। इस तथ्य का उपयोग करता है कि j|-jया तो नकारात्मक है (जब मैं! = X) या शून्य (जब मैं == x)। शिफ्टिंग एक ऑल-वन या ऑल-जीरो मास्क बनाता है, जिसका उपयोग केवल उस प्रविष्टि को चुनने के लिए किया जाता है जिसे हम चाहते हैं।

static const unsigned char t[256] = {
  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};

unsigned char SubBytes(unsigned char x) {
  unsigned char r = 255;
  for (int i = 0; i < 256; i++) {
    int j = i - x;
    r &= t[i] | ((j | -j) >> 31);
  }
  return r;
}

क्या यह कम अनुकूलित को छोड़कर मेरे दूसरे उत्तर के समान नहीं है?
पीटर टेलर

बंद, मुझे लगता है। मैं हस्ताक्षरित पारी का उपयोग कर रहा हूं इसलिए मुझे अंत में -1 नहीं करना है।
कीथ रान्डेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.