В математике арифметика конечного поля — это арифметика в конечном поле ( поле, содержащем конечное число элементов ) , в отличие от арифметики в поле с бесконечным числом элементов, например, в поле рациональных чисел .
Существует бесконечно много различных конечных полей. Их число элементов обязательно имеет вид p n , где p — простое число , а n — положительное целое число , и два конечных поля одинакового размера изоморфны . Простое число p называется характеристикой поля, а положительное целое число n называется размерностью поля над его простым полем .
Конечные поля используются в различных приложениях, в том числе в классической теории кодирования в линейных блочных кодах, таких как коды BCH и коды коррекции ошибок Рида-Соломона , в криптографических алгоритмах, таких как алгоритм шифрования Rijndael ( AES ), в планировании турниров и в разработке экспериментов .
Конечное поле с p n элементами обозначается GF( p n ) и также называется полем Галуа порядка p n , в честь основателя теории конечных полей Эвариста Галуа . GF( p ), где p — простое число, — это просто кольцо целых чисел по модулю p . То есть можно выполнять операции (сложение, вычитание, умножение), используя обычную операцию над целыми числами, за которой следует сокращение по модулю p . Например, в GF(5) 4 + 3 = 7 сокращается до 2 по модулю 5. Деление — это умножение на обратное по модулю p , которое можно вычислить с помощью расширенного алгоритма Евклида .
Частным случаем является GF(2) , где сложение — это исключающее ИЛИ (XOR), а умножение — И. Поскольку единственный обратимый элемент — 1, деление — это функция тождества .
Элементы GF( p n ) могут быть представлены как многочлены степени строго меньшей n над GF( p ). Затем операции выполняются по модулю m(x), где m(x) — неприводимый многочлен степени n над GF( p ), например, с использованием полиномиального деления в столбик . Сложение — это обычное сложение многочленов, но коэффициенты приводятся по модулю p . Умножение — это также обычное умножение многочленов, но с коэффициентами, умноженными по модулю p , и многочленами, умноженными по модулю многочлена m(x) . [1] Это представление в терминах полиномиальных коэффициентов называется мономиальным базисом (он же «полиномиальный базис»).
Существуют и другие представления элементов GF( p n ); некоторые из них изоморфны представлению полинома выше, а другие выглядят совершенно иначе (например, с использованием матриц). Использование нормального базиса может иметь преимущества в некоторых контекстах.
Когда простое число равно 2, принято выражать элементы GF( p n ) как двоичные числа , причем коэффициент каждого члена в многочлене представлен одним битом в двоичном выражении соответствующего элемента. Фигурные скобки ("{" и "}") или подобные разделители обычно добавляются к двоичным числам или к их шестнадцатеричным эквивалентам, чтобы указать, что значение дает коэффициенты базиса поля, тем самым представляя элемент поля. Например, ниже приведены эквивалентные представления одного и того же значения в конечном поле характеристики 2:
Существует множество неприводимых многочленов (иногда называемых приводящими многочленами ), которые можно использовать для генерации конечного поля, но не все они приводят к одному и тому же представлению поля.
Монический неприводимый многочлен степени n, имеющий коэффициенты в конечном поле GF( q ), где q = p t для некоторого простого числа p и положительного целого числа t , называется примитивным многочленом , если все его корни являются примитивными элементами GF( q n ). [2] [3] В полиномиальном представлении конечного поля это означает, что x является примитивным элементом. Существует по крайней мере один неприводимый многочлен, для которого x является примитивным элементом. [4] Другими словами, для примитивного многочлена степени x порождают каждое ненулевое значение в поле.
В следующих примерах лучше не использовать полиномиальное представление, так как значение x меняется между примерами. Монический неприводимый полином x 8 + x 4 + x 3 + x + 1 над GF(2) не является примитивным. Пусть λ будет корнем этого полинома (в полиномиальном представлении это будет x ), то есть λ 8 + λ 4 + λ 3 + λ + 1 = 0 . Теперь λ 51 = 1 , поэтому λ не является примитивным элементом GF(2 8 ) и порождает мультипликативную подгруппу порядка 51. [5] Монический неприводимый полином x 8 + x 4 + x 3 + x 2 + 1 над GF(2) является примитивным, и все 8 корней являются генераторами GF(2 8 ) .
Все GF(2 8 ) имеют в общей сложности 128 генераторов (см. Количество примитивных элементов ), и для примитивного многочлена 8 из них являются корнями редуцирующего многочлена. Наличие x в качестве генератора для конечного поля полезно для многих вычислительных математических операций.
Сложение и вычитание выполняются путем сложения или вычитания двух этих многочленов и уменьшения результата по модулю характеристики.
В конечном поле с характеристикой 2 сложение по модулю 2, вычитание по модулю 2 и XOR идентичны. Таким образом,
При обычном сложении многочленов сумма будет содержать член 2 x 6. Этот член становится 0 x 6 и отбрасывается при сокращении ответа по модулю 2.
Ниже приведена таблица с нормальной алгебраической суммой и конечной полевой суммой характеристики 2 нескольких многочленов:
В приложениях компьютерной науки операции упрощаются для конечных полей характеристики 2, также называемых полями Галуа GF(2 n ) , что делает эти поля особенно популярным выбором для приложений.
Умножение в конечном поле — это умножение по модулю неприводимого редуцирующего многочлена , используемого для определения конечного поля. (Т.е. это умножение, за которым следует деление с использованием редуцирующего многочлена в качестве делителя — остаток является произведением.) Символ «•» может использоваться для обозначения умножения в конечном поле.
Rijndael (стандартизированный как AES) использует конечное поле характеристики 2 с 256 элементами, которое также можно назвать полем Галуа GF(2 8 ). Он использует следующий редуцирующий полином для умножения:
Например, {53} • {CA} = {01} в поле Rijndael, потому что
и
Последнее можно продемонстрировать с помощью деления в столбик (показано с использованием двоичной записи, поскольку она хорошо подходит для этой задачи. Обратите внимание, что в примере применяется исключающее ИЛИ , а не арифметическое вычитание, как можно было бы использовать при делении в столбик в начальной школе):
11111101111110 (мод) 100011011 ^100011011 01110000011110 ^ 100011011 0110110101110 ^100011011 010101110110 ^100011011 00100011010 ^100011011 000000001
(Элементы {53} и {CA} являются мультипликативными обратными друг другу, поскольку их произведение равно 1. )
Умножение в этом конкретном конечном поле также может быть выполнено с использованием модифицированной версии "алгоритма крестьянина ". Каждый многочлен представлен с использованием той же двоичной записи, что и выше. Восьми бит достаточно, поскольку в терминах каждого (редуцированного) многочлена возможны только степени от 0 до 7.
В этом алгоритме используются три переменные (в смысле компьютерного программирования), каждая из которых содержит восьмибитное представление. a и b инициализируются множимыми; p накапливает произведение и должна быть инициализирована значением 0.
В начале и конце алгоритма, а также в начале и конце каждой итерации этот инвариант истинен: a b + p — это произведение. Это, очевидно, истинно, когда алгоритм начинается. Когда алгоритм завершается, a или b будут равны нулю, поэтому p будет содержать произведение.
0x1b
00011011 в двоичном формате). 0x1b
соответствует неприводимому многочлену с исключенным старшим членом. Концептуально, старший член неприводимого многочлена и перенос добавляются по модулю 2 к 0.Этот алгоритм легко обобщается на умножение по другим полям характеристики 2, изменяя длины a , b и p , а также значение 0x1b
соответствующим образом.
Мультипликативный обратный элемент для элемента a конечного поля можно вычислить несколькими способами:
При разработке алгоритмов для вычисления полей Галуа на малых полях Галуа распространенным подходом к оптимизации производительности является нахождение генератора g и использование тождества:
реализовать умножение как последовательность табличных поисков для функций log g ( a ) и g y и операцию сложения целых чисел. Это использует свойство, что каждое конечное поле содержит генераторы. В примере поля Rijndael многочлен x + 1 (или {03}) является одним из таких генераторов. Необходимое, но недостаточное условие для того, чтобы многочлен был генератором, — быть неприводимым .
Реализация должна проверять особый случай, когда a или b равны нулю, поскольку произведение также будет равно нулю.
Эту же стратегию можно использовать для определения мультипликативной инверсии с тождеством:
Здесь порядок генератора, | g |, — это число ненулевых элементов поля. В случае GF(2 8 ) это 2 8 − 1 = 255 . То есть, для примера Rijndael: ( x + 1) 255 = 1 . Так что это можно выполнить с помощью двух таблиц поиска и целочисленного вычитания. Использование этой идеи для возведения в степень также дает выгоду:
Это требует двух просмотров таблицы, целочисленного умножения и операции по целочисленному модулю. Снова необходимо выполнить тест для особого случая a = 0 .
Однако в криптографических реализациях следует быть осторожным с такими реализациями, поскольку архитектура кэша многих микропроцессоров приводит к переменному времени доступа к памяти. Это может привести к реализациям, уязвимым для атаки по времени .
Для двоичных полей GF(2 n ) умножение полей может быть реализовано с использованием умножения без переноса, такого как набор инструкций CLMUL , который хорош для n ≤ 64. Умножение использует одно умножение без переноса для получения произведения (до 2 n − 1 бит), другое умножение без переноса предварительно вычисленного обратного полинома поля для получения частного = ⌊product / (полином поля)⌋, умножение частного на полином поля, затем xor: результат = product ⊕ ((полином поля) ⌊product / (полином поля)⌋). Последние 3 шага (pclmulqdq, pclmulqdq, xor) используются на этапе сокращения Барретта для быстрого вычисления CRC с использованием инструкции x86 pclmulqdq. [7]
Когда k является составным числом , будут существовать изоморфизмы из двоичного поля GF(2 k ) в поле расширения одного из его подполей, то есть GF((2 m ) n ), где k = m n . Использование одного из этих изоморфизмов может упростить математические соображения, поскольку степень расширения меньше с компромиссом, что элементы теперь представлены в большем подполе. [8] Чтобы уменьшить количество вентилей для аппаратных реализаций, процесс может включать множественное вложение, такое как отображение из GF(2 8 ) в GF(((2 2 ) 2 ) 2 ). [9]
Вот код на языке C , который будет складывать и умножать числа в конечном поле с характеристикой 2 порядка 2 8 , используемый, например, алгоритмом Рейндала или Рида–Соломона, с использованием русского крестьянского алгоритма умножения :
/* Складываем два числа в конечном поле GF(2^8) */ uint8_t gadd ( uint8_t a , uint8_t b ) { return a ^ b ; } /* Умножить два числа в конечном поле GF(2^8), определенном * модульным полиномиальным отношением x^8 + x^4 + x^3 + x + 1 = 0 * (другой способ — выполнить умножение без переноса с последующим модульным сокращением) */ uint8_t gmul ( uint8_t a , uint8_t b ) { uint8_t p = 0 ; /* аккумулятор для результата умножения */ while ( a != 0 && b != 0 ) { if ( b & 1 ) /* если полином для b имеет постоянный член, добавить соответствующий a к p */ p ^= a ; /* сложение в GF(2^m) является XOR полиномиальных коэффициентов */ if ( a & 0x80 ) /* GF по модулю: если a имеет ненулевой член x^7, то его необходимо сократить, когда он станет x^8 */ a = ( a << 1 ) ^ 0x11b ; /* вычесть (XOR) примитивный многочлен x^8 + x^4 + x^3 + x + 1 (0b1_0001_1011) – вы можете изменить его, но он должен быть неприводимым */ else a <<= 1 ; /* эквивалентно a*x */ b >>= 1 ; } return p ; }
В этом примере имеются утечки кэша, синхронизации и предсказания ветвлений по побочным каналам , поэтому он не подходит для использования в криптографии.
Эта программа на языке D умножает числа в конечном поле Rijndael и генерирует изображение PGM :
/** Умножить два числа в конечном поле GF(2^8), определенном полиномом x^8 + x^4 + x^3 + x + 1. */ ubyte gMul ( ubyte a , ubyte b ) pure nothrow { ubyte p = 0 ; foreach ( неизменяемый счетчик ubyte ; 0 .. 8 ) { p ^= -( b & 1 ) &a a ; автомаска = -(( a >> 7 ) & 1 ); // 0b1_0001_1011 это x^8 + x^4 + x^3 + x + 1. a = cast ( ubyte )(( a << 1 ) ^ ( 0b1_0001_1011 & mask )); b >> = 1 ; } вернуть п ; } void main ( ) { import std.stdio , std.conv ; enum width = ubyte.max + 1 , height = width ; auto f = File ( " rijndael_finite_field_multiplication.pgm" , " wb" ); f.writefln ( "P5\n%d %d \ n255 " , width , height ) ; foreach ( immutable y ; 0 .. height ) foreach ( immutable x ; 0 .. width ) { immutable char c = gMul ( x.to ! ubyte , y.to ! ubyte ) ; f.write ( c ) ; } }
В этом примере не используются никакие ветвления или поиск по таблицам, чтобы избежать побочных каналов, и поэтому он подходит для использования в криптографии.