diff --git a/CMakeLists.txt b/CMakeLists.txt index 66ef8ff28503a70de816d546b72e21d8528f0e33..2d4bc8ecfe888da462689c2d62cdb896c6bdda0e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,14 @@ if(NOT $ENV{AIDGE_INSTALL} STREQUAL "") endif() find_package(aidge_core REQUIRED) +find_package(OpenSSL QUIET) +if(OpenSSL_FOUND) + message(STATUS "OpenSSL found: ${OPENSSL_VERSION}") + add_definitions(-DWITH_OPENSSL) +else() + message(WARNING "OpenSSL not found, SHA256 will not be available.") +endif() + ############################################## # Create target and set properties file(GLOB_RECURSE src_files "src/*.cpp") @@ -112,6 +120,10 @@ target_include_directories(${module_name} ${CMAKE_CURRENT_SOURCE_DIR}/src ) +if(OpenSSL_FOUND) + target_link_libraries(${module_name} PRIVATE OpenSSL::SSL OpenSSL::Crypto) +endif() + target_compile_features(${module_name} PRIVATE cxx_std_14) target_compile_options(${module_name} PRIVATE diff --git a/include/aidge/backend/cpu.hpp b/include/aidge/backend/cpu.hpp index ffc03ae5d6cb1d44637bc223ce4099af88f08070..80574b4a46fef0c843c9511836f162e02de5aab3 100644 --- a/include/aidge/backend/cpu.hpp +++ b/include/aidge/backend/cpu.hpp @@ -28,6 +28,7 @@ #include "aidge/backend/cpu/operator/ConvDepthWiseImpl.hpp" #include "aidge/backend/cpu/operator/ConvImpl.hpp" #include "aidge/backend/cpu/operator/ConstantOfShapeImpl.hpp" +#include "aidge/backend/cpu/operator/CryptoHashImpl.hpp" #include "aidge/backend/cpu/operator/DivImpl.hpp" #include "aidge/backend/cpu/operator/EqualImpl.hpp" #include "aidge/backend/cpu/operator/ErfImpl.hpp" @@ -40,6 +41,7 @@ #include "aidge/backend/cpu/operator/LeakyReLUImpl.hpp" #include "aidge/backend/cpu/operator/LnImpl.hpp" #include "aidge/backend/cpu/operator/MatMulImpl.hpp" +#include "aidge/backend/cpu/operator/ModImpl.hpp" #include "aidge/backend/cpu/operator/MulImpl.hpp" #include "aidge/backend/cpu/operator/PadImpl.hpp" #include "aidge/backend/cpu/operator/PaddedConvImpl.hpp" diff --git a/include/aidge/backend/cpu/operator/CryptoHashImpl.hpp b/include/aidge/backend/cpu/operator/CryptoHashImpl.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d7f07f999d47a3a6c88ba921bc91766a447de48a --- /dev/null +++ b/include/aidge/backend/cpu/operator/CryptoHashImpl.hpp @@ -0,0 +1,36 @@ +/******************************************************************************** + * Copyright (c) 2023 CEA-List + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + * + ********************************************************************************/ + +#ifndef AIDGE_CPU_OPERATOR_TANHIMPL_H_ +#define AIDGE_CPU_OPERATOR_TANHIMPL_H_ + +#include "aidge/backend/cpu/operator/OperatorImpl.hpp" +#include "aidge/operator/CryptoHash.hpp" +#include "aidge/utils/Registrar.hpp" +#include "aidge/utils/Types.h" +#include "aidge/backend/cpu/data/GetCPUPtr.h" +#include <memory> +#include <vector> + +#ifdef WITH_OPENSSL +#include <openssl/sha.h> + +namespace Aidge { +// Operator implementation entry point for the backend +using CryptoHashImpl_cpu = OperatorImpl_cpu<CryptoHash_Op, + void(const std::size_t, const void*, void*)>; + +// Implementation entry point registration to Operator +REGISTRAR(CryptoHash_Op, "cpu", Aidge::CryptoHashImpl_cpu::create); +} // namespace Aidge +#endif + +#endif /* AIDGE_CPU_OPERATOR_TANHIMPL_H_ */ diff --git a/include/aidge/backend/cpu/operator/CryptoHashImpl_kernels.hpp b/include/aidge/backend/cpu/operator/CryptoHashImpl_kernels.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cd596b6905988050666c7c2dff15a4cf8078e52a --- /dev/null +++ b/include/aidge/backend/cpu/operator/CryptoHashImpl_kernels.hpp @@ -0,0 +1,52 @@ +/******************************************************************************** + * Copyright (c) 2023 CEA-List + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + * + ********************************************************************************/ + +#ifndef AIDGE_CPU_OPERATOR_CRYPTOHASHIMPL_KERNELS_H_ +#define AIDGE_CPU_OPERATOR_CRYPTOHASHIMPL_KERNELS_H_ + +#include "aidge/utils/Registrar.hpp" + +#include "aidge/backend/cpu/operator/CryptoHashImpl.hpp" + +#ifdef WITH_OPENSSL +namespace Aidge { +template <class I, class O> +void CryptoHashImpl_cpu_forward_kernel(std::size_t inputLength, + const void* input_, + void* output_) { + + const I* input = static_cast<const I*>(input_); + O* output = static_cast<O*>(output_); + + // output must be at least SHA256_DIGEST_LENGTH bytes length + SHA256(reinterpret_cast<const uint8_t*>(input), inputLength * sizeof(I), reinterpret_cast<uint8_t*>(output)); +} + +// Kernels registration to implementation entry point +REGISTRAR(CryptoHashImpl_cpu, + {{DataType::UInt8, DataFormat::Any}, {DataType::UInt8}}, + {ProdConso::inPlaceModel, Aidge::CryptoHashImpl_cpu_forward_kernel<uint8_t, uint8_t>, nullptr}); +REGISTRAR(CryptoHashImpl_cpu, + {{DataType::UInt8, DataFormat::Any}, {DataType::UInt64}}, + {ProdConso::inPlaceModel, Aidge::CryptoHashImpl_cpu_forward_kernel<uint8_t, uint64_t>, nullptr}); +REGISTRAR(CryptoHashImpl_cpu, + {{DataType::Float32, DataFormat::Any}, {DataType::UInt8}}, + {ProdConso::inPlaceModel, Aidge::CryptoHashImpl_cpu_forward_kernel<float, uint8_t>, nullptr}); +REGISTRAR(CryptoHashImpl_cpu, + {{DataType::Float32, DataFormat::Any}, {DataType::UInt64}}, + {ProdConso::inPlaceModel, Aidge::CryptoHashImpl_cpu_forward_kernel<float, uint64_t>, nullptr}); +REGISTRAR(CryptoHashImpl_cpu, + {{DataType::Float64, DataFormat::Any}, {DataType::UInt8}}, + {ProdConso::inPlaceModel, Aidge::CryptoHashImpl_cpu_forward_kernel<double, uint8_t>, nullptr}); +} // namespace Aidge +#endif + +#endif /* AIDGE_CPU_OPERATOR_CRYPTOHASHIMPL_KERNELS_H_ */ diff --git a/include/aidge/backend/cpu/operator/ModImpl_kernels.hpp b/include/aidge/backend/cpu/operator/ModImpl_kernels.hpp index 940fa482c3f45ea0ae77a8dce4a279e3faa974ce..15d18bf4de5cee7e7d75817a2ccf425f5ff41971 100644 --- a/include/aidge/backend/cpu/operator/ModImpl_kernels.hpp +++ b/include/aidge/backend/cpu/operator/ModImpl_kernels.hpp @@ -72,6 +72,9 @@ REGISTRAR(ModImpl_cpu, REGISTRAR(ModImpl_cpu, {DataType::Int32}, {ProdConso::inPlaceModel, Aidge::ModImpl_cpu_forward_kernel<std::int32_t, std::int32_t, std::int32_t>, nullptr}); +REGISTRAR(ModImpl_cpu, + {DataType::UInt64}, + {ProdConso::inPlaceModel, Aidge::ModImpl_cpu_forward_kernel<std::uint64_t, std::uint64_t, std::uint64_t>, nullptr}); } // namespace Aidge #endif /* AIDGE_CPU_OPERATOR_MODIMPL_KERNELS_H_ */ diff --git a/src/operator/CryptoHashImpl.cpp b/src/operator/CryptoHashImpl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..10d82dd05408733b898da0c8d3edb38df76dbe1a --- /dev/null +++ b/src/operator/CryptoHashImpl.cpp @@ -0,0 +1,46 @@ +/******************************************************************************** + * Copyright (c) 2023 CEA-List + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + * + ********************************************************************************/ + +#include <cassert> +#include <chrono> // std::chrono::milliseconds +#include <numeric> // std::accumulate +#include <thread> // std::this_thread::sleep_for +#include <vector> + +#include "aidge/operator/CryptoHash.hpp" +#include "aidge/utils/Types.h" +#include "aidge/backend/cpu/data/GetCPUPtr.h" + +#include "aidge/backend/cpu/operator/CryptoHashImpl.hpp" +#include "aidge/backend/cpu/operator/CryptoHashImpl_kernels.hpp" + +#ifdef WITH_OPENSSL +template <> +void Aidge::CryptoHashImpl_cpu::forward() { + const CryptoHash_Op& op_ = dynamic_cast<const CryptoHash_Op&>(mOp); + std::shared_ptr<Tensor> in0 = op_.getInput(0); + std::shared_ptr<Tensor> out0 = op_.getOutput(0); + AIDGE_ASSERT(in0, "missing input #0"); + + // Find the correct kernel type + const auto impl = Registrar<CryptoHashImpl_cpu>::create(getBestMatch(getRequiredSpec())); + + // Call kernel + impl.forward(in0->size(), + getCPUPtr(mOp.getRawInput(0)), + getCPUPtr(mOp.getRawOutput(0))); +} + +template <> +void Aidge::CryptoHashImpl_cpu::backward() { + AIDGE_THROW_OR_ABORT(std::runtime_error, "Backward not available for CryptoHash_Op"); +} +#endif diff --git a/unit_tests/operator/Test_CryptoHash.cpp b/unit_tests/operator/Test_CryptoHash.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7453ea19c765d6a2bf79a66972d120b7a0ca6de5 --- /dev/null +++ b/unit_tests/operator/Test_CryptoHash.cpp @@ -0,0 +1,56 @@ +/******************************************************************************** + * Copyright (c) 2023 CEA-List + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + * + ********************************************************************************/ + +#include <cmath> // std::abs +#include <cstddef> // std::size_t +#include <memory> + +#include <catch2/catch_test_macros.hpp> + +#include "aidge/backend/cpu/operator/CryptoHashImpl.hpp" +#include "aidge/data/Data.hpp" +#include "aidge/data/Tensor.hpp" +#include "aidge/graph/Node.hpp" +#include "aidge/operator/CryptoHash.hpp" +#include "aidge/utils/ArrayHelpers.hpp" + +using namespace Aidge; + +#ifdef WITH_OPENSSL +TEST_CASE("[cpu/operator] CryptoHash(forward)") { + SECTION("1D Tensor") { + std::shared_ptr<Tensor> input0 = + std::make_shared<Tensor>(Array1D<uint8_t, 5>{ + {'a', 'b', 'c', 'd', 'e'}}); + std::shared_ptr<Tensor> expectedOutput = + std::make_shared<Tensor>(Array1D<uint8_t, 32>{ + {0x36, 0xbb, 0xe5, 0x0e, 0xd9, 0x68, 0x41, 0xd1, + 0x04, 0x43, 0xbc, 0xb6, 0x70, 0xd6, 0x55, 0x4f, + 0x0a, 0x34, 0xb7, 0x61, 0xbe, 0x67, 0xec, 0x9c, + 0x4a, 0x8a, 0xd2, 0xc0, 0xc4, 0x4c, 0xa4, 0x2c}}); + + std::shared_ptr<Node> myCryptoHash = CryptoHash(); + auto op = std::static_pointer_cast<CryptoHash_Op>(myCryptoHash->getOperator()); + op->associateInput(0, input0); + op->setDataType(DataType::UInt8); + op->setBackend("cpu"); + myCryptoHash->forward(); + + REQUIRE(op->getOutput(0)->size() == 32); + + uint8_t* resPtr = static_cast<uint8_t*>(op->getOutput(0)->getImpl()->rawPtr()); + uint8_t* expectedPtr = static_cast<uint8_t*>(expectedOutput->getImpl()->rawPtr()); + for (std::size_t i = 0; i < expectedOutput->size(); ++i) { + REQUIRE(resPtr[i] == expectedPtr[i]); + } + } +} +#endif diff --git a/unit_tests/scheduler/Test_Scheduler.cpp b/unit_tests/scheduler/Test_Scheduler.cpp index 956169c387c4a34f500f66b214dcf95a145feafd..5bd86eec01c922e50e80fe837c567091ac768b1f 100644 --- a/unit_tests/scheduler/Test_Scheduler.cpp +++ b/unit_tests/scheduler/Test_Scheduler.cpp @@ -21,6 +21,10 @@ #include "aidge/operator/Pop.hpp" #include "aidge/operator/Stack.hpp" #include "aidge/operator/Identity.hpp" +#include "aidge/operator/CryptoHash.hpp" +#include "aidge/operator/Mod.hpp" +#include "aidge/operator/Tanh.hpp" +#include "aidge/operator/Select.hpp" #include "aidge/operator/MetaOperator.hpp" #include "aidge/scheduler/SequentialScheduler.hpp" #include "aidge/scheduler/ParallelScheduler.hpp" @@ -30,6 +34,9 @@ #include "aidge/backend/cpu/operator/ReLUImpl.hpp" #include "aidge/backend/cpu/operator/SqrtImpl.hpp" #include "aidge/backend/cpu/operator/AddImpl.hpp" +#include "aidge/backend/cpu/operator/CryptoHashImpl.hpp" +#include "aidge/backend/cpu/operator/ModImpl.hpp" +#include "aidge/backend/cpu/operator/TanhImpl.hpp" #include "aidge/recipes/GraphViewHelper.hpp" @@ -512,4 +519,56 @@ TEST_CASE("[cpu/scheduler] Accumulate", "[scheduler]") { std::shared_ptr<Tensor> output = std::static_pointer_cast<OperatorTensor>(pop_o->getOperator())->getOutput(0); REQUIRE(*output == *expectedOutput); } + +#ifdef WITH_OPENSSL +TEST_CASE("[cpu/scheduler] Select", "[scheduler]") { + std::shared_ptr<Tensor> in = std::make_shared<Tensor>( + Array2D<float, 2, 3>{{{1, 2, 3}, {4, 5, 6}}}); + + std::shared_ptr<GraphView> g = Sequential({ + Producer(in, "input"), + Parallel({ + Sequential({ + CryptoHash("hash"), + Mod("mod") + }), + ReLU("relu"), + Tanh("tanh"), + Sqrt("sqrt") + }), + Select(3, "select") + }); + + auto modProd = Producer(std::make_shared<Tensor>(Array1D<uint64_t, 1>{{3}})); + modProd->addChild(g->getNode("mod"), 0, 1); + g->add(modProd); + + g->getNode("hash")->getOperator()->setDataType(DataType::UInt64); + g->getNode("mod")->getOperator()->setDataType(DataType::UInt64); + g->setBackend("cpu"); + g->save("select"); + + auto scheduler = SequentialScheduler(g); + scheduler.generateScheduling(); + scheduler.saveStaticSchedulingDiagram("select_scheduling"); + REQUIRE_NOTHROW(scheduler.forward(true)); + + g->save("select_forwarded"); + + auto expectedOutputHash = std::make_shared<Tensor>( + Array1D<uint64_t, 4>{{0x1b7cf58dfe2dae24, 0x3bac903def4ce580, 0x5f5a347389d97f41, 0x2c2dc759abc6b61}}); + auto outputHash = std::static_pointer_cast<OperatorTensor>(g->getNode("hash")->getOperator())->getOutput(0); + REQUIRE(*outputHash == *expectedOutputHash); + + auto expectedOutputMod = std::make_shared<Tensor>( + Array1D<uint64_t, 4>{{2, 1, 1, 2}}); + auto outputMod = std::static_pointer_cast<OperatorTensor>(g->getNode("mod")->getOperator())->getOutput(0); + REQUIRE(*outputMod == *expectedOutputMod); + + auto expectedOutput = std::make_shared<Tensor>( + Array2D<float, 2, 3>{{{std::sqrt(1), std::sqrt(2), std::sqrt(3)}, {std::sqrt(4), std::sqrt(5), std::sqrt(6)}}}); + auto output = std::static_pointer_cast<OperatorTensor>(g->getNode("select")->getOperator())->getOutput(0); + REQUIRE(*output == *expectedOutput); +} +#endif } // namespace Aidge