2011 Математические основы информатики и программирования №1(11)
МАТЕМАТИЧЕСКИЕ ОСНОВЫ ИНФОРМАТИКИ И ПРОГРАММИРОВАНИЯ
УДК 519.7
ТЕХНОЛОГИЯ ТРАНСЛЯЦИИ КОМБИНАТОРНЫХ ПРОБЛЕМ
В БУЛЕВЫ УРАВНЕНИЯ
И. В. Отпущенников, А. А. Семёнов Институт динамики систем и теории управления СО РАН, г. Иркутск, Россия E-mail: otilya@yandex.ru, biclop@rambler.ru
Рассматриваются проблемы сведения некоторых комбинаторных задач к задачам поиска решений булевых уравнений. Приведены теоретические результаты, являющиеся базой технологии пропозиционального кодирования алгоритмов, вычисляющих дискретные функции. Описан программный комплекс Transalg — многофункциональный транслятор комбинаторных проблем в булевы уравнения. Приведены примеры использования комплекса Transalg для сведения задач криптоанализа к SAT-задачам. Рассмотрены основы техники трансляции оптимизационных задач 0-1-ЦЛП в SAT-задачи.
Ключевые слова: дискретные функции, булевы уравнения, криптоанализ, пропозициональное кодирование.
Введение
Как известно, многие NP-трудные задачи возникли из совершенно конкретных практических постановок. В ряде направлений без умения решать данные задачи невозможно обойтись. Речь идет о проблемах синтеза и верификации дискретных управляющих/управляемых систем, проблемах экономики, производственного планирования, логистики и многих других. В этих областях вопросы построения практически эффективных алгоритмов решения соответствующих комбинаторных задач чрезвычайно актуальны. Большое число исследований посвящено построению приближенных алгоритмов решения NP-трудных проблем. Однако в некоторых приложениях, например в задачах верификации микросхем, требуется находить именно точные решения. Эта необходимость существенно сужает класс методов — методы непрерывной математики, генетические алгоритмы, разнообразные «эволюционные эвристики» в общем случае не дают точных решений.
В настоящей работе приведены основы «пропозиционального подхода» к решению комбинаторных задач из весьма широкого класса. Данный подход предполагает нахождение точных решений и включает две составляющих. Во-первых, это алгоритмы сведения комбинаторных задач к булевым уравнениям, и, во-вторых, это символьные алгоритмы поиска решений получаемых уравнений. В последние годы интерес именно к такому рассмотрению комбинаторных задач заметно усилился в связи с существенным прогрессом в алгоритмике булевых решателей (в первую очередь, SAT-задач), а также в связи с бурным развитием параллельных вычислительных технологий (булевы задачи допускают естественные формы параллелизма).
Библиография по решению булевых уравнений весьма обширна — от фундаментальной монографии С. Рудяну [1] до многочисленных в последние годы работ по БАТ-задачам. Работ, специально посвященных сведению комбинаторных проблем к булевым уравнениям, сравнительно мало (можно сослаться на обзорную статью [2] и список литературы к ней). Удивительно то, что в подавляющем большинстве эти результаты имеют характер наглядных примеров и правдоподобных рассуждений — самой строгой в этом смысле продолжает оставаться процедура, фигурирующая в оригинальном и последующих доказательствах теоремы Кука [3, 4]. Следует отметить, что реализовать на основе перечисленных результатов конкретные процедуры сведения, применимые к достаточно широким классам комбинаторных задач, крайне затруднительно: сведения, описанные в [2], слишком специфичны, а известные варианты теоремы Кука доказаны в отношении машины Тьюринга — модели, которая крайне далека от современных ЭВМ в плане языка и организации вычислений.
В работе [5] описаны механизмы пропозиционального кодирования программ, вычисляющих дискретные функции на машинах с произвольным доступом к памяти (ИАМ). Язык данной модели очень естествен — фактически это фрагмент ассемблера современных ЭВМ. Там же в общих чертах описаны основные принципы высокоуровневой трансляции алгоритмов, вычисляющих дискретные функции, в булевы уравнения. Реализацией этих идей стал программный комплекс Тгапяа^. В настоящей работе описаны его архитектура, функциональные возможности и применение для решения некоторых комбинаторных задач.
В п. 1 содержатся некоторые результаты работы [5]. Эти результаты являются базой для последующего материала. В п. 2 дается подробное описание архитектуры программного комплекса Тгапяа^, а также рассматривается специальный язык программирования ТА, используемый для описания алгоритмов вычисления дискретных функций. В п. 3 приводятся результаты использования комплекса Тгапяа^ для построения пропозициональных кодов некоторых криптографических алгоритмов. В п. 4 описаны основные принципы сведения задач с псевдобулевыми ограничениями к БАТ-задачам.
1. Трансляция формальных программ вычисления дискретных функций
в булевы уравнения
1.1. Трансляция И,АМ-программ
Через {0,1}п обозначается множество всех двоичных слов длины п, а через {0,1}* — множество всех двоичных слов произвольной конечной длины. Дискретными функциями называются произвольные функции вида
f : {0,1}* ^{0,1}*.
Далее рассмотрим такие дискретные функции, описаниями которых являются программы для детерминированной машины Тьюринга с алфавитом {0,1}. Пусть f — произвольная такая функция и М/ — вычисляющая ее ДМТ-программа. Дополнительно будем предполагать, что ёош f = {0,1}*, то есть М/ останавливается на произвольном двоичном слове, и что сложность М/ растет как некоторый полином с ростом длины входа. Очевидно, что М/ задает счетное семейство функций вида
и : {0,1}п ^ {0,1}*, асшД = {0,1}п, п Є N.
Проблемой обращения произвольной функции fn из данного семейства в точке y £ range fn называется следующая задача: зная Mf, число п и y £ range fn, найти такой x £ {0,1}n, что fn(x) = y.
Пропозициональный подход к данной задаче основан на следующем факте: процесс работы программы Mf на произвольном входе можно эффективно (в общем случае за полиномиальное от n время) представить в виде формулы исчисления высказываний. Истинность данной формулы при некоторых дополнительных условиях, характеризующих конкретный выход y £ range fn, означает существование такого входа x £ {0,1}n, результат трансформации которого посредством программы Mf есть y. Фактически в этом состоит теорема Кука [3].
Как уже отмечалось, построение процедуры пропозиционального кодирования ДМТ-программ имеет чисто теоретический интерес. Гораздо более близкими к современным реальным вычислителям являются машины с произвольным доступом, впервые описанные в [6]. Далее используем упрощенную (в сравнении с исходной) форму RAM, которой тем не менее оказалось достаточно для построения теории вычислимых (рекурсивных) функций [7].
Итак, далее рассматривается двоичная (бинарная) RAM в формализме Н. Катлен-да [7]. Данная модель включает потенциально бесконечную вправо ленту, разбитую на ячейки, которые пронумерованы натуральными числами. В каждой ячейке может быть записан только один бит. Произвольная бинарная RAM-программа — это нумерованный список команд, каждая из которых может быть командой одного из следующих двух типов:
1) команды записи в ячейку с номером k бита 0 или бита 1 — соответственно B0(k) и Bi(k);
2) команды условного перехода J(k, /, m): сравнить содержимое ячеек с номерами k и / , в случае совпадения перейти к команде с номером m, в противном случае перейти к команде, которая следует в списке за командой J(k,/,m).
Вычисление останавливается либо после выполнения последней команды в программе (если данная команда не является командой условного перехода), либо если происходит ссылка на несуществующую команду.
Пусть f — произвольная всюду определенная (тотальная) на {0,1}* полиномиально вычислимая дискретная функция, рассматриваемая как семейство f = {fn}n£N, fn : {0,1}n ^ {0,1}*, и Mf — ДМТ-программа, вычисляющая f. В соответствии с [4], значение функции сложности р(п) программы Mf равно максимуму числа шагов ДМТ, выполняющей Mf, по всевозможным входам из {0,1}n. Пусть Rfn —произвольная программа бинарной RAM, вычисляющая функцию fn. Поставим ей в соответствие значение функции $(п), равное максимальному по всевозможным входам из {0,1}n числу обращений к регистрам ленты RAM в процессе выполнения Rfn.
Приведем два утверждения из работы [5], являющиеся теоретической базой описываемых далее процедур трансляции алгоритмов.
Лемма 1 (о моделировании). Пусть Mf —ДМТ-программа, вычисляющая тотальную дискретную функцию f : {0,1}* ^ {0,1}*, и функция сложности программы Mf ограничена некоторым полиномом от n. Существует тотальная алгоритмически вычислимая функция д, которая за полиномиальное от п время по тексту программы Mf и числу п выдает текст программы Rfn, вычисляющей функцию fn. Функция $(п), сопоставляемая получаемому семейству RAM-программ, ограничена сверху полиномом от п.
Данный факт означает наличие эффективной процедуры перехода от ДМТ-про-граммы, вычисляющей f, к семейству двоичных RAM-программ, каждая из которых вычисляет функцию fn, п £ N. Как уже отмечалось, синтаксис RAM-программ близок к ассемблерным программам, что крайне важно при построении практичных процедур пропозиционального кодирования алгоритмов.
Теорема 1. Пусть f = {fn}ngN — семейство алгоритмически вычислимых за полиномиальное время дискретных функций и {Rfn }n^N — семейство бинарных RAM-программ, сопоставляемое f в соответствии с леммой о моделировании. Существует алгоритмически вычислимая тотальная функция h, которая, получая на входе текст программы Rfn, за полиномиальное в общем случае от п время строит такую систему булевых уравнений S (fn), что для произвольного y £ range fn система S (fn) |y совместна. Если x* —произвольное решение системы S (fn) |y, то из x* за линейное от |x*| время можно выделить некоторый x £ {0,1}n, такой, что fn(x) = y.
Здесь через S (fn) |y обозначена система булевых уравнений, которая получается из системы S (fn) в результате подстановки в нее вектора y £ range fn.
При доказательстве данной теоремы (см. [5]) в явном виде строится процедура, которая применима к трансляции RAM-программ, вычисляющих произвольные функции из описанного выше класса, в булевы уравнения. Процесс RAM-вычисления при этом рассматривается как последовательность переходов K0 ^ K1 ^ ... ^ Ke, где К0 — начальная, Ke — конечная, а K1,... , Ke-1 —промежуточные конфигурации RAM-вычисления. Каждой конфигурации Kj, i £ {0,1,... , e}, сопоставляется множество (массив) булевых переменных Xг, а каждому переходу — система булевых уравнений, связывающих соответствующие соседние массивы. Конъюнкция всех таких систем дает систему S (fn), кодирующую процесс выполнения программы Rfn на произвольном входе из {0,1}n.
От произвольной системы вида S (fn) |y возможен эффективный (в общем случае за полиномиальное от п время) переход к одному уравнению вида КНФ = 1. Этот переход осуществляется при помощи преобразований Цейтина [8]. Между множеством решений системы S (fn) |y и множеством решений получаемого уравнения КНФ = 1 существует биекция [9].
1.2. Основные принципы трансляции высокоуровневых программ в булевы уравнения
Близость синтаксиса RAM-программ к современным ассемблерным языкам позволяет рассматривать приведенные выше результаты в качестве идейной основы для разработки процедур трансляции высокоуровневых описаний алгоритмов в булевы уравнения.
Ядром пропозиционального подхода является идея представления булевыми уравнениями переходов из одной конфигурации формальной модели в другую. Для представления рабочей области современной ЭВМ следует использовать булевы массивы. Так же, как и в случае RAM, при реализации алгоритма вычисления дискретной функции на «высокоуровневой модели» каждой новой конфигурации соответствует массив, элементы которого кодируются булевыми переменными. Связь между двумя соседними конфигурациями определяется булевыми уравнениями, описывающими соответствующие зависимости между массивами. В таком представлении программа вычисления дискретной функции состоит только из команд записи битов в ячейки массивов и команд условного перехода. Только в «высокоуровневом случае» булевы переменные в новой конфигурации могут выражаться в виде суперпозиций булевых функций от
многих переменных предыдущей конфигурации. Соответственно и условия перехода могут выражаться сложными булевыми функциями.
Самым нетривиальным моментом (как и выше) является пропозициональное представление условных переходов. Далее будем рассматривать стандартную конструкцию условного оператора:
if (условие) then (переход) else (переход)
При этом ситуация «Условие выполнено» эквивалентна принятию некоторой булевой функцией g значения 1, ситуация «Условие не выполнено» эквивалентно принятию булевой функцией g значения 0. Иными словами,
if g(x1,...,xk ) = 1 then S (1)
else T (1)
для некоторых булевых переменных x1, . . . , xfc. Здесь S и T — это либо снова некоторые условные переходы, либо команды, формирующие массив, задающий ту конфигурацию, в которую осуществляется переход.
Пример 1. Предположим, что рассматривается некоторая программа для вычисления функции fn : {0,1}n ^ {0,1}*. Примером условного перехода типа (1) может быть следующий фрагмент программы:
if (£(уГ\ ... ,yk-1) = 1) then (yt := (yj-11 у2-1) yj := у}Лj £ {1,..., k}\{t})
else (yt := (y1-1 ^ y2-1) yj := yj^ j £ {1,... , k}\{t})
То есть если g(yj-1,... , yk-1) = 1, где yj-1, j £ {1,... , k} — компоненты массива, соответствующего (i — 1)-й конфигурации, то в i-й конфигурации значение yt совпадает со
значением функции y1-1 | y2-1. В противном случае, то есть если g(y 1—1,... , Ук-1) = 0, значение yt совпадает со значением функции y1-1 ^ У2-1. Значения переменных yj, j £ {1,... , k}\{t}, в обоих случаях совпадают со значениями переменных yj-1.
Пример 2. Предположим, что вычисляется функция f4 : {0,1}4 ^ {0,1}4, заданная следующей программой:
if (x1 ■ x2 V x3 = 1) then (y1 := (x1 | x2), У2 := x2, уз := x3, У4 := x4)
else (y1 := (x1 ^ x2), У2 := x2, Уз := x3, У4 := x4)
В контексте вышесказанного данной программе сопоставляется следующая система S (f4):
^У1 = ^(x1 I x2)(x1 ■ x2 V x3) V (x1 ^ x2)(x1 ■ x2 V x3)^ = 1,
< (У2 = x2) = 1,
(У3 = x3) = 1,
, (У4 = x4) = 1.
От данной системы переходим к одному уравнению вида КНФ = 1 при помощи преобразований Цейтина.
Вложенные условные операторы разбираются в соответствии с теми же принципами, что и для RAM-программ.
Пример 3. Рассмотрим программу
if g(xj! ,...,xjk ) = 1 then S
else if h(xj-1,..., xj) = 1 (2)
then T else U
В соответствии с описанными ранее принципами в процессе трансляции данного оператора объявляется массив булевых переменных у 1,... , уг, для значений которых имеются три альтернативы, определяемые блоками команд Б, Т и и. Предположим, что значения переменных у, г £ {1,...,г},в блоке Б определяются функциями Л^ (х1,... , хп), в блоке Т — функциями (х1,... , хп), в блоке и — функциями (х1,..., хп). Сказан-
ное означает, что результатом трансляции программы (2) является следующая система булевых уравнений:
{ (!Л = г(..,)ЛГ(...)V^(ТТж..К(...)Vг(...ж...к(...)) = 1,
| (?> = 9(.. .)Лг(...) V «(.. >■(.. (...) V й(.. .Ж.. .К1'(...)) = 1.
Рассмотренные принципы кодирования применимы к произвольным программам, вычисляющим всюду определенные дискретные функции, написанным на высокоуровневых языках программирования. При этом само вычисление интерпретируется последовательностью переписывающихся булевых массивов — элементы последующих массивов задаются булевыми функциями от элементов предыдущих массивов, а формулам, реализующим эти функции, сопоставляются булевы уравнения, образующие системы типа Б (/«).
2. Архитектура и функциональные возможности программного комплекса Transalg
Размерности систем булевых уравнений, которые кодируют комбинаторные задачи, возникающие в практических приложениях, таковы (иногда это десятки мегабайт), что процесс их построения требует автоматизации. Далее описаны основные элементы программного комплекса (транслятора) Тгапяа^, который стал практической реализацией перечисленных выше идей. Транслятор Тгапяа^ получает на входе программу вычисления некоторой дискретной функции, записанную на специальном процедурном языке программирования (язык ТА). Результатом трансляции ТА-программы является система булевых уравнений, кодирующая процесс вычисления рассматриваемой функции (система Б (/«)).
2.1. Базовые механизмы трансляции ТА-программ
Схематично процесс трансляции ТА-программ представлен на рис. 1.
Фазы анализа текста ТА-программы, построения дерева синтаксического разбора и обход полученного дерева с целью интерпретации реализованы стандартным способом (см., например, [10]). Нетривиальным моментом трансляции является процедура интерпретации конструкций языка, поскольку именно она отвечает за построение системы булевых уравнений, кодирующей процесс выполнения алгоритма. На этом этапе возникают многочисленные локальные проблемы, от решения которых может существенно зависеть как объем кода (в смысле общего числа задействованных в нем булевых переменных и количества уравнений), так и его структура.
Язык ТА представляет собой процедурный язык программирования с блочной структурой и С-подобным синтаксисом. Каждый блок — это список инструкций ТА-программы. Программа на языке ТА представляет собой набор определений функций, а также объявлений и определений глобальных переменных и констант. В языке ТА реализованы все основные примитивные конструкции, характерные для процедурных языков программирования (объявление/определение переменной или массива переменных; определение именованных констант; оператор присваивания; составной опе-
Рис. 1. Общая схема работы комплекса Transalg
ратор; условный переход; цикл; определение пользовательской функции; возврат из функции; вызов функции).
Переменные целочисленных типов хранят служебные параметры транслируемой программы. Например, это могут быть длины входного и выходного слов, количество итераций в циклах, целочисленные константы, используемые при вычислении дискретной функции.
Тип данных bit используется для объявления булевых переменных, кодирующих входную/выходную информацию транслируемой программы, а также информацию, возникающую в процессе работы этой программы. Речь идет о переменных, играющих ту же роль, что и переменные, кодирующие содержимое конфигураций К0, Ki, ..., Ke RAM (см. п. 1). Кроме этого, тип bit могут иметь переменные, используемые в тексте программы в качестве вспомогательных для хранения результатов промежуточных вычислений.
Действия с памятью, которые выполняются в любом современном вычислительном устройстве, аналогичны действиям с регистрами RAM. Далее будем рассматривать вычисление, которое осуществляет транслируемая программа, как последовательность изменений данных в памяти вычислительного устройства в моменты времени
0,1,... , е. В каждый момент времени i, i Е {0,... , e}, данные в памяти кодируются булевыми переменными, образующими множество X\ Таким образом, множество X0 образовано булевыми переменными, кодирующими входные данные, а множество Xe — переменными, кодирующими выходные данные рассматриваемого дискретного преобразования.
Особо подчеркнем, что переменные транслируемой ТА-программы и переменные пропозиционального кода этой программы представляют разные сущности. Переменные, фигурирующие в тексте транслируемой ТА-программы (далее «переменные программы»), понимаются в традиционном смысле — это идентификаторы областей памяти. Переменные, попадающие в пропозициональный код (далее «переменные кода»), понимаются как символы некоторого конечного алфавита. По своему смыслу переменные кода — это переменные итоговой системы булевых уравнений. Тем не менее эти два вида переменных тесно связаны. Каждой переменной программы соответствует специальная структура данных var_object. Эта структура хранит информацию о связи переменной кода с переменной программы на некотором шаге вычисления. При ин-
терпретации инструкций, содержащих переменные программы, транслятор проверяет соответствующие структуры var_object на наличие в них связи с переменными кода.
Переменные программы требуется различать по семантике. Для этой цели в языке при объявлении переменных типа bit используются специальные атрибуты. Атрибут _in сообщает транслятору, что данная переменная программы связана (посредством структуры var_object) с переменной кода, которая входит в множество X0. Эта связь осуществляется транслятором на начальном шаге (шаг инициализации). Атрибут _out используется для выделения переменных программы, связанных посредством var_object с переменными кода из множества Xе. Переменные с атрибутами _in или _out должны иметь глобальную область видимости, поскольку они сообщают транслятору информацию о входах и выходах кодируемого дискретного преобразования.
Кроме перечисленных, в тексте ТА-программы могут встречаться переменные, необходимые для хранения результатов промежуточных вычислений. Структура var_object таких переменных не связывает их с переменными кода. Далее такие переменные называются фиктивными. Проиллюстрируем все сказанное на следующем примере.
Пример 4. Рассмотрим ТА-программу, которая реализует (моделирует) изображённый на рис. 2 РСЛОС — регистр сдвига с линейной обратной связью [11], заданной полиномом над GF(2) P(x) = xi9 + xi8 + xi7 + xi4 + 1.
1 _in bit reg [19] ;
2 _out bit output [100] ;
3 bit shiftReg(){
4 bit x = reg [18];
5 bit y = reg[18]~reg[17]~reg [16]~reg [13];
6 for(int j = 18; j > 0; j = j - 1){
7 reg [j] = reg [j - 1];
8 }
9 reg [0] = y;
10 return x;
11 }
12 void main(){
13 for(int i = 0; i < 100; i = i + 1){
14 output[i] = shiftReg();
15 }
16 }
Массив булевых переменных reg описывает в каждый фиксированный момент времени текущее состояние регистра сдвига. На каждом шаге переменные программы reg[0], reg[18] связываются через структуры ¥аг_о^е^ с переменными ко-
да. Так, на начальном шаге переменные reg[0], ..., reg[18] связаны с переменными кода, образующими множество X0 = {х^..., х19}.
Представленная программа реализует 100 тактов работы регистра сдвига. В теле основной функции main() организован цикл, в котором вызывается функция сдвига регистра shiftReg(). Значения, возвращаемые функцией shiftReg(), определяют биты выходного слова, которое представлено в программе массивом output.
Сдвиг регистра обновляет значения всех элементов массива reg. На первом шаге данная операция приводит к вводу новых переменных кода, образующих множество Xi = {х20,... , х38}. Эти переменные связываются через структуры var_object с переменными программы reg[0], reg[18]. Данная связь интерпретируется сле-
дующей системой булевых уравнений:
(Х20 = Xig ф Xi8 ® Xi7 ® Xi4) = 1,
(X2i = Xi) = 1,
< (X22 = X2) = 1, (3)
^ (X38 = Xi8) = 1.
Переменная Xi9 кодирует первый бит ключевого потока, полученный в результате первого сдвига рассматриваемого РСЛОС. Отметим, что локальные переменные X и у функции shiftReg() необходимы лишь для корректной организации вычислений и не связаны с переменными кода программы. В контексте вышесказанного X и у — фиктивные переменные.
Можно заметить, что пропозициональный код, представляемый системой (3), является избыточным, поскольку переменные Xi и X2i кодируют одну и ту же информацию. Аналогично для переменных x2 и x22,. .., Xi8 и x38. Избежать подобных ситуаций позволяет описываемая далее техника, использующая при интерпретации инструкций ТА-программы специальный словарь термов S. Данный словарь образован термами над переменными кода транслируемой ТА-программы. Словарь S является динамически расширяемым. В начальном состоянии в S находятся только переменные множества X0 (то есть переменные, кодирующие входную информацию). В дальнейшем каждый новый терм, попадающий в словарь, является результатом интерпретации транслятором некоторой операции присваивания следующего вида:
z = Ф(^1 ,...,z>).
Здесь z — переменная программы, которая не является фиктивной, то есть связана через структуру var_object с некоторой переменной кода, а Ф^^,... , zjr) — терм над переменными программы. Транслятор обрабатывает терм Ф^.^,... , Zjr) и на его основе формирует терм ^(Xjx,..., xJr) над переменными кода. Затем транслятор проверяет словарь S на наличие в нем построенного терма. Если такой терм в словаре не найден, транслятор создает новую переменную кода X, терм ^(xj1,... ,xjr) добавляет в словарь S, а имеющаяся система булевых уравнений дополняется новым уравнением вида
(X = ^(хл , . . . , Xjr )) = 1
Если терм (^(Xj,... , xJr) содержится в S, это означает, что кодируемая этим термом информация уже учтена в пропозициональном коде транслируемой программы, то есть в системе булевых уравнений присутствует уравнение вида
(х' = ^(xji , . . . , Xjr )) = 1
В этом случае транслятор связывает переменную программы г с переменной кода Ж при помощи структуры var_object. Именно этот прием позволяет избегать ввода переменных кода, кодирующих одну и ту же информацию. Поясним сказанное на примере.
Пример 5. Рассмотрим процесс трансляции ТА-программы из примера 4. На начальном шаге трансляции в словарь термов включаются переменные кода, образую-тттие множество X0 = {ж1, ... , х19}. При этом связи между переменными программы, объединенными в массив reg, и переменными кода из множества X0 выглядят следующим образом (рис. 3):
Переменные программы (массив гед)
Переменные
кода
0 1 2
17 18
% 1 > > *4 >
х18, X
19
Рис. 3. Связь переменных программы с переменными кода до сдвига регистра
Интерпретируя сдвиг регистра, транслятор добавляет в словарь Б терм ^ = х19 ф фх18 ф х17 ф х14, кодирующий функцию обратной связи, создает новую переменную кода х20 и добавляет в систему булевых уравнений уравнение
(Ж20 = X19 ф X18 ф Ж17 ф Ж14) = 1.
Кроме этого, транслятор обновляет связи между элементами массива reg и переменными кода (рис. 4).
Переменные программы (массив гед)
Переменные
кода
0 1 2
17
18
*20’ '*'1 ’ *2'
У f
*17' *18’*19
Рис. 4. Связь переменных программы с переменными кода после сдвига регистра
Особо отметим, что для переменных программы reg[1], ..., reg[18] новые переменные кода не создавались — посредством структур var_object транслятор связал данные переменные с переменными кода x1, . . . , x18 соответственно.
2.2. Трансляция условных переходов В программном комплексе Transalg интерпретация условного оператора начинается с анализа условного выражения. Условный оператор — это оператор вида if $(zj1,... , Zjr) = 1 then Ветвь І; else Ветвь 2;
где терм условного выражения Ф(^^1,... , zjr) — терм над переменными программы. Если в терм условного выражения входят переменные программы, связанные посредством структур var_object с переменными кода, то транслятор переходит в режим ветвления. Первое действие транслятора в этом режиме заключается в интерпретации терма условного выражения Ф, результатом чего является терм ^ над переменными кода.
Ветвью условного оператора может быть произвольный блок операторов. Интерпретация ветви — это последовательная интерпретация всех операторов соответствующего блока. Особо отметим, что одна и та же переменная программы может фигурировать в различных ветвях условного оператора.
Рассмотрим условный оператор, имеющий две ветви условного перехода. Пусть в обеих ветвях данного оператора выполняется некоторая операция присваивания, и z — переменная программы, являющаяся левым операндом этой операции. Пусть Ai и Д2 — термы над переменными программы, являющиеся правыми операндами данной операции присваивания соответственно в 1-й и 2-й ветвях. В этой ситуации транслятор связывает переменную z с новой переменной кода X, в словарь S добавляется терм
( • ^ V ( • £2, а в систему булевых уравнений — уравнение
(X = ( • £i V ( • £2) = 1.
Здесь £i и £2 — термы над переменными кода, полученные в результате интерпретации термов Дi и Д2 соответственно. Для хранения пар вида (z, £1) и (z, £2) используются отдельные списки Li и L2.
Далее рассматривается конструкция из нескольких вложенных условных операторов:
if Ф1 (...) = 1 then Ветвь 1;
else if Ф2(...) = 1 then Ветвь 2;
else if Фп(...) = 1 then Ветвь n;
else Ветвь n +1;
В соответствии со сказанным выше, каждому терму Ф^, i = 1,... , n, сопоставляется терм (i над множеством переменных кода. Каждой ветви с номером i Е {1,... , n +1} ставится в соответствие список Lj, образованный парами вида (z,£j). Пусть z — переменная программы, выступающая в качестве левого операнда операций присваивания в ветвях с номерами от 1 до n + 1 рассматриваемого условного оператора. Тогда транслятор связывает переменную z с новой переменной кода X, в словарь S добавляется терм
(1 • £i V (Pi • (2 • £2 V ... V (pi • (р2 • ... • (n-i • (n • £n V (Pi • ... • (Pn • £n+i,
а в систему булевых уравнений — уравнение
(X = (i • £i v <pi • (2 • £2 v ... v <pi • (2 •... • (n-i • (n • £n v <pi •... • <pn • £n+i) = 1.
Проиллюстрируем сказанное на примере.
Пример 6. Рассматриваются два РСЛОС, обозначаемые через regA и regB. Рассмотрим ситуацию, в которой условие сдвига для каждого РСЛОС определяется значением некоторой булевой функции от битов его текущего состояния. Иными словами, сдвиг регистра происходит лишь тогда, когда значение данной функции равно 1. Алгоритм, реализующий функцию сдвига произвольного РСЛОС, описан в примере 5, поэтому определения функций shiftRegA() и shiftRegB() в следующей ТА-программе опущены.
1 _in bit regA[19];
2 _in bit regB [17] ;
3 _out bit output [100] ;
4 bit shiftRegA () {...}
5 bit shiftRegB () {...}
6 bit conditionA(){return regA [18] ~ regB [16];}
7 bit conditionB(){return regA [18] & regB [16];}
8 void main(){
9 for(int i = 0; i < 100; i = i + 1){
10 if( conditionA())
11 shiftRegA () ;
12 else if(conditionB())
13 shiftRegB();
14 e l s e {
15 shiftRegA () ;
16 shiftRegB () ;
17 }
18 output [i] = regA [18] ~ regB [16] ;
19 }
20 }
На начальном шаге транслятор формирует множество переменных кода
X0 = {Xi, . . . ,Xi9, X20, . .. ,Хзб}. regA regB
Данные переменные кодируют входную информацию рассматриваемой дискретной функции.
При интерпретации условных выражений транслятор обнаруживает (анализируя структуры var_object), что входящие в эти выражения переменные программы regA[18] и regB[16] связаны с переменными кода. В результате транслятор переходит в режим ветвления. Интерпретация условных выражений в операторе ветвления дает термы над переменными кода
(i = Xi9 ф х36, (2 = х19 • х36.
В ходе интерпретации ветвей условного перехода формируются списки Lj, i Е {1, 2, 3}. Обозначим через £i и £2 термы, полученные в результате интерпретации термов программы, выражающих функции обратной связи регистров regA и regB. В соответствии со сказанным выше, для рассматриваемого оператора ветвления транслятор формирует структуру данных, изображенную на рис. 5 (связи переменных программы с переменными кода обновляются в соответствии с описанной ранее техникой).
Рассмотренная схема дает эффективную процедуру связывания переменных программы с переменными кода при трансляции операторов условного перехода. Например, переменная regA[0] в результате трансляции будет связана с новой переменной кода X37, в словарь S будет добавлен терм
(1 • £i V (pi • (2 • Xi V (pi • (2 • £i, а в систему булевых уравнений — уравнение
(Xз7 = (l • £l V (l • (2 • Xl V (l • (P2 • ^l) = 1.
Переменные программы (массив regA)
Переменные
кода
Переменные программы (массив regB)
Переменные
кода
М
regA и regB
Переменные
кода
*38’ X20’ X2l>
17
18
f у
Xn> -*'18 J
15
16
f f
*34’ -^Зб J
Рис. Б. Вспомогательные структуры данных, представляющие условный переход
2.3. Кодирование целочисленных операций В комплексе Transalg предусмотрена возможность пропозиционального кодирования целочисленных операций. При трансляции целые числа представляются булевыми массивами. Однако в тексте ТА-программы присутствуют лишь операции над буквенными обозначениями чисел, что позволяет приблизить синтаксис выражений языка ТА к синтаксису выражений, общепринятому в процедурном программировании.
Пример Т. Рассмотрим следующую ТА-программу (n — произвольная натуральная константа):
1 .in bit a [n];
2 .in bit b [n];
3 .out bit c[n+i];
4 void main С){
Б c = a + b;
б }
Данная программа реализует дискретную функцию, которая получает на вход два целых неотрицательных числа а, b и на выходе выдает их сумму — целое неотрицательное число с. Для представления целых чисел a, b и с объявляются булевы массивы а = {а0,..., an-1}, b = {b0,..., bn-1} и с = {с0,..., cn}. Далее приведен результат трансляции данной программы в предположении, что для сложения двух неотрицательных целых чисел используется алгоритм «столбик»:
(co = а0 0 bo) = 1
(po = а0 • bo) = 1, ________
< (pj = , bj, рі-1)) = 1 j = 1, n - 1, (4) (с* = а* 0 bi 0 Pi-l) = 1, i = 1, n - 1,
k (cn = pn-1) - 1.
Запись maj(x, y, z) обозначает терм x • y V x • z V y • z. Для кодирования битов переноса транслятор вводит новые переменные кода p*, i = 0, n — 1. В трансляторе Transalg
реализована также возможность кодирования операций умножения, вычитания и сравнения пар целых чисел.
Как было отмечено в п. 1.1, для использования эффективных символьных решателей предпочтительно от полученной в результате трансляции алгоритма системы булевых уравнений перейти к некоторой нормальной форме. Наилучшие результаты на обширных классах практических задач показывают SAT-решатели, то есть решатели булевых уравнений вида КНФ = 1. В трансляторе Transalg переход от систем булевых уравнений описанного типа к уравнениям вида КНФ = 1 осуществляется при помощи преобразований Цейтина [8], дополненных процедурами минимизации булевых функций в классе КНФ. Кроме этого, возможен вывод пропозиционального кода алгоритма в форме систем полиномиальных уравнений над GF(2). Предусмотрена также возможность построения И-НЕ-графа, фактически представляющего алгоритм вычисления рассматриваемой функции в форме схемы из функциональных элементов над базисом {&, —}.
3. Применение комплекса Transalg для пропозиционального кодирования алгоритмов вычисления некоторых криптографических функций
Одной из наиболее наглядных областей применения описанной техники трансляции ТА-программ является криптография. Далее разбираются примеры построения пропозициональных кодов некоторых криптографических алгоритмов. Для ряда криптосистем данный подход позволил успешно решить задачи криптоанализа.
В работе [12] было отмечено, что пропозициональные коды алгоритмов шифрования можно использовать для построения аргументированно трудных тестов для разнообразных решателей комбинаторных задач (в том числе для SAT-решателей). В дальнейшем криптоанализ, рассматриваемый как процесс поиска решений булевых уравнений (в частности, SAT-задач), стали называть логическим криптоанализом [13].
Логический криптоанализ оказался эффективным в применении к некоторым генераторам ключевого потока [14, 15]. Быстрые генераторы поточного шифрования — это эффективно вычислимые дискретные функции, преобразующие двоичные последовательности конечной длины (инициализирующие последовательности) в бесконечные периодические двоичные последовательности (ключевой поток). Задача криптоанализа генератора ключевого потока заключается в нахождении инициализирующей последовательности по известному фрагменту ключевого потока и алгоритму функционирования генератора.
Программный комплекс Transalg по известному алгоритму генерации ключевого потока позволяет построить систему булевых уравнений, кодирующих процесс порождения произвольного фрагмента ключевого потока. Подстановка в полученную систему анализируемого фрагмента ключевого потока дает систему булевых уравнений, из решения которой можно эффективно выделить искомый секретный ключ (инициализирующую последовательность).
3.1. К о д и р о в а н и е г е н е р а т о р о в п о т о ч н о г о ш и ф р о в а н и я
Рассмотрим задачу пропозиционального кодирования генераторов поточного шифрования на примере суммирующего генератора Р. Рюппеля [16] (см. также [11]). Данный генератор состоит из R ^ 2 РСЛОС и специального регистра, называемого сумматором. Сумматор представляет собой одномерный массив ячеек памяти размерности [log R]. Отдельная ячейка позволяет хранить один бит информации. В начальный момент времени (т = 0) в сумматоре записан вектор двоичного представления нату-
рального числа Со (соответствующие биты образуют часть секретного ключа). В каждый такт с номером т, т Є {1, 2,...}, синхронно снимаемые с выходов РСЛОС биты подаются на вход сумматора, где целочисленно складываются с Ст_1. Полученное натуральное число обозначается через £т. Выходом генератора суммирования в такте с номером т, т Є {1, 2,...}, является младший бит двоичного представления числа £т. Значением сумматора в такте с номером т, т Є {1, 2,...}, является двоичное представление числа |_$т /2].
Рассмотрим суммирующий генератор, состоящий из трех РСЛОС (Я = 3), функции обратной связи которых задаются следующими полиномами над СЕ(2):
Рі(х)
х19 + ж18 + х17 + ж14 + 1; Р2(х)
х
22
+ х +1; Рз(х)
х23 + х22 + х21 + х8 + 1.
Запишем программу для комплекса Тгаша^, вычисляющую 180 бит ключевого потока для заданного генератора суммирования (функции вЫ^Б^АО, вЫ^Б^ВО и вЫ^Б^СО определяются по аналогии с функцией вЫ^Б^О из примера 5):
1 _іп Ь^ regA [19] ;
2 _іп bit regB [22] ;
3 _іп Ьit regC [23] ;
4 _іп Ьit summator [2] ;
5 _out Ьit output [180] ;
6 void та^ () {
7 for(int і = 0; і < 180; і = і + 1){
8 summator = shiftRegA() + shiftRegB()
9 + shiftRegC () +
10 output[і] = summator[0];
11 summator = summator >> 1;
12 }
13 }
Объявления булевых массивов с атрибутами _1п и _о^ позволяют транслятору создать множество переменных X0 = {х1, . . . , Х66}, кодирующих секретный ключ, и множество переменных Xе = {хг1,... , Х^180}, кодирующих 180-битовый начальный фрагмент ключевого потока. Пропозициональное кодирование процедур сдвига регистров осуществляется по схеме, описанной в п. 2.
Результатом трансляции первого такта работы суммирующего генератора является следующая система булевых уравнений:
(у1 = Х19 ф X18 ф X17 ф Х14) = 1,
(У2 = Х41 ф Х40) = 1,
(У3 = Х64 ф Х63 ф Х62 ф Х49) = 1 (у4 = Х19 ф Х41 ф Х64 ф Хбб) = 1,
(У5 = Х19 ■ Х41 ф Х66 ф Х64 ■ Х65 ф (Х19 ф Х41) ■ (Х64 ф Х6б)) = 1.
Здесь переменные у1, у2, у3 — это новые переменные кода, связанные с переменными программы regA[0], regB[0] и regC[0], а переменные у4, у5 кодируют соответственно младший и старший биты натурального числа, которое является новым значением
сумматора. Тем самым переменная у4 кодирует первый бит ключевого потока. Таким образом, кодирование с помощью комплекса Тташа^ одного такта работы рассматриваемого суммирующего генератора добавляет в кодировку пять новых булевых уравнений и пять дополнительных переменных.
Результатом трансляции 180 тактов работы данного генератора является система из 900 булевых уравнений от 966 булевых переменных. Эта система посредством преобразований Цейтина сводится к уравнению вида КНФ = 1. Результирующая КНФ состоит из 11532 дизъюнктов над множеством из 966 булевых переменных.
3.2. Кодирование криптоалгоритма ВЕБ Алгоритм ВЕБ является симметричным блочным алгоритмом шифрования, построенным на основе сети Фейстеля, с 56-битовым секретным ключом. Данный алгоритм фигурирует в массе источников (см., например, [11, 17]), поэтому его описание здесь не приводится. Первой работой, в которой был приведен пропозициональный код ВЕБ, является препринт [18]. Журнальный вариант данной работы появился годом позже [13]. Эти статьи (наряду с [12]) следует считать основополагающими работами по логическому криптоанализу.
Одними из базовых примитивов шифра ВЕБ являются перестановки. Перестановки в ВЕБ задаются таблицами натуральных чисел, которые не являются секретными. Произвольная перестановка применяется к некоторому множеству бит обрабатываемого слова. При пропозициональном кодировании операции перестановки транслятор Тгапяа^ не создает новых переменных кода — как видно из п. 2.1, транслятору достаточно обновить связи переменных программы с уже существующими элементами словаря термов Б. Данный факт означает, что операции перестановки не вносят в пропозициональный код алгоритма шифрования новой информации, никак не усложняя, таким образом, задачу логического криптоанализа.
В результате применения транслятора Тгапяа^ к алгоритму ВЕБ был получен пропозициональный код данного алгоритма (в форме КНФ), существенно более экономный, чем код, приведенный в [13, 18] (см. табл. 1).
Таблица 1
Кодирование процесса шифрования алгоритмом ЮББ одного блока открытого текста длиной 64 бита
Программный комплекс Transalg F. Massacci, L. Marraro, [13]
Без минимизации Минимизация (Espresso, [19])
Переменные Дизъюнкты Переменные Дизъюнкты Переменные Дизъюнкты
1912 37888 1912 264QQ 1Q336 61935
4. Процедуры сведения задач 0-1-ЦЛП к SAT-задачам
Наблюдающийся в последние годы прогресс в алгоритмике SAT-решателей стимулирует применение этих методов в решении задач дискретной оптимизации, которые на первый взгляд могут показаться далекими от проблем пропозициональной выполнимости. Одним из сравнительно новых направлений такого рода является применение SAT-подхода к задачам с «псевдобулевыми ограничениями». Данная тематика активно развивалась в 2QQ6-2QQ8 гг. Сейчас наблюдается заметный спад этой активности, однако продолжают проводиться соревнования [2Q] и даже регулярно проходят специализированные конференции, посвященные «псевдобулевым решателям». Работа [21] является, пожалуй, наиболее полным введением в проблему трансляции псевдобуле-вых задач в SAT.
Приведём исходную постановку задачи Q-1-целочисленного линейного программирования (Q-1-ЦЛП), а также кратко опишем базовые принципы трансляции псевдобу-левых ограничений в булевы.
Рассмотрим задачу 0-1-ЦЛП в стандартной постановке: дана система ограничений-неравенств
A • х ^ b, (5)
где A — (m х ^-матрица с целочисленными компонентами; b — вектор длины m, состоящий из целых чисел. Предполагается, что переменные хг, i G {1,... , n}, принимают значения в множестве целых чисел {0,1}. Множество решений (5) называется допустимым множеством. Распознавательный вариант задачи 0-1-ЦЛП подразумевает ответ на вопрос «Верно ли, что допустимое множество не пусто?» В оптимизационном варианте требуется минимизировать на допустимом множестве целевую функцию — линейную форму (с, х), где с — заданный целочисленный вектор длины n.
Процесс сведения данной задачи к SAT состоит в преобразовании линейных неравенств, образующих систему (5), в конъюнкции дизъюнктов. При этом можно использовать эквивалентные преобразования исходных ограничений, приводящие к ограничениям вида
(а;, х?) ^ bo, (6)
где а; — вектор длины n с целыми неотрицательными компонентами; х? — вектор, образованный литералами над переменными из множества X = {xi,... , xn}; b0 — неотрицательное целое число.
Пример 8. Рассмотрим ограничение 3х1 — 2х2 + 5х3 ^ 3. Результатом замены х2 = 1 — х2 является ограничение 3х1 + 2х2 + 5х3 ^ 5.
Сказанное означает, что от исходной задачи возможен эффективный переход к задаче минимизации линейной формы (с;,х?) при условии выполнения m ограничений вида (6).
Задачи 0-1-ЦЛП в последние годы называют также задачами с псевдобулевыми ограничениями. Этим подчеркивается, что переменные задачи принимают значения в {0,1}, однако это не значения истинности, а целые числа. Вообще, термины «псев-добулева задача», «псевдобулево ограничение» и т. п. более правомерны в отношении формулировок вида (6). Именно в таком контексте они и используются далее.
Очевидно, что неравенство
а^?1 + ... + а„хП" ^ 0
в предположении, что аг = 0, i G {1,... , n}, а хг принимают значения в {0,1}, выполняется лишь при х?1 = ... = хПп = 0. Поэтому далее рассматриваем псевдобулевы ограничения вида
а^?1 + ... + а„хПп ^ b, (7)
полагая, что аг, i G {1,... , n}, b — натуральные числа.
Произвольному целочисленному вектору с компонентами из {0,1} естественным образом сопоставляется внешне ничем от него не отличающийся булев вектор. В этом смысле произвольному ограничению (7) соответствует булева функция, которая принимает значение «истина» тогда и только тогда, когда выполняется (7).
Пусть (ak ... a0), aj G {0,1}, j G {0,... , k}, k = [logaj, —вектор двоичного представления натурального числа а. Тогда выражению ах? поставим в соответствие слово
А(ах?) = (Afc ... Ao)
над алфавитом {0,х?} по следующему правилу: если aj = 0, то Aj = 0; если aj = 1,
то Aj = х?.
Пример 9. В соответствии с описанными правилами выражению 5ж1 сопоставляется слово (Х10Х1) (число 5 в двоичном представлении задается вектором (101)).
Линейной форме а1ж?1 + ... + апжПп ставится в соответствие система булевых уравнений, связывающая компоненты слов А(а1ж?1),... , А(агажП"). Фактически данная система уравнений описывает процесс суммирования натуральных чисел, представленных двоичными векторами. Так, если А = (А& ... А0) и В = (В& ... В0) —построенные по описанным правилам слова, которые соответствуют выражениям а1ж?1 и а2ж22, то связывающая компоненты слов А и В система булевых уравнений будет аналогична системе (4).
Предположим, что построена система булевых уравнений, которая связывает компоненты слов А(а1 Х21),... , А(агажПп). К данной системе добавим уравнения, кодирующие тот факт, что результат целочисленного сложения а1ж21 + ... + апжПп не превосходит натурального числа Ь. Итоговую систему булевых уравнений обозначим через ^(а^1 + ... + ).
От систем типа ^ь(а1ж21 + ... + апжПп) переходим к уравнениям вида КНФ = 1 при помощи преобразований Цейтина. Итогом описанных действий является такая КНФ С (А, Ь), что между множеством решений системы (5) и множеством решений уравнения С (А, Ь) = 1 существует биекция, и от любого решения этого уравнения можно эффективно перейти к решению исходной системы целочисленных неравенств.
Пусть допустимое множество для исходной задачи 0-1-ЦЛП не пусто, ж0 = (а0,... ,
П
аП) —некоторая его точка и Я = ^ с^а0 —значение целевой функции в данной точке.
І=1
Чтобы попытаться улучшить значение целевой функции, можно добавить к системе ограничений (5) условие в форме линейного неравенства. Это могут быть неравенства вида (с,ж) ^ Я — 1, (с,ж) ^ |_Я/2] и т.п., все зависит от выбранной схемы поиска. От произвольного такого неравенства возможен переход к уравнению вида КНФ = 1 в соответствии с описанной выше техникой. Таким образом, оптимизационный вариант задачи 0-1-ЦЛП может быть сведен к решению серии БАТ-задач. При этом если Я — некоторое начальное приближение, то использование дихотомии гарантирует нахождение оптимального значения целевой функции (ж, с) на допустимом множестве, определяемом системой ограничений (5), за O(log Я) итераций.
Описанные преобразования псевдобулевых ограничений в булевы были реализованы в виде дополнительного модуля к транслятору Тгапяа^. В табл. 2 приведено сравнение результатов трансляции псевдобулевых задач (эти задачи были взяты из библиотеки [22]) в БАТ-задачи. Сравниваются КНФ, полученные транслятором Тгапяа^, и КНФ, полученные известной программой трансляции псевдобулевых задач МіпіБаі+ (см. [23]).
Т а б л и ц а 2 Сравнение результатов трансляции псевдобулевых задач в SAT
Задача Transalg MiniSat+
Переменные Дизъюнкты Переменные Дизъюнкты
AQ51QQ 2469 19577 3568 176Q8
D1Q2QQ 11987 1Q3Q72 17777 99316
D2Q1QQ 14847 128Q78 179Q5 1Q26QQ
D1Q4QQ 2411Q 197863 3438Q 191468
D2Q2QQ 3QQ12 259923 35739 2Q6813
D2Q4QQ 6Q243 51996Q 69789 4Q4Q14
D159QQ 818Q4 7Q5882 11Q942 651436
Заключение
Описанная технология пропозиционального кодирования алгоритмов может применяться при исследовании разнообразных систем, поведение которых описывается полиномиально вычислимыми дискретными функциями. Сказанное касается, прежде всего, дискретно-автоматных динамических систем — переходы в последующие состояния в таких системах происходят в дискретные моменты времени, и довольно часто функции, задающие эти переходы, оказываются эффективно вычислимыми. Устанавливать некоторые свойства такого рода систем можно, транслируя алгоритмы вычисления функций переходов в булевы уравнения и добавляя при необходимости к получаемым системам дополнительные ограничения. Трансляция соответствующих алгоритмов может осуществляться при помощи программного комплекса Transalg. Предполагаем, что данный подход окажется полезным в исследовании динамических свойств дискретных моделей генных сетей [24], а также при решении задач из области «Bounded Model Checking» [25].
ЛИТЕРАТУРА
1. Rudeanu S. Boolean functions and equations. Amsterdam; London: North-Holland Publishing Company, 1974. 442 p.
2. Prestwich S. CNF encodings. In Handbook of Satisfiability / eds. A. Biere, M. Heule, H. van Maaren, T. Walsh. IOS Press, 2009. P. 75-97.
3. Cook S. A. The complexity of theorem-proving procedures // Proc. 3rd Ann. ACM Symp. on
Theory of Computing (STOC 71). ACM. 1971. P. 151-159.
4. Garey M. R. and Johnson S. Computers and intractability: A guide to the theory of NP-
completeness. W. H. Freeman, 1979. 340 p.
5. Семёнов А. А. Трансляция алгоритмов вычисления дискретных функций в выражения пропозициональной логики // Прикладные алгоритмы в дискретном анализе. Сер. Дискретный анализ и информатика. 2008. Вып. 2. С. 70-98.
6. Shepherdson J. C. and Sturgis H. E. Computability of recursive functions // J. Assoc. Comp. Machinery. 1963. V. 10. P. 217-255.
7. Катленд Н. Вычислимость. Введение в теорию рекурсивных функций. М.: Мир, 1983. 256 с.
8. Цейтин Г. С. О сложности вывода в исчислении высказываний // Записки научных се-
минаров ЛОМИ АН СССР. 1968. Т. 8. С. 234-259.
9. Семёнов А. А. О преобразованиях Цейтина в логических уравнениях jj Прикладная дискретная математика. 2009. №4. С. 28-50.
10. Ахо А., Сети Р., Ульман Дж. Компиляторы. Принципы, технологии, инструменты. М.; СПб.; Киев: Вильямс, 2001. 7б8 c.
11. Menezes A., Oorschot P., and Vanstone S. Handbook of Applied Cryptography. CRC Press, 199б. б57 p.
12. Cook S. A. and MitchelG. Finding hard instances of the satisfiability problem: A survey jj DIMACS Ser. Discr. Mathem. Theoret. Comp. Scie. 1997. V. 35. P. 1-17.
13. Massacci F. and Marraro L. Logical Cryptanalysis as a SAT Problem jj J. Autom. Reas. 2000. V. 24. No. 1-2. P. 1б5-203.
14. Семёнов А. А., Заикин О. С., Беспалов Д. В., Ушаков А. А. SAT-подход в криптоанализе некоторых систем поточного шифрования jj Вычислительные технологии. 2008. Т. 13. №б. С. 134-150.
15. Посыпкин М. А., Заикин О. С., Беспалов Д. В., Семёнов А. А. Решение задач криптоанализа поточных шифров в распределенных вычислительных средах jj Труды ИСА РАН. 2009. Т.4б. С. 119-137.
16. Rueppel R. Correlation immunity and the summation generator jj LNCS. 198б. V. 218. P. 2б0-272.
17. Schneier B. Applied Cryptography, Second Edition: Protocols, Algorithms, and Source Code in C. John Wiley and Sons, 199б. 758 p.
18. Massacci F. and Marraro L. Logical Cryptoanalysis as a SAT Problem: the Encoding of the Data Encryption Standard. Preprint. Dipartimento di Imformatica e Sistemistica, Universita di Roma “La Sapienza”, 1999.
19. http://embedded.eecs.berkeley.edu/pubs/downloads/espresso
20. http://www.cril.univ-artois.fr/PB10/
21. EenN. and Sorensson N. Translating Pseudo-Boolean Constraints into SAT jj J. Satisfiab., Bool. Model. Comp. 200б. V. 2. P. 1-25.
22. http://miplib.zib.de MIPLIB — Mixed Integer Problem Library.
23. http://minisat.se/MiniSat+.html
24. Системная компьютерная биология j под ред. Н. А. Колчанова, С. С. Гончарова, В. А. Лихошвая, В. А. Иванисенко. Новосибирск: Изд-во СО РАН, 2008. 7б7 c.
25. Ganai M. and Gupta A. SAT-based scalable formal verification solutions. Springer, 2007. 32б p.