diff --git a/examples/std_kuznechik/std_kuznechik_decoder.cpp b/examples/std_kuznechik/std_kuznechik_decoder.cpp new file mode 100644 index 00000000..bc025f71 --- /dev/null +++ b/examples/std_kuznechik/std_kuznechik_decoder.cpp @@ -0,0 +1,17 @@ +//===----------------------------------------------------------------------===// +// +// Part of the Utopia HLS Project, under the Apache License v2.0 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 ISP RAS (http://www.ispras.ru) +// +//===----------------------------------------------------------------------===// + +#include "dfcxx/std/crypto/gost_34_12/kuznechik.h" + +#include + +std::unique_ptr start() { + using dfcxx::std::KuznechikDecoder; + KuznechikDecoder *kernel = new KuznechikDecoder(true); + return std::unique_ptr(kernel); +} diff --git a/examples/std_kuznechik/std_kuznechik_decoder_testbench0.sv b/examples/std_kuznechik/std_kuznechik_decoder_testbench0.sv new file mode 100644 index 00000000..7e8b5c0f --- /dev/null +++ b/examples/std_kuznechik/std_kuznechik_decoder_testbench0.sv @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the Utopia HLS Project, under the Apache License v2.0 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 ISP RAS (http://www.ispras.ru) +// +//===----------------------------------------------------------------------===// + +// Total: 0 stages. + +`timescale 1s/1s + +module KuznechikDecoder_test0(); + + localparam CIRCUIT_LATENCY = 0; + + reg [127:0] encoded; + reg [255:0] key; + reg [127:0] block; + reg [127:0] expected; + reg clk; + + KuznechikDecoder inst ( + .encoded(encoded), + .key(key), + .block(block), + .clk(clk) + ); + + initial clk = 0; + + always #1 clk = ~clk; + + initial begin + + @(negedge clk); + $display("[KuznechikDecoder: test 0] Input ready."); + + encoded = 128'h7f679d90bebc24305a468d42b9d4edcd; + key = 256'h8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef; + expected = 128'h1122334455667700ffeeddccbbaa9988; + $display("Input: [%0x], key: [%0x]", encoded, key); + end + + initial begin + // Wait for the first output. + #(2*CIRCUIT_LATENCY+3); + + $dumpfile("KuznechikDecoder_test0.vcd"); + $dumpvars(0, KuznechikDecoder_test0); + $display("[KuznechikDecoder: test 0] Started..."); + + $display("Output: %0h", block); + if (expected == block) begin + $display("GOOD: %0h == %0h", expected, block); + end else begin + $display("BAD: %0h != %0h", expected, block); + $display("[KuznechikDecoder: test 0] Stopped."); + $finish; + end + + $display("[KuznechikDecoder: test 0] Stopped."); + $finish; + end + +endmodule diff --git a/examples/std_kuznechik/std_kuznechik_encoder.cpp b/examples/std_kuznechik/std_kuznechik_encoder.cpp new file mode 100644 index 00000000..84d61560 --- /dev/null +++ b/examples/std_kuznechik/std_kuznechik_encoder.cpp @@ -0,0 +1,17 @@ +//===----------------------------------------------------------------------===// +// +// Part of the Utopia HLS Project, under the Apache License v2.0 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 ISP RAS (http://www.ispras.ru) +// +//===----------------------------------------------------------------------===// + +#include "dfcxx/std/crypto/gost_34_12/kuznechik.h" + +#include + +std::unique_ptr start() { + using dfcxx::std::KuznechikEncoder; + KuznechikEncoder *kernel = new KuznechikEncoder(true); + return std::unique_ptr(kernel); +} diff --git a/examples/std_kuznechik/std_kuznechik_encoder_testbench0.sv b/examples/std_kuznechik/std_kuznechik_encoder_testbench0.sv new file mode 100644 index 00000000..fedea6ee --- /dev/null +++ b/examples/std_kuznechik/std_kuznechik_encoder_testbench0.sv @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// Part of the Utopia HLS Project, under the Apache License v2.0 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 ISP RAS (http://www.ispras.ru) +// +//===----------------------------------------------------------------------===// + +// Total: 0 stages. + +`timescale 1s/1s + +module KuznechikEncoder_test0(); + + localparam CIRCUIT_LATENCY = 0; + + reg [127:0] block; + reg [255:0] key; + reg [127:0] encoded; + reg [127:0] expected; + reg clk; + + KuznechikEncoder inst ( + .block(block), + .key(key), + .encoded(encoded), + .clk(clk) + ); + + initial clk = 0; + + always #1 clk = ~clk; + + initial begin + + @(negedge clk); + $display("[KuznechikEncoder: test 0] Input ready."); + + block = 128'h1122334455667700ffeeddccbbaa9988; + key = 256'h8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef; + expected = 128'h7f679d90bebc24305a468d42b9d4edcd; + $display("Input: [%0x], key: [%0x]", block, key); + end + + initial begin + // Wait for the first output. + #(2*CIRCUIT_LATENCY+3); + + $dumpfile("KuznechikEncoder_test0.vcd"); + $dumpvars(0, KuznechikEncoder_test0); + $display("[KuznechikEncoder: test 0] Started..."); + + $display("Output: %0h", encoded); + if (expected == encoded) begin + $display("GOOD: %0h == %0h", expected, encoded); + end else begin + $display("BAD: %0h != %0h", expected, encoded); + $display("[KuznechikEncoder: test 0] Stopped."); + $finish; + end + + $display("[KuznechikEncoder: test 0] Stopped."); + $finish; + end + +endmodule diff --git a/examples/std_magma/add_int_2.json b/examples/std_magma/add_int_2.json new file mode 100644 index 00000000..a8188ffb --- /dev/null +++ b/examples/std_magma/add_int_2.json @@ -0,0 +1,5 @@ +{ + "dfcir": { + "ADD_INT": 2 + } +} diff --git a/examples/std_magma/std_magma_decoder.cpp b/examples/std_magma/std_magma_decoder.cpp new file mode 100644 index 00000000..5dc8de7e --- /dev/null +++ b/examples/std_magma/std_magma_decoder.cpp @@ -0,0 +1,17 @@ +//===----------------------------------------------------------------------===// +// +// Part of the Utopia HLS Project, under the Apache License v2.0 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 ISP RAS (http://www.ispras.ru) +// +//===----------------------------------------------------------------------===// + +#include "dfcxx/std/crypto/gost_34_12/magma.h" + +#include + +std::unique_ptr start() { + using dfcxx::std::MagmaDecoder; + MagmaDecoder *kernel = new MagmaDecoder(); + return std::unique_ptr(kernel); +} diff --git a/examples/std_magma/std_magma_decoder_testbench0.sv b/examples/std_magma/std_magma_decoder_testbench0.sv new file mode 100644 index 00000000..6220d16e --- /dev/null +++ b/examples/std_magma/std_magma_decoder_testbench0.sv @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the Utopia HLS Project, under the Apache License v2.0 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 ISP RAS (http://www.ispras.ru) +// +//===----------------------------------------------------------------------===// + +// Addition (integer): 2 stages each. +// Total: 64 stages. + +`timescale 1s/1s + +module MagmaDecoder_test0(); + + localparam CIRCUIT_LATENCY = 64; + + reg [63:0] encoded; + reg [255:0] key; + reg [63:0] block; + reg [63:0] expected; + reg clk; + + MagmaDecoder inst ( + .encoded(encoded), + .key(key), + .block(block), + .clk(clk) + ); + + initial clk = 0; + + always #1 clk = ~clk; + + initial begin + + @(negedge clk); + $display("[MagmaDecoder: test 0] Input ready."); + + encoded = 64'h4ee901e5c2d8ca3d; + key = 256'hffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff; + expected = 64'hfedcba9876543210; + $display("Input: [%0x], key: [%0x]", block, key); + end + + initial begin + // Wait for the first output. + #(2*CIRCUIT_LATENCY+3); + + $dumpfile("MagmaDecoder_test0.vcd"); + $dumpvars(0, MagmaDecoder_test0); + $display("[MagmaDecoder: test 0] Started..."); + + $display("Output: %0h", block); + if (expected == block) begin + $display("GOOD: %0h == %0h", expected, block); + end else begin + $display("BAD: %0h != %0h", expected, block); + $display("[MagmaDecoder: test 0] Stopped."); + $finish; + end + + $display("[MagmaDecoder: test 0] Stopped."); + $finish; + end + +endmodule diff --git a/examples/std_magma/std_magma_encoder.cpp b/examples/std_magma/std_magma_encoder.cpp new file mode 100644 index 00000000..266e3d54 --- /dev/null +++ b/examples/std_magma/std_magma_encoder.cpp @@ -0,0 +1,17 @@ +//===----------------------------------------------------------------------===// +// +// Part of the Utopia HLS Project, under the Apache License v2.0 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 ISP RAS (http://www.ispras.ru) +// +//===----------------------------------------------------------------------===// + +#include "dfcxx/std/crypto/gost_34_12/magma.h" + +#include + +std::unique_ptr start() { + using dfcxx::std::MagmaEncoder; + MagmaEncoder *kernel = new MagmaEncoder(); + return std::unique_ptr(kernel); +} diff --git a/examples/std_magma/std_magma_encoder_testbench0.sv b/examples/std_magma/std_magma_encoder_testbench0.sv new file mode 100644 index 00000000..454e5815 --- /dev/null +++ b/examples/std_magma/std_magma_encoder_testbench0.sv @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the Utopia HLS Project, under the Apache License v2.0 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 ISP RAS (http://www.ispras.ru) +// +//===----------------------------------------------------------------------===// + +// Addition (integer): 2 stages each. +// Total: 64 stages. + +`timescale 1s/1s + +module MagmaEncoder_test0(); + + localparam CIRCUIT_LATENCY = 64; + + reg [63:0] block; + reg [255:0] key; + reg [63:0] encoded; + reg [63:0] expected; + reg clk; + + MagmaEncoder inst ( + .block(block), + .key(key), + .encoded(encoded), + .clk(clk) + ); + + initial clk = 0; + + always #1 clk = ~clk; + + initial begin + + @(negedge clk); + $display("[MagmaEncoder: test 0] Input ready."); + + block = 64'hfedcba9876543210; + key = 256'hffeeddccbbaa99887766554433221100f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff; + expected = 64'h4ee901e5c2d8ca3d; + $display("Input: [%0x], key: [%0x]", block, key); + end + + initial begin + // Wait for the first output. + #(2*CIRCUIT_LATENCY+3); + + $dumpfile("MagmaEncoder_test0.vcd"); + $dumpvars(0, MagmaEncoder_test0); + $display("[MagmaEncoder: test 0] Started..."); + + $display("Output: %0h", encoded); + if (expected == encoded) begin + $display("GOOD: %0h == %0h", expected, encoded); + end else begin + $display("BAD: %0h != %0h", expected, encoded); + $display("[MagmaEncoder: test 0] Stopped."); + $finish; + end + + $display("[MagmaEncoder: test 0] Stopped."); + $finish; + end + +endmodule diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0a9ee160..32b1df2a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -18,7 +18,9 @@ target_include_directories(ukernel target_link_libraries(ukernel PUBLIC - Utopia::DFCXX) + Utopia::DFCXX + Utopia::DFCXXSTD +) add_library(Utopia::Kernel ALIAS ukernel) ##===----------------------------------------------------------------------===// @@ -41,6 +43,7 @@ target_link_libraries(umain PRIVATE Utopia::Kernel Utopia::DFCXX + Utopia::DFCXXSTD easyloggingpp CLI Json diff --git a/src/model/dfcxx/CMakeLists.txt b/src/model/dfcxx/CMakeLists.txt index 803d21ac..5bbcced3 100644 --- a/src/model/dfcxx/CMakeLists.txt +++ b/src/model/dfcxx/CMakeLists.txt @@ -7,3 +7,5 @@ find_package(CTemplate REQUIRED COMPONENTS nothreads) set(TEMPLATES_PATH "${PROJECT_SOURCE_DIR}/templates") add_subdirectory(include) add_subdirectory(lib) + +add_subdirectory(std) diff --git a/src/model/dfcxx/lib/dfcxx/io.cpp b/src/model/dfcxx/lib/dfcxx/io.cpp index 0cd7353b..9d4468b7 100644 --- a/src/model/dfcxx/lib/dfcxx/io.cpp +++ b/src/model/dfcxx/lib/dfcxx/io.cpp @@ -8,6 +8,8 @@ #include "dfcxx/io.h" +#include + namespace dfcxx { using IODirection = dfcxx::DFVariableImpl::IODirection; diff --git a/src/model/dfcxx/std/CMakeLists.txt b/src/model/dfcxx/std/CMakeLists.txt new file mode 100644 index 00000000..928d0c0c --- /dev/null +++ b/src/model/dfcxx/std/CMakeLists.txt @@ -0,0 +1,3 @@ +## SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(dfcxx) diff --git a/src/model/dfcxx/std/dfcxx/CMakeLists.txt b/src/model/dfcxx/std/dfcxx/CMakeLists.txt new file mode 100644 index 00000000..b7574c6d --- /dev/null +++ b/src/model/dfcxx/std/dfcxx/CMakeLists.txt @@ -0,0 +1,3 @@ +## SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(std) diff --git a/src/model/dfcxx/std/dfcxx/std/CMakeLists.txt b/src/model/dfcxx/std/dfcxx/std/CMakeLists.txt new file mode 100644 index 00000000..b91ba219 --- /dev/null +++ b/src/model/dfcxx/std/dfcxx/std/CMakeLists.txt @@ -0,0 +1,19 @@ +## SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(algebra) +add_subdirectory(crypto) + +add_library(DFCXXSTD INTERFACE) + +target_include_directories(DFCXXSTD + INTERFACE + $ + $ +) + +## MLIRDFCIR is ensured to be compiled beforehand. +target_link_libraries(DFCXXSTD + INTERFACE Utopia::DFCXX +) + +add_library(Utopia::DFCXXSTD ALIAS DFCXXSTD) diff --git a/src/model/dfcxx/std/dfcxx/std/algebra/CMakeLists.txt b/src/model/dfcxx/std/dfcxx/std/algebra/CMakeLists.txt new file mode 100644 index 00000000..34e6ea91 --- /dev/null +++ b/src/model/dfcxx/std/dfcxx/std/algebra/CMakeLists.txt @@ -0,0 +1,2 @@ +## SPDX-License-Identifier: Apache-2.0 + diff --git a/src/model/dfcxx/std/dfcxx/std/algebra/galois8mul.h b/src/model/dfcxx/std/dfcxx/std/algebra/galois8mul.h new file mode 100644 index 00000000..bc8b219d --- /dev/null +++ b/src/model/dfcxx/std/dfcxx/std/algebra/galois8mul.h @@ -0,0 +1,53 @@ +//===----------------------------------------------------------------------===// +// +// Part of the Utopia HLS Project, under the Apache License v2.0 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 ISP RAS (http://www.ispras.ru) +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "dfcxx/DFCXX.h" + +namespace dfcxx::std { + +class Galois8Mul : public dfcxx::Kernel { +public: + ::std::string_view getName() const override { + return "Galois8Mul"; + } + + ~Galois8Mul() override = default; + + using DFType = dfcxx::DFType; + using DFVariable = dfcxx::DFVariable; + + Galois8Mul() : dfcxx::Kernel() { + const DFType ioType = dfUInt(8); + + DFVariable left = io.input("left", ioType); + DFVariable right = io.input("right", ioType); + + DFVariable c0 = constant.var(ioType, uint64_t(0)); + DFVariable c195 = constant.var(ioType, uint64_t(195)); + DFVariable currValue = c0; + + for (int i = 0; i < 7; ++i) { + DFVariable isBitSet = right(0, 0); + currValue = currValue ^ control.mux(isBitSet, {c0, left}); + DFVariable aboutToOverflow = left(7, 7); + DFVariable muxed = control.mux(aboutToOverflow, {c0, c195}); + left = (left << 1) ^ muxed; + right = right >> 1; + } + + DFVariable isBitSet = right(0, 0); + currValue = currValue ^ control.mux(isBitSet, {c0, left}); + + DFVariable result = io.output("result", ioType); + result.connect(currValue); + } +}; + +} // namespace dfcxx::std diff --git a/src/model/dfcxx/std/dfcxx/std/crypto/CMakeLists.txt b/src/model/dfcxx/std/dfcxx/std/crypto/CMakeLists.txt new file mode 100644 index 00000000..cdc72bf6 --- /dev/null +++ b/src/model/dfcxx/std/dfcxx/std/crypto/CMakeLists.txt @@ -0,0 +1,3 @@ +## SPDX-License-Identifier: Apache-2.0 + +add_subdirectory(gost_34_12) diff --git a/src/model/dfcxx/std/dfcxx/std/crypto/gost_34_12/CMakeLists.txt b/src/model/dfcxx/std/dfcxx/std/crypto/gost_34_12/CMakeLists.txt new file mode 100644 index 00000000..34e6ea91 --- /dev/null +++ b/src/model/dfcxx/std/dfcxx/std/crypto/gost_34_12/CMakeLists.txt @@ -0,0 +1,2 @@ +## SPDX-License-Identifier: Apache-2.0 + diff --git a/src/model/dfcxx/std/dfcxx/std/crypto/gost_34_12/kuznechik.h b/src/model/dfcxx/std/dfcxx/std/crypto/gost_34_12/kuznechik.h new file mode 100644 index 00000000..3159413f --- /dev/null +++ b/src/model/dfcxx/std/dfcxx/std/crypto/gost_34_12/kuznechik.h @@ -0,0 +1,329 @@ +//===----------------------------------------------------------------------===// +// +// Part of the Utopia HLS Project, under the Apache License v2.0 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 ISP RAS (http://www.ispras.ru) +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include "dfcxx/DFCXX.h" +#include "dfcxx/std/algebra/galois8mul.h" +#include "dfcxx/std/crypto/gost_34_12/kuznechik_galois8mul.h" + +#include +#include + +namespace dfcxx::std { + +#define C(NUM) constant.var(type, uint64_t(NUM)) + +class KuznechikBase : public dfcxx::Kernel { +protected: + bool opt_mul; + +public: + ::std::string_view getName() const override { + return "KuznechikBase"; + } + + ~KuznechikBase() override = default; + + using DFType = dfcxx::DFType; + using DFVariable = dfcxx::DFVariable; + + DFVariable tablePermut(DFVariable val, bool inv) { + const DFType type = dfUInt(8); + if (inv) { + return control.mux(val, { + C(165), C(45), C(50), C(143), C(14), C(48), C(56), C(192), + C(84), C(230), C(158), C(57), C(85), C(126), C(82), C(145), + C(100), C(3), C(87), C(90), C(28), C(96), C(7), C(24), + C(33), C(114), C(168), C(209), C(41), C(198), C(164), C(63), + C(224), C(39), C(141), C(12), C(130), C(234), C(174), C(180), + C(154), C(99), C(73), C(229), C(66), C(228), C(21), C(183), + C(200), C(6), C(112), C(157), C(65), C(117), C(25), C(201), + C(170), C(252), C(77), C(191), C(42), C(115), C(132), C(213), + C(195), C(175), C(43), C(134), C(167), C(177), C(178), C(91), + C(70), C(211), C(159), C(253), C(212), C(15), C(156), C(47), + C(155), C(67), C(239), C(217), C(121), C(182), C(83), C(127), + C(193), C(240), C(35), C(231), C(37), C(94), C(181), C(30), + C(162), C(223), C(166), C(254), C(172), C(34), C(249), C(226), + C(74), C(188), C(53), C(202), C(238), C(120), C(5), C(107), + C(81), C(225), C(89), C(163), C(242), C(113), C(86), C(17), + C(106), C(137), C(148), C(101), C(140), C(187), C(119), C(60), + C(123), C(40), C(171), C(210), C(49), C(222), C(196), C(95), + C(204), C(207), C(118), C(44), C(184), C(216), C(46), C(54), + C(219), C(105), C(179), C(20), C(149), C(190), C(98), C(161), + C(59), C(22), C(102), C(233), C(92), C(108), C(109), C(173), + C(55), C(97), C(75), C(185), C(227), C(186), C(241), C(160), + C(133), C(131), C(218), C(71), C(197), C(176), C(51), C(250), + C(150), C(111), C(110), C(194), C(246), C(80), C(255), C(93), + C(169), C(142), C(23), C(27), C(151), C(125), C(236), C(88), + C(247), C(31), C(251), C(124), C(9), C(13), C(122), C(103), + C(69), C(135), C(220), C(232), C(79), C(29), C(78), C(4), + C(235), C(248), C(243), C(62), C(61), C(189), C(138), C(136), + C(221), C(205), C(11), C(19), C(152), C(2), C(147), C(128), + C(144), C(208), C(36), C(52), C(203), C(237), C(244), C(206), + C(153), C(16), C(68), C(64), C(146), C(58), C(1), C(38), + C(18), C(26), C(72), C(104), C(245), C(129), C(139), C(199), + C(214), C(32), C(10), C(8), C(0), C(76), C(215), C(116) + }); + } else { + return control.mux(val, { + C(252), C(238), C(221), C(17), C(207), C(110), C(49), C(22), + C(251), C(196), C(250), C(218), C(35), C(197), C(4), C(77), + C(233), C(119), C(240), C(219), C(147), C(46), C(153), C(186), + C(23), C(54), C(241), C(187), C(20), C(205), C(95), C(193), + C(249), C(24), C(101), C(90), C(226), C(92), C(239), C(33), + C(129), C(28), C(60), C(66), C(139), C(1), C(142), C(79), + C(5), C(132), C(2), C(174), C(227), C(106), C(143), C(160), + C(6), C(11), C(237), C(152), C(127), C(212), C(211), C(31), + C(235), C(52), C(44), C(81), C(234), C(200), C(72), C(171), + C(242), C(42), C(104), C(162), C(253), C(58), C(206), C(204), + C(181), C(112), C(14), C(86), C(8), C(12), C(118), C(18), + C(191), C(114), C(19), C(71), C(156), C(183), C(93), C(135), + C(21), C(161), C(150), C(41), C(16), C(123), C(154), C(199), + C(243), C(145), C(120), C(111), C(157), C(158), C(178), C(177), + C(50), C(117), C(25), C(61), C(255), C(53), C(138), C(126), + C(109), C(84), C(198), C(128), C(195), C(189), C(13), C(87), + C(223), C(245), C(36), C(169), C(62), C(168), C(67), C(201), + C(215), C(121), C(214), C(246), C(124), C(34), C(185), C(3), + C(224), C(15), C(236), C(222), C(122), C(148), C(176), C(188), + C(220), C(232), C(40), C(80), C(78), C(51), C(10), C(74), + C(167), C(151), C(96), C(115), C(30), C(0), C(98), C(68), + C(26), C(184), C(56), C(130), C(100), C(159), C(38), C(65), + C(173), C(69), C(70), C(146), C(39), C(94), C(85), C(47), + C(140), C(163), C(165), C(125), C(105), C(213), C(149), C(59), + C(7), C(88), C(179), C(64), C(134), C(172), C(29), C(247), + C(48), C(55), C(107), C(228), C(136), C(217), C(231), C(137), + C(225), C(27), C(131), C(73), C(76), C(63), C(248), C(254), + C(141), C(83), C(170), C(144), C(202), C(216), C(133), C(97), + C(32), C(113), C(103), C(164), C(45), C(43), C(9), C(91), + C(203), C(155), C(37), C(208), C(190), C(229), C(108), C(82), + C(89), C(166), C(116), C(210), C(230), C(244), C(180), C(192), + C(209), C(102), C(175), C(194), C(57), C(75), C(99), C(182) + }); + } + } + + DFVariable S(DFVariable value, bool inv) { + DFVariable subst = tablePermut(value(127, 120), inv); + for (int i = 119; i >= 0; i -= 8) { + subst = subst.cat(tablePermut(value(i, i - 7), inv)); + } + + return subst; + } + + DFVariable LGalois(DFVariable val) { + const DFType type = dfUInt(8); + + // Use optimized multiplication if needed, ... + if (opt_mul) { + static ::std::vector int_consts = { + 148, 32, 133, 16, 194, 192, 1, 251, + 1, 192, 194, 16, 133, 32, 148, 1 + }; + + DFVariable currSlice = val(127, 120); + DFVariable result = io.newStream(type); + instance({ + {currSlice, "in"}, + {result, "out"} + }, int_consts[0]); + + for (uint8_t i = 1; i < 16; ++i) { + DFVariable buf = io.newStream(type); + uint8_t ind = 127 - 8 * i; + DFVariable currSlice = val(ind, ind - 7); + instance({ + {currSlice, "in"}, + {buf, "out"} + }, int_consts[i]); + result = result ^ buf; + } + + return result; + } + + // ... otherwise use classic multiplication. + ::std::vector consts = { + constant.var(type, uint64_t(148)), constant.var(type, uint64_t(32)), + constant.var(type, uint64_t(133)), constant.var(type, uint64_t(16)), + constant.var(type, uint64_t(194)), constant.var(type, uint64_t(192)), + constant.var(type, uint64_t(1)), constant.var(type, uint64_t(251)), + constant.var(type, uint64_t(1)), constant.var(type, uint64_t(192)), + constant.var(type, uint64_t(194)), constant.var(type, uint64_t(16)), + constant.var(type, uint64_t(133)), constant.var(type, uint64_t(32)), + constant.var(type, uint64_t(148)), constant.var(type, uint64_t(1)) + }; + + DFVariable currSlice = val(127, 120); + DFVariable result = io.newStream(type); + instance({ + {consts[0], "left"}, + {currSlice, "right"}, + {result, "result"} + }); + + for (uint8_t i = 1; i < 16; ++i) { + DFVariable buf = io.newStream(type); + uint8_t ind = 127 - 8 * i; + DFVariable currSlice = val(ind, ind - 7); + instance({ + {consts[i], "left"}, + {currSlice, "right"}, + {buf, "result"}}); + result = result ^ buf; + } + + return result; + } + + DFVariable R(DFVariable val, bool inv) { + if (inv) { + DFVariable extracted = val(119, 0); + return extracted.cat(LGalois(extracted.cat(val(127, 120)))); + } else { + return LGalois(val).cat(val(127, 8)); + } + } + + DFVariable L(DFVariable val, bool inv) { + DFVariable currVal = val; + for (int i = 0; i < 16; ++i) { + currVal = R(currVal, inv); + } + return currVal; + } + + ::std::vector getConsts() { + const DFType type = dfUInt(64); + return { + C(0x6ea276726c487ab8).cat(C(0x5d27bd10dd849401)), + C(0xdc87ece4d890f4b3).cat(C(0xba4eb92079cbeb02)), + C(0xb2259a96b4d88e0b).cat(C(0xe7690430a44f7f03)), + C(0x7bcd1b0b73e32ba5).cat(C(0xb79cb140f2551504)), + C(0x156f6d791fab511d).cat(C(0xeabb0c502fd18105)), + C(0xa74af7efab73df16).cat(C(0x0dd208608b9efe06)), + C(0xc9e8819dc73ba5ae).cat(C(0x50f5b570561a6a07)), + C(0xf6593616e6055689).cat(C(0xadfba18027aa2a08)), + C(0x98fb40648a4d2c31).cat(C(0xf0dc1c90fa2ebe09)), + C(0x2adedaf23e95a23a).cat(C(0x17b518a05e61c10a)), + C(0x447cac8052ddd882).cat(C(0x4a92a5b083e5550b)), + C(0x8d942d1d95e67d2c).cat(C(0x1a6710c0d5ff3f0c)), + C(0xe3365b6ff9ae0794).cat(C(0x4740add0087bab0d)), + C(0x5113c1f94d76899f).cat(C(0xa029a9e0ac34d40e)), + C(0x3fb1b78b213ef327).cat(C(0xfd0e14f071b0400f)), + C(0x2fb26c2c0f0aacd1).cat(C(0x993581c34e975410)), + C(0x41101a5e6342d669).cat(C(0xc4123cd39313c011)), + C(0xf33580c8d79a5862).cat(C(0x237b38e3375cbf12)), + C(0x9d97f6babbd222da).cat(C(0x7e5c85f3ead82b13)), + C(0x547f77277ce98774).cat(C(0x2ea93083bcc24114)), + C(0x3add015510a1fdcc).cat(C(0x738e8d936146d515)), + C(0x88f89bc3a47973c7).cat(C(0x94e789a3c509aa16)), + C(0xe65aedb1c831097f).cat(C(0xc9c034b3188d3e17)), + C(0xd9eb5a3ae90ffa58).cat(C(0x34ce2043693d7e18)), + C(0xb7492c48854780e0).cat(C(0x69e99d53b4b9ea19)), + C(0x056cb6de319f0eeb).cat(C(0x8e80996310f6951a)), + C(0x6bcec0ac5dd77453).cat(C(0xd3a72473cd72011b)), + C(0xa22641319aecd1fd).cat(C(0x835291039b686b1c)), + C(0xcc843743f6a4ab45).cat(C(0xde752c1346ecff1d)), + C(0x7ea1add5427c254e).cat(C(0x391c2823e2a3801e)), + C(0x1003dba72e345ff6).cat(C(0x643b95333f27141f)), + C(0x5ea7d8581e149b61).cat(C(0xf16ac1459ceda820)) + }; + } + + ::std::pair + F(DFVariable constVal, DFVariable a1, DFVariable a0) { + return ::std::make_pair(XSL(constVal, a1) ^ a0, a1); + } + + ::std::vector genKeys(DFVariable k0, DFVariable k1) { + ::std::vector consts = getConsts(); + ::std::vector keys; + keys.push_back(k0); + keys.push_back(k1); + + for (int i = 0; i < 4; ++i) { + auto curr = ::std::make_pair(keys[2 * i], keys[2 * i + 1]); + for (int j = 0; j < 8; ++j) { + curr = F(consts[8 * i + j], curr.first, curr.second); + } + keys.push_back(curr.first); + keys.push_back(curr.second); + } + return keys; + } + + DFVariable XSL(DFVariable key, DFVariable value) { + DFVariable addedKey = key ^ value; + DFVariable permut = S(addedKey, false); + return L(permut, false); + } + + DFVariable LSX(DFVariable key, DFVariable value) { + DFVariable lResult = L(value, true); + DFVariable permut = S(lResult, true); + return key ^ permut; + } + + KuznechikBase(bool opt_mul) : dfcxx::Kernel() { + this->opt_mul = opt_mul; + } +}; + +class KuznechikEncoder: public KuznechikBase { +public: + ::std::string_view getName() const override { + return "KuznechikEncoder"; + } + + KuznechikEncoder(bool opt_mul = false) : KuznechikBase(opt_mul) { + const DFType ioType = dfUInt(128); + + DFVariable block = io.input("block", ioType); + DFVariable key = io.input("key", dfUInt(256)); + + ::std::vector gKeys = genKeys(key(255, 128), key(127, 0)); + + DFVariable currValue = block; + for (int i = 0; i < 9; ++i) { + currValue = XSL(gKeys[i], currValue); + } + + currValue = currValue ^ gKeys[9]; + + DFVariable encoded = io.output("encoded", ioType); + encoded.connect(currValue); + } +}; + +class KuznechikDecoder: public KuznechikBase { +public: + ::std::string_view getName() const override { + return "KuznechikDecoder"; + } + + KuznechikDecoder(bool opt_mul = false) : KuznechikBase(opt_mul) { + const DFType ioType = dfUInt(128); + + DFVariable encoded = io.input("encoded", ioType); + DFVariable key = io.input("key", dfUInt(256)); + + ::std::vector gKeys = genKeys(key(255, 128), key(127, 0)); + + DFVariable currValue = encoded ^ gKeys[9]; + for (int i = 8; i >= 0; --i) { + currValue = LSX(gKeys[i], currValue); + } + + DFVariable block = io.output("block", ioType); + block.connect(currValue); + } +}; + +} // namespace dfcxx::std diff --git a/src/model/dfcxx/std/dfcxx/std/crypto/gost_34_12/kuznechik_galois8mul.h b/src/model/dfcxx/std/dfcxx/std/crypto/gost_34_12/kuznechik_galois8mul.h new file mode 100644 index 00000000..3ba4f0b3 --- /dev/null +++ b/src/model/dfcxx/std/dfcxx/std/crypto/gost_34_12/kuznechik_galois8mul.h @@ -0,0 +1,257 @@ +//===----------------------------------------------------------------------===// +// +// Part of the Utopia HLS Project, under the Apache License v2.0 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 ISP RAS (http://www.ispras.ru) +// +//===----------------------------------------------------------------------===// + +#include "dfcxx/DFCXX.h" + +#include + +namespace dfcxx::std { + +class KuznechikGalois8Mul : public dfcxx::Kernel { +public: + ::std::string_view getName() const override { + return "KuznechikGalois8Mul"; + } + + ~KuznechikGalois8Mul() override = default; + + using DFType = dfcxx::DFType; + using DFVariable = dfcxx::DFVariable; + + KuznechikGalois8Mul(uint8_t constVal) : dfcxx::Kernel() { + const DFType type = dfUInt(8); + + #define C(NUM) constant.var(type, uint64_t(NUM)) + DFVariable in = io.input("in", type); + DFVariable out = io.output("out", type); + DFVariable muxed; + + switch (constVal) { + case 0x1: muxed = in; break; + case 0x94: muxed = control.mux(in, { + C(0), C(148), C(235), C(127), C(21), C(129), C(254), C(106), C(42), + C(190), C(193), C(85), C(63), C(171), C(212), C(64), C(84), C(192), + C(191), C(43), C(65), C(213), C(170), C(62), C(126), C(234), C(149), + C(1), C(107), C(255), C(128), C(20), C(168), C(60), C(67), C(215), + C(189), C(41), C(86), C(194), C(130), C(22), C(105), C(253), C(151), + C(3), C(124), C(232), C(252), C(104), C(23), C(131), C(233), C(125), + C(2), C(150), C(214), C(66), C(61), C(169), C(195), C(87), C(40), + C(188), C(147), C(7), C(120), C(236), C(134), C(18), C(109), C(249), + C(185), C(45), C(82), C(198), C(172), C(56), C(71), C(211), C(199), + C(83), C(44), C(184), C(210), C(70), C(57), C(173), C(237), C(121), + C(6), C(146), C(248), C(108), C(19), C(135), C(59), C(175), C(208), + C(68), C(46), C(186), C(197), C(81), C(17), C(133), C(250), C(110), + C(4), C(144), C(239), C(123), C(111), C(251), C(132), C(16), C(122), + C(238), C(145), C(5), C(69), C(209), C(174), C(58), C(80), C(196), + C(187), C(47), C(229), C(113), C(14), C(154), C(240), C(100), C(27), + C(143), C(207), C(91), C(36), C(176), C(218), C(78), C(49), C(165), + C(177), C(37), C(90), C(206), C(164), C(48), C(79), C(219), C(155), + C(15), C(112), C(228), C(142), C(26), C(101), C(241), C(77), C(217), + C(166), C(50), C(88), C(204), C(179), C(39), C(103), C(243), C(140), + C(24), C(114), C(230), C(153), C(13), C(25), C(141), C(242), C(102), + C(12), C(152), C(231), C(115), C(51), C(167), C(216), C(76), C(38), + C(178), C(205), C(89), C(118), C(226), C(157), C(9), C(99), C(247), + C(136), C(28), C(92), C(200), C(183), C(35), C(73), C(221), C(162), + C(54), C(34), C(182), C(201), C(93), C(55), C(163), C(220), C(72), + C(8), C(156), C(227), C(119), C(29), C(137), C(246), C(98), C(222), + C(74), C(53), C(161), C(203), C(95), C(32), C(180), C(244), C(96), + C(31), C(139), C(225), C(117), C(10), C(158), C(138), C(30), C(97), + C(245), C(159), C(11), C(116), C(224), C(160), C(52), C(75), C(223), + C(181), C(33), C(94), C(202)}); break; + case 0x20: muxed = control.mux(in, { + C(0), C(32), C(64), C(96), C(128), C(160), C(192), C(224), C(195), + C(227), C(131), C(163), C(67), C(99), C(3), C(35), C(69), C(101), + C(5), C(37), C(197), C(229), C(133), C(165), C(134), C(166), C(198), + C(230), C(6), C(38), C(70), C(102), C(138), C(170), C(202), C(234), + C(10), C(42), C(74), C(106), C(73), C(105), C(9), C(41), C(201), + C(233), C(137), C(169), C(207), C(239), C(143), C(175), C(79), + C(111), C(15), C(47), C(12), C(44), C(76), C(108), C(140), C(172), + C(204), C(236), C(215), C(247), C(151), C(183), C(87), C(119), C(23), + C(55), C(20), C(52), C(84), C(116), C(148), C(180), C(212), C(244), + C(146), C(178), C(210), C(242), C(18), C(50), C(82), C(114), C(81), + C(113), C(17), C(49), C(209), C(241), C(145), C(177), C(93), C(125), + C(29), C(61), C(221), C(253), C(157), C(189), C(158), C(190), C(222), + C(254), C(30), C(62), C(94), C(126), C(24), C(56), C(88), C(120), + C(152), C(184), C(216), C(248), C(219), C(251), C(155), C(187), + C(91), C(123), C(27), C(59), C(109), C(77), C(45), C(13), C(237), + C(205), C(173), C(141), C(174), C(142), C(238), C(206), C(46), C(14), + C(110), C(78), C(40), C(8), C(104), C(72), C(168), C(136), C(232), + C(200), C(235), C(203), C(171), C(139), C(107), C(75), C(43), C(11), + C(231), C(199), C(167), C(135), C(103), C(71), C(39), C(7), C(36), + C(4), C(100), C(68), C(164), C(132), C(228), C(196), C(162), C(130), + C(226), C(194), C(34), C(2), C(98), C(66), C(97), C(65), C(33), C(1), + C(225), C(193), C(161), C(129), C(186), C(154), C(250), C(218), C(58), + C(26), C(122), C(90), C(121), C(89), C(57), C(25), C(249), C(217), + C(185), C(153), C(255), C(223), C(191), C(159), C(127), C(95), C(63), + C(31), C(60), C(28), C(124), C(92), C(188), C(156), C(252), C(220), + C(48), C(16), C(112), C(80), C(176), C(144), C(240), C(208), C(243), + C(211), C(179), C(147), C(115), C(83), C(51), C(19), C(117), C(85), + C(53), C(21), C(245), C(213), C(181), C(149), C(182), C(150), C(246), + C(214), C(54), C(22), C(118), C(86)}); break; + case 0x85: muxed = control.mux(in, { + C(0), C(133), C(201), C(76), C(81), C(212), C(152), C(29), C(162), + C(39), C(107), C(238), C(243), C(118), C(58), C(191), C(135), C(2), + C(78), C(203), C(214), C(83), C(31), C(154), C(37), C(160), C(236), + C(105), C(116), C(241), C(189), C(56), C(205), C(72), C(4), C(129), + C(156), C(25), C(85), C(208), C(111), C(234), C(166), C(35), C(62), + C(187), C(247), C(114), C(74), C(207), C(131), C(6), C(27), C(158), + C(210), C(87), C(232), C(109), C(33), C(164), C(185), C(60), C(112), + C(245), C(89), C(220), C(144), C(21), C(8), C(141), C(193), C(68), + C(251), C(126), C(50), C(183), C(170), C(47), C(99), C(230), C(222), + C(91), C(23), C(146), C(143), C(10), C(70), C(195), C(124), C(249), + C(181), C(48), C(45), C(168), C(228), C(97), C(148), C(17), C(93), + C(216), C(197), C(64), C(12), C(137), C(54), C(179), C(255), C(122), + C(103), C(226), C(174), C(43), C(19), C(150), C(218), C(95), C(66), + C(199), C(139), C(14), C(177), C(52), C(120), C(253), C(224), C(101), + C(41), C(172), C(178), C(55), C(123), C(254), C(227), C(102), C(42), + C(175), C(16), C(149), C(217), C(92), C(65), C(196), C(136), C(13), + C(53), C(176), C(252), C(121), C(100), C(225), C(173), C(40), C(151), + C(18), C(94), C(219), C(198), C(67), C(15), C(138), C(127), C(250), + C(182), C(51), C(46), C(171), C(231), C(98), C(221), C(88), C(20), + C(145), C(140), C(9), C(69), C(192), C(248), C(125), C(49), C(180), + C(169), C(44), C(96), C(229), C(90), C(223), C(147), C(22), C(11), + C(142), C(194), C(71), C(235), C(110), C(34), C(167), C(186), C(63), + C(115), C(246), C(73), C(204), C(128), C(5), C(24), C(157), C(209), + C(84), C(108), C(233), C(165), C(32), C(61), C(184), C(244), C(113), + C(206), C(75), C(7), C(130), C(159), C(26), C(86), C(211), C(38), + C(163), C(239), C(106), C(119), C(242), C(190), C(59), C(132), C(1), + C(77), C(200), C(213), C(80), C(28), C(153), C(161), C(36), C(104), + C(237), C(240), C(117), C(57), C(188), C(3), C(134), C(202), C(79), + C(82), C(215), C(155), C(30)}); break; + case 0x10: muxed = control.mux(in, { + C(0), C(16), C(32), C(48), C(64), C(80), C(96), C(112), C(128), + C(144), C(160), C(176), C(192), C(208), C(224), C(240), C(195), + C(211), C(227), C(243), C(131), C(147), C(163), C(179), C(67), + C(83), C(99), C(115), C(3), C(19), C(35), C(51), C(69), C(85), + C(101), C(117), C(5), C(21), C(37), C(53), C(197), C(213), + C(229), C(245), C(133), C(149), C(165), C(181), C(134), C(150), + C(166), C(182), C(198), C(214), C(230), C(246), C(6), C(22), + C(38), C(54), C(70), C(86), C(102), C(118), C(138), C(154), + C(170), C(186), C(202), C(218), C(234), C(250), C(10), C(26), + C(42), C(58), C(74), C(90), C(106), C(122), C(73), C(89), C(105), + C(121), C(9), C(25), C(41), C(57), C(201), C(217), C(233), C(249), + C(137), C(153), C(169), C(185), C(207), C(223), C(239), C(255), + C(143), C(159), C(175), C(191), C(79), C(95), C(111), C(127), + C(15), C(31), C(47), C(63), C(12), C(28), C(44), C(60), C(76), + C(92), C(108), C(124), C(140), C(156), C(172), C(188), C(204), + C(220), C(236), C(252), C(215), C(199), C(247), C(231), C(151), + C(135), C(183), C(167), C(87), C(71), C(119), C(103), C(23), + C(7), C(55), C(39), C(20), C(4), C(52), C(36), C(84), C(68), + C(116), C(100), C(148), C(132), C(180), C(164), C(212), C(196), + C(244), C(228), C(146), C(130), C(178), C(162), C(210), C(194), + C(242), C(226), C(18), C(2), C(50), C(34), C(82), C(66), C(114), + C(98), C(81), C(65), C(113), C(97), C(17), C(1), C(49), C(33), + C(209), C(193), C(241), C(225), C(145), C(129), C(177), C(161), + C(93), C(77), C(125), C(109), C(29), C(13), C(61), C(45), C(221), + C(205), C(253), C(237), C(157), C(141), C(189), C(173), C(158), + C(142), C(190), C(174), C(222), C(206), C(254), C(238), C(30), + C(14), C(62), C(46), C(94), C(78), C(126), C(110), C(24), C(8), + C(56), C(40), C(88), C(72), C(120), C(104), C(152), C(136), C(184), + C(168), C(216), C(200), C(248), C(232), C(219), C(203), C(251), + C(235), C(155), C(139), C(187), C(171), C(91), C(75), C(123), + C(107), C(27), C(11), C(59), C(43)}); break; + case 0xC2: muxed = control.mux(in, { + C(0), C(194), C(71), C(133), C(142), C(76), C(201), C(11), C(223), + C(29), C(152), C(90), C(81), C(147), C(22), C(212), C(125), C(191), + C(58), C(248), C(243), C(49), C(180), C(118), C(162), C(96), C(229), + C(39), C(44), C(238), C(107), C(169), C(250), C(56), C(189), C(127), + C(116), C(182), C(51), C(241), C(37), C(231), C(98), C(160), C(171), + C(105), C(236), C(46), C(135), C(69), C(192), C(2), C(9), C(203), + C(78), C(140), C(88), C(154), C(31), C(221), C(214), C(20), C(145), + C(83), C(55), C(245), C(112), C(178), C(185), C(123), C(254), C(60), + C(232), C(42), C(175), C(109), C(102), C(164), C(33), C(227), C(74), + C(136), C(13), C(207), C(196), C(6), C(131), C(65), C(149), C(87), + C(210), C(16), C(27), C(217), C(92), C(158), C(205), C(15), C(138), + C(72), C(67), C(129), C(4), C(198), C(18), C(208), C(85), C(151), + C(156), C(94), C(219), C(25), C(176), C(114), C(247), C(53), C(62), + C(252), C(121), C(187), C(111), C(173), C(40), C(234), C(225), C(35), + C(166), C(100), C(110), C(172), C(41), C(235), C(224), C(34), C(167), + C(101), C(177), C(115), C(246), C(52), C(63), C(253), C(120), C(186), + C(19), C(209), C(84), C(150), C(157), C(95), C(218), C(24), C(204), + C(14), C(139), C(73), C(66), C(128), C(5), C(199), C(148), C(86), + C(211), C(17), C(26), C(216), C(93), C(159), C(75), C(137), C(12), + C(206), C(197), C(7), C(130), C(64), C(233), C(43), C(174), C(108), + C(103), C(165), C(32), C(226), C(54), C(244), C(113), C(179), C(184), + C(122), C(255), C(61), C(89), C(155), C(30), C(220), C(215), C(21), + C(144), C(82), C(134), C(68), C(193), C(3), C(8), C(202), C(79), + C(141), C(36), C(230), C(99), C(161), C(170), C(104), C(237), + C(47), C(251), C(57), C(188), C(126), C(117), C(183), C(50), C(240), + C(163), C(97), C(228), C(38), C(45), C(239), C(106), C(168), C(124), + C(190), C(59), C(249), C(242), C(48), C(181), C(119), C(222), C(28), + C(153), C(91), C(80), C(146), C(23), C(213), C(1), C(195), C(70), + C(132), C(143), C(77), C(200), C(10)}); break; + case 0xC0: muxed = control.mux(in, { + C(0), C(192), C(67), C(131), C(134), C(70), C(197), C(5), C(207), + C(15), C(140), C(76), C(73), C(137), C(10), C(202), C(93), C(157), + C(30), C(222), C(219), C(27), C(152), C(88), C(146), C(82), C(209), + C(17), C(20), C(212), C(87), C(151), C(186), C(122), C(249), C(57), + C(60), C(252), C(127), C(191), C(117), C(181), C(54), C(246), C(243), + C(51), C(176), C(112), C(231), C(39), C(164), C(100), C(97), C(161), + C(34), C(226), C(40), C(232), C(107), C(171), C(174), C(110), C(237), + C(45), C(183), C(119), C(244), C(52), C(49), C(241), C(114), C(178), + C(120), C(184), C(59), C(251), C(254), C(62), C(189), C(125), C(234), + C(42), C(169), C(105), C(108), C(172), C(47), C(239), C(37), C(229), + C(102), C(166), C(163), C(99), C(224), C(32), C(13), C(205), C(78), + C(142), C(139), C(75), C(200), C(8), C(194), C(2), C(129), C(65), + C(68), C(132), C(7), C(199), C(80), C(144), C(19), C(211), C(214), + C(22), C(149), C(85), C(159), C(95), C(220), C(28), C(25), C(217), + C(90), C(154), C(173), C(109), C(238), C(46), C(43), C(235), C(104), + C(168), C(98), C(162), C(33), C(225), C(228), C(36), C(167), C(103), + C(240), C(48), C(179), C(115), C(118), C(182), C(53), C(245), C(63), + C(255), C(124), C(188), C(185), C(121), C(250), C(58), C(23), C(215), + C(84), C(148), C(145), C(81), C(210), C(18), C(216), C(24), C(155), + C(91), C(94), C(158), C(29), C(221), C(74), C(138), C(9), C(201), + C(204), C(12), C(143), C(79), C(133), C(69), C(198), C(6), C(3), + C(195), C(64), C(128), C(26), C(218), C(89), C(153), C(156), C(92), + C(223), C(31), C(213), C(21), C(150), C(86), C(83), C(147), C(16), + C(208), C(71), C(135), C(4), C(196), C(193), C(1), C(130), C(66), + C(136), C(72), C(203), C(11), C(14), C(206), C(77), C(141), C(160), + C(96), C(227), C(35), C(38), C(230), C(101), C(165), C(111), C(175), + C(44), C(236), C(233), C(41), C(170), C(106), C(253), C(61), C(190), + C(126), C(123), C(187), C(56), C(248), C(50), C(242), C(113), C(177), + C(180), C(116), C(247), C(55)}); break; + case 0xFB: muxed = control.mux(in, { + C(0), C(251), C(53), C(206), C(106), C(145), C(95), C(164), C(212), + C(47), C(225), C(26), C(190), C(69), C(139), C(112), C(107), C(144), + C(94), C(165), C(1), C(250), C(52), C(207), C(191), C(68), C(138), + C(113), C(213), C(46), C(224), C(27), C(214), C(45), C(227), C(24), + C(188), C(71), C(137), C(114), C(2), C(249), C(55), C(204), C(104), + C(147), C(93), C(166), C(189), C(70), C(136), C(115), C(215), C(44), + C(226), C(25), C(105), C(146), C(92), C(167), C(3), C(248), C(54), + C(205), C(111), C(148), C(90), C(161), C(5), C(254), C(48), C(203), + C(187), C(64), C(142), C(117), C(209), C(42), C(228), C(31), C(4), + C(255), C(49), C(202), C(110), C(149), C(91), C(160), C(208), C(43), + C(229), C(30), C(186), C(65), C(143), C(116), C(185), C(66), C(140), + C(119), C(211), C(40), C(230), C(29), C(109), C(150), C(88), C(163), + C(7), C(252), C(50), C(201), C(210), C(41), C(231), C(28), C(184), + C(67), C(141), C(118), C(6), C(253), C(51), C(200), C(108), C(151), + C(89), C(162), C(222), C(37), C(235), C(16), C(180), C(79), C(129), + C(122), C(10), C(241), C(63), C(196), C(96), C(155), C(85), C(174), + C(181), C(78), C(128), C(123), C(223), C(36), C(234), C(17), C(97), + C(154), C(84), C(175), C(11), C(240), C(62), C(197), C(8), C(243), + C(61), C(198), C(98), C(153), C(87), C(172), C(220), C(39), C(233), + C(18), C(182), C(77), C(131), C(120), C(99), C(152), C(86), C(173), + C(9), C(242), C(60), C(199), C(183), C(76), C(130), C(121), C(221), + C(38), C(232), C(19), C(177), C(74), C(132), C(127), C(219), C(32), + C(238), C(21), C(101), C(158), C(80), C(171), C(15), C(244), C(58), + C(193), C(218), C(33), C(239), C(20), C(176), C(75), C(133), C(126), + C(14), C(245), C(59), C(192), C(100), C(159), C(81), C(170), C(103), + C(156), C(82), C(169), C(13), C(246), C(56), C(195), C(179), C(72), + C(134), C(125), C(217), C(34), C(236), C(23), C(12), C(247), C(57), + C(194), C(102), C(157), C(83), C(168), C(216), C(35), C(237), C(22), + C(178), C(73), C(135), C(124)}); break; + + default: assert(false && "Invalid constant was provided."); + } + out.connect(muxed); + #undef C + } +}; + +} // namespace dfcxx::std + diff --git a/src/model/dfcxx/std/dfcxx/std/crypto/gost_34_12/magma.h b/src/model/dfcxx/std/dfcxx/std/crypto/gost_34_12/magma.h new file mode 100644 index 00000000..fd7bdc16 --- /dev/null +++ b/src/model/dfcxx/std/dfcxx/std/crypto/gost_34_12/magma.h @@ -0,0 +1,195 @@ +//===----------------------------------------------------------------------===// +// +// Part of the Utopia HLS Project, under the Apache License v2.0 +// SPDX-License-Identifier: Apache-2.0 +// Copyright 2025 ISP RAS (http://www.ispras.ru) +// +//===----------------------------------------------------------------------===// + +#include "dfcxx/DFCXX.h" + +#include +#include + +namespace dfcxx::std { + +class MagmaBase : public dfcxx::Kernel { +public: + ::std::string_view getName() const override { + return "MagmaBase"; + } + + ~MagmaBase() override = default; + + using DFType = dfcxx::DFType; + using DFVariable = dfcxx::DFVariable; + + DFVariable permut(int tableId, DFVariable val) { + const DFType type = dfUInt(4); + + DFVariable c0 = constant.var(type, uint64_t(0)); + DFVariable c1 = constant.var(type, uint64_t(1)); + DFVariable c2 = constant.var(type, uint64_t(2)); + DFVariable c3 = constant.var(type, uint64_t(3)); + DFVariable c4 = constant.var(type, uint64_t(4)); + DFVariable c5 = constant.var(type, uint64_t(5)); + DFVariable c6 = constant.var(type, uint64_t(6)); + DFVariable c7 = constant.var(type, uint64_t(7)); + DFVariable c8 = constant.var(type, uint64_t(8)); + DFVariable c9 = constant.var(type, uint64_t(9)); + DFVariable c10 = constant.var(type, uint64_t(10)); + DFVariable c11 = constant.var(type, uint64_t(11)); + DFVariable c12 = constant.var(type, uint64_t(12)); + DFVariable c13 = constant.var(type, uint64_t(13)); + DFVariable c14 = constant.var(type, uint64_t(14)); + DFVariable c15 = constant.var(type, uint64_t(15)); + + switch (tableId) { + case 0: { + return control.mux(val, { + c12, c4, c6, c2, + c10, c5, c11, c9, + c14, c8, c13, c7, + c0, c3, c15, c1 + }); + } + case 1: { + return control.mux(val, { + c6, c8, c2, c3, + c9, c10, c5, c12, + c1, c14, c4, c7, + c11, c13, c0, c15 + }); + } + case 2: { + return control.mux(val, { + c11, c3, c5, c8, + c2, c15, c10, c13, + c14, c1, c7, c4, + c12, c9, c6, c0 + }); + } + case 3: { + return control.mux(val, { + c12, c8, c2, c1, + c13, c4, c15, c6, + c7, c0, c10, c5, + c3, c14, c9, c11 + }); + } + case 4: { + return control.mux(val, { + c7, c15, c5, c10, + c8, c1, c6, c13, + c0, c9, c3, c14, + c11, c4, c2, c12 + }); + } + case 5: { + return control.mux(val, { + c5, c13, c15, c6, + c9, c2, c12, c10, + c11, c7, c8, c1, + c4, c3, c14, c0 + }); + } + case 6: { + return control.mux(val, { + c8, c14, c2, c5, + c6, c9, c1, c12, + c15, c4, c11, c0, + c13, c10, c3, c7 + }); + } + case 7: { + return control.mux(val, { + c1, c7, c14, c13, + c0, c5, c8, c3, + c4, c15, c10, c6, + c9, c12, c11, c2 + }); + } + default: return c0; + } + } + + ::std::pair + round(DFVariable left, DFVariable right, DFVariable key) { + const DFType type = dfUInt(32); + + DFVariable sum = right.cast(type) + key.cast(type); + ::std::vector parts; + for (int i = 0; i < 31; i += 4) { parts.push_back(sum(i + 3, i)); } + + DFVariable subst = permut(7, parts[7]); + for (int i = 6; i >= 0; --i) { + subst = subst.cat(permut(i, parts[i])); + } + + DFVariable shifted = subst(20, 0).cat(subst(31, 21)); + return ::std::make_pair(right, left ^ shifted); + } +}; + +class MagmaEncoder : public MagmaBase { +public: + ::std::string_view getName() const override { + return "MagmaEncoder"; + } + + MagmaEncoder() : MagmaBase() { + const DFType ioType = dfUInt(64); + DFVariable block = io.input("block", ioType); + DFVariable key = io.input("key", dfUInt(256)); + auto curr = ::std::make_pair(block(63, 32), block(31, 0)); + + ::std::vector keys; + for (int i = 255; i >= 0; i -= 32) { keys.push_back(key(i, i - 31)); } + + for (int i = 0; i < 3; ++i) { + for (int kInd = 0; kInd < 8; ++kInd) { + curr = round(curr.first, curr.second, keys[kInd]); + } + } + + for (int kInd = 7; kInd >= 0; --kInd) { + curr = round(curr.first, curr.second, keys[kInd]); + } + + DFVariable encoded = io.output("encoded", ioType); + encoded.connect(curr.second.cat(curr.first)); + } +}; + +class MagmaDecoder : public MagmaBase { +public: + ::std::string_view getName() const override { + return "MagmaDecoder"; + } + + MagmaDecoder() : MagmaBase() { + const DFType ioType = dfUInt(64); + DFVariable encoded = io.input("encoded", ioType); + DFVariable key = io.input("key", dfUInt(256)); + auto curr = ::std::make_pair(encoded(63, 32), encoded(31, 0)); + + ::std::vector keys; + for (int i = 255; i >= 0; i -= 32) { keys.push_back(key(i, i - 31)); } + + for (int kInd = 0; kInd < 8; ++kInd) { + curr = round(curr.first, curr.second, keys[kInd]); + } + + for (int i = 0; i < 3; ++i) { + for (int kInd = 7; kInd >= 0; --kInd) { + curr = round(curr.first, curr.second, keys[kInd]); + } + } + + DFVariable block = io.output("block", ioType); + block.connect(curr.second.cat(curr.first)); + } +}; + +} // namespace dfcxx::std + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6bb9b275..ed08c135 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -60,6 +60,7 @@ target_link_libraries(utest Utopia::DFCIR Utopia::DFCIRPasses Utopia::DFCXX + Utopia::DFCXXSTD easyloggingpp )