Не давно дошли наконец руки до программируемой логики. Потребовался быстрый брутфорс некоторого количества кодов, для изучения алгоритма построения ответов одной железки, контроллер которой пока не могу вычитать.
Для начала краткая предыстория.
Я написал алгоритм проверки в VHDL после большого количества исправлений (ругалось при компиляции, все-то им не нравится, то точка с запятой лишняя, то не хватает чего…) собрал, попытался запустить симуляцию… и результатом — какая-то белиберда…два дня мучений и переписывания алгоритма, обогатили меня знаниями в VHDL, но не сдвинули с места результат. тогда я решил пойти от простого к сложному. Уменьшил элементы алгоритма до 4-х бит и оставил всего несколько шагов от самого алгоритма.
И вот теперь мы перейдем к основной части, построение «вычислительной» системы на FPGA (field programmable gate array) или CPLD(Complex Programmable Logic Device), иными словами на программируемой логике.
По сути что у нас используется в алгоритмах шифрования? Сложение, вычитание, сдвиги, и набор логических операторов. Бывает еще табличный метод, но мы его рассматривать не будем. Все эти действия могут быть произведены процессором, а можно для них создать схему на «жесткой» логике. Ну или запрограммировать эту самую схему в кристалле ПЛИС(интегральная схема программируемой логики). И тогда у нас получится аппарат, который в идеале получив на входе исходный блок данных, на выходе тут же дает шифрованный или дешифрованный (смотря какой алгоритм и какой аппарат мы создавали). На самом деле, конечно, не тут же. Все элементы имеют задержку пропускания сигнала, и пока сигнал в цепях схемы не пройдет самый длинный из всех параллельных путей, результат будет не достоверным. Это будет так называемый переходный процесс, и его время будет зависеть от быстродействия ячеек FPGA и сложности алгоритма. Но в любом случае, кроме самых «гротескных» это будет быстрее, чем процессор бы выполнил последовательность всех действий.
для начала создаем элементы, из которых будем собирать нашу «функцию».

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity element1 is
port(
a,b,c,d : in std_logic_vector(3 downto 0 );
y : out std_logic_vector(3 downto 0 )
);
end entity element1;

architecture h_xor of element1 is
constant cn : unsigned := x"5"; -- cn <= x"5C4DD124";
begin
y <= unsigned(a) + cn + unsigned( b xor c xor d );
end architecture h_xor;

architecture h_major of element1 is
begin
y <= unsigned(a) + unsigned( ((b or c) and d) or ( b and c ) );
end architecture h_major;

в самом начале идет "шапка" библиотеки, она указывает какой тип библиотек и синтаксиса используется. Во всех источниках, что я читал, советуют просто скопировать все это, и добавить к use свои библиотеки, если нужно.
Далее мы объявляем что-то вроде интерфейса (entity). Наш интерфейс объявляет элементы с четырьмя, четырехразрядными входами (a,b,c,d) и одним четырехразрядным выходом (y).
После этого объявляем архитектуры требуемых элементов. Первый у нас реализует функцию xor со сложением: y = a + (b ^ c ^ d); А второй мажоритарное или со сложением y = a + maj_or(b, c, d);

Теперь переходим к основному файлу:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;

entity tut01 is
port(
x: in std_logic_vector(3 downto 0);
y: out std_logic_vector(3 downto 0)
);
end entity tut01;

architecture tutor of tut01 is
signal s0,s1,s2,s3,s4,s5,s6,s7,s8 : std_logic_vector(3 downto 0);
begin
e1: entity work.element1(h_major) port map( x"1", x"2", x"3", x, s0 );
e2: entity work.element1(h_xor) port map( x"4", x"5",x, s0, s1 );
e3: entity work.element1(h_major) port map( x"6", x, s0, s1, s2 );
e4: entity work.element1(h_xor) port map( x, s0, s1 , s2, s3 );
y <= s3;
end architecture tutor;

Ну в области "шапки" и объявления интерфейса, ничего для нас нового нет, а вот в самой архитектуре объекта tutor. пожалуй, кое-что требует объяснения.
во-первых тут используются "переменные", точнее сигналы (s0..s8)
во-вторых тут объявляются "объекты" ранее определенных "типов" (e1..e4).
в третьих у объявленных элементов (объектов) используется порт маппинг (подключение портов, непосредственно при объявлении), причем некоторые порты, изначально "забиваются" шестнадцатиричными константами (x"4", x"6"...).

Далее, я думаю нужны некоторые объяснения. В VHDL, как и в любом языке описания аппаратуры, используется принцип "одновременности" действий. Т.е. все действия происходят одновременно, т.е. если мы пишем что-то вроде:

a <= b + c;
b <= c + a;

где в начале a = 1, b = 2, c = 3, то у нас по выполнению этого буде a =5, b = 4; и только на втором проходе b станет равным 8, но при этом a уже будет равно 7...
Если же требуется произвести последовательность действий, то нужно обьявлять процесс, а внутри него вместо <= использовать присвоение, как в паскале :=, но об этом как нибудь в другой раз.
Сейчас же, посмотрим что у нас получилось. Для начала схематическая диаграмма полученной функции (иногда помогает увидеть, как можно упростить всю систему в целом, кроме того она удобнее людям привыкшим не к программированию, а к сборке "в железе").
Схематическая диаграмма
Ну и смотрим на результат работы. В качестве параметров при симуляции были заданы случайные числа, подаваемые на вход X.
Симуляция процессов в ПЛИС
Здесь в районе 65 наносекунд, явно видны "всплески" значений вызванных, так называемым переходным процессом. Т.е. когда часть элементов, уже переключилась, на новые значения, а часть еще нет, и это вызывает кратковременные "паразитные" значения на выходе.

Для начала, я думаю будет достаточно. если кому это покажется интересным, то можно скачать с сайта altera.com программу Quartus (рекомендую поискать в сети или спросить у меня версию 9, потому как в более поздней, симуляцию уже исключили и рекомендуют для нее использовать стороннюю программу) и "поиграться". Реально мы смогли добиться при брутфорсе, быстродействия более чем в 100 раз превышающего вычисление той же крипто-функции, на процессоре с частотой 2800 Мгц (имейте ввиду что функция целиком умещается в кеше процессора).



Оставить комментарий