diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..833d981 Binary files /dev/null and b/.DS_Store differ diff --git a/.vs/CMake Overview b/.vs/CMake Overview new file mode 100644 index 0000000..e69de29 diff --git a/.vs/KGC/FileContentIndex/1f7c3579-20ab-4e7f-802d-bf403df89daf.vsidx b/.vs/KGC/FileContentIndex/1f7c3579-20ab-4e7f-802d-bf403df89daf.vsidx new file mode 100644 index 0000000..d978ef7 Binary files /dev/null and b/.vs/KGC/FileContentIndex/1f7c3579-20ab-4e7f-802d-bf403df89daf.vsidx differ diff --git a/.vs/KGC/FileContentIndex/2d65281a-80f8-4373-afa1-d467ad0689d1.vsidx b/.vs/KGC/FileContentIndex/2d65281a-80f8-4373-afa1-d467ad0689d1.vsidx new file mode 100644 index 0000000..456d28b Binary files /dev/null and b/.vs/KGC/FileContentIndex/2d65281a-80f8-4373-afa1-d467ad0689d1.vsidx differ diff --git a/.vs/KGC/FileContentIndex/402dcfbd-fffe-4c37-a38f-1ce47ee68ce0.vsidx b/.vs/KGC/FileContentIndex/402dcfbd-fffe-4c37-a38f-1ce47ee68ce0.vsidx new file mode 100644 index 0000000..0d33940 Binary files /dev/null and b/.vs/KGC/FileContentIndex/402dcfbd-fffe-4c37-a38f-1ce47ee68ce0.vsidx differ diff --git a/.vs/KGC/FileContentIndex/72627c78-8166-4040-a5eb-525354373247.vsidx b/.vs/KGC/FileContentIndex/72627c78-8166-4040-a5eb-525354373247.vsidx new file mode 100644 index 0000000..19d2638 Binary files /dev/null and b/.vs/KGC/FileContentIndex/72627c78-8166-4040-a5eb-525354373247.vsidx differ diff --git a/.vs/KGC/FileContentIndex/read.lock b/.vs/KGC/FileContentIndex/read.lock new file mode 100644 index 0000000..e69de29 diff --git a/.vs/KGC/v17/.suo b/.vs/KGC/v17/.suo new file mode 100644 index 0000000..4bf352b Binary files /dev/null and b/.vs/KGC/v17/.suo differ diff --git a/.vs/KGC/v17/Browse.VC.db b/.vs/KGC/v17/Browse.VC.db new file mode 100644 index 0000000..e36017e Binary files /dev/null and b/.vs/KGC/v17/Browse.VC.db differ diff --git a/.vs/KGC/v17/ipch/AutoPCH/8504fe4dc05b7cb1/UTILS.ipch b/.vs/KGC/v17/ipch/AutoPCH/8504fe4dc05b7cb1/UTILS.ipch new file mode 100644 index 0000000..a6b307b Binary files /dev/null and b/.vs/KGC/v17/ipch/AutoPCH/8504fe4dc05b7cb1/UTILS.ipch differ diff --git a/.vs/KGC/v17/ipch/AutoPCH/aaf84237246deadb/MAIN.ipch b/.vs/KGC/v17/ipch/AutoPCH/aaf84237246deadb/MAIN.ipch new file mode 100644 index 0000000..889794d Binary files /dev/null and b/.vs/KGC/v17/ipch/AutoPCH/aaf84237246deadb/MAIN.ipch differ diff --git a/.vs/KGC/v17/ipch/AutoPCH/b6d261708b0fd737/KGC.ipch b/.vs/KGC/v17/ipch/AutoPCH/b6d261708b0fd737/KGC.ipch new file mode 100644 index 0000000..23beff4 Binary files /dev/null and b/.vs/KGC/v17/ipch/AutoPCH/b6d261708b0fd737/KGC.ipch differ diff --git a/.vs/KGC/v17/ipch/AutoPCH/c7528dccf1137267/MAIN.ipch b/.vs/KGC/v17/ipch/AutoPCH/c7528dccf1137267/MAIN.ipch new file mode 100644 index 0000000..83896bb Binary files /dev/null and b/.vs/KGC/v17/ipch/AutoPCH/c7528dccf1137267/MAIN.ipch differ diff --git a/.vs/KGC/v17/ipch/AutoPCH/e0ab2bceadaf748b/MAIN.ipch b/.vs/KGC/v17/ipch/AutoPCH/e0ab2bceadaf748b/MAIN.ipch new file mode 100644 index 0000000..821d902 Binary files /dev/null and b/.vs/KGC/v17/ipch/AutoPCH/e0ab2bceadaf748b/MAIN.ipch differ diff --git a/.vs/KGC/v17/ipch/AutoPCH/f2d4fc7b85a9752f/SIGN.ipch b/.vs/KGC/v17/ipch/AutoPCH/f2d4fc7b85a9752f/SIGN.ipch new file mode 100644 index 0000000..06d1ecd Binary files /dev/null and b/.vs/KGC/v17/ipch/AutoPCH/f2d4fc7b85a9752f/SIGN.ipch differ diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json new file mode 100644 index 0000000..38c5f00 --- /dev/null +++ b/.vs/ProjectSettings.json @@ -0,0 +1,3 @@ +{ + "CurrentProjectSetting": "x86-Debug" +} \ No newline at end of file diff --git a/.vs/VSWorkspaceState.json b/.vs/VSWorkspaceState.json new file mode 100644 index 0000000..6b61141 --- /dev/null +++ b/.vs/VSWorkspaceState.json @@ -0,0 +1,6 @@ +{ + "ExpandedNodes": [ + "" + ], + "PreviewInSolutionExplorer": false +} \ No newline at end of file diff --git a/.vs/cmake.db b/.vs/cmake.db new file mode 100644 index 0000000..0873bf6 Binary files /dev/null and b/.vs/cmake.db differ diff --git a/.vs/launch.vs.json b/.vs/launch.vs.json new file mode 100644 index 0000000..96d1405 --- /dev/null +++ b/.vs/launch.vs.json @@ -0,0 +1,12 @@ +{ + "version": "0.2.1", + "defaults": {}, + "configurations": [ + { + "type": "default", + "project": "CMakeLists.txt", + "projectTarget": "KGC_demo.exe", + "name": "KGC_demo.exe" + } + ] +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000..bc3f244 Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..deaefb0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,100 @@ +cmake_minimum_required(VERSION 3.21.0) +project(KGC) + +include(GNUInstallDirs) + +set(MIRACL_INSTALL_INCLUDEDIR ${CMAKE_CURRENT_BINARY_DIR}/output/include) +set(MIRACL_INSTALL_LIBDIR ${CMAKE_CURRENT_BINARY_DIR}/output/temp) +set(MIRACL_INSTALL_BINDIR ${CMAKE_CURRENT_BINARY_DIR}/output/temp) +add_subdirectory(miracl) + +aux_source_directory(. APP_SRC) + +# 创建 KGC 静态库并链接 Miracl +add_library(${PROJECT_NAME} STATIC ${APP_SRC}) + +target_link_libraries(${PROJECT_NAME} PUBLIC Miracl) + +target_include_directories(${PROJECT_NAME} PUBLIC + include + ${CMAKE_CURRENT_SOURCE_DIR} +) + +file(GLOB_RECURSE MIRACL_HEADER_FILES ${CMAKE_CURRENT_BINARY_DIR}/miracl/*.h) +file(COPY ${MIRACL_HEADER_FILES} DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/output/include") + +file(GLOB HEADER_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.h) +file(COPY ${HEADER_FILES} DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/output/include") + +if(EXISTS "${CMAKE_CURRENT_BINARY_DIR}/output/lib/lib${PROJECT_NAME}All.a" OR "${CMAKE_CURRENT_BINARY_DIR}/output/lib/lib${PROJECT_NAME}All.lib") + if(MSVC) + file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/output/lib/lib${PROJECT_NAME}All.lib) + else() + file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/output/lib/lib${PROJECT_NAME}All.a) + endif() +endif() + +if(APPLE) + add_custom_command(OUTPUT lib${PROJECT_NAME}All + COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/output/lib" + COMMAND libtool -static -o "${CMAKE_CURRENT_BINARY_DIR}/output/lib/lib${PROJECT_NAME}All.a" $ $ + DEPENDS ${PROJECT_NAME} Miracl) +elseif(MSVC) + add_custom_command(OUTPUT lib${PROJECT_NAME}All + COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/output/lib" + COMMAND lib.exe "-OUT:${CMAKE_CURRENT_BINARY_DIR}/output/lib/lib${PROJECT_NAME}All.lib" $ $ + DEPENDS ${PROJECT_NAME} Miracl) +elseif(WIN32) + add_custom_command(OUTPUT lib${PROJECT_NAME}All + COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/output/temp" + COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/output/lib" + COMMAND ${CMAKE_COMMAND} -E copy $ $ "${CMAKE_CURRENT_BINARY_DIR}/output/temp" + COMMAND cd "${CMAKE_CURRENT_BINARY_DIR}/output/temp" + COMMAND ${CMAKE_AR} x "${CMAKE_CURRENT_BINARY_DIR}/output/temp/libMiracl.a" + COMMAND ${CMAKE_AR} x "${CMAKE_CURRENT_BINARY_DIR}/output/temp/lib${PROJECT_NAME}.a" + COMMAND ${CMAKE_AR} crs "${CMAKE_CURRENT_BINARY_DIR}/output/lib/lib${PROJECT_NAME}All.a" "${CMAKE_CURRENT_BINARY_DIR}/output/temp/*.obj" + DEPENDS ${PROJECT_NAME} Miracl + ) +else() + add_custom_command(OUTPUT lib${PROJECT_NAME}All + COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/output/temp" + COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/output/lib" + COMMAND ${CMAKE_COMMAND} -E copy $ $ "${CMAKE_CURRENT_BINARY_DIR}/output/temp" + COMMAND cd "${CMAKE_CURRENT_BINARY_DIR}/output/temp" + COMMAND ${CMAKE_AR} x "${CMAKE_CURRENT_BINARY_DIR}/output/temp/libMiracl.a" + COMMAND ${CMAKE_AR} x "${CMAKE_CURRENT_BINARY_DIR}/output/temp/lib${PROJECT_NAME}.a" + COMMAND ${CMAKE_AR} crs "${CMAKE_CURRENT_BINARY_DIR}/output/lib/lib${PROJECT_NAME}All.a" "${CMAKE_CURRENT_BINARY_DIR}/output/temp/*.o" + DEPENDS ${PROJECT_NAME} Miracl + ) +endif() + +add_custom_target(${PROJECT_NAME}All ALL DEPENDS lib${PROJECT_NAME}All) + +if(KGC_INSTALL_BINDIR) + set(CMAKE_INSTALL_BINDIR ${KGC_INSTALL_BINDIR}) +endif() + +if(KGC_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR ${KGC_INSTALL_LIBDIR}) +endif() + +if(KGC_INSTALL_INCLUDEDIR) + set(CMAKE_INSTALL_INCLUDEDIR ${KGC_INSTALL_INCLUDEDIR}) +endif() + +install(TARGETS ${PROJECT_NAME} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +if(MSVC) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/output/lib/lib${PROJECT_NAME}All.lib" + DESTINATION ${CMAKE_INSTALL_LIBDIR}) +else() + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/output/lib/lib${PROJECT_NAME}All.a" + DESTINATION ${CMAKE_INSTALL_LIBDIR}) +endif() + +file(GLOB HEADER_FILES ${CMAKE_CURRENT_BINARY_DIR}/output/include/*.h) +install(FILES ${HEADER_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/CMakeLists.txt.user b/CMakeLists.txt.user new file mode 100644 index 0000000..9e23732 --- /dev/null +++ b/CMakeLists.txt.user @@ -0,0 +1,418 @@ + + + + + + EnvironmentId + {7795ecad-0ea3-4fc2-a933-fbc01bf1ad55} + + + ProjectExplorer.Project.ActiveTarget + 0 + + + ProjectExplorer.Project.EditorSettings + + true + false + true + + Cpp + + CppGlobal + + + + QmlJS + + QmlJSGlobal + + + 2 + UTF-8 + false + 4 + false + 80 + true + true + 1 + 0 + false + true + false + 2 + true + true + 0 + 8 + true + false + 1 + true + true + true + *.md, *.MD, Makefile + false + true + true + + + + ProjectExplorer.Project.PluginSettings + + + true + false + true + true + true + true + + + 0 + true + + true + true + Builtin.DefaultTidyAndClazy + 2 + true + + + + true + + + + + ProjectExplorer.Project.Target.0 + + Desktop + Desktop Qt 6.5.3 MinGW 64-bit + Desktop Qt 6.5.3 MinGW 64-bit + qt.qt6.653.win64_mingw_kit + 0 + 0 + 0 + + Debug + 2 + false + + -DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_BUILD_TYPE:STRING=Debug +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} + 0 + C:\KGC\build\Desktop_Qt_6_5_3_MinGW_64_bit-Debug + + + + + all + + false + + true + 构建 + CMakeProjectManager.MakeStep + + 1 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + + + clean + + false + + true + 构建 + CMakeProjectManager.MakeStep + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Debug + CMakeProjectManager.CMakeBuildConfiguration + + + Release + 2 + false + + -DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_BUILD_TYPE:STRING=Release +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} + C:\KGC\build\Desktop_Qt_6_5_3_MinGW_64_bit-Release + + + + + all + + false + + true + CMakeProjectManager.MakeStep + + 1 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + + + clean + + false + + true + CMakeProjectManager.MakeStep + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Release + CMakeProjectManager.CMakeBuildConfiguration + + + RelWithDebInfo + 2 + false + + -DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} + C:\KGC\build\Desktop_Qt_6_5_3_MinGW_64_bit-RelWithDebInfo + + + + + all + + false + + true + CMakeProjectManager.MakeStep + + 1 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + + + clean + + false + + true + CMakeProjectManager.MakeStep + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Release with Debug Information + CMakeProjectManager.CMakeBuildConfiguration + + + RelWithDebInfo + 2 + false + + -DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_BUILD_TYPE:STRING=RelWithDebInfo +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} + 0 + C:\KGC\build\Desktop_Qt_6_5_3_MinGW_64_bit-Profile + + + + + all + + false + + true + CMakeProjectManager.MakeStep + + 1 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + + + clean + + false + + true + CMakeProjectManager.MakeStep + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Profile + CMakeProjectManager.CMakeBuildConfiguration + + + MinSizeRel + 2 + false + + -DCMAKE_GENERATOR:STRING=Ninja +-DCMAKE_BUILD_TYPE:STRING=MinSizeRel +-DCMAKE_PROJECT_INCLUDE_BEFORE:FILEPATH=%{BuildConfig:BuildDirectory:NativeFilePath}/.qtc/package-manager/auto-setup.cmake +-DQT_QMAKE_EXECUTABLE:FILEPATH=%{Qt:qmakeExecutable} +-DCMAKE_PREFIX_PATH:PATH=%{Qt:QT_INSTALL_PREFIX} +-DCMAKE_C_COMPILER:FILEPATH=%{Compiler:Executable:C} +-DCMAKE_CXX_COMPILER:FILEPATH=%{Compiler:Executable:Cxx} +-DCMAKE_CXX_FLAGS_INIT:STRING=%{Qt:QML_DEBUG_FLAG} + C:\KGC\build\Desktop_Qt_6_5_3_MinGW_64_bit-MinSizeRel + + + + + all + + false + + true + CMakeProjectManager.MakeStep + + 1 + 构建 + 构建 + ProjectExplorer.BuildSteps.Build + + + + + + clean + + false + + true + CMakeProjectManager.MakeStep + + 1 + 清除 + 清除 + ProjectExplorer.BuildSteps.Clean + + 2 + false + + false + + Minimum Size Release + CMakeProjectManager.CMakeBuildConfiguration + + 5 + + + 0 + 部署 + 部署 + ProjectExplorer.BuildSteps.Deploy + + 1 + + false + ProjectExplorer.DefaultDeployConfiguration + + 1 + + true + true + 0 + true + + 2 + + false + -e cpu-cycles --call-graph "dwarf,4096" -F 250 + + ProjectExplorer.CustomExecutableRunConfiguration + + false + true + true + + 1 + + + + ProjectExplorer.Project.TargetCount + 1 + + + ProjectExplorer.Project.Updater.FileVersion + 22 + + + Version + 22 + + diff --git a/CMakeSettings.json b/CMakeSettings.json new file mode 100644 index 0000000..eb87a46 --- /dev/null +++ b/CMakeSettings.json @@ -0,0 +1,61 @@ +{ + "configurations": [ + { + "name": "x64-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ "msvc_x64_x64" ], + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "" + }, + { + "name": "x86-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "msvc_x86" ] + }, + { + "name": "Mingw64-Release", + "generator": "Ninja", + "configurationType": "RelWithDebInfo", + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "-v", + "ctestCommandArgs": "", + "inheritEnvironments": [ "mingw_64" ], + "environments": [ + { + "MINGW64_ROOT": "C:/msys64/mingw64", + "BIN_ROOT": "${env.MINGW64_ROOT}/bin", + "FLAVOR": "x86_64-w64-mingw32", + "TOOLSET_VERSION": "9.1.0", + "PATH": "${env.MINGW64_ROOT}/bin;${env.MINGW64_ROOT}/../usr/local/bin;${env.MINGW64_ROOT}/../usr/bin;${env.MINGW64_ROOT}/../bin;${env.PATH}", + "INCLUDE": "${env.INCLUDE};${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION};${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION}/tr1;${env.MINGW64_ROOT}/include/c++/${env.TOOLSET_VERSION}/${env.FLAVOR}", + "environment": "mingw_64" + } + ], + "variables": [ + { + "name": "CMAKE_C_COMPILER", + "value": "${env.BIN_ROOT}/gcc.exe", + "type": "STRING" + }, + { + "name": "CMAKE_CXX_COMPILER", + "value": "${env.BIN_ROOT}/g++.exe", + "type": "STRING" + } + ], + "intelliSenseMode": "linux-gcc-x64" + } + ] +} \ No newline at end of file diff --git a/ecurve.cpp b/ecurve.cpp new file mode 100644 index 0000000..50e87dd --- /dev/null +++ b/ecurve.cpp @@ -0,0 +1,69 @@ +#include "ecurve.h" + +// 使用的椭圆曲线(SECP256K1)公开参数 +char Q[] = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"; // 有限域的模q +char A[] = "0000000000000000000000000000000000000000000000000000000000000000"; // 曲线方程系数a +char B[] = "0000000000000000000000000000000000000000000000000000000000000007"; // 曲线方程系数b +char X[] = "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"; // 基点P的x坐标 +char Y[] = "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"; // 基点P的y坐标 +char P_N[] = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"; // 基点P的阶:令nP=O的最小整数 + +bool setupEcurve(ECC_PARAMS *params) +{ + // 初始化变量 + (*params).a = mirvar(0); + (*params).b = mirvar(0); + (*params).q = mirvar(0); + (*params).p = mirvar(0); + (*params).P_x = mirvar(0); + (*params).P_y = mirvar(0); + (*params).P = epoint_init(); + + // 赋值 + cinstr((*params).a, A); + cinstr((*params).b, B); + cinstr((*params).q, Q); + cinstr((*params).p, P_N); + + cinstr((*params).P_x, X); + cinstr((*params).P_y, Y); + + // 椭圆曲线方程初始化 + ecurve_init((*params).a, (*params).b, (*params).q, MR_PROJECTIVE); + + // 设置点坐标(P_x,P_y)为点P,此函数同时能判断P是否在上面初始化成功的椭圆曲线上 + if (!epoint_set((*params).P_x, (*params).P_y, 0, (*params).P)) + { + freeEcurve(params); + return false; + } + + // 判断P是否是阶为p的基点,判断依据:基点乘以阶为无穷远点 + bool bRv = false; + epoint *P_test = epoint_init(); + ecurve_mult((*params).p, (*params).P, P_test); + if (point_at_infinity(P_test)) + { + bRv = true; + } + else + { + freeEcurve(params); + bRv = false; + } + epoint_free(P_test); + + return bRv; +} + +void freeEcurve(ECC_PARAMS *params) +{ + mirkill((*params).a); + mirkill((*params).b); + mirkill((*params).q); + mirkill((*params).p); + mirkill((*params).P_x); + mirkill((*params).P_y); + + epoint_free((*params).P); +} \ No newline at end of file diff --git a/ecurve.h b/ecurve.h new file mode 100644 index 0000000..42c286e --- /dev/null +++ b/ecurve.h @@ -0,0 +1,25 @@ +#ifndef __ECURVE_H__ +#define __ECURVE_H__ + +extern "C" +{ +#include "miracl.h" +#include "mirdef.h" +} + +typedef struct ecc_params +{ + big a; // 椭圆曲线方程系数a + big b; // 椭圆曲线方程系数b + big q; // 模 + big p; // 阶 + big P_x; // 基点横坐标 + big P_y; // 基点纵坐标 + epoint *P; // 基点 +} ECC_PARAMS; + +bool setupEcurve(ECC_PARAMS *params); + +void freeEcurve(ECC_PARAMS *params); + +#endif // ecurve.h \ No newline at end of file diff --git a/generator_cgo/.idea/.gitignore b/generator_cgo/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/generator_cgo/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/generator_cgo/.idea/.name b/generator_cgo/.idea/.name new file mode 100644 index 0000000..30de634 --- /dev/null +++ b/generator_cgo/.idea/.name @@ -0,0 +1 @@ +main.go \ No newline at end of file diff --git a/generator_cgo/.idea/cgo.iml b/generator_cgo/.idea/cgo.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/generator_cgo/.idea/cgo.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/generator_cgo/.idea/modules.xml b/generator_cgo/.idea/modules.xml new file mode 100644 index 0000000..5f95085 --- /dev/null +++ b/generator_cgo/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/generator_cgo/.vscode/tasks.json b/generator_cgo/.vscode/tasks.json new file mode 100644 index 0000000..38de289 --- /dev/null +++ b/generator_cgo/.vscode/tasks.json @@ -0,0 +1,18 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "go", + "label": "go: build package", + "command": "build", + "args": [ + "${fileDirname}" + ], + "problemMatcher": [ + "$go" + ], + "group": "build", + "detail": "cd c:\\Users\\25761\\Desktop\\cgo; go build ${fileDirname}" + } + ] +} \ No newline at end of file diff --git a/generator_cgo/go.mod b/generator_cgo/go.mod new file mode 100644 index 0000000..e26fe90 --- /dev/null +++ b/generator_cgo/go.mod @@ -0,0 +1,3 @@ +module example.com/m/v2 + +go 1.20 diff --git a/generator_cgo/go.sum b/generator_cgo/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/generator_cgo/include/big.h b/generator_cgo/include/big.h new file mode 100644 index 0000000..bbc2b25 --- /dev/null +++ b/generator_cgo/include/big.h @@ -0,0 +1,451 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * + * MIRACL C++ Header file big.h + * + * AUTHOR : N.Coghlan + * Modified by M.Scott + * + * PURPOSE : Definition of class Big + * + * Bigs are normally created on the heap, but by defining BIGS=m + * on the compiler command line, Bigs are instead mostly created from the + * stack. Note that m must be same or less than the n in the main program + * with for example + * + * Miracl precison(n,0); + * + * where n is the (fixed) size in words of each Big. + * + * This may be faster, as C++ tends to create and destroy lots of + * temporaries. Especially recommended if m is small. Do not use + * for program development + * + * However Bigs created from a string are always allocated from the heap. + * This is useful for creating large read-only constants which are larger + * than m. + * + * NOTE:- I/O conversion + * + * To convert a hex character string to a Big + * + * Big x; + * char c[100]; + * + * mip->IOBASE=16; + * x=c; + * + * To convert a Big to a hex character string + * + * mip->IOBASE=16; + * c << x; + * + * To convert to/from pure binary, see the from_binary() + * and to_binary() friend functions. + * + * int len; + * char c[100]; + * ... + * Big x=from_binary(len,c); // creates Big x from len bytes of binary in c + * + * len=to_binary(x,100,c,FALSE); // converts Big x to len bytes binary in c[100] + * len=to_binary(x,100,c,TRUE); // converts Big x to len bytes binary in c[100] + * // (right justified with leading zeros) + */ + +#ifndef BIG_H +#define BIG_H + +#include +//#include +#include + +#include "mirdef.h" + +#ifdef MR_CPP +#include "miracl.h" +#else +extern "C" +{ + #include "miracl.h" +} +#endif + +#ifndef MR_NO_STANDARD_IO +#include +using std::istream; +using std::ostream; +#endif + +#ifndef MIRACL_CLASS +#define MIRACL_CLASS + +#ifdef __cplusplus +#ifdef MR_GENERIC_MT +#error "The generic method isn't supported for C++, its C only" +#endif +#endif + +class Miracl +{ /* dummy class to initialise MIRACL - MUST be called before any Bigs * + * are created. This could be a problem for static/global data declared * + * in modules other than the main module */ + miracl *mr; +public: + Miracl(int nd,mr_small nb=0) + {mr=mirsys(nd,nb); +#ifdef MR_FLASH +mr->RPOINT=TRUE; +#endif +} + miracl *operator&() {return mr;} + ~Miracl() {mirexit();} +}; + +#endif + +/* +#ifdef BIGS +#define MR_INIT_BIG memset(mem,0,mr_big_reserve(1,BIGS)); fn=(big)mirvar_mem_variable(mem,0,BIGS); +#else +#define MR_INIT_BIG mem=(char *)memalloc(1); fn=(big)mirvar_mem(mem,0); +#endif +*/ + +#ifdef BIGS +#define MR_INIT_BIG fn=&b; b.w=a; b.len=0; for (int i=0;ilen=1; fn->w[0]=s; return *this;} + Big& operator=(const Big& b) {copy(b.fn,fn); return *this;} + Big& operator=(big& b) {copy(b,fn); return *this;} + Big& operator=(big* b) {fn=*b; return *this;} +#ifndef MR_SIMPLE_IO +#ifdef MR_SIMPLE_BASE + Big& operator=(char* s){instr(fn,s);return *this;} +#else + Big& operator=(char* s){cinstr(fn,s);return *this;} +#endif +#endif + Big& operator++() {incr(fn,1,fn); return *this;} + Big& operator--() {decr(fn,1,fn); return *this;} + Big& operator+=(int i) {incr(fn,i,fn); return *this;} + Big& operator+=(const Big& b){add(fn,b.fn,fn); return *this;} + + Big& operator-=(int i) {decr(fn,i,fn); return *this;} + Big& operator-=(const Big& b) {subtract(fn,b.fn,fn); return *this;} + + Big& operator*=(int i) {premult(fn,i,fn); return *this;} + Big& operator*=(const Big& b) {multiply(fn,b.fn,fn); return *this;} + + Big& operator/=(int i) {subdiv(fn,i,fn); return *this;} + Big& operator/=(const Big& b) {divide(fn,b.fn,fn); return *this;} + + Big& operator%=(int i) {convert(subdiv(fn,i,fn),fn); return *this;} + Big& operator%=(const Big& b) {divide(fn,b.fn,b.fn); return *this;} + + Big& operator<<=(int i) {sftbit(fn,i,fn); return *this;} + Big& operator>>=(int i) {sftbit(fn,-i,fn); return *this;} + + Big& shift(int n) {mr_shift(fn,n,fn); return *this;} + + mr_small& operator[](int i) {return fn->w[i];} + + void negate() const; + BOOL iszero() const; + BOOL isone() const; + int get(int index) { int m; m=getdig(fn,index); return m; } + void set(int index,int n) { putdig(n,fn,index);} + int len() const; + + big getbig() const; + + friend class Flash; + + friend Big operator-(const Big&); + + friend Big operator+(const Big&,int); + friend Big operator+(int,const Big&); + friend Big operator+(const Big&,const Big&); + + friend Big operator-(const Big&, int); + friend Big operator-(int,const Big&); + friend Big operator-(const Big&,const Big&); + + friend Big operator*(const Big&, int); + friend Big operator*(int,const Big&); + friend Big operator*(const Big&,const Big&); + + friend BOOL fmth(int n,const Big&,const Big&,Big&); // fast mult - top half + + friend Big operator/(const Big&,int); + friend Big operator/(const Big&,const Big&); + + friend int operator%(const Big&, int); + friend Big operator%(const Big&, const Big&); + + friend Big operator<<(const Big&, int); + friend Big operator>>(const Big&, int); + + friend BOOL operator<=(const Big& b1,const Big& b2) + {if (mr_compare(b1.fn,b2.fn)<=0) return TRUE; else return FALSE;} + friend BOOL operator>=(const Big& b1,const Big& b2) + {if (mr_compare(b1.fn,b2.fn)>=0) return TRUE; else return FALSE;} + friend BOOL operator==(const Big& b1,const Big& b2) + {if (mr_compare(b1.fn,b2.fn)==0) return TRUE; else return FALSE;} + friend BOOL operator!=(const Big& b1,const Big& b2) + {if (mr_compare(b1.fn,b2.fn)!=0) return TRUE; else return FALSE;} + friend BOOL operator<(const Big& b1,const Big& b2) + {if (mr_compare(b1.fn,b2.fn)<0) return TRUE; else return FALSE;} + friend BOOL operator>(const Big& b1,const Big& b2) + {if (mr_compare(b1.fn,b2.fn)>0) return TRUE; else return FALSE;} + + friend Big from_binary(int,char *); + + friend int to_binary(const Big& b,int max,char *ptr,BOOL justify=FALSE) + { + return big_to_bytes(max,b.fn,ptr,justify); + } + //friend int to_binary(const Big&,int,char *,BOOL justify=FALSE); + friend Big modmult(const Big&,const Big&,const Big&); + friend Big mad(const Big&,const Big&,const Big&,const Big&,Big&); + friend Big norm(const Big&); + friend Big sqrt(const Big&); + friend Big root(const Big&,int); + friend Big gcd(const Big&,const Big&); + friend void set_zzn3(int cnr,Big& sru) {get_mip()->cnr=cnr; nres(sru.fn,get_mip()->sru);} + friend int recode(const Big& e,int t,int w,int i) {return recode(e.fn,t,w,i);} + +#ifndef MR_FP + friend Big land(const Big&,const Big&); // logical AND + friend Big lxor(const Big&,const Big&); // logical XOR +#endif + friend Big pow(const Big&,int); // x^m + friend Big pow(const Big&, int, const Big&); // x^m mod n + friend Big pow(int, const Big&, const Big&); // x^m mod n + friend Big pow(const Big&, const Big&, const Big&); // x^m mod n + friend Big pow(const Big&, const Big&, const Big&, const Big&, const Big&); + // x^m.y^k mod n + friend Big pow(int,Big *,Big *,Big); // x[0]^m[0].x[1].m[1]... mod n + + friend Big luc(const Big& b1,const Big& b2, const Big& b3, Big *b4=NULL) + { + Big z; if (b4!=NULL) lucas(b1.fn,b2.fn,b3.fn,b4->fn,z.fn); + else lucas(b1.fn,b2.fn,b3.fn,z.fn,z.fn); + return z; + } + //friend Big luc(const Big& ,const Big&, const Big&, Big *b4=NULL); + friend Big moddiv(const Big&,const Big&,const Big&); + friend Big inverse(const Big&, const Big&); + friend void multi_inverse(int,Big*,const Big&,Big *); +#ifndef MR_NO_RAND + friend Big rand(const Big&); // 0 < rand < parameter + friend Big rand(int,int); // (digits,base) e.g. (32,16) + friend Big randbits(int); // n random bits + friend Big strong_rand(csprng *,const Big&); + friend Big strong_rand(csprng *,int,int); +#endif + friend Big abs(const Big&); +// This next only works if MIRACL is using a binary base... + friend int bit(const Big& b,int i) {return mr_testbit(b.fn,i);} + friend int bits(const Big& b) {return logb2(b.fn);} + friend int ham(const Big& b) {return hamming(b.fn);} + friend int jacobi(const Big& b1,const Big& b2) {return jack(b1.fn,b2.fn);} + friend int toint(const Big& b) {return size(b.fn);} + friend BOOL prime(const Big& b) {return isprime(b.fn);} + friend Big nextprime(const Big&); + friend Big nextsafeprime(int type,int subset,const Big&); + friend Big trial_divide(const Big& b); + friend BOOL small_factors(const Big& b); + friend BOOL perfect_power(const Big& b); + friend Big sqrt(const Big&,const Big&); + + friend void ecurve(const Big&,const Big&,const Big&,int); + friend BOOL ecurve2(int,int,int,int,const Big&,const Big&,BOOL,int); + friend BOOL is_on_curve(const Big&); + friend void modulo(const Big&); + friend BOOL modulo(int,int,int,int,BOOL); + friend Big get_modulus(void); + friend int window(const Big& x,int i,int* nbs,int *nzs,int window_size=5) + { + return mr_window(x.fn,i,nbs,nzs,window_size); + } + + + //friend int window(const Big&,int,int*,int*,int window_size=5); + friend int naf_window(const Big& x,const Big& x3,int i,int* nbs,int* nzs,int store=11) + { + return mr_naf_window(x.fn,x3.fn,i,nbs,nzs,store); + } + + + //friend int naf_window(const Big&,const Big&,int,int*,int*,int store=11); + friend void jsf(const Big&,const Big&,Big&,Big&,Big&,Big&); + +/* Montgomery stuff */ + + friend Big nres(const Big&); + friend Big redc(const Big&); +/* + friend Big nres_negate(const Big&); + friend Big nres_modmult(const Big&,const Big&); + friend Big nres_premult(const Big&,int); + friend Big nres_pow(const Big&,const Big&); + friend Big nres_pow2(const Big&,const Big&,const Big&,const Big&); + friend Big nres_pown(int,Big *,Big *); + friend Big nres_luc(const Big&,const Big&,Big *b3=NULL); + friend Big nres_sqrt(const Big&); + friend Big nres_modadd(const Big&,const Big&); + friend Big nres_modsub(const Big&,const Big&); + friend Big nres_moddiv(const Big&,const Big&); +*/ +/* these are faster.... */ +/* + friend void nres_modmult(Big& a,const Big& b,Big& c) + {nres_modmult(a.fn,b.fn,c.fn);} + friend void nres_modadd(Big& a,const Big& b,Big& c) + {nres_modadd(a.fn,b.fn,c.fn);} + friend void nres_modsub(Big& a,const Big& b,Big& c) + {nres_modsub(a.fn,b.fn,c.fn);} + friend void nres_negate(Big& a,Big& b) + {nres_negate(a.fn,b.fn);} + friend void nres_premult(Big& a,int b,Big& c) + {nres_premult(a.fn,b,c.fn);} + friend void nres_moddiv(Big & a,const Big& b,Big& c) + {nres_moddiv(a.fn,b.fn,c.fn);} +*/ + friend Big shift(const Big&b,int n); + friend int length(const Big&b); + + +/* Note that when inputting text as a number the CR is NOT * + * included in the text, unlike C I/O which does include CR. */ + +#ifndef MR_NO_STANDARD_IO + + friend istream& operator>>(istream&, Big&); + friend ostream& operator<<(ostream&, const Big&); + friend ostream& otfloat(ostream&,const Big&,int); + +#endif + +// output Big to a String + friend char * operator<<(char * s,const Big&); + + ~Big() { + // zero(fn); +#ifndef BIGS + mr_free(fn); +#endif + } +}; + +extern BOOL modulo(int,int,int,int,BOOL); +extern Big get_modulus(void); +extern Big rand(int,int); +extern Big strong_rand(csprng *,int,int); +extern Big from_binary(int,char *); +//extern int to_binary(const Big&,int,char *,BOOL); + +using namespace std; + +#endif + diff --git a/generator_cgo/include/brick.h b/generator_cgo/include/brick.h new file mode 100644 index 0000000..bf06b4b --- /dev/null +++ b/generator_cgo/include/brick.h @@ -0,0 +1,36 @@ +/* + * MIRACL C++ Header file brick.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class Brick + * Comb method for fast exponentiation with + * precomputation + * NOTE : Must be used in conjunction with big.cpp + * + */ + +#ifndef BRICK_H +#define BRICK_H + +#include "big.h" + +class Brick +{ + BOOL created; + brick b; +public: + Brick(Big g,Big n,int window,int nb) + {brick_init(&b,g.getbig(),n.getbig(),window,nb); created=TRUE;} + + Brick(brick *bb) { b=*bb; created=FALSE; } + + brick *get(void) {return &b;} + + Big pow(Big &e) {Big w; pow_brick(&b,e.getbig(),w.getbig()); return w;} + + ~Brick() {if (created) brick_end(&b);} +}; + +#endif + diff --git a/generator_cgo/include/crt.h b/generator_cgo/include/crt.h new file mode 100644 index 0000000..65e7ea2 --- /dev/null +++ b/generator_cgo/include/crt.h @@ -0,0 +1,39 @@ +/* + * MIRACL C++ Header file crt.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class Crt (Chinese Remainder Thereom) + * NOTE : Must be used in conjunction with big.cpp + * Can be used with either Big or utype moduli + */ + +#ifndef CRT_H +#define CRT_H + +#include "big.h" + +#define MR_CRT_BIG 0 +#define MR_CRT_SMALL 1 + +class Crt +{ + big_chinese bc; + small_chinese sc; + int type; +public: + Crt(int,Big *); + Crt(int,mr_utype *); + + Big eval(Big *); + Big eval(mr_utype *); + + ~Crt() + { /* destructor */ + if (type==MR_CRT_BIG) crt_end(&bc); + if (type==MR_CRT_SMALL) scrt_end(&sc); + } +}; + +#endif + diff --git a/generator_cgo/include/ebrick.h b/generator_cgo/include/ebrick.h new file mode 100644 index 0000000..f87effd --- /dev/null +++ b/generator_cgo/include/ebrick.h @@ -0,0 +1,37 @@ +/* + * MIRACL C++ Header file ebrick.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class EBrick + * Brickell et al's method for fast exponentiation with + * precomputation - elliptic curve version GF(p) + * NOTE : Must be used in conjunction with big.cpp + * + */ + +#ifndef EBRICK_H +#define EBRICK_H + +#include "big.h" + +class EBrick +{ + BOOL created; + ebrick B; +public: + EBrick(Big x,Big y,Big a,Big b,Big n,int window,int nb) + {ebrick_init(&B,x.getbig(),y.getbig(),a.getbig(),b.getbig(),n.getbig(),window,nb); + created=TRUE;} + + EBrick(ebrick *b) {B=*b; created=FALSE;} /* set structure */ + + ebrick *get(void) {return &B;} /* get address of structure */ + + int mul(Big &e,Big &x,Big &y) {int d=mul_brick(&B,e.getbig(),x.getbig(),y.getbig()); return d;} + + ~EBrick() {if (created) ebrick_end(&B);} +}; + +#endif + diff --git a/generator_cgo/include/ebrick2.h b/generator_cgo/include/ebrick2.h new file mode 100644 index 0000000..1bd6b6a --- /dev/null +++ b/generator_cgo/include/ebrick2.h @@ -0,0 +1,36 @@ +/* + * MIRACL C++ Header file ebrick2.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class EBrick2 + * Brickell et al's method for fast exponentiation with + * precomputation - elliptic curve version GF(2^m) + * NOTE : Must be used in conjunction with big.cpp + */ + +#ifndef EBRICK2_H +#define EBRICK2_H + +#include "big.h" + +class EBrick2 +{ + BOOL created; + ebrick2 B; +public: + EBrick2(Big x,Big y,Big a2,Big a6,int m,int a,int b,int c,int window,int nb) + {ebrick2_init(&B,x.getbig(),y.getbig(),a2.getbig(),a6.getbig(),m,a,b,c,window,nb); + created=TRUE;} + + EBrick2(ebrick2 *b) {B=*b; created=FALSE;} /* set structure */ + + ebrick2 *get(void) {return &B;} /* get address of structure */ + + int mul(Big &e,Big &x,Big &y) {int d=mul2_brick(&B,e.getbig(),x.getbig(),y.getbig()); return d;} + + ~EBrick2() {if (created) ebrick2_end(&B);} +}; + +#endif + diff --git a/generator_cgo/include/ec2.h b/generator_cgo/include/ec2.h new file mode 100644 index 0000000..32f6a83 --- /dev/null +++ b/generator_cgo/include/ec2.h @@ -0,0 +1,146 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ec2.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class EC2 (Arithmetic on an Elliptic Curve, + * over GF(2^m) + * + * NOTE : Must be used in conjunction with ec2.cpp and big.cpp + * The active curve is set dynamically (via the Big ecurve2() + * routine) - so beware the pitfalls implicit in declaring + * static or global EC2's (which are initialised before the + * curve is set!). Uninitialised data is OK + */ + +#ifndef EC2_H +#define EC2_H + +#include +#include "big.h" + +#ifdef GF2MS +#define MR_INIT_EC2 memset(mem,0,mr_ecp_reserve(1,GF2MS)); p=(epoint *)epoint_init_mem_variable(mem,0,GF2MS); +#else +#define MR_INIT_EC2 mem=(char *)ecp_memalloc(1); p=(epoint *)epoint_init_mem(mem,0); +#endif + +class EC2 +{ + epoint *p; +#ifdef GF2MS + char mem[mr_ecp_reserve(1,GF2MS)]; +#else + char *mem; +#endif + +public: + EC2() { MR_INIT_EC2} + + EC2(const Big &x,const Big& y) {MR_INIT_EC2 + epoint2_set(x.getbig(),y.getbig(),0,p); } + + // This next constructor restores a point on the curve from "compressed" + // data, that is the full x co-ordinate, and the LSB of y/x (0 or 1) + + EC2(const Big& x,int cb) {MR_INIT_EC2 + epoint2_set(x.getbig(),x.getbig(),cb,p); } + + EC2(const EC2 &b) {MR_INIT_EC2 epoint2_copy(b.p,p);} + + epoint *get_point() const; + + EC2& operator=(const EC2& b) {epoint2_copy(b.p,p);return *this;} + + EC2& operator+=(const EC2& b) {ecurve2_add(b.p,p); return *this;} + EC2& operator-=(const EC2& b) {ecurve2_sub(b.p,p); return *this;} + + // Multiplication of a point by an integer. + + EC2& operator*=(const Big& k) {ecurve2_mult(k.getbig(),p,p); return *this;} + big add(const EC2& b) {return ecurve2_add(b.p,p); } + // returns line slope as a big + big sub(const EC2& b) {return ecurve2_sub(b.p,p); } + + void clear() {epoint2_set(NULL,NULL,0,p);} + BOOL set(const Big& x,const Big& y) {return epoint2_set(x.getbig(),y.getbig(),0,p);} + int get(Big& x,Big& y) const; + BOOL iszero() const; + // This gets the point in compressed form. Return value is LSB of y-coordinate + int get(Big& x) const; + + void getx(Big &x) const; + void getxy(Big &x,Big& y) const; + void getxyz(Big &x,Big &y,Big& z) const; + + // point compression + + // This sets the point from compressed form. cb is LSB of y/x + + BOOL set(const Big& x,int cb=0) {return epoint2_set(x.getbig(),x.getbig(),cb,p);} + + friend EC2 operator-(const EC2&); + friend void multi_add(int,EC2 *,EC2 *); + + friend EC2 mul(const Big&, const EC2&, const Big&, const EC2&); + friend EC2 mul(int, const Big *, EC2 *); + + friend void normalise(EC2 &e) {epoint2_norm(e.p);} + + friend BOOL operator==(const EC2& a,const EC2& b) + {return epoint2_comp(a.p,b.p);} + friend BOOL operator!=(const EC2& a,const EC2& b) + {return (!epoint2_comp(a.p,b.p));} + + friend EC2 operator*(const Big &,const EC2&); + +#ifndef MR_NO_STANDARD_IO + + friend ostream& operator<<(ostream&,const EC2&); + +#endif + + ~EC2() + { +#ifndef GF2MS + mr_free(mem); +#endif + } +}; + +#endif + diff --git a/generator_cgo/include/ecn.h b/generator_cgo/include/ecn.h new file mode 100644 index 0000000..df2f3b0 --- /dev/null +++ b/generator_cgo/include/ecn.h @@ -0,0 +1,159 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * + * MIRACL C++ Header file ecn.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class ECn (Arithmetic on an Elliptic Curve, + * mod n) + * + * NOTE : Must be used in conjunction with ecn.cpp and big.cpp + * The active curve is set dynamically (via the Big ecurve() + * routine) - so beware the pitfalls implicit in declaring + * static or global ECn's (which are initialised before the + * curve is set!). Uninitialised data is OK + * + */ + +#ifndef ECN_H +#define ECN_H + +#include +#include "big.h" + +#ifdef ZZNS +#define MR_INIT_ECN memset(mem,0,mr_ecp_reserve(1,ZZNS)); p=(epoint *)epoint_init_mem_variable(mem,0,ZZNS); +#else +#define MR_INIT_ECN mem=(char *)ecp_memalloc(1); p=(epoint *)epoint_init_mem(mem,0); +#endif + +class ECn +{ + epoint *p; +#ifdef ZZNS + char mem[mr_ecp_reserve(1,ZZNS)]; +#else + char *mem; +#endif +public: + ECn() {MR_INIT_ECN } + + ECn(const Big &x,const Big& y) {MR_INIT_ECN + epoint_set(x.getbig(),y.getbig(),0,p); } + + // This next constructor restores a point on the curve from "compressed" + // data, that is the full x co-ordinate, and the LSB of y (0 or 1) + +#ifndef MR_SUPPORT_COMPRESSION + ECn(const Big& x,int cb) {MR_INIT_ECN + epoint_set(x.getbig(),x.getbig(),cb,p); } +#endif + + ECn(const ECn &b) {MR_INIT_ECN epoint_copy(b.p,p);} + + epoint *get_point() const; + int get_status() {return p->marker;} + ECn& operator=(const ECn& b) {epoint_copy(b.p,p);return *this;} + + ECn& operator+=(const ECn& b) {ecurve_add(b.p,p); return *this;} + + int add(const ECn&,big *,big *ex1=NULL,big *ex2=NULL) const; + // returns line slope as a big + int sub(const ECn&,big *,big *ex1=NULL,big *ex2=NULL) const; + + ECn& operator-=(const ECn& b) {ecurve_sub(b.p,p); return *this;} + + // Multiplication of a point by an integer. + + ECn& operator*=(const Big& k) {ecurve_mult(k.getbig(),p,p); return *this;} + + void clear() {epoint_set(NULL,NULL,0,p);} + BOOL set(const Big& x,const Big& y) {return epoint_set(x.getbig(),y.getbig(),0,p);} +#ifndef MR_AFFINE_ONLY +// use with care if at all + void setz(const Big& z) {nres(z.getbig(),p->Z); p->marker=MR_EPOINT_GENERAL;} +#endif + BOOL iszero() const; + int get(Big& x,Big& y) const; + + // This gets the point in compressed form. Return value is LSB of y-coordinate + int get(Big& x) const; + + // get raw coordinates + void getx(Big &x) const; + void getxy(Big &x,Big &y) const; + void getxyz(Big &x,Big &y,Big &z) const; + + // point compression + + // This sets the point from compressed form. cb is LSB of y coordinate +#ifndef MR_SUPPORT_COMPRESSION + BOOL set(const Big& x,int cb=0) {return epoint_set(x.getbig(),x.getbig(),cb,p);} +#endif + friend ECn operator-(const ECn&); + friend void multi_add(int,ECn *,ECn *); + friend void double_add(ECn&,ECn&,ECn&,ECn&,big&,big&); + + friend ECn mul(const Big&, const ECn&, const Big&, const ECn&); + friend ECn mul(int, const Big *, ECn *); + + friend void normalise(ECn &e) {epoint_norm(e.p);} + friend void multi_norm(int,ECn *); + + friend BOOL operator==(const ECn& a,const ECn& b) + {return epoint_comp(a.p,b.p);} + friend BOOL operator!=(const ECn& a,const ECn& b) + {return (!epoint_comp(a.p,b.p));} + + friend ECn operator*(const Big &,const ECn&); + +#ifndef MR_NO_STANDARD_IO + + friend ostream& operator<<(ostream&,const ECn&); + +#endif + + ~ECn() { +#ifndef ZZNS + mr_free(mem); +#endif + } + +}; + +#endif + diff --git a/generator_cgo/include/ecnzzn.h b/generator_cgo/include/ecnzzn.h new file mode 100644 index 0000000..4f7a028 --- /dev/null +++ b/generator_cgo/include/ecnzzn.h @@ -0,0 +1,22 @@ +// +// Utility functions to force an ECn to be created from 2 or 3 ZZn +// And to extract an ECn into ZZns +// + +#ifndef ECNZZN_H +#define ECNZZN_H + +#include "zzn.h" +#include "ecn.h" + +#ifndef MR_AFFINE_ONLY + +extern void force(ZZn&,ZZn&,ZZn&,ECn&); +extern void extract(ECn&,ZZn&,ZZn&,ZZn&); + +#endif + +extern void force(ZZn&,ZZn&,ECn&); +extern void extract(ECn&,ZZn&,ZZn&); + +#endif diff --git a/generator_cgo/include/ecurve.cpp b/generator_cgo/include/ecurve.cpp new file mode 100644 index 0000000..5f3b5c6 --- /dev/null +++ b/generator_cgo/include/ecurve.cpp @@ -0,0 +1,70 @@ +#include "ecurve.h" +#include + +// 使用的椭圆曲线(SECP256K1)公开参数 +char Q[] = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F"; // 有限域的模q +char A[] = "0000000000000000000000000000000000000000000000000000000000000000"; // 曲线方程系数a +char B[] = "0000000000000000000000000000000000000000000000000000000000000007"; // 曲线方程系数b +char X[] = "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"; // 基点P的x坐标 +char Y[] = "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"; // 基点P的y坐标 +char P_N[] = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"; // 基点P的阶:令nP=O的最小整数 + +bool setupEcurve(ECC_PARAMS *params) +{ + // 初始化变量 + (*params).a = mirvar(0); + (*params).b = mirvar(0); + (*params).q = mirvar(0); + (*params).p = mirvar(0); + (*params).P_x = mirvar(0); + (*params).P_y = mirvar(0); + (*params).P = epoint_init(); + + // 赋值 + cinstr((*params).a, A); + cinstr((*params).b, B); + cinstr((*params).q, Q); + cinstr((*params).p, P_N); + + cinstr((*params).P_x, X); + cinstr((*params).P_y, Y); + + // 椭圆曲线方程初始化 + ecurve_init((*params).a, (*params).b, (*params).q, MR_PROJECTIVE); + + // 设置点坐标(P_x,P_y)为点P,此函数同时能判断P是否在上面初始化成功的椭圆曲线上 + if (!epoint_set((*params).P_x, (*params).P_y, 0, (*params).P)) + { + freeEcurve(params); + return false; + } + + // 判断P是否是阶为p的基点,判断依据:基点乘以阶为无穷远点 + bool bRv = false; + epoint *P_test = epoint_init(); + ecurve_mult((*params).p, (*params).P, P_test); + if (point_at_infinity(P_test)) + { + bRv = true; + } + else + { + freeEcurve(params); + bRv = false; + } + epoint_free(P_test); + + return bRv; +} + +void freeEcurve(ECC_PARAMS *params) +{ + mirkill((*params).a); + mirkill((*params).b); + mirkill((*params).q); + mirkill((*params).p); + mirkill((*params).P_x); + mirkill((*params).P_y); + + epoint_free((*params).P); +} \ No newline at end of file diff --git a/generator_cgo/include/ecurve.h b/generator_cgo/include/ecurve.h new file mode 100644 index 0000000..76e754c --- /dev/null +++ b/generator_cgo/include/ecurve.h @@ -0,0 +1,23 @@ +#ifndef __ECURVE_H__ +#define __ECURVE_H__ + +#include "miracl.h" +#include "mirdef.h" +#include + +typedef struct ecc_params +{ + big a; // 椭圆曲线方程系数a + big b; // 椭圆曲线方程系数b + big q; // 模 + big p; // 阶 + big P_x; // 基点横坐标 + big P_y; // 基点纵坐标 + epoint *P; // 基点 +} ECC_PARAMS; + +bool setupEcurve(ECC_PARAMS *params); + +void freeEcurve(ECC_PARAMS *params); + +#endif // ecurve.h \ No newline at end of file diff --git a/generator_cgo/include/flash.h b/generator_cgo/include/flash.h new file mode 100644 index 0000000..bac7750 --- /dev/null +++ b/generator_cgo/include/flash.h @@ -0,0 +1,163 @@ +/* + * MIRACL C++ Header file flash.h + * + * AUTHOR : N.Coghlan + * Modified by M.Scott + * + * PURPOSE : Definition of class Flash + * + */ + +#ifndef FLASH_H +#define FLASH_H + +#include "big.h" + +#ifdef MR_FLASH + +#ifdef BIGS +#define MR_FINIT_BIG fn=&b; b.w=a; b.len=0; for (int i=0;i=(const Flash& f1, const Flash& f2) + {if (fcomp(f1.fn,f2.fn) >= 0) return TRUE; else return FALSE;} + friend BOOL operator==(const Flash& f1, const Flash& f2) + {if (fcomp(f1.fn,f2.fn) == 0) return TRUE; else return FALSE;} + friend BOOL operator!=(const Flash& f1, const Flash& f2) + {if (fcomp(f1.fn,f2.fn) != 0) return TRUE; else return FALSE;} + friend BOOL operator<(const Flash& f1, const Flash& f2) + {if (fcomp(f1.fn,f2.fn) < 0) return TRUE; else return FALSE;} + friend BOOL operator>(const Flash& f1, const Flash& f2) + {if (fcomp(f1.fn,f2.fn) > 0) return TRUE; else return FALSE;} + + friend Flash inverse(const Flash&); + friend Flash pi(void); + friend Flash cos(const Flash&); + friend Flash sin(const Flash&); + friend Flash tan(const Flash&); + + friend Flash acos(const Flash&); + friend Flash asin(const Flash&); + friend Flash atan(const Flash&); + + friend Flash cosh(const Flash&); + friend Flash sinh(const Flash&); + friend Flash tanh(const Flash&); + + friend Flash acosh(const Flash&); + friend Flash asinh(const Flash&); + friend Flash atanh(const Flash&); + + friend Flash log(const Flash&); + friend Flash exp(const Flash&); + friend Flash pow(const Flash&,const Flash&); + friend Flash sqrt(const Flash&); + friend Flash nroot(const Flash&,int); + friend Flash fabs(const Flash&); + + friend double todouble(const Flash& f) { return fdsize(f.fn);} + +#ifndef MR_NO_STANDARD_IO + + friend istream& operator>>(istream&, Flash&); + friend ostream& operator<<(ostream&, const Flash&); + +#endif + + +#ifdef BIGS + ~Flash() { } +#else + ~Flash() {mirkill(fn);} +#endif +}; + +extern Flash pi(void); + +#endif +#endif + diff --git a/generator_cgo/include/floating.h b/generator_cgo/include/floating.h new file mode 100644 index 0000000..5ab7c5f --- /dev/null +++ b/generator_cgo/include/floating.h @@ -0,0 +1,94 @@ +/* + * MIRACL C++ Header file float.h + * + * AUTHOR : M.Scott + * + * PURPOSE : Definition of class Float + * + */ + +#ifndef FLOAT_H +#define FLOAT_H + +#include +#include "big.h" + +extern void setprecision(int); + +class Float +{ + int e; // exponent + Big m; // mantissa +public: + Float() { } + Float(int i) {m=i; e=1;} + Float(const Float& f) {e=f.e; m=f.m; } + Float(const Big &b) {m=b; e=length(b);} + Float(const Big &b,int ex) {m=b; e=ex;} + Float(double); + + Big trunc(Float *rem=NULL); + void negate() const; + BOOL iszero() const; + BOOL isone() const; + int sign() const; + Float& operator=(double); + BOOL add(const Float&); + Float& operator+=(const Float&); + BOOL sub(const Float&); + Float& operator-=(const Float&); + Float& operator*=(const Float&); + Float& operator*=(int); + Float& operator/=(const Float&); + Float& operator/=(int); + Float& operator=(const Float&); + + friend Float reciprocal(const Float&); + friend double todouble(const Float&); + friend Float makefloat(int,int); + friend Float operator-(const Float&); + friend Float operator+(const Float&,const Float&); + friend Float operator-(const Float&,const Float&); + friend Float operator*(const Float&,const Float&); + friend Float operator*(const Float&,int); + friend Float operator*(int,const Float&); + friend Float operator/(const Float&,const Float&); + friend Float operator/(const Float&,int); + friend Float sqrt(const Float&); + friend Float nroot(const Float&,int); + friend Float exp(const Float&); + friend Float sin(const Float&); + friend Float cos(const Float&); + friend Float pow(const Float&,int); + friend Float fpi(void); + + friend Big trunc(const Float&); + friend int norm(int,Float&); + friend Float fabs(const Float&); + + /* relational ops */ + friend int fcomp(const Float&,const Float&); + + friend BOOL operator<=(const Float& f1, const Float& f2) + {if (fcomp(f1,f2) <= 0) return TRUE; else return FALSE;} + friend BOOL operator>=(const Float& f1, const Float& f2) + {if (fcomp(f1,f2) >= 0) return TRUE; else return FALSE;} + friend BOOL operator==(const Float& f1, const Float& f2) + {if (fcomp(f1,f2) == 0) return TRUE; else return FALSE;} + friend BOOL operator!=(const Float& f1, const Float& f2) + {if (fcomp(f1,f2) != 0) return TRUE; else return FALSE;} + friend BOOL operator<(const Float& f1, const Float& f2) + {if (fcomp(f1,f2) < 0) return TRUE; else return FALSE;} + friend BOOL operator>(const Float& f1, const Float& f2) + {if (fcomp(f1,f2) > 0) return TRUE; else return FALSE;} + + friend ostream& operator<<(ostream&,const Float&); + + ~Float() { } +}; + +extern Float fpi(void); +extern Float makefloat(int,int); + +#endif + diff --git a/generator_cgo/include/gf2m.h b/generator_cgo/include/gf2m.h new file mode 100644 index 0000000..cd95f65 --- /dev/null +++ b/generator_cgo/include/gf2m.h @@ -0,0 +1,171 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file gf2m.h + * + * AUTHOR : M.Scott + * + * PURPOSE : Definition of class GF2m (Arithmetic in the field GF(2^m) + * + * NOTE: : The field basis is set dynamically via the modulo() routine. + * Must be used with big.h and big.cpp + */ + +#ifndef GF2M_H +#define GF2M_H + +#include "big.h" + +/* +#ifdef GF2MS +#define MR_INIT_GF2M memset(mem,0,mr_big_reserve(1,GF2MS)); fn=(big)mirvar_mem_variable(mem,0,GF2MS); +#define MR_CLONE_GF2M(x) fn->len=x->len; for (int i=0;iw[i]=x->w[i]; +#define MR_ZERO_GF2M {fn->len=0; for (int i=0;iw[i]=0;} +#else +#define MR_INIT_GF2M mem=(char *)memalloc(1); fn=(big)mirvar_mem(mem,0); +#define MR_CLONE_GF2M(x) copy(x,fn); +#define MR_ZERO_GF2M zero(fn); +#endif +*/ + + +#ifdef GF2MS +#define MR_INIT_GF2M fn=&b; b.w=a; b.len=GF2MS; +#define MR_CLONE_GF2M(x) b.len=x->len; for (int i=0;iw[i]; +#define MR_ZERO_GF2M {b.len=0; for (int i=0;i GF2m */ + GF2m(big& c) {MR_INIT_GF2M MR_CLONE_GF2M(c)} + GF2m(const GF2m& c) {MR_INIT_GF2M MR_CLONE_GF2M(c.fn)} + GF2m(char *s) {MR_INIT_GF2M cinstr(fn,s); reduce2(fn,fn);} + + GF2m& operator=(const GF2m& c) {MR_CLONE_GF2M(c.fn) return *this;} + GF2m& operator=(big c) {MR_CLONE_GF2M(c) return *this;} + + GF2m& operator=(int i) {if (i==0) MR_ZERO_GF2M else {convert(i,fn); reduce2(fn,fn);} return *this;} + GF2m& operator=(const Big& b) { reduce2(b.getbig(),fn); return *this; } + GF2m& operator=(char *s) { cinstr(fn,s); reduce2(fn,fn); return *this;} + GF2m& operator++() {incr2(fn,1,fn); return *this; } + + GF2m& operator+=(const GF2m& c) + { +#ifdef GF2MS + for (int i=0;iw[i]^=c.fn->w[i]; + fn->len=GF2MS; + if (fn->w[GF2MS-1]==0) mr_lzero(fn); +#else + add2(fn,c.fn,fn); +#endif + return *this; + } + + GF2m& operator+=(int i) {incr2(fn,i,fn); return *this; } + GF2m& operator*=(const GF2m& b) {modmult2(fn,b.fn,fn); return *this;} + GF2m& square() {modsquare2(fn,fn); return *this;} + GF2m& inverse() {inverse2(fn,fn); return *this;} + BOOL quadratic(GF2m& b) {return quad2(fn,b.fn);} + int degree() {return degree2(fn);} + + BOOL iszero() const; + BOOL isone() const; + operator Big() {return (Big)fn;} /* GF2m -> Big */ + friend big getbig(GF2m& z) {return z.fn;} + friend int trace(GF2m & z) {return trace2(z.fn);} + + GF2m& operator/=(const GF2m&); + + friend GF2m operator+(const GF2m&,const GF2m&); + friend GF2m operator+(const GF2m&,int); + friend GF2m operator*(const GF2m&,const GF2m&); + friend GF2m operator/(const GF2m&,const GF2m&); + + friend BOOL operator==(const GF2m& b1,const GF2m& b2) + { if (mr_compare(b1.fn,b2.fn)==0) return TRUE; else return FALSE;} + friend BOOL operator!=(const GF2m& b1,const GF2m& b2) + { if (mr_compare(b1.fn,b2.fn)!=0) return TRUE; else return FALSE;} + + friend GF2m square(const GF2m&); + friend GF2m inverse(const GF2m&); + friend GF2m pow(const GF2m&,int); + friend GF2m sqrt(const GF2m&); + friend GF2m halftrace(const GF2m&); + friend GF2m quad(const GF2m&); +#ifndef MR_NO_RAND + friend GF2m random2(void); +#endif + friend GF2m gcd(const GF2m&,const GF2m&); + + friend void kar2x2(const GF2m*,const GF2m*,GF2m*); + friend void kar3x3(const GF2m*,const GF2m*,GF2m*); + + friend int degree(const GF2m& x) {return degree2(x.fn);} + + ~GF2m() + { + // zero(fn); +#ifndef GF2MS + mr_free(fn); +#endif + } +}; +#ifndef MR_NO_RAND +extern GF2m random2(void); +#endif +#endif diff --git a/generator_cgo/include/hash.cpp b/generator_cgo/include/hash.cpp new file mode 100644 index 0000000..82e9d5b --- /dev/null +++ b/generator_cgo/include/hash.cpp @@ -0,0 +1,61 @@ +#include +#include "hash.h" +#include "ecurve.h" +#include "utils.h" + +void hash1(char *ID, epoint *Q, epoint *PK_pub, big p, big h_1_big) +{ + // 计算hash值H_1(ID, R, PK_pub) + //hash1(ID, Q, PK_pub) + sha256 sh; + char h_1[33] = {0}; + + shs256_init(&sh); + sha256_update_string(sh, ID, strlen(ID)); + sha256_update_point(sh, Q); + sha256_update_point(sh, PK_pub); + shs256_hash(&sh, h_1); + + bytes_to_big(32, h_1, h_1_big); + power(h_1_big, 1, p, h_1_big); // mod p +} + +void hash2(char *ID, epoint *X, big p, big h_2_big) +{ + // 计算hash值H_2(ID, X) + sha256 sh; + char h_2[33] = {0}; + + shs256_init(&sh); + sha256_update_string(sh, ID, strlen(ID)); + sha256_update_point(sh, X); + shs256_hash(&sh, h_2); + + bytes_to_big(32, h_2, h_2_big); + power(h_2_big, 1, p, h_2_big); // mod p +} + +void hash3( + char *ID, + char *msg, + epoint *Q, + epoint *U, + epoint *PK_pub, + big p, + big h_3_big +) +{ + sha256 sh; + char h_3[33] = {0}; + + shs256_init(&sh); + sha256_update_string(sh, ID, strlen(ID)); + sha256_update_string(sh, msg, strlen(msg)); + sha256_update_point(sh, Q); + sha256_update_point(sh, U); + sha256_update_point(sh, PK_pub); + shs256_hash(&sh, h_3); + + bytes_to_big(32, h_3, h_3_big); + power(h_3_big, 1, p, h_3_big); // mod p +} diff --git a/generator_cgo/include/hash.h b/generator_cgo/include/hash.h new file mode 100644 index 0000000..5f96cab --- /dev/null +++ b/generator_cgo/include/hash.h @@ -0,0 +1,24 @@ +#ifndef __HASH_H__ +#define __HASH_H__ + +#include "miracl.h" +#include "mirdef.h" + +//hash1(ID, Q, PK_pub, h_1_big) +void hash1(char *ID, epoint *Q, epoint *PK_pub, big p, big h_1_big); + +//hash2(ID, X, h_2_big) +void hash2(char *ID, epoint *X, big p, big h_2_big); + +//hash3(ID, msg, Q, U, PK_pub, h_3_big) +void hash3( + char *ID, + char *msg, + epoint *Q, + epoint *U, + epoint *PK_pub, + big p, + big h_3_big +); + +#endif \ No newline at end of file diff --git a/generator_cgo/include/kgc.cpp b/generator_cgo/include/kgc.cpp new file mode 100644 index 0000000..4d9e0aa --- /dev/null +++ b/generator_cgo/include/kgc.cpp @@ -0,0 +1,84 @@ +#include +#include "kgc.h" +#include "hash.h" + +void genKGCkey(ECC_PARAMS *params, big msk, epoint *PK_pub) +{ + bigrand((*params).p, msk); // 产生小于p的随机数 + ecurve_mult(msk, (*params).P, PK_pub); +} + +bool genPPK_std( + ECC_PARAMS *params, + big msk, // KGC私钥 + epoint *PK_pub, // KGC公钥 + char ID[], // 输入用户ID + big d, // 输出部分私钥 + epoint *Q, // 产生的用户公钥 + epoint *X) // 输入用户秘密值 +{ + // 产生随机数r,计算R=rP + epoint *R_A = epoint_init(); + big r = mirvar(0); + bigrand((*params).p, r); + ecurve_mult(r, (*params).P, R_A); + + //计算h_2 = H_2(ID,X) + big h_2_big = mirvar(0); + hash2(ID, X, (*params).p, h_2_big); + + //计算h_2 * X + epoint *h2X = epoint_init(); + ecurve_mult(h_2_big, X, h2X); + + //计算Q = R + h_2 * X + ecurve_add(R_A, Q); + ecurve_add(h2X, Q); + + //计算h_1 = H_1(ID,Q,PK_pub) + big h_1_big = mirvar(0); + hash1(ID, Q, PK_pub, (*params).p, h_1_big); + + // 计算d = r + msk * h_1 mod p + big tmp = mirvar(0); + multiply(msk, h_1_big, tmp); + add(r, tmp, d); + power(d, 1, (*params).p, d); // mod p + + //计算h_1 * PK_pub + epoint *h1PK = epoint_init(); + ecurve_mult(h_1_big, PK_pub, h1PK); + + // 用d * P = Q - h2 * X + h1 * PK_pub验证一下(d,Q)是否正确 + // 点的减法 pa = pa - a Function: void ecurve_sub(p,pa) + epoint *left = epoint_init(); + ecurve_mult(d, (*params).P, left); + epoint *right = epoint_init(); + ecurve_add(Q, right); + ecurve_sub(h2X, right); + ecurve_add(h1PK, right); + + bool bRv = false; + if (epoint_comp(left, right)) + { + bRv = true; + + } + else + { + bRv = false; + } + + mirkill(r); + mirkill(h_1_big); + mirkill(h_2_big); + mirkill(tmp); + + epoint_free(R_A); + epoint_free(left); + epoint_free(right); + epoint_free(h1PK); + epoint_free(h2X); + + return bRv; +} \ No newline at end of file diff --git a/generator_cgo/include/kgc.h b/generator_cgo/include/kgc.h new file mode 100644 index 0000000..f848b19 --- /dev/null +++ b/generator_cgo/include/kgc.h @@ -0,0 +1,22 @@ +#ifndef __KGC_H__ +#define __KGC_H__ + +#include "ecurve.h" +#include "miracl.h" +#include "mirdef.h" +#include + + +void genKGCkey(ECC_PARAMS *params, big msk, epoint *PK_pub); + +_Bool genPPK_std( + ECC_PARAMS *params, + big msk, + epoint *PK_pub, + char ID[], + big d, + epoint *Q, + epoint *X +); + +#endif \ No newline at end of file diff --git a/generator_cgo/include/miracl.h b/generator_cgo/include/miracl.h new file mode 100644 index 0000000..558d19c --- /dev/null +++ b/generator_cgo/include/miracl.h @@ -0,0 +1,1563 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ + +#ifndef MIRACL_H +#define MIRACL_H + +/* + * main MIRACL header - miracl.h. + */ + +#include "mirdef.h" + +/* Some modifiable defaults... */ + +/* Use a smaller buffer if space is limited, don't be so wasteful! */ + +#ifdef MR_STATIC +#define MR_DEFAULT_BUFFER_SIZE 260 +#else +#define MR_DEFAULT_BUFFER_SIZE 1024 +#endif + +/* see mrgf2m.c */ + +#ifndef MR_KARATSUBA +#define MR_KARATSUBA 2 +#endif + +#ifndef MR_DOUBLE_BIG + +#ifdef MR_KCM + #ifdef MR_FLASH + #define MR_SPACES 32 + #else + #define MR_SPACES 31 + #endif +#else + #ifdef MR_FLASH + #define MR_SPACES 28 + #else + #define MR_SPACES 27 + #endif +#endif + +#else + +#ifdef MR_KCM + #ifdef MR_FLASH + #define MR_SPACES 44 + #else + #define MR_SPACES 43 + #endif +#else + #ifdef MR_FLASH + #define MR_SPACES 40 + #else + #define MR_SPACES 39 + #endif +#endif + +#endif + +/* To avoid name clashes - undefine this */ + +/* #define compare mr_compare */ + +#ifdef MR_AVR +#include +#endif + +/* size of bigs and elliptic curve points for memory allocation from stack or heap */ + +#define MR_ROUNDUP(a,b) ((a)-1)/(b)+1 + +#define MR_SL sizeof(long) + +#ifdef MR_STATIC + +#define MR_SIZE (((sizeof(struct bigtype)+(MR_STATIC+2)*sizeof(mr_utype))-1)/MR_SL+1)*MR_SL +#define MR_BIG_RESERVE(n) ((n)*MR_SIZE+MR_SL) + +#ifdef MR_AFFINE_ONLY +#define MR_ESIZE (((sizeof(epoint)+MR_BIG_RESERVE(2))-1)/MR_SL+1)*MR_SL +#else +#define MR_ESIZE (((sizeof(epoint)+MR_BIG_RESERVE(3))-1)/MR_SL+1)*MR_SL +#endif +#define MR_ECP_RESERVE(n) ((n)*MR_ESIZE+MR_SL) + +#define MR_ESIZE_A (((sizeof(epoint)+MR_BIG_RESERVE(2))-1)/MR_SL+1)*MR_SL +#define MR_ECP_RESERVE_A(n) ((n)*MR_ESIZE_A+MR_SL) + + +#endif + +/* useful macro to convert size of big in words, to size of required structure */ + +#define mr_size(n) (((sizeof(struct bigtype)+((n)+2)*sizeof(mr_utype))-1)/MR_SL+1)*MR_SL +#define mr_big_reserve(n,m) ((n)*mr_size(m)+MR_SL) + +#define mr_esize_a(n) (((sizeof(epoint)+mr_big_reserve(2,(n)))-1)/MR_SL+1)*MR_SL +#define mr_ecp_reserve_a(n,m) ((n)*mr_esize_a(m)+MR_SL) + +#ifdef MR_AFFINE_ONLY +#define mr_esize(n) (((sizeof(epoint)+mr_big_reserve(2,(n)))-1)/MR_SL+1)*MR_SL +#else +#define mr_esize(n) (((sizeof(epoint)+mr_big_reserve(3,(n)))-1)/MR_SL+1)*MR_SL +#endif +#define mr_ecp_reserve(n,m) ((n)*mr_esize(m)+MR_SL) + + +/* if basic library is static, make sure and use static C++ */ + +#ifdef MR_STATIC + #ifndef BIGS + #define BIGS MR_STATIC + #endif + #ifndef ZZNS + #define ZZNS MR_STATIC + #endif + #ifndef GF2MS + #define GF2MS MR_STATIC + #endif +#endif + +#ifdef __ia64__ +#if MIRACL==64 +#define MR_ITANIUM +#include +#endif +#endif + +#ifdef _M_X64 +#ifdef _WIN64 +#if MIRACL==64 +#define MR_WIN64 +#include +#endif +#endif +#endif + +#ifndef MR_NO_FILE_IO +#include +#endif + /* error returns */ + +#define MR_ERR_BASE_TOO_BIG 1 +#define MR_ERR_DIV_BY_ZERO 2 +#define MR_ERR_OVERFLOW 3 +#define MR_ERR_NEG_RESULT 4 +#define MR_ERR_BAD_FORMAT 5 +#define MR_ERR_BAD_BASE 6 +#define MR_ERR_BAD_PARAMETERS 7 +#define MR_ERR_OUT_OF_MEMORY 8 +#define MR_ERR_NEG_ROOT 9 +#define MR_ERR_NEG_POWER 10 +#define MR_ERR_BAD_ROOT 11 +#define MR_ERR_INT_OP 12 +#define MR_ERR_FLASH_OVERFLOW 13 +#define MR_ERR_TOO_BIG 14 +#define MR_ERR_NEG_LOG 15 +#define MR_ERR_DOUBLE_FAIL 16 +#define MR_ERR_IO_OVERFLOW 17 +#define MR_ERR_NO_MIRSYS 18 +#define MR_ERR_BAD_MODULUS 19 +#define MR_ERR_NO_MODULUS 20 +#define MR_ERR_EXP_TOO_BIG 21 +#define MR_ERR_NOT_SUPPORTED 22 +#define MR_ERR_NOT_DOUBLE_LEN 23 +#define MR_ERR_NOT_IRREDUC 24 +#define MR_ERR_NO_ROUNDING 25 +#define MR_ERR_NOT_BINARY 26 +#define MR_ERR_NO_BASIS 27 +#define MR_ERR_COMPOSITE_MODULUS 28 +#define MR_ERR_DEV_RANDOM 29 + + /* some useful definitions */ + +#define forever for(;;) + +#define mr_abs(x) ((x)<0? (-(x)) : (x)) + +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + +#define OFF 0 +#define ON 1 +#define PLUS 1 +#define MINUS (-1) + +#define M1 (MIRACL-1) +#define M2 (MIRACL-2) +#define M3 (MIRACL-3) +#define M4 (MIRACL-4) +#define TOPBIT ((mr_small)1<= MR_IBITS +#define MR_TOOBIG (1<<(MR_IBITS-2)) +#else +#define MR_TOOBIG (1<<(MIRACL-1)) +#endif + +#ifdef MR_FLASH +#define MR_EBITS (8*sizeof(double) - MR_FLASH) + /* no of Bits per double exponent */ +#define MR_BTS 16 +#define MR_MSK 0xFFFF + +#endif + +/* Default Hash function output size in bytes */ +#define MR_HASH_BYTES 32 + +/* Marsaglia & Zaman Random number generator */ +/* constants alternatives */ +#define NK 37 /* 21 */ +#define NJ 24 /* 6 */ +#define NV 14 /* 8 */ + +/* Use smaller values if memory is precious */ + +#ifdef mr_dltype + +#ifdef MR_LITTLE_ENDIAN +#define MR_BOT 0 +#define MR_TOP 1 +#endif +#ifdef MR_BIG_ENDIAN +#define MR_BOT 1 +#define MR_TOP 0 +#endif + +union doubleword +{ + mr_large d; + mr_small h[2]; +}; + +#endif + +/* chinese remainder theorem structures */ + +typedef struct { +big *C; +big *V; +big *M; +int NP; +} big_chinese; + +typedef struct { +mr_utype *C; +mr_utype *V; +mr_utype *M; +int NP; +} small_chinese; + +/* Cryptographically strong pseudo-random number generator */ + +typedef struct { +mr_unsign32 ira[NK]; /* random number... */ +int rndptr; /* ...array & pointer */ +mr_unsign32 borrow; +int pool_ptr; +char pool[MR_HASH_BYTES]; /* random pool */ +} csprng; + +/* secure hash Algorithm structure */ + +typedef struct { +mr_unsign32 length[2]; +mr_unsign32 h[8]; +mr_unsign32 w[80]; +} sha256; + +typedef sha256 sha; + +#ifdef mr_unsign64 + +typedef struct { +mr_unsign64 length[2]; +mr_unsign64 h[8]; +mr_unsign64 w[80]; +} sha512; + +typedef sha512 sha384; + +typedef struct { +mr_unsign64 length; +mr_unsign64 S[5][5]; +int rate,len; +} sha3; + +#endif + +/* Symmetric Encryption algorithm structure */ + +#define MR_ECB 0 +#define MR_CBC 1 +#define MR_CFB1 2 +#define MR_CFB2 3 +#define MR_CFB4 5 +#define MR_PCFB1 10 +#define MR_PCFB2 11 +#define MR_PCFB4 13 +#define MR_OFB1 14 +#define MR_OFB2 15 +#define MR_OFB4 17 +#define MR_OFB8 21 +#define MR_OFB16 29 + +typedef struct { +int Nk,Nr; +int mode; +mr_unsign32 fkey[60]; +mr_unsign32 rkey[60]; +char f[16]; +} aes; + +/* AES-GCM suppport. See mrgcm.c */ + +#define GCM_ACCEPTING_HEADER 0 +#define GCM_ACCEPTING_CIPHER 1 +#define GCM_NOT_ACCEPTING_MORE 2 +#define GCM_FINISHED 3 +#define GCM_ENCRYPTING 0 +#define GCM_DECRYPTING 1 + +typedef struct { +mr_unsign32 table[128][4]; /* 2k bytes */ +MR_BYTE stateX[16]; +MR_BYTE Y_0[16]; +mr_unsign32 counter; +mr_unsign32 lenA[2],lenC[2]; +int status; +aes a; +} gcm; + + /* Elliptic curve point status */ + +#define MR_EPOINT_GENERAL 0 +#define MR_EPOINT_NORMALIZED 1 +#define MR_EPOINT_INFINITY 2 + +#define MR_NOTSET 0 +#define MR_PROJECTIVE 0 +#define MR_AFFINE 1 +#define MR_BEST 2 +#define MR_TWIST 8 + +#define MR_OVER 0 +#define MR_ADD 1 +#define MR_DOUBLE 2 + +/* Twist type */ + +#define MR_QUADRATIC 2 +#define MR_CUBIC_M 0x3A +#define MR_CUBIC_D 0x3B +#define MR_QUARTIC_M 0x4A +#define MR_QUARTIC_D 0x4B +#define MR_SEXTIC_M 0x6A +#define MR_SEXTIC_D 0x6B + + +/* Fractional Sliding Windows for ECC - how much precomputation storage to use ? */ +/* Note that for variable point multiplication there is an optimal value + which can be reduced if space is short. For fixed points its a matter of + how much ROM is available to store precomputed points. + We are storing the k points (P,3P,5P,7P,...,[2k-1].P) */ + +/* These values can be manually tuned for optimal performance... */ + +#ifdef MR_SMALL_EWINDOW +#define MR_ECC_STORE_N 3 /* point store for ecn variable point multiplication */ +#define MR_ECC_STORE_2M 3 /* point store for ec2m variable point multiplication */ +#define MR_ECC_STORE_N2 3 /* point store for ecn2 variable point multiplication */ +#else +#define MR_ECC_STORE_N 8 /* 8/9 is close to optimal for 256 bit exponents */ +#define MR_ECC_STORE_2M 9 +#define MR_ECC_STORE_N2 8 +#endif + +/*#define MR_ECC_STORE_N2_PRECOMP MR_ECC_STORE_N2 */ + /* Might want to make this bigger.. */ + +/* If multi-addition is of m points, and s precomputed values are required, this is max of m*s (=4.10?) */ +#define MR_MAX_M_T_S 64 + +/* Elliptic Curve epoint structure. Uses projective (X,Y,Z) co-ordinates */ + +typedef struct { +int marker; +big X; +big Y; +#ifndef MR_AFFINE_ONLY +big Z; +#endif +} epoint; + + +/* Structure for Comb method for finite * + field exponentiation with precomputation */ + +typedef struct { +#ifdef MR_STATIC + const mr_small *table; +#else + mr_small *table; +#endif + big n; + int window; + int max; +} brick; + +/* Structure for Comb method for elliptic * + curve exponentiation with precomputation */ + +typedef struct { +#ifdef MR_STATIC + const mr_small *table; +#else + mr_small *table; +#endif + big a,b,n; + int window; + int max; +} ebrick; + +typedef struct { +#ifdef MR_STATIC + const mr_small *table; +#else + mr_small *table; +#endif + big a6,a2; + int m,a,b,c; + int window; + int max; +} ebrick2; + +typedef struct +{ + big a; + big b; +} zzn2; + +typedef struct +{ + zzn2 a; + zzn2 b; + BOOL unitary; +} zzn4; + +typedef struct +{ + int marker; + zzn2 x; + zzn2 y; +#ifndef MR_AFFINE_ONLY + zzn2 z; +#endif + +} ecn2; + +typedef struct +{ + big a; + big b; + big c; +} zzn3; + +typedef struct +{ + zzn2 a; + zzn2 b; + zzn2 c; +} zzn6_3x2; + +/* main MIRACL instance structure */ + +/* ------------------------------------------------------------------------*/ + +typedef struct { +mr_small base; /* number base */ +mr_small apbase; /* apparent base */ +int pack; /* packing density */ +int lg2b; /* bits in base */ +mr_small base2; /* 2^mr_lg2b */ +BOOL (*user)(void); /* pointer to user supplied function */ + +int nib; /* length of bigs */ +#ifndef MR_STRIPPED_DOWN +int depth; /* error tracing ..*/ +int trace[MR_MAXDEPTH]; /* .. mechanism */ +#endif +BOOL check; /* overflow check */ +BOOL fout; /* Output to file */ +BOOL fin; /* Input from file */ +BOOL active; + +#ifndef MR_NO_FILE_IO + +FILE *infile; /* Input file */ +FILE *otfile; /* Output file */ + +#endif + + +#ifndef MR_NO_RAND +mr_unsign32 ira[NK]; /* random number... */ +int rndptr; /* ...array & pointer */ +mr_unsign32 borrow; +#endif + + /* Montgomery constants */ +mr_small ndash; +big modulus; +big pR; +BOOL ACTIVE; +BOOL MONTY; + + /* Elliptic Curve details */ +#ifndef MR_NO_SS +BOOL SS; /* True for Super-Singular */ +#endif +#ifndef MR_NOKOBLITZ +BOOL KOBLITZ; /* True for a Koblitz curve */ +#endif +#ifndef MR_AFFINE_ONLY +int coord; +#endif +int Asize,Bsize; + +int M,AA,BB,CC; /* for GF(2^m) curves */ + +/* +mr_small pm,mask; +int e,k,Me,m; for GF(p^m) curves */ + + +#ifndef MR_STATIC + +int logN; /* constants for fast fourier fft multiplication */ +int nprimes,degree; +mr_utype *prime,*cr; +mr_utype *inverse,**roots; +small_chinese chin; +mr_utype const1,const2,const3; +mr_small msw,lsw; +mr_utype **s1,**s2; /* pre-computed tables for polynomial reduction */ +mr_utype **t; /* workspace */ +mr_utype *wa; +mr_utype *wb; +mr_utype *wc; + +#endif + +BOOL same; +BOOL first_one; +BOOL debug; + +big w0; /* workspace bigs */ +big w1,w2,w3,w4; +big w5,w6,w7; +big w8,w9,w10,w11; +big w12,w13,w14,w15; +big sru; +big one; + +#ifdef MR_KCM +big big_ndash; +big ws,wt; +#endif + +big A,B; + +/* User modifiables */ + +#ifndef MR_SIMPLE_IO +int IOBSIZ; /* size of i/o buffer */ +#endif +BOOL ERCON; /* error control */ +int ERNUM; /* last error code */ +int NTRY; /* no. of tries for probablistic primality testing */ +#ifndef MR_SIMPLE_IO +int INPLEN; /* input length */ +#ifndef MR_SIMPLE_BASE +int IOBASE; /* base for input and output */ + +#endif +#endif +#ifdef MR_FLASH +BOOL EXACT; /* exact flag */ +BOOL RPOINT; /* =ON for radix point, =OFF for fractions in output */ +#endif +#ifndef MR_STRIPPED_DOWN +BOOL TRACER; /* turns trace tracker on/off */ +#endif + +#ifdef MR_STATIC +const int *PRIMES; /* small primes array */ +#ifndef MR_SIMPLE_IO +char IOBUFF[MR_DEFAULT_BUFFER_SIZE]; /* i/o buffer */ +#endif +#else +int *PRIMES; /* small primes array */ +#ifndef MR_SIMPLE_IO +char *IOBUFF; /* i/o buffer */ +#endif +#endif + +#ifdef MR_FLASH +int workprec; +int stprec; /* start precision */ + +int RS,RD; +double D; + +double db,n,p; +int a,b,c,d,r,q,oldn,ndig; +mr_small u,v,ku,kv; + +BOOL last,carryon; +flash pi; + +#endif + +#ifdef MR_FP_ROUNDING +mr_large inverse_base; +#endif + +#ifndef MR_STATIC +char *workspace; +#else +char workspace[MR_BIG_RESERVE(MR_SPACES)]; +#endif + +int TWIST; /* set to twisted curve */ +int qnr; /* a QNR -1 for p=3 mod 4, -2 for p=5 mod 8, 0 otherwise */ +int cnr; /* a cubic non-residue */ +int pmod8; +int pmod9; +BOOL NO_CARRY; +} miracl; + +/* ------------------------------------------------------------------------*/ + + +#ifndef MR_GENERIC_MT + +#ifdef MR_WINDOWS_MT +#define MR_OS_THREADS +#endif + +#ifdef MR_UNIX_MT +#define MR_OS_THREADS +#endif + +#ifdef MR_OPENMP_MT +#define MR_OS_THREADS +#endif + + +#ifndef MR_OS_THREADS + +extern miracl *mr_mip; /* pointer to MIRACL's only global variable */ + +#endif + +#endif + +#ifdef MR_GENERIC_MT + +#ifdef MR_STATIC +#define MR_GENERIC_AND_STATIC +#endif + +#define _MIPT_ miracl *, +#define _MIPTO_ miracl * +#define _MIPD_ miracl *mr_mip, +#define _MIPDO_ miracl *mr_mip +#define _MIPP_ mr_mip, +#define _MIPPO_ mr_mip + +#else + +#define _MIPT_ +#define _MIPTO_ void +#define _MIPD_ +#define _MIPDO_ void +#define _MIPP_ +#define _MIPPO_ + +#endif + +/* Preamble and exit code for MIRACL routines. * + * Not used if MR_STRIPPED_DOWN is defined */ + +#ifdef MR_STRIPPED_DOWN +#define MR_OUT +#define MR_IN(N) +#else +#define MR_OUT mr_mip->depth--; +#define MR_IN(N) mr_mip->depth++; if (mr_mip->depthtrace[mr_mip->depth]=(N); if (mr_mip->TRACER) mr_track(_MIPPO_); } +#endif + +/* Function definitions */ + +/* Group 0 - Internal routines */ + +extern void mr_berror(_MIPT_ int); +extern mr_small mr_shiftbits(mr_small,int); +extern mr_small mr_setbase(_MIPT_ mr_small); +extern void mr_track(_MIPTO_ ); +extern void mr_lzero(big); +extern BOOL mr_notint(flash); +extern int mr_lent(flash); +extern void mr_padd(_MIPT_ big,big,big); +extern void mr_psub(_MIPT_ big,big,big); +extern void mr_pmul(_MIPT_ big,mr_small,big); +#ifdef MR_FP_ROUNDING +extern mr_large mr_invert(mr_small); +extern mr_small imuldiv(mr_small,mr_small,mr_small,mr_small,mr_large,mr_small *); +extern mr_small mr_sdiv(_MIPT_ big,mr_small,mr_large,big); +#else +extern mr_small mr_sdiv(_MIPT_ big,mr_small,big); +extern void mr_and(big,big,big); +extern void mr_xor(big,big,big); +#endif +extern void mr_shift(_MIPT_ big,int,big); +extern miracl *mr_first_alloc(void); +extern void *mr_alloc(_MIPT_ int,int); +extern void mr_free(void *); +extern void set_user_function(_MIPT_ BOOL (*)(void)); +extern void set_io_buffer_size(_MIPT_ int); +extern int mr_testbit(_MIPT_ big,int); +extern void mr_addbit(_MIPT_ big,int); +extern int recode(_MIPT_ big ,int ,int ,int ); +extern int mr_window(_MIPT_ big,int,int *,int *,int); +extern int mr_window2(_MIPT_ big,big,int,int *,int *); +extern int mr_naf_window(_MIPT_ big,big,int,int *,int *,int); + +extern int mr_fft_init(_MIPT_ int,big,big,BOOL); +extern void mr_dif_fft(_MIPT_ int,int,mr_utype *); +extern void mr_dit_fft(_MIPT_ int,int,mr_utype *); +extern void fft_reset(_MIPTO_); + +extern int mr_poly_mul(_MIPT_ int,big*,int,big*,big*); +extern int mr_poly_sqr(_MIPT_ int,big*,big*); +extern void mr_polymod_set(_MIPT_ int,big*,big*); +extern int mr_poly_rem(_MIPT_ int,big *,big *); + +extern int mr_ps_big_mul(_MIPT_ int,big *,big *,big *); +extern int mr_ps_zzn_mul(_MIPT_ int,big *,big *,big *); + +extern mr_small muldiv(mr_small,mr_small,mr_small,mr_small,mr_small *); +extern mr_small muldvm(mr_small,mr_small,mr_small,mr_small *); +extern mr_small muldvd(mr_small,mr_small,mr_small,mr_small *); +extern void muldvd2(mr_small,mr_small,mr_small *,mr_small *); + +extern flash mirvar_mem_variable(char *,int,int); +extern epoint* epoint_init_mem_variable(_MIPT_ char *,int,int); + +/* Group 1 - General purpose, I/O and basic arithmetic routines */ + +extern unsigned int igcd(unsigned int,unsigned int); +extern unsigned long lgcd(unsigned long,unsigned long); +extern mr_small sgcd(mr_small,mr_small); +extern unsigned int isqrt(unsigned int,unsigned int); +extern unsigned long mr_lsqrt(unsigned long,unsigned long); +extern void irand(_MIPT_ mr_unsign32); +extern mr_small brand(_MIPTO_ ); +extern void zero(flash); +extern void convert(_MIPT_ int,big); +extern void uconvert(_MIPT_ unsigned int,big); +extern void lgconv(_MIPT_ long,big); +extern void ulgconv(_MIPT_ unsigned long,big); +extern void tconvert(_MIPT_ mr_utype,big); + +#ifdef mr_dltype +extern void dlconv(_MIPT_ mr_dltype,big); +#endif + +extern flash mirvar(_MIPT_ int); +extern flash mirvar_mem(_MIPT_ char *,int); +extern void mirkill(big); +extern void *memalloc(_MIPT_ int); +extern void memkill(_MIPT_ char *,int); +extern void mr_init_threading(void); +extern void mr_end_threading(void); +extern miracl *get_mip(void ); +extern void set_mip(miracl *); +#ifdef MR_GENERIC_AND_STATIC +extern miracl *mirsys(miracl *,int,mr_small); +#else +extern miracl *mirsys(int,mr_small); +#endif +extern miracl *mirsys_basic(miracl *,int,mr_small); +extern void mirexit(_MIPTO_ ); +extern int exsign(flash); +extern void insign(int,flash); +extern int getdig(_MIPT_ big,int); +extern int numdig(_MIPT_ big); +extern void putdig(_MIPT_ int,big,int); +extern void copy(flash,flash); +extern void negify(flash,flash); +extern void absol(flash,flash); +extern int size(big); +extern int mr_compare(big,big); +extern void add(_MIPT_ big,big,big); +extern void subtract(_MIPT_ big,big,big); +extern void incr(_MIPT_ big,int,big); +extern void decr(_MIPT_ big,int,big); +extern void premult(_MIPT_ big,int,big); +extern int subdiv(_MIPT_ big,int,big); +extern BOOL subdivisible(_MIPT_ big,int); +extern int remain(_MIPT_ big,int); +extern void bytes_to_big(_MIPT_ int,const char *,big); +extern int big_to_bytes(_MIPT_ int,big,char *,BOOL); +extern mr_small normalise(_MIPT_ big,big); +extern void multiply(_MIPT_ big,big,big); +extern void fft_mult(_MIPT_ big,big,big); +extern BOOL fastmultop(_MIPT_ int,big,big,big); +extern void divide(_MIPT_ big,big,big); +extern BOOL divisible(_MIPT_ big,big); +extern void mad(_MIPT_ big,big,big,big,big,big); +extern int instr(_MIPT_ flash,char *); +extern int otstr(_MIPT_ flash,char *); +extern int cinstr(_MIPT_ flash,char *); +extern int cotstr(_MIPT_ flash,char *); +extern epoint* epoint_init(_MIPTO_ ); +extern epoint* epoint_init_mem(_MIPT_ char *,int); +extern void* ecp_memalloc(_MIPT_ int); +void ecp_memkill(_MIPT_ char *,int); +BOOL init_big_from_rom(big,int,const mr_small *,int ,int *); +BOOL init_point_from_rom(epoint *,int,const mr_small *,int,int *); + +#ifndef MR_NO_FILE_IO + +extern int innum(_MIPT_ flash,FILE *); +extern int otnum(_MIPT_ flash,FILE *); +extern int cinnum(_MIPT_ flash,FILE *); +extern int cotnum(_MIPT_ flash,FILE *); + +#endif + +/* Group 2 - Advanced arithmetic routines */ + +extern mr_small smul(mr_small,mr_small,mr_small); +extern mr_small spmd(mr_small,mr_small,mr_small); +extern mr_small invers(mr_small,mr_small); +extern mr_small sqrmp(mr_small,mr_small); +extern int jac(mr_small,mr_small); + +extern void gprime(_MIPT_ int); +extern int jack(_MIPT_ big,big); +extern int egcd(_MIPT_ big,big,big); +extern int xgcd(_MIPT_ big,big,big,big,big); +extern int invmodp(_MIPT_ big,big,big); +extern int logb2(_MIPT_ big); +extern int hamming(_MIPT_ big); +extern void expb2(_MIPT_ int,big); +extern void bigbits(_MIPT_ int,big); +extern void expint(_MIPT_ int,int,big); +extern void sftbit(_MIPT_ big,int,big); +extern void power(_MIPT_ big,long,big,big); +extern void powmod(_MIPT_ big,big,big,big); +extern void powmod2(_MIPT_ big,big,big,big,big,big); +extern void powmodn(_MIPT_ int,big *,big *,big,big); +extern int powltr(_MIPT_ int,big,big,big); +extern BOOL double_inverse(_MIPT_ big,big,big,big,big); +extern BOOL multi_inverse(_MIPT_ int,big*,big,big*); +extern void lucas(_MIPT_ big,big,big,big,big); +extern BOOL nroot(_MIPT_ big,int,big); +extern BOOL sqroot(_MIPT_ big,big,big); +extern void bigrand(_MIPT_ big,big); +extern void bigdig(_MIPT_ int,int,big); +extern int trial_division(_MIPT_ big,big); +extern BOOL isprime(_MIPT_ big); +extern BOOL nxprime(_MIPT_ big,big); +extern BOOL nxsafeprime(_MIPT_ int,int,big,big); +extern BOOL crt_init(_MIPT_ big_chinese *,int,big *); +extern void crt(_MIPT_ big_chinese *,big *,big); +extern void crt_end(big_chinese *); +extern BOOL scrt_init(_MIPT_ small_chinese *,int,mr_utype *); +extern void scrt(_MIPT_ small_chinese*,mr_utype *,big); +extern void scrt_end(small_chinese *); +#ifndef MR_STATIC +extern BOOL brick_init(_MIPT_ brick *,big,big,int,int); +extern void brick_end(brick *); +#else +extern void brick_init(brick *,const mr_small *,big,int,int); +#endif +extern void pow_brick(_MIPT_ brick *,big,big); +#ifndef MR_STATIC +extern BOOL ebrick_init(_MIPT_ ebrick *,big,big,big,big,big,int,int); +extern void ebrick_end(ebrick *); +#else +extern void ebrick_init(ebrick *,const mr_small *,big,big,big,int,int); +#endif +extern int mul_brick(_MIPT_ ebrick*,big,big,big); +#ifndef MR_STATIC +extern BOOL ebrick2_init(_MIPT_ ebrick2 *,big,big,big,big,int,int,int,int,int,int); +extern void ebrick2_end(ebrick2 *); +#else +extern void ebrick2_init(ebrick2 *,const mr_small *,big,big,int,int,int,int,int,int); +#endif +extern int mul2_brick(_MIPT_ ebrick2*,big,big,big); + +/* Montgomery stuff */ + +extern mr_small prepare_monty(_MIPT_ big); +extern void kill_monty(_MIPTO_ ); +extern void nres(_MIPT_ big,big); +extern void redc(_MIPT_ big,big); + +extern void nres_negate(_MIPT_ big,big); +extern void nres_modadd(_MIPT_ big,big,big); +extern void nres_modsub(_MIPT_ big,big,big); +extern void nres_lazy(_MIPT_ big,big,big,big,big,big); +extern void nres_complex(_MIPT_ big,big,big,big); +extern void nres_double_modadd(_MIPT_ big,big,big); +extern void nres_double_modsub(_MIPT_ big,big,big); +extern void nres_premult(_MIPT_ big,int,big); +extern void nres_modmult(_MIPT_ big,big,big); +extern int nres_moddiv(_MIPT_ big,big,big); +extern void nres_dotprod(_MIPT_ int,big *,big *,big); +extern void nres_powmod(_MIPT_ big,big,big); +extern void nres_powltr(_MIPT_ int,big,big); +extern void nres_powmod2(_MIPT_ big,big,big,big,big); +extern void nres_powmodn(_MIPT_ int,big *,big *,big); +extern BOOL nres_sqroot(_MIPT_ big,big); +extern void nres_lucas(_MIPT_ big,big,big,big); +extern BOOL nres_double_inverse(_MIPT_ big,big,big,big); +extern BOOL nres_multi_inverse(_MIPT_ int,big *,big *); +extern void nres_div2(_MIPT_ big,big); +extern void nres_div3(_MIPT_ big,big); +extern void nres_div5(_MIPT_ big,big); + +extern void shs_init(sha *); +extern void shs_process(sha *,int); +extern void shs_hash(sha *,char *); + +extern void shs256_init(sha256 *); +extern void shs256_process(sha256 *,int); +extern void shs256_hash(sha256 *,char *); + +#ifdef mr_unsign64 + +extern void shs512_init(sha512 *); +extern void shs512_process(sha512 *,int); +extern void shs512_hash(sha512 *,char *); + +extern void shs384_init(sha384 *); +extern void shs384_process(sha384 *,int); +extern void shs384_hash(sha384 *,char *); + +extern void sha3_init(sha3 *,int); +extern void sha3_process(sha3 *,int); +extern void sha3_hash(sha3 *,char *); + +#endif + +extern BOOL aes_init(aes *,int,int,char *,char *); +extern void aes_getreg(aes *,char *); +extern void aes_ecb_encrypt(aes *,MR_BYTE *); +extern void aes_ecb_decrypt(aes *,MR_BYTE *); +extern mr_unsign32 aes_encrypt(aes *,char *); +extern mr_unsign32 aes_decrypt(aes *,char *); +extern void aes_reset(aes *,int,char *); +extern void aes_end(aes *); + +extern void gcm_init(gcm *,int,char *,int,char *); +extern BOOL gcm_add_header(gcm *,char *,int); +extern BOOL gcm_add_cipher(gcm *,int,char *,int,char *); +extern void gcm_finish(gcm *,char *); + +extern void FPE_encrypt(int ,aes *,mr_unsign32 ,mr_unsign32 ,char *,int); +extern void FPE_decrypt(int ,aes *,mr_unsign32 ,mr_unsign32 ,char *,int); + +extern void strong_init(csprng *,int,char *,mr_unsign32); +extern int strong_rng(csprng *); +extern void strong_bigrand(_MIPT_ csprng *,big,big); +extern void strong_bigdig(_MIPT_ csprng *,int,int,big); +extern void strong_kill(csprng *); + +/* special modular multipliers */ + +extern void comba_mult(big,big,big); +extern void comba_square(big,big); +extern void comba_redc(_MIPT_ big,big); +extern void comba_modadd(_MIPT_ big,big,big); +extern void comba_modsub(_MIPT_ big,big,big); +extern void comba_double_modadd(_MIPT_ big,big,big); +extern void comba_double_modsub(_MIPT_ big,big,big); +extern void comba_negate(_MIPT_ big,big); +extern void comba_add(big,big,big); +extern void comba_sub(big,big,big); +extern void comba_double_add(big,big,big); +extern void comba_double_sub(big,big,big); + +extern void comba_mult2(_MIPT_ big,big,big); + +extern void fastmodmult(_MIPT_ big,big,big); +extern void fastmodsquare(_MIPT_ big,big); + +extern void kcm_mul(_MIPT_ big,big,big); +extern void kcm_sqr(_MIPT_ big,big); +extern void kcm_redc(_MIPT_ big,big); + +extern void kcm_multiply(_MIPT_ int,big,big,big); +extern void kcm_square(_MIPT_ int,big,big); +extern BOOL kcm_top(_MIPT_ int,big,big,big); + +/* elliptic curve stuff */ + +extern BOOL point_at_infinity(epoint *); + +extern void mr_jsf(_MIPT_ big,big,big,big,big,big); + +extern void ecurve_init(_MIPT_ big,big,big,int); +extern int ecurve_add(_MIPT_ epoint *,epoint *); +extern int ecurve_sub(_MIPT_ epoint *,epoint *); +extern void ecurve_double_add(_MIPT_ epoint *,epoint *,epoint *,epoint *,big *,big *); +extern void ecurve_multi_add(_MIPT_ int,epoint **,epoint **); +extern void ecurve_double(_MIPT_ epoint*); +extern int ecurve_mult(_MIPT_ big,epoint *,epoint *); +extern void ecurve_mult2(_MIPT_ big,epoint *,big,epoint *,epoint *); +extern void ecurve_multn(_MIPT_ int,big *,epoint**,epoint *); + +extern BOOL epoint_x(_MIPT_ big); +extern BOOL epoint_set(_MIPT_ big,big,int,epoint*); +extern int epoint_get(_MIPT_ epoint*,big,big); +extern void epoint_getxyz(_MIPT_ epoint *,big,big,big); +extern BOOL epoint_norm(_MIPT_ epoint *); +extern BOOL epoint_multi_norm(_MIPT_ int,big *,epoint **); +extern void epoint_free(epoint *); +extern void epoint_copy(epoint *,epoint *); +extern BOOL epoint_comp(_MIPT_ epoint *,epoint *); +extern void epoint_negate(_MIPT_ epoint *); + +extern BOOL ecurve2_init(_MIPT_ int,int,int,int,big,big,BOOL,int); +extern big ecurve2_add(_MIPT_ epoint *,epoint *); +extern big ecurve2_sub(_MIPT_ epoint *,epoint *); +extern void ecurve2_multi_add(_MIPT_ int,epoint **,epoint **); +extern void ecurve2_mult(_MIPT_ big,epoint *,epoint *); +extern void ecurve2_mult2(_MIPT_ big,epoint *,big,epoint *,epoint *); +extern void ecurve2_multn(_MIPT_ int,big *,epoint**,epoint *); + +extern epoint* epoint2_init(_MIPTO_ ); +extern BOOL epoint2_set(_MIPT_ big,big,int,epoint*); +extern int epoint2_get(_MIPT_ epoint*,big,big); +extern void epoint2_getxyz(_MIPT_ epoint *,big,big,big); +extern int epoint2_norm(_MIPT_ epoint *); +extern void epoint2_free(epoint *); +extern void epoint2_copy(epoint *,epoint *); +extern BOOL epoint2_comp(_MIPT_ epoint *,epoint *); +extern void epoint2_negate(_MIPT_ epoint *); + +/* GF(2) stuff */ + +extern BOOL prepare_basis(_MIPT_ int,int,int,int,BOOL); +extern int parity2(big); +extern BOOL multi_inverse2(_MIPT_ int,big *,big *); +extern void add2(big,big,big); +extern void incr2(big,int,big); +extern void reduce2(_MIPT_ big,big); +extern void multiply2(_MIPT_ big,big,big); +extern void modmult2(_MIPT_ big,big,big); +extern void modsquare2(_MIPT_ big,big); +extern void power2(_MIPT_ big,int,big); +extern void sqroot2(_MIPT_ big,big); +extern void halftrace2(_MIPT_ big,big); +extern BOOL quad2(_MIPT_ big,big); +extern BOOL inverse2(_MIPT_ big,big); +extern void karmul2(int,mr_small *,mr_small *,mr_small *,mr_small *); +extern void karmul2_poly(_MIPT_ int,big *,big *,big *,big *); +extern void karmul2_poly_upper(_MIPT_ int,big *,big *,big *,big *); +extern void gf2m_dotprod(_MIPT_ int,big *,big *,big); +extern int trace2(_MIPT_ big); +extern void rand2(_MIPT_ big); +extern void gcd2(_MIPT_ big,big,big); +extern int degree2(big); + +/* zzn2 stuff */ + +extern BOOL zzn2_iszero(zzn2 *); +extern BOOL zzn2_isunity(_MIPT_ zzn2 *); +extern void zzn2_from_int(_MIPT_ int,zzn2 *); +extern void zzn2_from_ints(_MIPT_ int,int,zzn2 *); +extern void zzn2_copy(zzn2 *,zzn2 *); +extern void zzn2_zero(zzn2 *); +extern void zzn2_negate(_MIPT_ zzn2 *,zzn2 *); +extern void zzn2_conj(_MIPT_ zzn2 *,zzn2 *); +extern void zzn2_add(_MIPT_ zzn2 *,zzn2 *,zzn2 *); +extern void zzn2_sub(_MIPT_ zzn2 *,zzn2 *,zzn2 *); +extern void zzn2_smul(_MIPT_ zzn2 *,big,zzn2 *); +extern void zzn2_mul(_MIPT_ zzn2 *,zzn2 *,zzn2 *); +extern void zzn2_sqr(_MIPT_ zzn2 *,zzn2 *); +extern void zzn2_inv(_MIPT_ zzn2 *); +extern void zzn2_timesi(_MIPT_ zzn2 *); +extern void zzn2_powl(_MIPT_ zzn2 *,big,zzn2 *); +extern void zzn2_from_zzns(big,big,zzn2 *); +extern void zzn2_from_bigs(_MIPT_ big,big,zzn2 *); +extern void zzn2_from_zzn(big,zzn2 *); +extern void zzn2_from_big(_MIPT_ big, zzn2 *); +extern void zzn2_sadd(_MIPT_ zzn2 *,big,zzn2 *); +extern void zzn2_ssub(_MIPT_ zzn2 *,big,zzn2 *); +extern void zzn2_div2(_MIPT_ zzn2 *); +extern void zzn2_div3(_MIPT_ zzn2 *); +extern void zzn2_div5(_MIPT_ zzn2 *); +extern void zzn2_imul(_MIPT_ zzn2 *,int,zzn2 *); +extern BOOL zzn2_compare(zzn2 *,zzn2 *); +extern void zzn2_txx(_MIPT_ zzn2 *); +extern void zzn2_txd(_MIPT_ zzn2 *); +extern BOOL zzn2_sqrt(_MIPT_ zzn2 *,zzn2 *); +extern BOOL zzn2_qr(_MIPT_ zzn2 *); +extern BOOL zzn2_multi_inverse(_MIPT_ int,zzn2 *,zzn2 *); + + +/* zzn3 stuff */ + +extern void zzn3_set(_MIPT_ int,big); +extern BOOL zzn3_iszero(zzn3 *); +extern BOOL zzn3_isunity(_MIPT_ zzn3 *); +extern void zzn3_from_int(_MIPT_ int,zzn3 *); +extern void zzn3_from_ints(_MIPT_ int,int,int,zzn3 *); +extern void zzn3_copy(zzn3 *,zzn3 *); +extern void zzn3_zero(zzn3 *); +extern void zzn3_negate(_MIPT_ zzn3 *,zzn3 *); +extern void zzn3_powq(_MIPT_ zzn3 *,zzn3 *); +extern void zzn3_add(_MIPT_ zzn3 *,zzn3 *,zzn3 *); +extern void zzn3_sub(_MIPT_ zzn3 *,zzn3 *,zzn3 *); +extern void zzn3_smul(_MIPT_ zzn3 *,big,zzn3 *); +extern void zzn3_mul(_MIPT_ zzn3 *,zzn3 *,zzn3 *); +extern void zzn3_inv(_MIPT_ zzn3 *); +extern void zzn3_timesi(_MIPT_ zzn3 *); +extern void zzn3_timesi2(_MIPT_ zzn3 *); +extern void zzn3_powl(_MIPT_ zzn3 *,big,zzn3 *); +extern void zzn3_from_zzns(big,big,big,zzn3 *); +extern void zzn3_from_bigs(_MIPT_ big,big,big,zzn3 *); +extern void zzn3_from_zzn(big,zzn3 *); +extern void zzn3_from_zzn_1(big,zzn3 *); +extern void zzn3_from_zzn_2(big,zzn3 *); +extern void zzn3_from_big(_MIPT_ big, zzn3 *); +extern void zzn3_sadd(_MIPT_ zzn3 *,big,zzn3 *); +extern void zzn3_ssub(_MIPT_ zzn3 *,big,zzn3 *); +extern void zzn3_div2(_MIPT_ zzn3 *); +extern void zzn3_imul(_MIPT_ zzn3 *,int,zzn3 *); +extern BOOL zzn3_compare(zzn3 *,zzn3 *); + +/* zzn4 stuff */ + +extern BOOL zzn4_iszero(zzn4 *); +extern BOOL zzn4_isunity(_MIPT_ zzn4 *); +extern void zzn4_from_int(_MIPT_ int,zzn4 *); +extern void zzn4_copy(zzn4 *,zzn4 *); +extern void zzn4_zero(zzn4 *); +extern void zzn4_negate(_MIPT_ zzn4 *,zzn4 *); +extern void zzn4_powq(_MIPT_ zzn2 *,zzn4 *); +extern void zzn4_add(_MIPT_ zzn4 *,zzn4 *,zzn4 *); +extern void zzn4_sub(_MIPT_ zzn4 *,zzn4 *,zzn4 *); +extern void zzn4_smul(_MIPT_ zzn4 *,zzn2 *,zzn4 *); +extern void zzn4_sqr(_MIPT_ zzn4 *,zzn4 *); +extern void zzn4_mul(_MIPT_ zzn4 *,zzn4 *,zzn4 *); +extern void zzn4_inv(_MIPT_ zzn4 *); +extern void zzn4_timesi(_MIPT_ zzn4 *); +extern void zzn4_tx(_MIPT_ zzn4 *); +extern void zzn4_from_zzn2s(zzn2 *,zzn2 *,zzn4 *); +extern void zzn4_from_zzn2(zzn2 *,zzn4 *); +extern void zzn4_from_zzn2h(zzn2 *,zzn4 *); +extern void zzn4_from_zzn(big,zzn4 *); +extern void zzn4_from_big(_MIPT_ big , zzn4 *); +extern void zzn4_sadd(_MIPT_ zzn4 *,zzn2 *,zzn4 *); +extern void zzn4_ssub(_MIPT_ zzn4 *,zzn2 *,zzn4 *); +extern void zzn4_div2(_MIPT_ zzn4 *); +extern void zzn4_conj(_MIPT_ zzn4 *,zzn4 *); +extern void zzn4_imul(_MIPT_ zzn4 *,int,zzn4 *); +extern void zzn4_lmul(_MIPT_ zzn4 *,big,zzn4 *); +extern BOOL zzn4_compare(zzn4 *,zzn4 *); + +/* ecn2 stuff */ + +extern BOOL ecn2_iszero(ecn2 *); +extern void ecn2_copy(ecn2 *,ecn2 *); +extern void ecn2_zero(ecn2 *); +extern BOOL ecn2_compare(_MIPT_ ecn2 *,ecn2 *); +extern void ecn2_norm(_MIPT_ ecn2 *); +extern void ecn2_get(_MIPT_ ecn2 *,zzn2 *,zzn2 *,zzn2 *); +extern void ecn2_getxy(ecn2 *,zzn2 *,zzn2 *); +extern void ecn2_getx(ecn2 *,zzn2 *); +extern void ecn2_getz(_MIPT_ ecn2 *,zzn2 *); +extern void ecn2_rhs(_MIPT_ zzn2 *,zzn2 *); +extern BOOL ecn2_set(_MIPT_ zzn2 *,zzn2 *,ecn2 *); +extern BOOL ecn2_setx(_MIPT_ zzn2 *,ecn2 *); +extern void ecn2_setxyz(_MIPT_ zzn2 *,zzn2 *,zzn2 *,ecn2 *); +extern void ecn2_negate(_MIPT_ ecn2 *,ecn2 *); +extern BOOL ecn2_add3(_MIPT_ ecn2 *,ecn2 *,zzn2 *,zzn2 *,zzn2 *); +extern BOOL ecn2_add2(_MIPT_ ecn2 *,ecn2 *,zzn2 *,zzn2 *); +extern BOOL ecn2_add1(_MIPT_ ecn2 *,ecn2 *,zzn2 *); +extern BOOL ecn2_add(_MIPT_ ecn2 *,ecn2 *); +extern BOOL ecn2_sub(_MIPT_ ecn2 *,ecn2 *); +extern BOOL ecn2_add_sub(_MIPT_ ecn2 *,ecn2 *,ecn2 *,ecn2 *); +extern int ecn2_mul2_jsf(_MIPT_ big,ecn2 *,big,ecn2 *,ecn2 *); +extern int ecn2_mul(_MIPT_ big,ecn2 *); +extern void ecn2_psi(_MIPT_ zzn2 *,ecn2 *); +extern BOOL ecn2_multi_norm(_MIPT_ int ,zzn2 *,ecn2 *); +extern int ecn2_mul4_gls_v(_MIPT_ big *,int,ecn2 *,big *,ecn2 *,zzn2 *,ecn2 *); +extern int ecn2_muln_engine(_MIPT_ int,int,int,int,big *,big *,big *,big *,ecn2 *,ecn2 *,ecn2 *); +extern void ecn2_precomp_gls(_MIPT_ int,BOOL,ecn2 *,zzn2 *,ecn2 *); +extern int ecn2_mul2_gls(_MIPT_ big *,ecn2 *,zzn2 *,ecn2 *); +extern void ecn2_precomp(_MIPT_ int,BOOL,ecn2 *,ecn2 *); +extern int ecn2_mul2(_MIPT_ big,int,ecn2 *,big,ecn2 *,ecn2 *); +#ifndef MR_STATIC +extern BOOL ecn2_brick_init(_MIPT_ ebrick *,zzn2 *,zzn2 *,big,big,big,int,int); +extern void ecn2_brick_end(ebrick *); +#else +extern void ebrick_init(ebrick *,const mr_small *,big,big,big,int,int); +#endif +extern void ecn2_mul_brick_gls(_MIPT_ ebrick *B,big *,zzn2 *,zzn2 *,zzn2 *); +extern void ecn2_multn(_MIPT_ int,big *,ecn2 *,ecn2 *); +extern void ecn2_mult4(_MIPT_ big *,ecn2 *,ecn2 *); +/* Group 3 - Floating-slash routines */ + +#ifdef MR_FLASH +extern void fpack(_MIPT_ big,big,flash); +extern void numer(_MIPT_ flash,big); +extern void denom(_MIPT_ flash,big); +extern BOOL fit(big,big,int); +extern void build(_MIPT_ flash,int (*)(_MIPT_ big,int)); +extern void mround(_MIPT_ big,big,flash); +extern void flop(_MIPT_ flash,flash,int *,flash); +extern void fmul(_MIPT_ flash,flash,flash); +extern void fdiv(_MIPT_ flash,flash,flash); +extern void fadd(_MIPT_ flash,flash,flash); +extern void fsub(_MIPT_ flash,flash,flash); +extern int fcomp(_MIPT_ flash,flash); +extern void fconv(_MIPT_ int,int,flash); +extern void frecip(_MIPT_ flash,flash); +extern void ftrunc(_MIPT_ flash,big,flash); +extern void fmodulo(_MIPT_ flash,flash,flash); +extern void fpmul(_MIPT_ flash,int,int,flash); +extern void fincr(_MIPT_ flash,int,int,flash); +extern void dconv(_MIPT_ double,flash); +extern double fdsize(_MIPT_ flash); +extern void frand(_MIPT_ flash); + +/* Group 4 - Advanced Flash routines */ + +extern void fpower(_MIPT_ flash,int,flash); +extern BOOL froot(_MIPT_ flash,int,flash); +extern void fpi(_MIPT_ flash); +extern void fexp(_MIPT_ flash,flash); +extern void flog(_MIPT_ flash,flash); +extern void fpowf(_MIPT_ flash,flash,flash); +extern void ftan(_MIPT_ flash,flash); +extern void fatan(_MIPT_ flash,flash); +extern void fsin(_MIPT_ flash,flash); +extern void fasin(_MIPT_ flash,flash); +extern void fcos(_MIPT_ flash,flash); +extern void facos(_MIPT_ flash,flash); +extern void ftanh(_MIPT_ flash,flash); +extern void fatanh(_MIPT_ flash,flash); +extern void fsinh(_MIPT_ flash,flash); +extern void fasinh(_MIPT_ flash,flash); +extern void fcosh(_MIPT_ flash,flash); +extern void facosh(_MIPT_ flash,flash); +#endif + + +/* Test predefined Macros to determine compiler type, and hopefully + selectively use fast in-line assembler (or other compiler specific + optimisations. Note I am unsure of Microsoft version numbers. So I + suspect are Microsoft. + + Note: It seems to be impossible to get the 16-bit Microsoft compiler + to allow inline 32-bit op-codes. So I suspect that INLINE_ASM == 2 will + never work with it. Pity. + +#define INLINE_ASM 1 -> generates 8086 inline assembly +#define INLINE_ASM 2 -> generates mixed 8086 & 80386 inline assembly, + so you can get some benefit while running in a + 16-bit environment on 32-bit hardware (DOS, Windows + 3.1...) +#define INLINE_ASM 3 -> generate true 80386 inline assembly - (Using DOS + extender, Windows '95/Windows NT) + Actually optimised for Pentium + +#define INLINE_ASM 4 -> 80386 code in the GNU style (for (DJGPP) + +Small, medium, compact and large memory models are supported for the +first two of the above. + +*/ + +/* To allow for inline assembly */ + +#ifdef __GNUC__ + #define ASM __asm__ __volatile__ +#endif + +#ifdef __TURBOC__ + #define ASM asm +#endif + +#ifdef _MSC_VER + #define ASM _asm +#endif + +#ifndef MR_NOASM + +/* Win64 - inline the time critical function */ +#ifndef MR_NO_INTRINSICS + #ifdef MR_WIN64 + #define muldvd(a,b,c,rp) (*(rp)=_umul128((a),(b),&(tm)),*(rp)+=(c),tm+=(*(rp)<(c)),tm) + #define muldvd2(a,b,c,rp) (tr=_umul128((a),(b),&(tm)),tr+=(*(c)),tm+=(tr<(*(c))),tr+=(*(rp)),tm+=(tr<(*(rp))),*(rp)=tr,*(c)=tm) + #endif + +/* Itanium - inline the time-critical functions */ + + #ifdef MR_ITANIUM + #define muldvd(a,b,c,rp) (tm=_m64_xmahu((a),(b),(c)),*(rp)=_m64_xmalu((a),(b),(c)),tm) + #define muldvd2(a,b,c,rp) (tm=_m64_xmalu((a),(b),(*(c))),*(c)=_m64_xmahu((a),(b),(*(c))),tm+=*(rp),*(c)+=(tm<*(rp)),*(rp)=tm) + #endif +#endif +/* + +SSE2 code. Works as for itanium - but in fact it is slower than the regular code so not recommended +Would require a call to emmintrin.h or xmmintrin.h, and an __m128i variable tm to be declared in effected +functions. But it works! + + #define muldvd(a,b,c,rp) (tm=_mm_add_epi64(_mm_mul_epu32(_mm_cvtsi32_si128((a)),_mm_cvtsi32_si128((b))),_mm_cvtsi32_si128((c))),*(rp)=_mm_cvtsi128_si32(tm),_mm_cvtsi128_si32(_mm_shuffle_epi32(tm,_MM_SHUFFLE(3,2,0,1))) ) + #define muldvd2(a,b,c,rp) (tm=_mm_add_epi64(_mm_add_epi64(_mm_mul_epu32(_mm_cvtsi32_si128((a)),_mm_cvtsi32_si128((b))),_mm_cvtsi32_si128(*(c))),_mm_cvtsi32_si128(*(rp))),*(rp)=_mm_cvtsi128_si32(tm),*(c)=_mm_cvtsi128_si32( _mm_shuffle_epi32(tm,_MM_SHUFFLE(3,2,0,1)) ) +*/ + +/* Borland C/Turbo C */ + + #ifdef __TURBOC__ + #ifndef __HUGE__ + #if defined(__COMPACT__) || defined(__LARGE__) + #define MR_LMM + #endif + + #if MIRACL==16 + #define INLINE_ASM 1 + #endif + + #if __TURBOC__>=0x410 + #if MIRACL==32 +#if defined(__SMALL__) || defined(__MEDIUM__) || defined(__LARGE__) || defined(__COMPACT__) + #define INLINE_ASM 2 + #else + #define INLINE_ASM 3 + #endif + #endif + #endif + #endif + #endif + +/* Microsoft C */ + + #ifdef _MSC_VER + #ifndef M_I86HM + #if defined(M_I86CM) || defined(M_I86LM) + #define MR_LMM + #endif + #if _MSC_VER>=600 + #if _MSC_VER<1200 + #if MIRACL==16 + #define INLINE_ASM 1 + #endif + #endif + #endif + #if _MSC_VER>=1000 + #if _MSC_VER<1500 + #if MIRACL==32 + #define INLINE_ASM 3 + #endif + #endif + #endif + #endif + #endif + +/* DJGPP GNU C */ + + #ifdef __GNUC__ + #ifdef i386 + #if MIRACL==32 + #define INLINE_ASM 4 + #endif + #endif + #endif + +#endif + + + +/* + The following contribution is from Tielo Jongmans, Netherlands + These inline assembler routines are suitable for Watcom 10.0 and up + + Added into miracl.h. Notice the override of the original declarations + of these routines, which should be removed. + + The following pragma is optional, it is dangerous, but it saves a + calling sequence +*/ + +/* + +#pragma off (check_stack); + +extern unsigned int muldiv(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int *); +#pragma aux muldiv= \ + "mul edx" \ + "add eax,ebx" \ + "adc edx,0" \ + "div ecx" \ + "mov [esi],edx" \ + parm [eax] [edx] [ebx] [ecx] [esi] \ + value [eax] \ + modify [eax edx]; + +extern unsigned int muldvm(unsigned int, unsigned int, unsigned int, unsigned int *); +#pragma aux muldvm= \ + "div ebx" \ + "mov [ecx],edx" \ + parm [edx] [eax] [ebx] [ecx] \ + value [eax] \ + modify [eax edx]; + +extern unsigned int muldvd(unsigned int, unsigned int, unsigned int, unsigned int *); +#pragma aux muldvd= \ + "mul edx" \ + "add eax,ebx" \ + "adc edx,0" \ + "mov [ecx],eax" \ + "mov eax,edx" \ + parm [eax] [edx] [ebx] [ecx] \ + value [eax] \ + modify [eax edx]; + +*/ + + +#endif + + diff --git a/generator_cgo/include/mirdef.h b/generator_cgo/include/mirdef.h new file mode 100644 index 0000000..54fa13a --- /dev/null +++ b/generator_cgo/include/mirdef.h @@ -0,0 +1,15 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype long long +#define mr_unsign64 unsigned long long +#define MR_IBITS 32 +#define MR_LBITS 64 +#define mr_unsign32 unsigned int +#define MR_FLASH 52 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 + diff --git a/generator_cgo/include/sign.cpp b/generator_cgo/include/sign.cpp new file mode 100644 index 0000000..852ee76 --- /dev/null +++ b/generator_cgo/include/sign.cpp @@ -0,0 +1,107 @@ + +#include +#include "sign.h" +#include "hash.h" +#include "utils.h" + +void getFullkey( + ECC_PARAMS *params, + char *ID, // 用户ID + big d, // 用户部分私钥 + big x, // 用户秘密值 + epoint *X, // 用户公钥 + big sa // 用户完整私钥 +) +{ + // 计算hash值H_2(ID, X) + big h_2_big = mirvar(0); + hash2(ID, X, (*params).p, h_2_big); + + // 计算sa = d + h_2*x mod p + big tmp = mirvar(0); + multiply(x, h_2_big, tmp); + add(d, tmp, sa); + power(sa, 1, (*params).p, sa); // mod p + + mirkill(h_2_big); + mirkill(tmp); +} + +void sign_Thumbur( + ECC_PARAMS *params, + char *ID, // 用户ID + char *msg, // 签名消息 + big sa, // 输入用户完整私钥 + epoint *Q, // 输入用户完整公钥 + epoint *U, // 输出签名的随机数变换 + epoint *PK_pub, //输入KGC的公钥 + big v // 输出签名的计算值 +) +{ + // 产生随机数u,计算U=uP + big u = mirvar(0); + bigrand((*params).p, u); + ecurve_mult(u, (*params).P, U); + + // 计算hash值H_3(ID, msg, Q, U, PK_pub) + big h_3_big = mirvar(0); + hash3(ID, msg, Q, U, PK_pub, (*params).p, h_3_big); + + // 计算签名值 v = u + h_3*sa + big tmp = mirvar(0); + multiply(sa, h_3_big, tmp); + add(u, tmp, v); + power(v, 1, (*params).p, v); // mod p + outbig(v, "v"); + + mirkill(u); + mirkill(h_3_big); + mirkill(tmp); +} + +bool verify_Thumbur( + ECC_PARAMS *params, + char *ID, + char *msg, + epoint *Q, + epoint *PK_pub, + epoint *U, + big v +) +{ + // 计算hash值H_1(ID, Q, PK_pub) + big h_1_big = mirvar(0); + hash1(ID, Q, PK_pub, (*params).p, h_1_big); + + // 计算hash值H_3(ID, msg, Q, U, PK_pub) + big h_3_big = mirvar(0); + hash3(ID, msg, Q, U, PK_pub, (*params).p, h_3_big); + + // 验签等式 v*P = U + h_3(Q + h_1*P_pub) + // 等式左边: + epoint *left = epoint_init(); + ecurve_mult(v, (*params).P, left); + + // 等式右边: + epoint *tmp_p = epoint_init(); + ecurve_mult(h_1_big, PK_pub, tmp_p); + ecurve_add(Q, tmp_p); + ecurve_mult(h_3_big, tmp_p, tmp_p); + ecurve_add(U, tmp_p); + + bool bRv = false; + if (epoint_comp(left, tmp_p)) + { + bRv = true; + } + else + { + bRv = false; + } + + mirkill(h_1_big); + mirkill(h_3_big); + epoint_free(left); + epoint_free(tmp_p); + return bRv; +} \ No newline at end of file diff --git a/generator_cgo/include/sign.h b/generator_cgo/include/sign.h new file mode 100644 index 0000000..20ca11f --- /dev/null +++ b/generator_cgo/include/sign.h @@ -0,0 +1,39 @@ +#ifndef __SIGN_H__ +#define __SIGN_H__ + +#include "ecurve.h" +#include "miracl.h" +#include "mirdef.h" +#include + +void getFullkey( + ECC_PARAMS *params, + char *ID, // 用户ID + big d, // 用户部分私钥 + big x, // 用户秘密值 + epoint *X, // 用户公钥 + big sa // 用户完整私钥 +); + +void sign_Thumbur( + ECC_PARAMS *params, + char *ID, // 用户ID + char *msg, // 签名消息 + big sa, // 用户完整私钥 + epoint *Q, // 用户完整公钥 + epoint *U, // 输出签名的随机数变换 + epoint *PK_pub, //kgc公钥 + big v // 输出签名的计算值 +); + +bool verify_Thumbur( + ECC_PARAMS *params, + char *ID, + char *msg, + epoint *Q, + epoint *PK_pub, + epoint *U, + big v +); + +#endif \ No newline at end of file diff --git a/generator_cgo/include/utils.cpp b/generator_cgo/include/utils.cpp new file mode 100644 index 0000000..394c78c --- /dev/null +++ b/generator_cgo/include/utils.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include "utils.h" +#include "ecurve.h" +#include "kgc.h" + +//将big大数类型转为char*类型 +void outbig(big num, char *val_name) +{ + char out_str[257] = {0}; + cotstr(num, out_str); + printf("\nchar str_%s[] = \"%s\";", val_name, out_str); +} + +//将big大数类型转为char*类型 +void outpoint(epoint *PO, char *val_name) +{ + char out_str[257] = {0}; + big PO_x = mirvar(0); + big PO_y = mirvar(0); + epoint_get(PO, PO_x, PO_y); + cotstr(PO_x, out_str); + printf("\nchar str_%s_x[]= \"%s\";", val_name, out_str); + cotstr(PO_y, out_str); + printf("\nchar str_%s_y[]= \"%s\";", val_name, out_str); +} + +// 设置随机数种子 +void setRandSeed() +{ + time_t seed; + time(&seed); // 用系统时间做种子 + irand((long)seed); + return; +} + +// +void sha256_update_string(sha256 sh, const char *data, long data_len) +{ + for (long i = 0; i < data_len; i++) + { + shs256_process(&sh, data[i]); + } +} + +void sha256_update_point(sha256 sh, epoint *point) +{ + big point_x = mirvar(0); + big point_y = mirvar(0); + char point_x_string[256] = {0}; + char point_y_string[256] = {0}; + epoint_get(point, point_x, point_y); + cotstr(point_x, point_x_string); + cotstr(point_y, point_y_string); + + for (unsigned int i = 0; i < strlen(point_x_string); i++) + { + shs256_process(&sh, point_x_string[i]); + } + + for (unsigned int i = 0; i < strlen(point_y_string); i++) + { + shs256_process(&sh, point_y_string[i]); + } + + mirkill(point_x); + mirkill(point_y); +} + +//用户产生秘密值x,以及与基点点乘后的X +void genSecret(ECC_PARAMS *params, big x, epoint *X) +{ + bigrand((*params).p, x); //产生小于阶p的big值 + ecurve_mult(x, (*params).P, X); +} diff --git a/generator_cgo/include/utils.h b/generator_cgo/include/utils.h new file mode 100644 index 0000000..90ad46f --- /dev/null +++ b/generator_cgo/include/utils.h @@ -0,0 +1,24 @@ +#ifndef __UNTILS_H__ +#define __UNTILS_H__ + + +#include "miracl.h" +#include "mirdef.h" +#include "ecurve.h" + +void outbig(big num, char *val_name); + +void outpoint(epoint *PO, char *val_name); + +void setRandSeed(); + +void sha256_update_string(sha256 sh, const char *data, long data_len); + +void sha256_update_point(sha256 sh, epoint *point); + +void genSecret(ECC_PARAMS *params, big x, epoint *X); + +bool Setup(); + + +#endif \ No newline at end of file diff --git a/generator_cgo/include/zzn.h b/generator_cgo/include/zzn.h new file mode 100644 index 0000000..850df10 --- /dev/null +++ b/generator_cgo/include/zzn.h @@ -0,0 +1,219 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * + * MIRACL C++ Header file zzn.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class ZZn (Arithmetic mod n), using + * Montgomery's Method for modular multiplication + * NOTE : Must be used in conjunction with zzn.cpp + * The modulus n is always set dynamically (via the modulo() + * routine) - so beware the pitfalls implicit in declaring + * static or global ZZn's (which are initialised before n is + * set!). Uninitialised data is OK + */ + +#ifndef ZZN_H +#define ZZN_H + +#include "big.h" + +/* + +#ifdef ZZNS +#define MR_INIT_ZZN memset(mem,0,mr_big_reserve(1,ZZNS)); fn=(big)mirvar_mem_variable(mem,0,ZZNS); +#define MR_CLONE_ZZN(x) fn->len=x->len; for (int i=0;iw[i]=x->w[i]; +#define MR_ZERO_ZZN {fn->len=0; for (int i=0;iw[i]=0;} +#else +#define MR_INIT_ZZN mem=(char *)memalloc(1); fn=(big)mirvar_mem(mem,0); +#define MR_CLONE_ZZN(x) copy(x,fn); +#define MR_ZERO_ZZN zero(fn); +#endif + +*/ + +#ifdef ZZNS +#ifdef MR_COMBA +#define UZZNS ZZNS +#else +#define UZZNS ZZNS+1 // one extra required in case of carry overflow in addition +#endif +#endif + +#ifdef ZZNS +#define MR_INIT_ZZN fn=&b; b.w=a; b.len=UZZNS; +#define MR_CLONE_ZZN(x) b.len=x->len; for (int i=0;iw[i]; +#define MR_ZERO_ZZN {b.len=0; for (int i=0;i ZZn */ + ZZn(big& c) {MR_INIT_ZZN MR_CLONE_ZZN(c);} + ZZn(const ZZn& c) {MR_INIT_ZZN MR_CLONE_ZZN(c.fn);} + ZZn(char* s) {MR_INIT_ZZN cinstr(fn,s); nres(fn,fn);} + + ZZn& operator=(const ZZn& c) {MR_CLONE_ZZN(c.fn) return *this;} + ZZn& operator=(big c) {MR_CLONE_ZZN(c) return *this; } + + ZZn& operator=(int i) {if (i==0) MR_ZERO_ZZN else {convert(i,fn); nres(fn,fn);} return *this;} + ZZn& operator=(char* s){cinstr(fn,s); nres(fn,fn); return *this;} + + +/* Use fast in-line code */ + + ZZn& operator++() + {nres_modadd(fn,get_mip()->one,fn);return *this;} + ZZn& operator--() + {nres_modsub(fn,get_mip()->one,fn);return *this;} + ZZn& operator+=(int i) + {ZZn inc=i; nres_modadd(fn,inc.fn,fn);return *this;} + ZZn& operator-=(int i) + {ZZn dec=i; nres_modsub(fn,dec.fn,fn); return *this;} + ZZn& operator+=(const ZZn& b) + {nres_modadd(fn,b.fn,fn); return *this;} + ZZn& operator-=(const ZZn& b) + {nres_modsub(fn,b.fn,fn); return *this;} + ZZn& operator*=(const ZZn& b) + {nres_modmult(fn,b.fn,fn); return *this;} + ZZn& operator*=(int i) + {nres_premult(fn,i,fn); return *this;} + + ZZn& negate() + {nres_negate(fn,fn); return *this;} + + BOOL iszero() const; + + operator Big() {Big c; redc(fn,c.getbig()); return c;} /* ZZn -> Big */ + friend big getbig(ZZn& z) {return z.fn;} + + ZZn& operator/=(const ZZn& b) {nres_moddiv(fn,b.fn,fn); return *this;} + ZZn& operator/=(int); + + friend ZZn operator-(const ZZn&); + friend ZZn operator+(const ZZn&,int); + friend ZZn operator+(int, const ZZn&); + friend ZZn operator+(const ZZn&, const ZZn&); + + friend ZZn operator-(const ZZn&, int); + friend ZZn operator-(int, const ZZn&); + friend ZZn operator-(const ZZn&, const ZZn&); + + friend ZZn operator*(const ZZn&,int); + friend ZZn operator*(int, const ZZn&); + friend ZZn operator*(const ZZn&, const ZZn&); + + friend ZZn operator/(const ZZn&, int); + friend ZZn operator/(int, const ZZn&); + friend ZZn operator/(const ZZn&, const ZZn&); + + friend BOOL operator==(const ZZn& b1,const ZZn& b2) + { if (mr_compare(b1.fn,b2.fn)==0) return TRUE; else return FALSE;} + friend BOOL operator!=(const ZZn& b1,const ZZn& b2) + { if (mr_compare(b1.fn,b2.fn)!=0) return TRUE; else return FALSE;} + + friend ZZn one(void); + friend ZZn pow( const ZZn&, const Big&); + friend ZZn pow( const ZZn&,int); + friend ZZn powl(const ZZn&, const Big&); + friend ZZn pow( const ZZn&, const Big&, const ZZn&, const Big&); + friend ZZn pow( int,ZZn *,Big *); + friend int jacobi(const ZZn&); +#ifndef MR_NO_RAND + friend ZZn randn(void); // random number < modulus +#endif + friend BOOL qr(const ZZn&); // test for quadratic residue + friend BOOL qnr(const ZZn&); // test for quadratic non-residue + friend ZZn getA(void); // get A parameter of elliptic curve + friend ZZn getB(void); // get B parameter of elliptic curve + + friend ZZn sqrt(const ZZn&); // only works if modulus is prime + + friend ZZn luc( const ZZn& b1, const Big& b2, ZZn* b3=NULL) + { + ZZn z; if (b3!=NULL) nres_lucas(b1.fn,b2.getbig(),b3->fn,z.fn); + else nres_lucas(b1.fn,b2.getbig(),z.fn,z.fn); + return z; + } + + //friend ZZn luc( const ZZn&, const Big&, ZZn* b3=NULL); + + big getzzn(void) const; + +#ifndef MR_NO_STANDARD_IO + friend ostream& operator<<(ostream&,const ZZn&); +#endif + + + ~ZZn() + { + // MR_ZERO_ZZN // slower but safer +#ifndef ZZNS + mr_free(fn); +#endif + } +}; +#ifndef MR_NO_RAND +extern ZZn randn(void); +#endif +extern ZZn getA(void); +extern ZZn getB(void); +extern ZZn one(void); + +#endif + diff --git a/generator_cgo/lib/libKGC.a b/generator_cgo/lib/libKGC.a new file mode 100644 index 0000000..ca2796e Binary files /dev/null and b/generator_cgo/lib/libKGC.a differ diff --git a/generator_cgo/lib/libKGCAll.a b/generator_cgo/lib/libKGCAll.a new file mode 100644 index 0000000..45524e6 Binary files /dev/null and b/generator_cgo/lib/libKGCAll.a differ diff --git a/generator_cgo/lib/libMiracl.a b/generator_cgo/lib/libMiracl.a new file mode 100644 index 0000000..34cf199 Binary files /dev/null and b/generator_cgo/lib/libMiracl.a differ diff --git a/generator_cgo/main.go b/generator_cgo/main.go new file mode 100644 index 0000000..61e3130 --- /dev/null +++ b/generator_cgo/main.go @@ -0,0 +1,112 @@ +package main + +/* +#cgo CFLAGS: -I./include +#cgo LDFLAGS: -L./lib -lKGCAll +#include "miracl.h" +#include "mirdef.h" +#include "hash.h" +#include "kgc.h" +#include "utils.h" +#include "ecurve.h" +#include "sign.h" + +#include "utils.cpp" +#include "ecurve.cpp" +#include "hash.cpp" +#include "sign.cpp" +#include "kgc.cpp" +#include +#include +#include +char* IDA = "1234567890111213141516171819202122232425"; // 发送者ID +char* IDB = "1448579437597582757693565726417498574267"; // 接受者ID +char* M = "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD"; +char* msk = "msk"; +char* PKP = "PK_pub"; +char* Public = "P_P"; +char* QA = "Q_A"; +char* dA = "d_A"; +char* xA = "x_A"; +char* XA = "X_A"; +char* saA = "sa_A"; +*/ +import "C" +import "fmt" + +func main() { + + mip := C.mirsys(512, 16) // 初始化MIRACL系统,512位,16进制数 + mip.IOBASE = 16 // 设置大整数为16进制 + a := C.mirvar(0) + C.mirkill(a) + C.setRandSeed() + + // 建立椭圆曲线 + var params C.ECC_PARAMS + if !C.setupEcurve(¶ms) { + fmt.Println("ecurve setup failed") + C.mirexit() + panic("椭圆曲线建立失败!") + } + + C.setRandSeed() // 随机数种子 + //初始化参数 + msk := C.mirvar(0) //私钥 + PK_pub := C.epoint_init() //公钥 + d_A := C.mirvar(0) //用户A产生的部分私钥 + x_A := C.mirvar(0) //用户产生的秘密值 + X_A := C.epoint_init() + sa_A := C.mirvar(0) //用户完整私钥 + Q_A := C.epoint_init() //用户完整公钥 + val := C.mirvar(0) //用户返回的签名值 + U := C.epoint_init() //随机点值 + + // 产生KGC密钥对: msk, PK_pub + C.genKGCkey(¶ms, msk, PK_pub) + C.outbig(msk, C.msk) + + C.outpoint((¶ms).P, C.Public) + C.outpoint(PK_pub, C.PKP) + + // 产生用户A的秘密值 + C.genSecret(¶ms, x_A, X_A) + C.outbig(x_A, C.xA) + C.outpoint(X_A, C.XA) + + // 产生用户A的部分私钥和用户的完整公钥 + if !C.genPPK_std(¶ms, msk, PK_pub, C.IDA, d_A, Q_A, X_A) { + fmt.Println("Generate PPK for IDA failed.") + goto error + } + C.outbig(d_A, C.dA) + C.outpoint(Q_A, C.QA) + + // 输出完整的用户私钥 + C.getFullkey(¶ms, C.IDA, d_A, x_A, X_A, sa_A) + C.outbig(sa_A, C.saA) + + // 签名,Gowri Thumbur方案 + C.sign_Thumbur(¶ms, C.IDA, C.M, sa_A, Q_A, U, PK_pub, val) + + // 验签 + if C.verify_Thumbur(¶ms, C.IDA, C.M, Q_A, PK_pub, U, val) { + fmt.Println("\nsignature valid.") + } else { + fmt.Println("\nverify failed.") + } + +error: + C.mirkill(msk) + C.mirkill(d_A) + C.mirkill(x_A) + C.mirkill(sa_A) + C.epoint_free(PK_pub) + C.epoint_free(X_A) + C.epoint_free(Q_A) + C.epoint_free(U) + + C.freeEcurve(¶ms) + C.mirexit() // 退出MIRACL系统 + +} diff --git a/generator_cgo/params.txt b/generator_cgo/params.txt new file mode 100644 index 0000000..84ed46b --- /dev/null +++ b/generator_cgo/params.txt @@ -0,0 +1,19 @@ +char str_msk[] = "6D5DB11261A93275CD69A813F6CA4FE84A5613B346D27AFEFAF3D63D0DF307A7"; +char str_P_P_x[]= "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"; +char str_P_P_y[]= "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"; +char str_PK_pub_x[]= "6C723EBEDA3B3FF230BEFEB870DBCF38271F609A09E949FA06E512C74FEB4E76"; +char str_PK_pub_y[]= "5FAE4EB8F8B38B401C231D4EB682E53977A62663169B1B1908F4906E4758DD7C"; +char str_x_A[] = "80A80E35FB678995DE03E0DE6DCA75651D48D57C82923C4F8097A7CF80FFDC0F"; +char str_X_A_x[]= "3E9FD587517E568102447F7BFDA9955EAFF9F8984DE497813269546ADAB30D8A"; +char str_X_A_y[]= "3AC044504324E5FD14D16FC396133EE7FD4B4743E0F4F3245BF69F3634CD74F4"; +char str_d_A[] = "37F0619702B66C78D898A2135FAF59AFF5439BBA388FB114CEDA6180FF8E395C"; +char str_sa_A[] = "6A7C930DDCFE3B505D5AD7824B63ABA9110883D261CE67C04AF01E395E248766"; +char str_Q_A_x[]= "6E87706053DD52225354602E031A1D025115B54B8C600D3C47AB66749D0852DC"; +char str_Q_A_y[]= "71C165DCBF5E07903517A5AAB4919104229A1E65D6D57C23B95147ED79BA23E4"; +char str_v[] = "33979BEB2B89412DEA04EC7DD07FF8F98792F490A6A519AE64766BAE30B7874A"; +signature valid. + +用户ID:char* IDA = "1234567890111213141516171819202122232425"; +用户私钥:char str_sa_A[] = "6A7C930DDCFE3B505D5AD7824B63ABA9110883D261CE67C04AF01E395E248766"; +用户公钥:char str_Q_A_x[]= "6E87706053DD52225354602E031A1D025115B54B8C600D3C47AB66749D0852DC"; + char str_Q_A_y[]= "71C165DCBF5E07903517A5AAB4919104229A1E65D6D57C23B95147ED79BA23E4"; diff --git a/hash.cpp b/hash.cpp new file mode 100644 index 0000000..82e9d5b --- /dev/null +++ b/hash.cpp @@ -0,0 +1,61 @@ +#include +#include "hash.h" +#include "ecurve.h" +#include "utils.h" + +void hash1(char *ID, epoint *Q, epoint *PK_pub, big p, big h_1_big) +{ + // 计算hash值H_1(ID, R, PK_pub) + //hash1(ID, Q, PK_pub) + sha256 sh; + char h_1[33] = {0}; + + shs256_init(&sh); + sha256_update_string(sh, ID, strlen(ID)); + sha256_update_point(sh, Q); + sha256_update_point(sh, PK_pub); + shs256_hash(&sh, h_1); + + bytes_to_big(32, h_1, h_1_big); + power(h_1_big, 1, p, h_1_big); // mod p +} + +void hash2(char *ID, epoint *X, big p, big h_2_big) +{ + // 计算hash值H_2(ID, X) + sha256 sh; + char h_2[33] = {0}; + + shs256_init(&sh); + sha256_update_string(sh, ID, strlen(ID)); + sha256_update_point(sh, X); + shs256_hash(&sh, h_2); + + bytes_to_big(32, h_2, h_2_big); + power(h_2_big, 1, p, h_2_big); // mod p +} + +void hash3( + char *ID, + char *msg, + epoint *Q, + epoint *U, + epoint *PK_pub, + big p, + big h_3_big +) +{ + sha256 sh; + char h_3[33] = {0}; + + shs256_init(&sh); + sha256_update_string(sh, ID, strlen(ID)); + sha256_update_string(sh, msg, strlen(msg)); + sha256_update_point(sh, Q); + sha256_update_point(sh, U); + sha256_update_point(sh, PK_pub); + shs256_hash(&sh, h_3); + + bytes_to_big(32, h_3, h_3_big); + power(h_3_big, 1, p, h_3_big); // mod p +} diff --git a/hash.h b/hash.h new file mode 100644 index 0000000..aab82a8 --- /dev/null +++ b/hash.h @@ -0,0 +1,27 @@ +#ifndef __HASH_H__ +#define __HASH_H__ + +extern "C" +{ +#include "miracl.h" +#include "mirdef.h" +} + +//hash1(ID, Q, PK_pub, h_1_big) +void hash1(char *ID, epoint *Q, epoint *PK_pub, big p, big h_1_big); + +//hash2(ID, X, h_2_big) +void hash2(char *ID, epoint *X, big p, big h_2_big); + +//hash3(ID, msg, Q, U, PK_pub, h_3_big) +void hash3( + char *ID, + char *msg, + epoint *Q, + epoint *U, + epoint *PK_pub, + big p, + big h_3_big +); + +#endif \ No newline at end of file diff --git a/kgc.cpp b/kgc.cpp new file mode 100644 index 0000000..4d9e0aa --- /dev/null +++ b/kgc.cpp @@ -0,0 +1,84 @@ +#include +#include "kgc.h" +#include "hash.h" + +void genKGCkey(ECC_PARAMS *params, big msk, epoint *PK_pub) +{ + bigrand((*params).p, msk); // 产生小于p的随机数 + ecurve_mult(msk, (*params).P, PK_pub); +} + +bool genPPK_std( + ECC_PARAMS *params, + big msk, // KGC私钥 + epoint *PK_pub, // KGC公钥 + char ID[], // 输入用户ID + big d, // 输出部分私钥 + epoint *Q, // 产生的用户公钥 + epoint *X) // 输入用户秘密值 +{ + // 产生随机数r,计算R=rP + epoint *R_A = epoint_init(); + big r = mirvar(0); + bigrand((*params).p, r); + ecurve_mult(r, (*params).P, R_A); + + //计算h_2 = H_2(ID,X) + big h_2_big = mirvar(0); + hash2(ID, X, (*params).p, h_2_big); + + //计算h_2 * X + epoint *h2X = epoint_init(); + ecurve_mult(h_2_big, X, h2X); + + //计算Q = R + h_2 * X + ecurve_add(R_A, Q); + ecurve_add(h2X, Q); + + //计算h_1 = H_1(ID,Q,PK_pub) + big h_1_big = mirvar(0); + hash1(ID, Q, PK_pub, (*params).p, h_1_big); + + // 计算d = r + msk * h_1 mod p + big tmp = mirvar(0); + multiply(msk, h_1_big, tmp); + add(r, tmp, d); + power(d, 1, (*params).p, d); // mod p + + //计算h_1 * PK_pub + epoint *h1PK = epoint_init(); + ecurve_mult(h_1_big, PK_pub, h1PK); + + // 用d * P = Q - h2 * X + h1 * PK_pub验证一下(d,Q)是否正确 + // 点的减法 pa = pa - a Function: void ecurve_sub(p,pa) + epoint *left = epoint_init(); + ecurve_mult(d, (*params).P, left); + epoint *right = epoint_init(); + ecurve_add(Q, right); + ecurve_sub(h2X, right); + ecurve_add(h1PK, right); + + bool bRv = false; + if (epoint_comp(left, right)) + { + bRv = true; + + } + else + { + bRv = false; + } + + mirkill(r); + mirkill(h_1_big); + mirkill(h_2_big); + mirkill(tmp); + + epoint_free(R_A); + epoint_free(left); + epoint_free(right); + epoint_free(h1PK); + epoint_free(h2X); + + return bRv; +} \ No newline at end of file diff --git a/kgc.h b/kgc.h new file mode 100644 index 0000000..c59bfe7 --- /dev/null +++ b/kgc.h @@ -0,0 +1,19 @@ +#ifndef __KGC_H__ +#define __KGC_H__ + +#include "ecurve.h" + + +void genKGCkey(ECC_PARAMS *params, big msk, epoint *PK_pub); + +bool genPPK_std( + ECC_PARAMS *params, + big msk, + epoint *PK_pub, + char ID[], + big d, + epoint *Q, + epoint *X +); + +#endif \ No newline at end of file diff --git a/miracl/.DS_Store b/miracl/.DS_Store new file mode 100644 index 0000000..872a9c0 Binary files /dev/null and b/miracl/.DS_Store differ diff --git a/miracl/CMakeLists.txt b/miracl/CMakeLists.txt new file mode 100644 index 0000000..f985024 --- /dev/null +++ b/miracl/CMakeLists.txt @@ -0,0 +1,104 @@ +cmake_minimum_required(VERSION 3.21) +project(Miracl) + +include(GNUInstallDirs) + +set(SOURCE_FILES source/mrcore.c source/mrarth0.c source/mrarth1.c + source/mrarth2.c source/mralloc.c source/mrsmall.c source/mrio1.c + source/mrio2.c source/mrgcd.c source/mrjack.c source/mrxgcd.c + source/mrarth3.c source/mrbits.c source/mrrand.c source/mrprime.c + source/mrcrt.c source/mrscrt.c source/mrmonty.c source/mrpower.c + source/mrsroot.c source/mrcurve.c source/mrfast.c source/mrshs.c + source/mrshs256.c source/mrshs512.c source/mrsha3.c source/mrfpe.c + source/mraes.c source/mrgcm.c source/mrlucas.c source/mrzzn2.c + source/mrzzn2b.c source/mrzzn3.c source/mrzzn4.c source/mrecn2.c + source/mrstrong.c source/mrbrick.c source/mrebrick.c source/mrec2m.c + source/mrgf2m.c source/mrflash.c source/mrfrnd.c source/mrdouble.c + source/mrround.c source/mrbuild.c source/mrflsh1.c source/mrpi.c + source/mrflsh2.c source/mrflsh3.c source/mrflsh4.c) + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) # X64 or aarch64 + message(STATUS "MIRACL: 64-bit build") + set(MIRDEF_SUFFIX "h64") + if(MSVC) + set(MRMULDV_SUFFIX "w64") + set(DIR_FLAG "win64") + elseif(MINGW) + set(MIRDEF_SUFFIX "mgwn") + set(DIR_FLAG "win64") + set(MRMULDV_SUFFIX "g64") + else() + if(APPLE) + set(DIR_FLAG "macOS") + set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "" FORCE) + elseif(WIN32) + set(DIR_FLAG "win64") + else() + set(DIR_FLAG "linux64") + endif() + set(MRMULDV_SUFFIX "g64") + endif() +else() + message(STATUS "MIRACL: 32-bit build") + set(MIRDEF_SUFFIX "h32") + if(MSVC) + set(MRMULDV_SUFFIX "c") + set(DIR_FLAG "win32") + else() + if(APPLE) + set(DIR_FLAG "OSX") + set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE STRING "" FORCE) + elseif(WIN32) + set(DIR_FLAG "win32") + else() + set(DIR_FLAG "linux32") + endif() + set(MRMULDV_SUFFIX "gcc") + endif() +endif() + + +file(GLOB HEADER_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/include include/*.h) +foreach(HEADER_FILE ${HEADER_FILES}) + file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/include/${HEADER_FILE} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/${DIR_FLAG}/include) + list(APPEND SOURCE_FILES ${CMAKE_CURRENT_BINARY_DIR}/${DIR_FLAG}/include/${HEADER_FILE}) +endforeach() +file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/include/mirdef.${MIRDEF_SUFFIX}" + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/${DIR_FLAG}/include) +file(RENAME ${CMAKE_CURRENT_BINARY_DIR}/${DIR_FLAG}/include/mirdef.${MIRDEF_SUFFIX} + ${CMAKE_CURRENT_BINARY_DIR}/${DIR_FLAG}/include/mirdef.h) +list(APPEND SOURCE_FILES "${CMAKE_CURRENT_BINARY_DIR}/${DIR_FLAG}/include/mirdef.h") + +file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/source/mrmuldv.${MRMULDV_SUFFIX}" + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/${DIR_FLAG}/source) +file(RENAME ${CMAKE_CURRENT_BINARY_DIR}/${DIR_FLAG}/source/mrmuldv.${MRMULDV_SUFFIX} + ${CMAKE_CURRENT_BINARY_DIR}/${DIR_FLAG}/source/mrmuldv.c) +list(APPEND SOURCE_FILES "${CMAKE_CURRENT_BINARY_DIR}/${DIR_FLAG}/source/mrmuldv.c") + +# 生成静态库 +add_library(${PROJECT_NAME} STATIC ${SOURCE_FILES}) + +target_include_directories(${PROJECT_NAME} PUBLIC +    ${CMAKE_CURRENT_BINARY_DIR}/${DIR_FLAG}/include +) + +if(MIRACL_INSTALL_BINDIR) + set(CMAKE_INSTALL_BINDIR ${MIRACL_INSTALL_BINDIR}) +endif() + +if(MIRACL_INSTALL_LIBDIR) + set(CMAKE_INSTALL_LIBDIR ${MIRACL_INSTALL_LIBDIR}) +endif() + +if(MIRACL_INSTALL_INCLUDEDIR) + set(CMAKE_INSTALL_INCLUDEDIR ${MIRACL_INSTALL_INCLUDEDIR}) +endif() + +install(TARGETS ${PROJECT_NAME} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) + +file(GLOB HEADER_FILES ${CMAKE_CURRENT_BINARY_DIR}/${DIR_FLAG}/include/*.h) +install(FILES ${HEADER_FILES} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/miracl/README.md b/miracl/README.md new file mode 100644 index 0000000..db6eeea --- /dev/null +++ b/miracl/README.md @@ -0,0 +1,72 @@ +MIRACL +====== +What is MIRACL? +Multiprecision Integer and Rational Arithmetic Cryptographic Library – the MIRACL Crypto SDK – is a C software library that is widely regarded by developers as the gold standard open source SDK for elliptic curve cryptography (ECC). + +Why is it different? +While many other cryptographic SDKs are focused on PC use, MIRACL also enables developers to build security into highly constrained environments, including embedded, mobile apps and SCADA. + +Full documentation can be accessed here: + + +

MIRACL enables

+ +
    +
  • Reduced program code
  • +
  • Greatly simplified program development
  • +
  • Developer-designed APIs
  • +
  • Rapid implementation, using inline code wrappers, example programs and other innovations
  • +
+ +These unique qualities are the reason MIRACL, and the solutions and services built using it, are in use in hundreds of organizations across the world, including BAE Systems, Hitachi, Intel, Panasonic, Toyota and many others. + +

Features and Benefits: why MIRACL is the right choice

+MIRACL delivers a wide and unique range of benefits, enabling developers to secure even the most constrained environments quickly, easily and effectively. It features, amongst others: + +
    +
  • An inline C++ wrapper – greatly simplifying program development
  • +
  • Over 25 example programs in C and C++, covering a wide range of applications, to give development a head start
  • +
  • Optimization of both embedded processors and RAM, to help developers overcome device and memory constraints
  • +
  • Compatibility with industry security technologies including AES encryption, RSA public key cryptography, Diffie-Hellman key exchange, DSA digital signature, and others
  • +
  • A set of tools that enable any new number-theoretic technique to be implemented quickly
  • +
+ +The MIRACL library consists of well over 100 routines that cover all aspects of multi-precision arithmetic. Two new data-types are defined - big for large integers and flash (short for floating-slash) for large rational numbers. The large integer routines are based on Knuth’s algorithms, described in Chapter 4 of his classic work ‘The Art of Computer Programming’. Floating-slash arithmetic, which works with rounded fractions, was originally proposed by D. Matula and P. Kornerup. All routines have been thoroughly optimised for speed and efficiency, while at the same time remaining standard, portable C. However optional fast assembly language alternatives for certain time-critical routines are also included, particularly for the popular Intel 80x86 range of processors. A C++ interface is also provided. Full source code is included. + +

Bug Tracker

+ MIRACL Ltd. uses JIRA for bug and feature tracking which is integrated with our development system.   If you find a bug, you should report bugs into the MIRACL bug tracker .  You can check that the bug hasn't already been reported by searching for it. If you find the bug already reported, you can add a comment of your own about it, or change its status to "Confirmed". If the bug hasn't been reported, you can file a new bug report.

+

Community

+ MIRACL Ltd. is most of all a community of like-minded information security professionals who believe that cryptography is a necessary tool to advance individual freedom and safeguard privacy. MIRACL Ltd. acts on that belief by providing tools that can be used to secure information, guard privacy and advance individual freedom.
+ Anyone who uses MIRACL Ltd. code or services is part of this global community, and we invite you to help shape MIRACL to better meet your needs. To make it yours!
+ Keep track of development and community news.

+ +

Contributing:

+ MIRACL Ltd. provides an Open Source suite of solutions for data security.  The MIRACL Ltd. team firmly believes that our solutions and the organizations and users who benefit by them all derive value from active contributions from the community.
+ You can contribute to help shape and improve our MIRACL Ltd. products.  If you have ideas and suggestions on new features and improvements that you would like to see and help bring to MIRACL Ltd., please fork the public available code on GitHub. +

Authors:

+ MIRACL Ltd.

+ + +

Copyright and License:

+

© 2018 MIRACL UK Ltd., All Rights Reserved.

+

MIRACL SDK provides developers with an extensive and efficient set of cryptographic functions. For further information about its features and functionalities please refer to https://miracl.com.

+

MIRACL SDK is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

+

MIRACL SDK is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.

+

You can be released from the requirements of the license by purchasing a commercial license. Buying such a license is mandatory as soon as you develop commercial activities involving MIRACL without disclosing the source code of your own applications, or shipping MIRACL with a closed source product.

+

For full details regarding our MIRACL Ltd. terms of service please refer to the following links:

+ diff --git a/miracl/aesgcm.txt b/miracl/aesgcm.txt new file mode 100644 index 0000000..0112f5d --- /dev/null +++ b/miracl/aesgcm.txt @@ -0,0 +1,22 @@ +There is a new simple implementation of the AES-GCM Encryption/Authentication mode. +See new module mrgcm.c +To test uncomment example program at the bottom of mrgcm.c and link with mraes.c + +This version is not the fastest possible, but it does use only +a small amount of memory. Only 2k bytes of RAM are required for +precomputed tables. + +Some restrictions.. +1. Only for use with AES +2. 96-bit IV only supported +3. Returned tag is always 128-bits. Truncate at your own risk. +4. The order of function calls must follow some rules + +Typical sequence of calls.. +1. call gcm_init +2. call gcm_add_header any number of times, as long as length of header is multiple of 16 bytes (block size) +3. call gcm_add_header one last time with any length of header +4. call gcm_add_cipher any number of times, as long as length of cipher/plaintext is multiple of 16 bytes +5. call gcm_add_cipher one last time with any length of cipher/plaintext +6. call gcm_finish to extract the tag. +See full description at http://www.mindspring.com/~dmcgrew/gcm-nist-6.pdf diff --git a/miracl/amd64.txt b/miracl/amd64.txt new file mode 100644 index 0000000..7a43960 --- /dev/null +++ b/miracl/amd64.txt @@ -0,0 +1,187 @@ + +AMD64 processor now fully supported using Intel GCC Compiler + +Use a header file like + +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype long +#define MR_IBITS 32 +#define MR_LBITS 64 +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned long +#define MR_FLASH 52 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define BITSINCHAR 8 + +and use assembly language file mrmuldv.s64 + +Note that the above header file assumes an LP64-compatible compiler. +For an LLP64 compiler, change mr_utype to a 64-bit "long long" or __int64 + +To build the miracl library, extract below into a file "amd64" and execute + +bash amd64 + + +------------------------------- + +rm miracl.a +gcc -c -m64 -O2 mrcore.c +gcc -c -m64 -O2 mrarth0.c +gcc -c -m64 -O2 mrarth1.c +gcc -c -m64 -O2 mrarth2.c +gcc -c -m64 -O2 mralloc.c +gcc -c -m64 -O2 mrsmall.c +gcc -c -m64 -O2 mrio1.c +gcc -c -m64 -O2 mrio2.c +gcc -c -m64 -O2 mrgcd.c +gcc -c -m64 -O2 mrjack.c +gcc -c -m64 -O2 mrxgcd.c +gcc -c -m64 -O2 mrarth3.c +gcc -c -m64 -O2 mrbits.c +gcc -c -m64 -O2 mrrand.c +gcc -c -m64 -O2 mrprime.c +gcc -c -m64 -O2 mrcrt.c +gcc -c -m64 -O2 mrscrt.c +gcc -c -m64 -O2 mrmonty.c +gcc -c -m64 -O2 mrpower.c +gcc -c -m64 -O2 mrsroot.c +gcc -c -m64 -O2 mrcurve.c +gcc -c -m64 -O2 mrfast.c +gcc -c -m64 -O2 mrshs.c +gcc -c -m64 -O2 mrshs256.c +gcc -c -m64 -O2 mrshs512.c +gcc -c -m64 -O2 mrsha3.c +gcc -c -m64 -O2 mrfpe.c +gcc -c -m64 -O2 mraes.c +gcc -c -m64 -O2 mrgcm.c +gcc -c -m64 -O2 mrlucas.c +gcc -c -m64 -O2 mrzzn2.c +gcc -c -m64 -O2 mrzzn2b.c +gcc -c -m64 -O2 mrzzn3.c +gcc -c -m64 -O2 mrzzn4.c +gcc -c -m64 -O2 mrecn2.c +gcc -c -m64 -O2 mrstrong.c +gcc -c -m64 -O2 mrbrick.c +gcc -c -m64 -O2 mrebrick.c +gcc -c -m64 -O2 mrec2m.c +gcc -c -m64 -O2 mrgf2m.c +gcc -c -m64 -O2 mrflash.c +gcc -c -m64 -O2 mrfrnd.c +gcc -c -m64 -O2 mrdouble.c +gcc -c -m64 -O2 mrround.c +gcc -c -m64 -O2 mrbuild.c +gcc -c -m64 -O2 mrflsh1.c +gcc -c -m64 -O2 mrpi.c +gcc -c -m64 -O2 mrflsh2.c +gcc -c -m64 -O2 mrflsh3.c +gcc -c -m64 -O2 mrflsh4.c +cp mrmuldv.g64 mrmuldv.c +gcc -c -m64 -O2 mrmuldv.c +ar rc miracl.a mrcore.o mrarth0.o mrarth1.o mrarth2.o mralloc.o mrsmall.o mrzzn2.o mrzzn3.o +ar r miracl.a mrio1.o mrio2.o mrjack.o mrgcd.o mrxgcd.o mrarth3.o mrbits.o mrecn2.o mrzzn4.o +ar r miracl.a mrrand.o mrprime.o mrcrt.o mrscrt.o mrmonty.o mrcurve.o mrsroot.o mrzzn2b.o +ar r miracl.a mrpower.o mrfast.o mrshs.o mrshs256.o mraes.o mrlucas.o mrstrong.o mrgcm.o +ar r miracl.a mrflash.o mrfrnd.o mrdouble.o mrround.o mrbuild.o +ar r miracl.a mrflsh1.o mrpi.o mrflsh2.o mrflsh3.o mrflsh4.o +ar r miracl.a mrbrick.o mrebrick.o mrec2m.o mrgf2m.o mrmuldv.o mrshs512.o mrsha3.o mrfpe.o +gcc -I. -O2 factor.c miracl.a -lm -o factor +rm mr*.o + +---------------------------------------------------- + +There is also a macro file amd64.mcs - see kcmcomba.txt and makemcs.txt + + +For example use the following to build a very fast version of ake12t.cpp + +( But first change + +Miracl precision(8,0); + +to + +Miracl precision(4,0); + +And execute + +mex 4 amd64 mrcomba + +to create the module mrcomba.c ) + +/* + AMD64 mirdef.h file + optimized for a 256 (=4x64) bit modulus, using COMBA method +*/ +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype long +#define MR_IBITS 32 +#define MR_LBITS 64 +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned long +#define MR_ALWAYS_BINARY +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_COMBA 4 + +rm *.exe +rm *.lib +rm miracl.a +gcc -I. -c -O2 mrcore.c +gcc -I. -c -O2 mrarth0.c +gcc -I. -c -O2 mrarth1.c +gcc -I. -c -O2 mrarth2.c +gcc -I. -c -O2 mralloc.c +gcc -I. -c -O2 mrsmall.c +gcc -I. -c -O2 mrio1.c +gcc -I. -c -O2 mrio2.c +gcc -I. -c -O2 mrgcd.c +gcc -I. -c -O2 mrjack.c +gcc -I. -c -O2 mrxgcd.c +gcc -I. -c -O2 mrarth3.c +gcc -I. -c -O2 mrbits.c +gcc -I. -c -O2 mrrand.c +gcc -I. -c -O2 mrprime.c +gcc -I. -c -O2 mrcrt.c +gcc -I. -c -O2 mrscrt.c +gcc -I. -c -O2 mrmonty.c +gcc -I. -c -O2 mrpower.c +gcc -I. -c -O2 mrsroot.c +gcc -I. -c -O2 mrcurve.c +gcc -I. -c -O2 mrfast.c +gcc -I. -c -O2 mrshs.c +gcc -I. -c -O2 mrshs256.c +gcc -I. -c -O2 mrshs512.c +gcc -I. -c -O2 mraes.c +gcc -I. -c -O2 mrgcm.c +gcc -I. -c -O2 mrlucas.c +gcc -I. -c -O2 mrzzn2.c +gcc -I. -c -O2 mrstrong.c +gcc -I. -c -O2 mrbrick.c +gcc -I. -c -O2 mrebrick.c +gcc -I. -c -O2 mrec2m.c +gcc -I. -c -O2 mrgf2m.c +gcc -I. -c -O2 mrecn2.c +gcc -I. -c -O2 mrzzn4.c +gcc -I. -c -O2 mrzzn2b.c +gcc -I. -c -O2 mrcomba.c + +as mrmuldv.s64 -o mrmuldv.o +ar rc miracl.a mrcore.o mrarth0.o mrarth1.o mrarth2.o mralloc.o mrsmall.o mrzzn2.o +ar r miracl.a mrio1.o mrio2.o mrjack.o mrgcd.o mrxgcd.o mrarth3.o mrbits.o mrgcm.o +ar r miracl.a mrrand.o mrprime.o mrcrt.o mrscrt.o mrmonty.o mrcurve.o mrsroot.o +ar r miracl.a mrpower.o mrfast.o mrshs.o mrshs256.o mraes.o mrlucas.o mrstrong.o +ar r miracl.a mrbrick.o mrebrick.o mrec2m.o mrgf2m.o mrmuldv.o mrshs512.o mrcomba.o +ar r miracl.a mrecn2.o mrzzn4.o mrzzn2b.o +rm mr*.o + +g++ -I. -c -O2 -DZZNS=4 zzn.cpp +g++ -I. -c -O2 -DZZNS=4 big.cpp +g++ -I. -c -O2 -DZZNS=4 zzn12a.cpp +g++ -I. -c -O2 -DZZNS=4 zzn4.cpp +g++ -I. -c -O2 -DZZNS=4 zzn2.cpp +g++ -I. -c -O2 -DZZNS=4 ecn2.cpp +g++ -I. -c -O2 -DZZNS=4 ecn.cpp +g++ -I. -O2 -DZZNS=4 ake12bnx.cpp zzn12a.o zzn4.o zzn2.o ecn2.o ecn.o zzn.o big.o miracl.a -o ake12bnx diff --git a/miracl/arm.txt b/miracl/arm.txt new file mode 100644 index 0000000..87a239b --- /dev/null +++ b/miracl/arm.txt @@ -0,0 +1,219 @@ +If developing for the ARM, or indeed any other new processor, you should +first build a C-only library. + +For the ARM, this mirdef.h header would be appropriate for an integer- +only build of the library. + +-------------------------------------- + +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN + +/* or possibly +#define MR_BIG_ENDIAN +*/ + +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_dltype long long +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned long long +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + + +#define MR_NOASM + +--------------------------------------------- + +Assuming that the mirdef.h, miracl.h and mr*.c files are all in the same +directory, then a suitable batch file for building a MIRACL library might +look like this:- + +------------------------------- + +armcc -I. -c -O2 mrcore.c +armcc -I. -c -O2 mrarth0.c +armcc -I. -c -O2 mrarth1.c +armcc -I. -c -O2 mrarth2.c +armcc -I. -c -O2 mralloc.c +armcc -I. -c -O2 mrsmall.c +armcc -I. -c -O2 mrio1.c +armcc -I. -c -O2 mrio2.c +armcc -I. -c -O2 mrgcd.c +armcc -I. -c -O2 mrjack.c +armcc -I. -c -O2 mrbits.c +armcc -I. -c -O2 mrxgcd.c +armcc -I. -c -O2 mrarth3.c +armcc -I. -c -O2 mrrand.c +armcc -I. -c -O2 mrprime.c +armcc -I. -c -O2 mrcrt.c +armcc -I. -c -O2 mrscrt.c +armcc -I. -c -O2 mrmonty.c +armcc -I. -c -O2 mrpower.c +armcc -I. -c -O2 mrsroot.c +armcc -I. -c -O2 mrcurve.c +armcc -I. -c -O2 mrfast.c +armcc -I. -c -O2 mrshs.c +armcc -I. -c -O2 mrshs256.c +armcc -I. -c -O2 mrshs512.c +armcc -I. -c -O2 mraes.c +armcc -I. -c -O2 mrgcm.c +armcc -I. -c -O2 mrlucas.c +armcc -I. -c -O2 mrstrong.c +armcc -I. -c -O2 mrbrick.c +armcc -I. -c -O2 mrebrick.c +armcc -I. -c -O2 mrgf2m.c +armcc -I. -c -O2 mrec2m.c +armcc -I. -c -O2 mrzzn2.c +armcc -I. -c -O2 mrzzn2b.c +armcc -I. -c -O2 mrzzn3.c +armcc -I. -c -O2 mrecn2.c +armar -rc miracl.a mrcore.o mrarth0.o mrarth1.o mrarth2.o mralloc.o mrsmall.o +armar -r miracl.a mrio1.o mrio2.o mrjack.o mrgcd.o mrxgcd.o mrarth3.o mrgcm.o +armar -r miracl.a mrrand.o mrprime.o mrcrt.o mrscrt.o mrmonty.o mrcurve.o +armar -r miracl.a mrfast.o mrshs.o mraes.o mrlucas.o mrstrong.o mrbrick.o +armar -r miracl.a mrebrick.o mrec2m.o mrgf2m.o mrpower.o mrsroot.o mrzzn2b.o +armar -r miracl.a mrshs256.o mrshs512.o mrbits.o mrzzn2.o mrzzn3.o mrecn2.o +del mr*.o +armcc -I. -c pk-demo.c +armlink pk-demo.o miracl.a -o pk-demo.axf + +-------------------------------------------- + +This may be fast enough for you. If its not you can use the assembly language +macros provided in arm.mcs or gccarm.mcs for greater speed. See kcmcomba.txt. + +For faster RSA and DH implementations replace the MR_NOASM definition with +MR_KCM n (where n is usually 4, 8 or 16 - experiment. n*MIRACL must divide the +modulus size in bits exactly, which it will for standard moduli of 1024 bit +for example). Compile and run the utility mex.c + +c:\miracl>mex n arm mrkcm + +(Yes its the same n). Rebuild the MIRACL library, but this time include the +modules mrkcm.c and mrmuldv.c (you can find the latter in mrmuldv.ccc This +standard C version will do.) + +For fast GF(p) elliptic curves, replace MR_NOASM with MR_COMBA n. This time +32*n is exactly the size of p in bits (assuming 32-bit processor). + +This approach is also optimal for 1024-bit RSA decryption using the Chinese +Remainder Theorem. Set n=16 (512=16*32) + +c:\miracl>mex n arm mrcomba + +Rebuild the MIRACL library, but this time include the modules mrcomba.c and +mrmuldv.c. + +Still not fast enough? If the prime p is of a "special" form for an Elliptic +curve, define in mirdef.h MR_SPECIAL. Edit mrcomba.tpl to insert "special" code +for modular reduction - its quite easy and you will find examples there +already. Run mex as before, and rebuild MIRACL again. + + +See ecdhp32.c for a worked example. + + +For processors other than the ARM, the basic procedure is the same. A C-only +build is always possible. To go faster you will need to create a .mcs file +for your processor, and then you can proceed as above. + +An alternative is to do a C-only build and then go in and optimise the +generated assembly language. The time-critical routines are usually +multiply() and redc() which can be found in mrarth2.c and mrmonty.c + +This will probably not be as fast as the highly optimised approach outlined +above. + + +NOTE: There is a nasty ARM compiler bug in the version I am using. It can +cause problems, if for example using the C-only macros from c.mcs or c1.mcs + +Use this program to illustrate the bug, or to see if your Compiler is +affected. + +/* Short program to illustrate ARM compiler bug + works fine with -O0, gets wrong answer for -O1 and -O2 optimization + Answer should be 0xffffffff00000001 but it gets 0x1 +*/ + +#include + +int main() +{ + unsigned long long x; + unsigned long a,b; + a=0; + b=0xFFFFFFFF; + x=(unsigned long long)a-b; + printf("x= %llx\n",x); + return 0; +} + + +Another problem may arise with systems that do not fully support unsigned long +long arithmetic (you may be getting linker errors with names like __udivdi3 +functions not found). In this case for a C only build delete the #define +MR_NOASM from mirdef.h and use the blakely-sloan versions of mrmuldiv and +mrmuldvm with the standard versions of mrmuldvd and mrmuldvd2 (from +mrmuldv.ccc) to create a file mrmuldv.c which should then be included in the +library. Also insert an #undef mr_dltype at the start of mrxgcd.c + + +If using GCC under winARM to build ARM application, try this example + +/* Header mirdef.h */ + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_dltype long long +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned long long +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 6 +#define MR_STATIC 6 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MR_SPECIAL +#define MR_NO_STANDARD_IO +#define MR_NO_FILE_IO + + +/* batch file */ + +mex 6 gccarm mrcomba +copy mrmuldv.ccc mrmuldv.c +arm-elf-gcc -I. -c -O2 mrcore.c +arm-elf-gcc -I. -c -O2 mrarth0.c +arm-elf-gcc -I. -c -O2 mrarth1.c +arm-elf-gcc -I. -c -O2 mrarth2.c +arm-elf-gcc -I. -c -O2 mrsmall.c +arm-elf-gcc -I. -c -O2 mrjack.c +arm-elf-gcc -I. -c -O2 mrbits.c +arm-elf-gcc -I. -c -O2 mrxgcd.c +arm-elf-gcc -I. -c -O2 mrmonty.c +arm-elf-gcc -I. -c -O2 mrsroot.c +arm-elf-gcc -I. -c -O2 mrcurve.c +arm-elf-gcc -I. -c -O2 mrlucas.c +arm-elf-gcc -I. -c -O2 mrebrick.c +arm-elf-gcc -I. -O2 -c mrcomba.c +arm-elf-gcc -I. -c -O2 mrmuldv.c + +arm-elf-ar -rc miracl.a mrcore.o mrarth0.o mrarth1.o mrarth2.o mrsmall.o +arm-elf-ar -r miracl.a mrjack.o mrxgcd.o +arm-elf-ar -r miracl.a mrmonty.o mrcurve.o +arm-elf-ar -r miracl.a mrebrick.o mrsroot.o mrlucas.o +arm-elf-ar -r miracl.a mrbits.o mrcomba.o mrmuldv.o +del mr*.o +arm-elf-gcc -I. --debug -c ecdhp.c +arm-elf-ld ecdhp.o miracl.a libgcc.a -lc -lm -o ecdhp.axf diff --git a/miracl/blackfin.txt b/miracl/blackfin.txt new file mode 100644 index 0000000..ba7e769 --- /dev/null +++ b/miracl/blackfin.txt @@ -0,0 +1,14 @@ + +A good starting point with this processor is the example program ecdh2m.c + +This runs "out-of-the-box", with no modifications required, on the +VisualDSP++ simulator. Takes about 17 Million clock cycles (release mode) +to complete both sides of a Diffie-Hellman key exchange using C-only code. + +The Blackfin is a 16/32 bit processor. For GF(2^m) applications it is best +considered 32-bit, but over GF(p) it is probably best to consider it as a +16-bit processor. + +There is a macro file blackfin.mcs which can be used to build the application +ecdhp16.c using VisualDSP++. Takes about 9 Million clock cycles to complete +both sides of a Diffie-Hellman key exchange. diff --git a/miracl/borland.txt b/miracl/borland.txt new file mode 100644 index 0000000..baf2a21 --- /dev/null +++ b/miracl/borland.txt @@ -0,0 +1,40 @@ +You have just downloaded the "free" and excellent Borland Compiler from +www.borland.com, and you want to compile the MIRACL library and create some +applications. If so, read on.... + +If you have the TASM assembler (which is not free) then unzip all the MIRACL +files into one directory, read the comments at the start of bc32doit.bat +and if happy execute the batch file. Some example commands to build some +representative applications are at the end of the batch file. + +If you don't have TASM then you can still build a C-only library (which will +be slower). Proceed as follows.. + +1. Unzip MIRACL into a single directory - do not tick the Use Folder Names + box if using WinZip + +2. Use this header for mirdef.h. Note that Borland now supports a 64-bit data + type called __int64 (compatible with Microsoft C) + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype __int64 +#define mr_unsign64 unsigned __int64 +#define MR_NOASM +#define MR_FLASH 52 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + + +3. Copy all the miracl header files into the directory where Borland C + puts its standard headers. This may be c:\borland\bcc55\include + +4. Edit bc32doit.bat. Read the comments at the start. Remove all -B compiler + flags (these invoke TASM, and you haven't got TASM). + Delete all references to mrmuldv.c + +5. Run the batch file. + diff --git a/miracl/config.c b/miracl/config.c new file mode 100644 index 0000000..f8fec51 --- /dev/null +++ b/miracl/config.c @@ -0,0 +1,1086 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL utility program to automatically generate a mirdef.h file + * + * config.c + * + * Compile WITHOUT any optimization + * + * Run this with your computer/compiler configuration. It will + * attempt to create best-fit mirdef.h file for compiling the MIRACL + * library. + * + * Generated are mirdef.tst - the suggested mirdef.h file, and + * miracl.lst which tells which modules should be included in the library + * build. + */ + +#include +#include +#include + +static int answer(void) +{ + char ch; + scanf("%c",&ch); + getchar(); + if (ch=='Y' || ch=='y') return 1; + return 0; +} + +int main() +{ + int chosen,chosen2,utlen,dllen,flsh,stripped,standard,nofull,port,mant,r,userlen; + int nbits,i,b,dlong,threaded,choice,selected,special,sb,ab; + int chosen64,no64,step_size,double_type,rounding,lmant,dmant,static_build,maxsize; + int maxbase,bitsinchar,llsize,nio,edwards,double_length_type; + int qlong,qllen; + long end; + unsigned char byte; + char *ptr; + char longlong[20]; + double s,magic; + double x,y,eps; + long double lx,ly,leps; + FILE *fp,*fpl; + + bitsinchar=0; + byte=1; + while (byte!=0) {byte<<=1; bitsinchar++;} + + printf("This program attempts to generate a mirdef.h file from your\n"); + printf("responses to some simple questions, and by some internal tests\n"); + printf("of its own.\n\n"); + printf("The most fundamental decision is that of the 'underlying type'\n"); + printf("that is the C data type to be used to store each digit of a\n"); + printf("big number. You input the number of bits in this type, and \n"); + printf("this program finds a suitable candidate (usually short, int or \n"); + printf("long). Typical values would be 16, 32 or perhaps 64. \n"); + printf("The bigger the better, but a good starting point would be to\n"); + printf("enter the native wordlength of your computer\n\n"); + printf("For your information:-\n"); + printf("The size of a char is %d bits\n",bitsinchar); + printf("The size of a short is %d bits\n",bitsinchar*sizeof(short)); + printf("The size of an int is %d bits\n",bitsinchar*sizeof(int)); + printf("The size of a long is %d bits\n",bitsinchar*sizeof(long)); + + eps=1.0; + for (dmant=0;;dmant++) + { /* IMPORTANT TO FOOL OPTIMIZER!!!!!! */ + x=1.0+eps; + y=1.0; + if (x==y) break; + eps/=2.0; + } + + printf("The size of a double is %d bits, its mantissa is %d bits\n",bitsinchar*sizeof(double),dmant); + + leps=1.0; + for (lmant=0;;lmant++) + { /* IMPORTANT TO FOOL OPTIMIZER!!!!!! */ + lx=1.0+leps; + ly=1.0; + if (lx==ly) break; + leps/=2.0; + } + printf("The size of a long double is %d bits, its mantissa is %d bits\n",bitsinchar*sizeof(long double),lmant); + + + fp=fopen("mirdef.tst","wt"); + fprintf(fp,"/*\n * MIRACL compiler/hardware definitions - mirdef.h\n */\n"); + end=1; + ptr=(char *)(&end); + + if ((*ptr) == 1) + { + printf("\n Little-endian processor detected\n\n"); + fprintf(fp,"#define MR_LITTLE_ENDIAN\n"); + } + else + { + printf(" Big-endian processor detected\n\n"); + fprintf(fp,"#define MR_BIG_ENDIAN\n"); + + } + printf("A double can be used as the underlying type. In rare circumstances\n"); + printf(" this may be optimal. NOT recommended!\n\n"); + + printf("Do you wish to use a double as the underlying type? (Y/N)?"); + double_type=answer(); + nofull=0; + chosen=0; + chosen64=0; + llsize=-1; /* no check for long long yet */ + no64=0; + if (double_type) + { + fprintf(fp,"#define MIRACL %d\n",bitsinchar*sizeof(double)); + fprintf(fp,"#define mr_utype double\n"); + fprintf(fp,"#define mr_dltype long double\n"); + fprintf(fp,"#define MR_NOFULLWIDTH\n"); + fprintf(fp,"#define MR_FP\n"); + nofull=1; + } + else + { + printf("\nNow enter number of bits in underlying type= "); + scanf("%d",&utlen); + getchar(); + printf("\n"); + if (utlen!=8 && utlen!=16 && utlen!=32 && utlen!=64) + { + printf("Non-standard system - this program cannot help!\n"); + fclose(fp); + exit(0); + } + + fprintf(fp,"#define MIRACL %d\n",utlen); + + if (utlen==bitsinchar) + { + printf(" underlying type is a char\n"); + fprintf(fp,"#define mr_utype char\n"); + chosen=1; + } + if (!chosen && utlen==bitsinchar*sizeof(short)) + { + printf(" underlying type is a short\n"); + fprintf(fp,"#define mr_utype short\n"); + chosen=1; + } + if (!chosen && utlen==bitsinchar*sizeof(int)) + { + printf(" underlying type is an int\n"); + fprintf(fp,"#define mr_utype int\n"); + chosen=1; + } + if (!chosen && utlen==bitsinchar*sizeof(long)) + { + printf(" underlying type is a long\n"); + fprintf(fp,"#define mr_utype long\n"); + chosen=1; + } + dlong=0; + if (!chosen && utlen==2*bitsinchar*sizeof(long)) + { + printf("\nDoes compiler support a %d bit unsigned type? (Y/N)?", + utlen); + dlong=answer(); + if (dlong) + { + llsize=utlen; /* there is a long long */ + printf("Is it called long long? (Y/N)?"); + if (!answer()) + { + printf("Enter its name : "); + scanf("%s",longlong); + getchar(); + } + else strcpy(longlong,"long long"); + printf(" underlying type is a %s\n",longlong); + fprintf(fp,"#define mr_utype %s\n",longlong); + chosen=1; + if (64==utlen && !chosen64) + { + printf(" 64 bit unsigned type is an unsigned %s\n",longlong); + fprintf(fp,"#define mr_unsign64 unsigned %s\n",longlong); + chosen64=1; + } + } + else + { + llsize=0; /* there is no long long */ + if (utlen==64) no64=1; /* there is no 64-bit type */ + } + } + + if (!chosen) + { + printf("No suitable underlying type could be found\n"); + fclose(fp); + exit(0); + } + } + + fprintf(fp,"#define MR_IBITS %d\n",bitsinchar*sizeof(int)); + fprintf(fp,"#define MR_LBITS %d\n",bitsinchar*sizeof(long)); + +/* Now try to find 32-bit unsigned types */ + + chosen=0; + if (32==bitsinchar*sizeof(unsigned short)) + { + printf(" 32 bit unsigned type is a unsigned short\n"); + fprintf(fp,"#define mr_unsign32 unsigned short\n"); + chosen=1; + } + if (!chosen && 32==bitsinchar*sizeof(unsigned int)) + { + printf(" 32 bit unsigned type is an unsigned int\n"); + fprintf(fp,"#define mr_unsign32 unsigned int\n"); + chosen=1; + } + if (!chosen && 32==bitsinchar*sizeof(long)) + { + printf(" 32 bit unsigned type is an unsigned long\n"); + fprintf(fp,"#define mr_unsign32 unsigned long\n"); + chosen=1; + } + + if (!chosen) + { + printf("No suitable 32 bit unsigned type could be found\n"); + fclose(fp); + exit(0); + } + +/* are some of the built-in types 64-bit? */ + + if (64==bitsinchar*sizeof(int)) + { + printf(" 64 bit unsigned type is an unsigned int\n"); + fprintf(fp,"#define mr_unsign64 unsigned int\n"); + chosen64=1; + } + if (!chosen64 && 64==bitsinchar*sizeof(long)) + { + printf(" 64 bit unsigned type is an unsigned long\n"); + fprintf(fp,"#define mr_unsign64 unsigned long\n"); + chosen64=1; + } + if (!chosen64 && llsize>0 && 64==llsize) + { + printf(" 64 bit unsigned type is a %s\n",longlong); + fprintf(fp,"#define mr_unsign64 %s\n",longlong); + chosen64=1; + } + +/* Now try to find a double length type */ + dlong=0; + dllen=0; + double_length_type=0; + if (!double_type) + { + dllen=2*utlen; + chosen=0; + if (!chosen && dllen==bitsinchar*sizeof(short)) + { + printf(" double length type is a short\n"); + fprintf(fp,"#define mr_dltype short\n"); + double_length_type=1; + if (sizeof(short)==sizeof(int)) fprintf(fp,"#define MR_DLTYPE_IS_INT\n"); + chosen=1; + } + if (!chosen && dllen==bitsinchar*sizeof(int)) + { + printf(" double length type is an int\n"); + fprintf(fp,"#define mr_dltype int\n"); + double_length_type=1; + fprintf(fp,"#define MR_DLTYPE_IS_INT\n"); + chosen=1; + } + if (!chosen && dllen==bitsinchar*sizeof(long)) + { + printf(" double length type is a long\n"); + fprintf(fp,"#define mr_dltype long\n"); + double_length_type=1; + fprintf(fp,"#define MR_DLTYPE_IS_LONG\n"); + chosen=1; + } + if (!chosen && llsize>0 && dllen==llsize) + { + printf(" double length type is a %s\n",longlong); + fprintf(fp,"#define mr_dltype %s\n",longlong); + double_length_type=1; + chosen=1; + } + if (!chosen && dllen==2*bitsinchar*sizeof(long)) + { + printf("\nDoes compiler support a %d bit integer type? (Y/N)?", + dllen); + dlong=answer(); + + if (dlong) + { + printf("Is it called long long? (Y/N)?"); + if (!answer()) + { + printf("Enter its name : "); + scanf("%s",longlong); + getchar(); + } + else strcpy(longlong,"long long"); + + printf(" double length type is a %s\n",longlong); + fprintf(fp,"#define mr_dltype %s\n",longlong); + double_length_type=1; + chosen=1; + if (64==dllen && !chosen64) + { + printf(" 64 bit unsigned type is an unsigned %s\n",longlong); + fprintf(fp,"#define mr_unsign64 unsigned %s\n",longlong); + chosen64=1; + } + } + else + { + if (dllen==64) no64=1; /* there is no 64-bit type */ + } + } + } + else dlong=1; + +/* Now try to find a double length type */ + qlong=0; + + if (!double_type) + { + qllen=4*utlen; + chosen2=0; + + if (!chosen2 && qllen==bitsinchar*sizeof(long)) + { + printf(" quad length type is a long\n"); + fprintf(fp,"#define mr_qltype long\n"); + chosen2=1; + } + if (!chosen2 && llsize>0 && dllen==llsize) + { + printf(" quad length type is a %s\n",longlong); + fprintf(fp,"#define mr_qltype %s\n",longlong); + chosen2=1; + } + if (!chosen2 && qllen==2*bitsinchar*sizeof(long)) + { + printf("\nDoes compiler support a %d bit integer type? (Y/N)?", + qllen); + qlong=answer(); + + if (qlong) + { + printf("Is it called long long? (Y/N)?"); + if (!answer()) + { + printf("Enter its name : "); + scanf("%s",longlong); + getchar(); + } + else strcpy(longlong,"long long"); + + printf(" quad length type is a %s\n",longlong); + fprintf(fp,"#define mr_qltype %s\n",longlong); + chosen2=1; + if (64==qllen && !chosen64) + { + printf(" 64 bit unsigned type is an unsigned %s\n",longlong); + fprintf(fp,"#define mr_unsign64 unsigned %s\n",longlong); + chosen64=1; + } + } + else + { + if (qllen==64) no64=1; /* there is no 64-bit type */ + } + } + } + else qlong=1; + + + if (!no64 && !chosen64) + { /* Still no 64-bit type, but not ruled out either */ + printf("\nDoes compiler support a 64-bit integer type? (Y/N)?"); + dlong=answer(); + + if (dlong) + { + printf("Is it called long long? (Y/N)?"); + if (!answer()) + { + printf("Enter its name : "); + scanf("%s",longlong); + getchar(); + } + else strcpy(longlong,"long long"); + + printf(" 64-bit type is a %s\n",longlong); + fprintf(fp,"#define mr_unsign64 unsigned %s\n",longlong); + chosen64=1; + } + } + + fpl=fopen("miracl.lst","wt"); + ab=0; + static_build=0; + if (!double_type) + { + printf("\nFor very constrained environments it is possible to build a version of MIRACL\n"); + printf("which does not require a heap. Not recommended for beginners.\n"); + printf("Some routines are not available in this mode and the max length of Big\n"); + printf("variables is fixed at compile time\n"); + printf("Do you want a no-heap version of the MIRACL C library? (Y/N)? "); + static_build=answer(); + if (static_build) + { + printf("Please enter the max size of your Big numbers in bits= "); + scanf("%d",&nbits); + getchar(); + maxsize=nbits/utlen; + if ((nbits%utlen)!=0) maxsize++; + fprintf(fp,"#define MR_STATIC %d\n",maxsize); + fprintf(fp,"#define MR_ALWAYS_BINARY\n"); + ab=1; + } + } + fprintf(fpl,"mrcore.c\n"); + fprintf(fpl,"mrarth0.c\n"); + fprintf(fpl,"mrarth1.c\n"); + fprintf(fpl,"mrarth2.c\n"); + fprintf(fpl,"mrsmall.c\n"); + fprintf(fpl,"mrio1.c\n"); + fprintf(fpl,"mrio2.c\n"); + fprintf(fpl,"mrgcd.c\n"); + fprintf(fpl,"mrjack.c\n"); + fprintf(fpl,"mrxgcd.c\n"); + fprintf(fpl,"mrarth3.c\n"); + fprintf(fpl,"mrbits.c\n"); + fprintf(fpl,"mrrand.c\n"); + fprintf(fpl,"mrprime.c\n"); + fprintf(fpl,"mrcrt.c\n"); + fprintf(fpl,"mrscrt.c\n"); + fprintf(fpl,"mrmonty.c\n"); + fprintf(fpl,"mrpower.c\n"); + fprintf(fpl,"mrsroot.c\n"); + fprintf(fpl,"mrlucas.c\n"); + fprintf(fpl,"mrshs.c\n"); + fprintf(fpl,"mrshs256.c\n"); + fprintf(fpl,"mraes.c\n"); + fprintf(fpl,"mrgcm.c\n"); + fprintf(fpl,"mrfpe.c\n"); + fprintf(fpl,"mrstrong.c\n"); + fprintf(fpl,"mrcurve.c\n"); + fprintf(fpl,"mrbrick.c\n"); + fprintf(fpl,"mrebrick.c\n"); + fprintf(fpl,"mrzzn2.c\n"); + fprintf(fpl,"mrzzn2b.c\n"); + fprintf(fpl,"mrzzn3.c\n"); + fprintf(fpl,"mrecn2.c\n"); + + if (!static_build) + { + fprintf(fpl,"mrfast.c\n"); + fprintf(fpl,"mralloc.c\n"); + } + if (chosen64) + { + fprintf(fpl,"mrshs512.c\n"); + fprintf(fpl,"mrsha3.c\n"); + } + port=0; + if (chosen && double_length_type) + { + printf("\nDo you want a C-only version of MIRACL (Y/N)?"); + port=answer(); + if (port) fprintf(fp,"#define MR_NOASM\n"); + } + rounding=0; + if (double_type) + { +#ifdef __TURBOC__ + rounding=1; +#endif +#ifdef _MSC_VER + rounding=1; +#endif +#ifdef __GNUC__ + rounding=1; +#endif + if (!rounding) + { + printf("It will help if rounding control can be exercised on doubles\n"); + printf("Can you implement this in mrarth1.c?? (Y/N)?"); + if (answer()) rounding=1; + } + if (rounding) + { + fprintf(fp,"#define MR_FP_ROUNDING\n"); + magic=1.0; + for (i=0;i32) + { + printf("Enter field size in bits = "); + scanf("%d",&nbits); + getchar(); + step_size=nbits/utlen; + if ((nbits%utlen)!=0) step_size++; + } + + printf("\nTo create the file MRCOMBA2.C you must next execute\n"); + if (port) printf("MEX %d C MRCOMBA2\n",step_size); + else + { + printf("MEX %d MRCOMBA2\n",step_size); + printf("where is the name of the macro .mcs file (e.g. smartmips)\n"); + } + + fprintf(fp,"#define MR_COMBA2 %d\n",step_size); + fprintf(fpl,"mrcomba2.c\n"); + + printf("\nSpecial routines for polynomial multiplication will now \n"); + printf("automatically be invoked \n"); + } + fprintf(fp,"#define MAXBASE ((mr_small)1<<(MIRACL-1))\n"); + } + else + { + if (!double_type) fprintf(fp,"#define MAXBASE ((mr_small)1<<(MIRACL-2))\n"); + } + + + printf("\nDo you wish to use the Karatsuba/Comba/Montgomery method\n"); + printf("for modular arithmetic - as used by exponentiation\n"); + printf("cryptosystems like RSA.\n"); + if (port) + { + printf("This method may be faster than the standard method when\n"); + printf("using larger moduli, or if your processor has no \n"); + printf("unsigned integer multiply/divide instruction in its\n"); + printf("instruction set. This is true of some popular RISC computers\n"); + } + else + { + printf("This method is probably fastest om most processors which\n"); + printf("which support unsigned mul and a carry flag\n"); + printf("NOTE: your compiler must support in-line assembly,\n"); + printf("and you must be able to supply a suitable .mcs file\n"); + printf("like, for example, ms86.mcs for pentium processors\n"); + } + printf("\nAnswer (Y/N)?"); + r=answer(); + if (r) + { + printf("\nThis method can only be used with moduli whose length in\n"); + printf("bits can be represented as %d*(step size)*2^n, for any value\n",utlen); + printf("of n. For example if you input a step size of 8, then \n"); + printf("moduli of 256, 512, 1024 bits etc will use this fast code\n"); + if (nofull) printf("(assuming a full-length base)\n"); + + if (port) + printf("In this case case a step size of about 4 is probably optimal\n"); + else + { + printf("The best step size can be determined by experiment, but\n"); + printf("larger step sizes generate more code. For the Pentium 8 is \n"); + printf("about optimal. For the Pentium Pro/Pentium II 16 is better.\n"); + if (!nofull) printf("If in doubt, set to 8\n"); + } + step_size=0; + while (step_size<2 || step_size>16) + { + printf("Enter step size = "); + scanf("%d",&step_size); + getchar(); + } + + printf("\nTo create the file MRKCM.C you must next execute\n"); + if (port) printf("MEX %d C MRKCM\n",step_size); + else + { + printf("MEX %d MRKCM\n",step_size); + printf("where is the name of the macro .mcs file (e.g. ms86)\n"); + } + + printf("\nSpecial routines for modular multiplication will now be\n"); + printf("automatically be invoked when, for example, powmod() is called\n"); + printf("\nRemember to use a full-width base in your programs\n"); + printf("by calling mirsys(..,0) or mirsys(..,256) at the start of the program\n"); + + fprintf(fp,"#define MR_KCM %d\n",step_size); + fprintf(fpl,"mrkcm.c\n"); + selected=1; + } + else + { + printf("\nDo you want to create a Comba fixed size modular\n"); + printf("multiplier, for faster modular multiplication with\n"); + printf("smaller moduli. Can generate a lot of code \n"); + printf("Useful particularly for Elliptic Curve cryptosystems over GF(p).\n"); + printf("\nAnswer (Y/N)?"); + r=answer(); + if (r) + { + step_size=0; + while (step_size<2 || step_size>32) + { + printf("Enter modulus size in bits = "); + scanf("%d",&nbits); + getchar(); + if (nofull) + { + printf("Enter base size in bits = "); + scanf("%d",&userlen); + getchar(); + } + else userlen=utlen; + step_size=nbits/userlen; + if ((nbits%userlen)!=0) step_size++; + } + if (!nofull && (nbits%utlen)==0) + { + printf("\nDo you wish to use a \"special\" fast method\n"); + printf("for modular reduction, for a particular modulus\n"); + printf("Two types are supported - Generalised Mersenne Primes\n"); + printf("also known as Solinas primes\n"); + printf("(many already supported - easy to add more - see mrcomba.tpl)\n"); + printf("and Pseudo Mersenne Primes (automatically supported)\n"); + printf("If in any doubt answer No (Y/N)?"); + r=answer(); + if (r) + { + special=1; + printf("\nIs your modulus a Generalized Mersenne Prime (Y/N)?"); + r=answer(); + if (r) special=1; + else + { + printf("\nIs your modulus a \"Pseudo Mersenne\" Prime of the form\n"); + printf("2^%d-c where c fits in a single word (Y/N)?",nbits); + r=answer(); + if (r) special=2; + } + } + } + printf("\nTo create the file MRCOMBA.C you must next execute\n"); + if (port) printf("MEX %d C MRCOMBA\n",step_size); + else + { + printf("MEX %d MRCOMBA\n",step_size); + printf("where is the name of the macro .mcs file (e.g. ms86)\n"); + } + + fprintf(fp,"#define MR_COMBA %d\n",step_size); + if (special) fprintf(fp,"#define MR_SPECIAL\n"); + if (special==1) fprintf(fp,"#define MR_GENERALIZED_MERSENNE\n"); + if (special==2) fprintf(fp,"#define MR_PSEUDO_MERSENNE\n"); + if (special) fprintf(fp,"#define MR_NO_LAZY_REDUCTION\n"); + + fprintf(fpl,"mrcomba.c\n"); + + printf("\nSpecial routines for modular multiplication will now \n"); + printf("automatically be invoked for this modulus\n"); + printf("\nRemember to use a full-width base in your programs\n"); + printf("by calling mirsys(..,0) or mirsys(,..,256) at the start of the program\n"); + selected=1; + } + + } + + + if (double_type) + { + maxbase=0; +#ifdef __TURBOC__ + if (!port && !selected) + { + printf("\nDoes your computer have a Pentium processor\n"); + printf("and do you wish to exploit its built-in FP coprocessor\n"); + printf("NOTE: this may not be optimal for Pentium Pro or Pentium II\n"); + printf("Supported only for 80x86 processors, and Borland C Compilers\n"); + printf("This is a little experimental - so use with care\n"); + printf("Answer (Y/N)?"); + r=answer(); + if (r) + { + printf("Enter (maximum) modulus size in bits = "); + scanf("%d",&nbits); + getchar(); + b=31; + do { + b--; + r=64-b-b; + s=1.0; + for (i=0;i=lmant) break; + s*=2.0; + } + fprintf(fp,"#define MAXBASE %lf\n",s); + } + } + fprintf(fp,"#define MR_BITSINCHAR %d\n",bitsinchar); + + printf("\nDo you want to save space by using a smaller but slightly slower \n"); + printf("AES implementation. Default to No. (Y/N)?"); + r=answer(); + if (r) + { + fprintf(fp,"#define MR_SMALL_AES\n"); + } + + edwards=0; + printf("\nDo you want to use Edwards paramaterization of elliptic curves over Fp\n"); + printf("This is faster for basic Elliptic Curve cryptography (but does not support\n"); + printf("Pairing-based Cryptography and some applications). Default to No. (Y/N)?"); + r=answer(); + if (r) + { + edwards=1; + fprintf(fp,"#define MR_EDWARDS\n"); + } + + if (!edwards) + { + printf("\nDo you want to save space by using only affine coordinates \n"); + printf("for elliptic curve cryptography. Default to No. (Y/N)?"); + r=answer(); + if (r) + { + fprintf(fp,"#define MR_AFFINE_ONLY\n"); + } + } + printf("\nDo you want to save space by not using point compression \n"); + printf("for EC(p) elliptic curve cryptography. Default to No. (Y/N)?"); + r=answer(); + if (r) + fprintf(fp,"#define MR_NOSUPPORT_COMPRESSION\n"); + + printf("\nDo you want to save space by not supporting special code \n"); + printf("for EC double-addition, as required for ECDSA signature \n"); + printf("verification, or any multi-addition of points. Default to No. (Y/N)?"); + r=answer(); + if (r) + fprintf(fp,"#define MR_NO_ECC_MULTIADD\n"); + + + printf("\nDo you want to save RAM by using a smaller sliding window \n"); + printf("for all elliptic curve cryptography. Default to No. (Y/N)?"); + r=answer(); + if (r) + fprintf(fp,"#define MR_SMALL_EWINDOW\n"); + + if (!special) + { + printf("\nDo you want to save some space by supressing Lazy Reduction? \n"); + printf("(as used for ZZn2 arithmetic). Default to No. (Y/N)?"); + r=answer(); + if (r) + fprintf(fp,"#define MR_NO_LAZY_REDUCTION\n"); + } + + printf("\nDo you NOT want to use the built in random number generator?\n"); + printf("Removing it saves space, and maybe you have your own source\n"); + printf("of randomness? Default to No. (Y/N)?"); + r=answer(); + if (r) + fprintf(fp,"#define MR_NO_RAND\n"); + + sb=0; + if (!nofull && ab) + { + printf("\nDo you want to save space by only using a simple number base?\n"); + printf("(the number base in mirsys(.) must be 0 or must divide 2^U\n"); + printf("exactly, where U is number of bits in the underlying type)\n"); + printf("NOTE: no number base changes possible\n"); + printf("Default to No. (Y/N)?"); + r=answer(); + if (r) + { + sb=1; + fprintf(fp,"#define MR_SIMPLE_BASE\n"); + } + } + if (sb) + { + printf("\nDo you want to save space by only using simple I/O? \n"); + printf("(Input from ROM, and Input/Output as binary bytes only) \n"); + printf("(However crude HEX-only output is supported) \n"); + printf("Default to No. (Y/N)?"); + r=answer(); + if (r) + fprintf(fp,"#define MR_SIMPLE_IO\n"); + } + + if (!double_type) + { + printf("\nDo you want to save space by NOT supporting KOBLITZ curves \n"); + printf("for EC(2^m) elliptic curve cryptography. Default to No. (Y/N)?"); + r=answer(); + if (r) + fprintf(fp,"#define MR_NOKOBLITZ\n"); + + printf("\nDo you want to save space by NOT supporting SUPERSINGULAR curves \n"); + printf("for EC(2^m) elliptic curve cryptography. Default to No. (Y/N)?"); + r=answer(); + if (r) + { + fprintf(fp,"#define MR_NO_SS\n"); + } + } + + printf("\nDo you want to enable a Double Precision big type. See doubig.txt\n"); + printf("for more information. Default to No. (Y/N)?"); + r=answer(); + if (r) + { + fprintf(fp,"#define MR_DOUBLE_BIG\n"); + } + + printf("\nDo you want to compile MIRACL as a C++ library, rather than a C library?\n"); + printf("Default to No. (Y/N)?"); + r=answer(); + if (r) + { + fprintf(fp,"#define MR_CPP\n"); + } + + printf("\nDo you want to avoid the use of compiler intrinsics?\n"); + printf("Default to No. (Y/N)?"); + r=answer(); + if (r) + { + fprintf(fp,"#define MR_NO_INTRINSICS\n"); + } + + if (!port) + { + if (!dlong) printf("\nYou must now provide an assembly language file mrmuldv.c,\n"); + else printf("\nYou must now provide an assembly or C file mrmuldv.c,\n"); + if (!nofull) + printf("containing implementations of muldiv(), muldvd(), muldvd2() and muldvm()\n"); + else + { + printf("containing an implementation of muldiv()\n"); + if (rounding) printf("..and imuldiv()\n"); + } + if (!dlong) + printf("Check mrmuldv.any - an assembly language version may be\n"); + else + printf("Check mrmuldv.any - a C or assembly language version is\n"); + printf("there already\n"); + + fprintf(fpl,"mrmuldv.c\n"); + + } + printf("\nA file mirdef.tst has been generated. If you are happy with it,\n"); + printf("rename it to mirdef.h and use for compiling the MIRACL library.\n"); + + printf("A file miracl.lst has been generated that includes all the \n"); + printf("files to be included in this build of the MIRACL library.\n"); + + fprintf(fpl,"\nCompile the above with -O2 optimization\n"); + if (threaded) + fprintf(fpl,"Also use appropriate flag for multi-threaded compilation\n"); + + if (!port) + { + fprintf(fpl,"Note that mrmuldv.c file may be pure assembly, so may \n"); + fprintf(fpl,"be renamed to mrmuldv.asm or mrmuldv.s, and assembled \n"); + fprintf(fpl,"rather than compiled\n"); + } + fclose(fp); + fclose(fpl); + + return 0; +} + diff --git a/miracl/cpp.txt b/miracl/cpp.txt new file mode 100644 index 0000000..ab1dfb0 --- /dev/null +++ b/miracl/cpp.txt @@ -0,0 +1,9 @@ +Although MIRACL is a C library, it can also be built as an entirely C++ library. +This can be quite convenient for general purpose use. Some of the common +C++ modules like big.cpp can now be included into the library. + +On 64-bit Windows using Microsoft C++, build using the batch file ms64doit_cpp.bat + +On 64-bit Linux build using "bash linux64_cpp" + +The same approach can be adopted on other platforms. diff --git a/miracl/cygwin.txt b/miracl/cygwin.txt new file mode 100644 index 0000000..e868941 --- /dev/null +++ b/miracl/cygwin.txt @@ -0,0 +1,22 @@ +It is quite easy to build MIRACL to work with Cygwin. + +Basically follow the intructions in linux.txt, except first + +(1) Copy mrmuldv.gcc to mrmuldv.c, and + +(2) Change the file linux to replace the line + +as mrmuldv.s -o mrmuldv.o + +with the line + +gcc -O2 -c mrmuldv.c + +Then build the library and applications as usual with + +$bash linux + +(Make sure that the file "linux" has the correct Unix file format +for CR/LF - not Windows format) + + diff --git a/miracl/devcpp.txt b/miracl/devcpp.txt new file mode 100644 index 0000000..c3848d4 --- /dev/null +++ b/miracl/devcpp.txt @@ -0,0 +1,96 @@ +To build an example application using the Dev-CPP development tool on a PC + + +Use this mirdef.h + +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype long long +#define mr_unsign64 unsigned long long +#define MR_NOASM +#define MR_FLASH 52 +#define MR_ALWAYS_BINARY +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 + + +Create a "Static Library" C project called miracl, and "Add to Project" this +mirdef.h, miracl.h, and all of these files + +mrcore.c +mrarth0.c +mrarth1.c +mrarth2.c +mrsmall.c +mrio1.c +mrio2.c +mrgcd.c +mrjack.c +mrxgcd.c +mrarth3.c +mrbits.c +mrrand.c +mrprime.c +mrcrt.c +mrscrt.c +mrmonty.c +mrpower.c +mrsroot.c +mrlucas.c +mrshs.c +mrshs256.c +mraes.c +mrgcm.c +mrstrong.c +mrcurve.c +mrbrick.c +mrebrick.c +mrzzn2.c +mrzzn2b.c +mrzzn3.c +mrecn2.c +mrfast.c +mralloc.c +mrshs512.c +mrflash.c +mrfrnd.c +mrdouble.c +mrround.c +mrbuild.c +mrflsh1.c +mrpi.c +mrflsh2.c +mrflsh3.c +mrflsh4.c +mrec2m.c +mrgf2m.c + +Compile this project to create the static library file miracl.a + +Close this project, and open a new C++ console application called demo. + +Remove the default main program main.cpp from the project, and "Add to Project" the files + +big.h +big.cpp +ecn.h +ecn.cpp +pk-demo.cpp + +Now click on "Project Options", and click on the "Parameters" Tab. +Then click on "Add Library or Object", and find the miracl.a file created earlier. + +Now compile and run the program. One problem - it runs very fast and then exits. So +edit pk-demo.cpp and and just before the final "return 0;" statement add the line "cin >> ia;" + +Now try again... + + diff --git a/miracl/docs/.DS_Store b/miracl/docs/.DS_Store new file mode 100644 index 0000000..3df39bf Binary files /dev/null and b/miracl/docs/.DS_Store differ diff --git a/miracl/docs/README.md b/miracl/docs/README.md new file mode 100644 index 0000000..250b57a --- /dev/null +++ b/miracl/docs/README.md @@ -0,0 +1,8 @@ +Crypto Library overview +--- + +Multiprecision Integer and Rational Arithmetic C Library (MIRACL) – the MIRACL Crypto SDK – is a C software library that is widely regarded by developers as the gold standard open source SDK for elliptic curve cryptography (ECC). + +The MIRACL library consists of well over 100 routines that cover all aspects of multi-precision arithmetic. Two new data-types are defined - big for large integers and flash (short for floating-slash) for large rational numbers. The large integer routines are based on Knuth’s algorithms, described in Chapter 4 of his classic work ‘The Art of Computer Programming’. Floating-slash arithmetic, which works with rounded fractions, was originally proposed by D. Matula and P. Kornerup. + +All routines have been thoroughly optimised for speed and efficiency, while at the same time remaining standard, portable C. However optional fast assembly language alternatives for certain time-critical routines are also included, particularly for the popular Intel 80x86 range of processors. A C++ interface is also provided along with full source code. diff --git a/miracl/docs/miracl-explained/README.md b/miracl/docs/miracl-explained/README.md new file mode 100644 index 0000000..78f78f7 --- /dev/null +++ b/miracl/docs/miracl-explained/README.md @@ -0,0 +1,67 @@ +* What Is Miracl +* [Security Advisory](security-advisory.md) +* [Benchmarks](benchmarks.md) +* [Miracl Standard Curves](miracl-standard-curves.md) +* [IEEE 1363](ieee-1363.md) +* [Elliptic Curves](elliptic-curves.md) +* [Licensing](licensing.md) +* Reference Manual + * [Low Level Routines](reference-manual/low-level-routines.md) + * [Advanced Arithmetic Routines](reference-manual/advanced-arithmetic-routines.md) + * [Montgomery Arithmetic Routines](reference-manual/montgomery-arithmetic-routines.md) + * [ZZn2 Arithmetic Routines](reference-manual/zzn2-arithmetic-routines.md) + * [Encryption Routines](reference-manual/encryption-routines.md) + * [Elliptic Curve Routines](reference-manual/elliptic-curve-routines.md) + * [Floating Slash Routines](reference-manual/floating-slash-routines.md) + * [Structure Reference](reference-manual/structure-reference.md) + + +What is Miracl? +--- + +![Miracl Logo](images/miracl.png) + + +Multiprecision Integer and Rational Arithmetic C Library – the MIRACL Crypto SDK – is a C software library that is widely regarded by developers as the golden standard open source SDK for elliptic curve cryptography (ECC). + +Device or memory constraints? No problem. While there are many libraries that support Cryptography on a PC, MIRACL does more by securing embedded-devices and mobile smart devices like no other SDK in the global market today. For developers who have found other cryptographic libraries ill suited for these constrained platforms, MIRACL is your answer. MIRACL has support for even the most constrained environments imaginable. In this mode of operation, all memory can be allocated exclusively from the stack so that no fragmenting of precious RAM resources is required. New configuration options further reduce the amount of program code. + +MIRACL is particularly adept at methods based on Elliptic Curves, and the new paradigm of Pairing-Based Cryptography. + +MIRACL is easy to use, and includes an inline C++ wrapper, which greatly simplifies program development. MIRACL comes with multiple example programs (25+ of them) that cover a wide range of applications, and most are provided in both C and C++ versions. + +MIRACL's special purpose macro assembler feature facilitates the achievement of best possible performance from your embedded processor with an automatically generated Assembly Language engine. Use your compiler to compile and run a simple configuration program, which proceeds with user interaction to generate optimal settings for your environment. + +AES encryption, RSA public key cryptography, Diffie-Hellman Key exchange and DSA digital signature are all just a few procedure calls away. MIRACL is the gold standard for Elliptic Curve Cryptography over GF(p) and GF(2m) and supports even more esoteric Elliptic Curves and Lucas function based schemes. + +Unlike other Cryptographic libraries, MIRACL does not merely provide an opaque interface to a pre-determined set of cryptographic methods, but rather a set of tools that enable any new number-theoretic technique to be implemented quickly so that you, the developer, is free to design your own cryptographic API. + +MIRACL comes with a secure channel to connect with the CertiVox Key Management Service out of the box, so your application can get the enhanced security agility of on-board key management right from the get go. Download MIRACL, learn the code or talk to a solution specialist today to make the most of your MIRACL. + +And yes, MIRACL supports mainframes, too! (Is that really such a big deal?) + +## Why is it different? + +While many other cryptographic SDKs are focused on PC use, MIRACL also enables developers to build security into highly constrained environments, including embedded, mobile apps and SCADA. + +## MIRACL enables: + +- reduced program code +- greatly simplified program development +- developer-designed APIs +- rapid implementation, using inline code wrappers, example programs and other innovations. + +These unique qualities are the reason MIRACL, and the solutions and services built using it, are in use in hundreds of organisations across the world, including BAE Systems, Hitachi, Intel, Panasonic, Toyota and many others. + +## Features and Benefits: why MIRACL is the right choice + +MIRACL delivers a wide and unique range of benefits, enabling developers to secure even the most constrained environments quickly, easily and effectively. It features, amongst others: + +- an inline C++ wrapper – greatly simplifying program development +- over 25 example programs in C and C++, covering a wide range of applications, to give development a head start +- optimization of both embedded processors and RAM, to help developers overcome device and memory constraints +- compatibility with industry security technologies including AES encryption, RSA public key cryptography, Diffie-Hellman key exchange, DSA digital signature, and others +- a set of tools that enable any new number-theoretic technique to be implemented quickly. + +MIRACL also supports a wide range of platforms, including, among others: +![Logos](images/logos.png) diff --git a/miracl/docs/miracl-explained/benchmarks.md b/miracl/docs/miracl-explained/benchmarks.md new file mode 100644 index 0000000..dbf501d --- /dev/null +++ b/miracl/docs/miracl-explained/benchmarks.md @@ -0,0 +1,472 @@ +* [What Is Miracl](README.md) +* [Security Advisory](security-advisory.md) +* Benchmarks +* [Miracl Standard Curves](miracl-standard-curves.md) +* [IEEE 1363](ieee-1363.md) +* [Elliptic Curves](elliptic-curves.md) +* [Licensing](licensing.md) +* Reference Manual + * [Low Level Routines](reference-manual/low-level-routines.md) + * [Advanced Arithmetic Routines](reference-manual/advanced-arithmetic-routines.md) + * [Montgomery Arithmetic Routines](reference-manual/montgomery-arithmetic-routines.md) + * [ZZn2 Arithmetic Routines](reference-manual/zzn2-arithmetic-routines.md) + * [Encryption Routines](reference-manual/encryption-routines.md) + * [Elliptic Curve Routines](reference-manual/elliptic-curve-routines.md) + * [Floating Slash Routines](reference-manual/floating-slash-routines.md) + * [Structure Reference](reference-manual/structure-reference.md) + + +Benchmarks +--- + +* [Overview](#overview) +* [Output of the BMARK Program](#output) +* [Elliptic Curve Point Multiplication](#curve) +* [Pairing-Based Crypto](#pairing) + +## Overview + +**Performance is the biggest single issue for implementors, and MIRACL allows a variety of techniques (algorithmic tricks and/or assembly language) to be used to squeeze maximum performance from a particular environment. So use MIRACL in your cryptographic API for a performance boost - you may not need that expensive Cryptographic accelerator!** + +This diagram below shows timings for modular exponentiation, that is the calculation of xy mod n, for x, y and n all the same size in-bits - the size shown along the horizontal axis. The exponent y is chosen at random. This is the bottleneck calculation in many cryptographic protocols. Five different methods are implemented for the Intel 80x86/Pentium family. Timings on the horizontal axes are correct in seconds for 8192-bit exponentiation. For 4096-bits divide by 8, for 2048-bits divide by 8 again, etc. For a paper describing the methods in more details see [timings.doc](miracl-explained/timings.doc ':ignore'). + +The following timings were obtained using the Borland C/C++ Compiler/assembler, for modular exponentiation. + +Times in milliseconds for optimal technique: + +| | 512-bits | 1024-bits | 2048-bits | 4096-bits | +|--------------------|----------|-----------|-----------|-----------| +| 33MHz 80486DX | 370 | 2833 | 17833 | 111000 | +| 60MHz Pentium | 48 | 353 | 2452 | 18500 | +| 180MHz Pentium Pro | 12 | 90 | 564 | 3551 | +| 233MHz Pentium II | 10 | 80 | 510 | 3250 | + +**On a 233 Mhz Pentium II - Best times (without precomputation)** + +- A 1024-bit RSA decryption/signature takes 20ms. * +- A 2048-bit RSA decryption takes 160 ms. + +- A 1024-bit (160-bit exponent) DSS verification takes 16ms. + +- A 2048-bit (256-bit exponent) DSS verification takes 79ms + +- A 160-bit Elliptic Curve ECS verification takes 11 ms. * +- A 256-bit Elliptic Curve ECS verification takes 26ms. * +- A 192-bit Elliptic Curve ECS verification takes 9ms (NIST Standard Curve - Special Modulus) * +- A 224-bit Elliptic Curve ECS verification takes 13ms (NIST Standard Curve - Special Modulus) * + +**On 80MHz ARM7TDMI - Best times (without precomputation)** + +- A 1024-bit RSA decryption/signature takes 120ms * +- A 192-bit Elliptic Curve point multiplication takes 38ms (NIST Standard Curve - Special Modulus) * +- A 224-bit Elliptic Curve point multiplication takes 53ms (NIST Standard Curve - Special Modulus) * + +MIRACL contains fast experimental implementations of [Identity-Based Encryption](http://crypto.stanford.edu/ibe/). + +Timings include all number theoretic components of encrypt/decrypt processing. The most time-consuming component is the calculation of the Tate Pairing. The discrete logarithm-bit-length security of a pairing-based system is a function of the product of the _security multiplier k and the-bit length of the base field. In these cases k=2 and the base field is 512-bits, for 1024-bit security. + +**On a 1GHz Pentium III** + +- A 1024-bit IBE encrypt takes 35ms * +- A 1024-bit IBE decrypt takes 27ms * +- A 1024-bit IBE encrypt takes 22ms (with precomputation) * +- A 1024-bit IBE decrypt takes 17ms (with precomputation) * +- A 1024-bit Tate pairing takes 20ms * +- A 1024-bit Tate pairing takes 8.6ms (with precomputation) * + +* - Using Comba Method for modular multiplication
++ - Using KCM Method for modular multiplication + +## Output of the BMARK program + +Below is the output of the BMARK program, on a single core of a 2.4GHz Intel i5 520 processor, compiled with GCC, with standard /O2 compiler optimisation. + +> This is for the standard version of MIRACL, with no special optimizations. + +- MIRACL – 64-bit version +- Little Endian processor +- Using some assembly language +- No special optimizations +- Precomputation uses fixed Window size = 8 +- So 256 values are precomputed and stored + +> No optimizations/assembly language apply to GF(2^m) Elliptic Curves.
Times are elapsed real-times - so make sure nothing else is running! + +Modular exponentiation benchmarks – calculating g^e mod p. From these figures it should be possible to roughly estimate the time required for your favourite PK algorithm, RSA, DSA, DH, etc. + +**Key** + +- R – random base-bits/random exponent-bits +- V – random base-bits/(small exponent e) +- S – (small base g) /random exponent-bits +- P – exponentiation with precomputation (fixed base g) +- D – double exponentiation g^e.a^b mod p +- F3 = 257, F4 = 65537 +- RSA - Rivest-Shamir-Adleman +- DH - Diffie Hellman Key exchange +- DSA - Digital Signature Algorithm + +**512-bit prime** + +- R - 54945 iterations of 512/ 160 0.18 ms per iteration +- D - 45015 iterations of 512/ 160 0.22 ms per iteration +- R - 18292 iterations of 512/ 512 0.55 ms per iteration +- S - 67125 iterations of g=3/ 160 0.15 ms per iteration +- P - 281436 iterations of 512/ 160 0.04 ms per iteration + +**1024-bit RSA decryption** + +1.09 ms + +**512-bit DH 160-bit exponent** + +- Offline, no precomputation 0.18 ms +- Offline, small base 0.15 ms +- Offline, w. precomputation 0.04 ms +- Online 0.18 ms + +**512-bit DSA 160-bit exponent** + +- Signature no precomputation 0.18 ms +- Signature w. precomputation 0.04 ms +- Verification 0.22 ms + +**1024-bit prime** + +- R - 17875 iterations of 1024/ 160 0.56 ms per iteration +- D - 14859 iterations of 1024/ 160 0.67 ms per iteration +- V - 1163058 iterations of 1024/e= 3 0.01 ms per iteration +- V - 154892 iterations of 1024/e=F4 0.06 ms per iteration +- S - 22799 iterations of g=3/ 160 0.44 ms per iteration +- P - 89730 iterations of 1024/ 160 0.11 ms per iteration + +**2048-bit RSA decryption** + +6.62 ms + +**1024-bit RSA encryption e=3** + +0.01 ms + +**1024-bit RSA encryption e=65537** + +0.06 ms + +**1024-bit DH 160-bit exponent** + +- Offline, no precomputation 0.56 ms +- Offline, small base 0.44 ms +- Offline, w. precomputation 0.11 ms +- Online 0.56 ms + +**1024-bit DSA 160-bit exponent** + +- Signature no precomputation 0.56 ms +- Signature w. precomputation 0.11 ms +- Verification 0.67 ms + +**2048-bit prime** + +- R - 2982 iterations of 2048/ 256 3.35 ms per iteration +- D - 2335 iterations of 2048/ 256 4.28 ms per iteration +- R - 398 iterations of 2048/2048 25.13 ms per iteration +- V - 366871 iterations of 2048/e= 3 0.03 ms per iteration +- V - 48125 iterations of 2048/e=F4 0.21 ms per iteration +- S - 4223 iterations of g=3/ 256 2.37 ms per iteration +- P - 15500 iterations of 2048/ 256 0.65 ms per iteration + +**2048-bit RSA encryption e=3** + +0.03 ms + +**2048-bit RSA encryption e=65537** + +0.21 ms + +**2048-bit DH 256-bit exponent** + +- Offline, no precomputation 3.35 ms +- Offline, small base 2.37 ms +- Offline, w. precomputation 0.65 ms +- Online 3.35 ms + +**2048-bit DSA 256-bit exponent** + +- Signature no precomputation 3.35 ms +- Signature w. precomputation 0.65 ms +- Verification 4.28 ms + +## Elliptic Curve Point Multiplication + +Elliptic Curve point multiplication benchmarks – calculating r.P +From these figures it should be possible to roughly estimate the time required for your favourite EC PK algorithm, ECDSA, ECDH, etc. + +**Key** +- ER - Elliptic Curve point multiplication r.P +- ED - Elliptic Curve double multiplication r.P + s.Q +- EP - Elliptic Curve multiplication with precomputation +- EC - Elliptic curve GF(p) - p of no special form +- ECDH - Diffie Hellman Key exchange +- ECDSA - Digital Signature Algorithm + +**160-bit GF(p) Elliptic Curve** + +- ER - 22280 iterations 0.45 ms per iteration +- ED - 17217 iterations 0.58 ms per iteration +- EP - 96332 iterations 0.10 ms per iteration + +**160-bit ECDH** + +- Offline, no precomputation 0.45 ms +- Offline, w. precomputation 0.10 ms +- Online 0.45 ms + +**160-bit ECDSA** + +- Signature no precomputation 0.45 ms +- Signature w. precomputation 0.10 ms +- Verification 0.58 ms + +**192-bit GF(p) Elliptic Curve** + +- ER - 17095 iterations 0.58 ms per iteration +- ED - 12936 iterations 0.77 ms per iteration +- EP - 74904 iterations 0.13 ms per iteration + +**192-bit ECDH** + +- Offline, no precomputation 0.58 ms +- Offline, w. precomputation 0.13 ms +- Online 0.58 ms + +**192-bit ECDSA** + +- Signature no precomputation 0.58 ms +- Signature w. precomputation 0.13 ms +- Verification 0.77 ms + +**224-bit GF(p) Elliptic Curve** + +- ER - 11832 iterations 0.85 ms per iteration +- ED - 9486 iterations 1.05 ms per iteration +- EP - 52869 iterations 0.19 ms per iteration + +**224-bit ECDH** + +- Offline, no precomputation 0.85 ms +- Offline, w. precomputation 0.19 ms +- Online 0.85 ms + +**224-bit ECDSA** + +- Signature no precomputation 0.85 ms +- Signature w. precomputation 0.19 ms +- Verification 1.05 ms + +**256-bit GF(p) Elliptic Curve** + +- ER - 9410 iterations 1.06 ms per iteration +- ED - 7124 iterations 1.40 ms per iteration +- EP - 41546 iterations 0.24 ms per iteration + +**256-bit ECDH** + +- Offline, no precomputation 1.06 ms +- Offline, w. precomputation 0.24 ms +- Online 1.06 ms + +**256-bit ECDSA** + +- Signature no precomputation 1.06 ms +- Signature w. precomputation 0.24 ms +- Verification 1.40 ms + +**163-bit GF(2^m) Elliptic Curve** + +- ER - 27160 iterations 0.37 ms per iteration +- ED - 20689 iterations 0.48 ms per iteration +- EP - 107712 iterations 0.09 ms per iteration + +**163-bit ECDH** + +- Offline, no precomputation 0.37 ms +- Offline, w. precomputation 0.09 ms +- Online 0.37 ms + +**163-bit ECDSA** + +- Signature no precomputation 0.37 ms +- Signature w. precomputation 0.09 ms +- Verification 0.48 ms + +**163-bit GF(2^m) Koblitz Elliptic Curve** + +- ER - 43413 iterations 0.23 ms per iteration +- ED - 23882 iterations 0.42 ms per iteration +- EP - 111239 iterations 0.09 ms per iteration + +**163-bit ECDH** + +- Offline, no precomputation 0.23 ms +- Offline, w. precomputation 0.09 ms +- Online 0.23 ms + +**163-bit ECDSA** + +- Signature no precomputation 0.23 ms +- Signature w. precomputation 0.09 ms +- Verification 0.42 ms + +**233-bit GF(2^m) Elliptic Curve** + +- ER - 16703 iterations 0.60 ms per iteration +- ED - 12460 iterations 0.80 ms per iteration +- EP - 62551 iterations 0.16 ms per iteration + +**233-bit ECDH** + +- Offline, no precomputation 0.60 ms +- Offline, w. precomputation 0.16 ms +- Online 0.60 ms + +**233-bit ECDSA** + +- Signature no precomputation 0.60 ms +- Signature w. precomputation 0.16 ms +- Verification 0.80 ms + +**233-bit GF(2^m) Koblitz Elliptic Curve** + +- ER - 27404 iterations 0.36 ms per iteration +- ED - 13872 iterations 0.72 ms per iteration +- EP - 62887 iterations 0.16 ms per iteration + +**233-bit ECDH** + +- Offline, no precomputation 0.36 ms +- Offline, w. precomputation 0.16 ms +- Online 0.36 ms + +**233-bit ECDSA** + +- Signature no precomputation 0.36 ms +- Signature w. precomputation 0.16 ms +- Verification 0.72 ms + +**283-bit GF(2^m) Elliptic Curve** + +- ER - 9870 iterations 1.01 ms per iteration +- ED - 7095 iterations 1.41 ms per iteration +- EP - 37435 iterations 0.27 ms per iteration + +**283-bit ECDH** + +- Offline, no precomputation 1.01 ms +- Offline, w. precomputation 0.27 ms +- Online 1.01 ms + +**283-bit ECDSA** + +- Signature no precomputation 1.01 ms +- Signature w. precomputation 0.27 ms +- Verification 1.41 ms + +**283-bit GF(2^m) Koblitz Elliptic Curve** + +- ER - 19687 iterations 0.51 ms per iteration +- ED - 8968 iterations 1.12 ms per iteration +- EP - 37505 iterations 0.27 ms per iteration + +**283-bit ECDH** + +- Offline, no precomputation 0.51 ms +- Offline, w. precomputation 0.27 ms +- Online 0.51 ms + +**283-bit ECDSA** + +- Signature no precomputation 0.51 ms +- Signature w. precomputation 0.27 ms +- Verification 1.12 ms + +**571-bit GF(2^m) Elliptic Curve** + +- ER - 2227 iterations 4.49 ms per iteration +- ED - 1504 iterations 6.65 ms per iteration +- EP - 8231 iterations 1.21 ms per iteration + +**571-bit ECDH** + +- Offline, no precomputation 4.49 ms +- Offline, w. precomputation 1.21 ms +- Online 4.49 ms + +**571-bit ECDSA** + +- Signature no precomputation 4.49 ms +- Signature w. precomputation 1.21 ms +- Verification 6.65 ms + +**571-bit GF(2^m) Koblitz Elliptic Curve** + +- ER - 5035 iterations 1.99 ms per iteration +- ED - 2242 iterations 4.46 ms per iteration +- EP - 8247 iterations 1.21 ms per iteration + +**571-bit ECDH** + +- Offline, no precomputation 1.99 ms +- Offline, w. precomputation 1.21 ms +- Online 1.99 ms + +**571-bit ECDSA** + +- Signature no precomputation 1.99 ms +- Signature w. precomputation 1.21 ms +- Verification 4.46 ms + +## Pairing-Based Crypto + +Processor: 2.4 GHz Intel i5 520M.
+AES refers to equivalent AES-bits of security. For example 128-bits refers to AES with a 128-bit key.
+For G1, G2 and GT precomputation, 8-bit windows are used.
+All timings are in milli-seconds. Maximum optimization applied.
+"One More" refers to the cost of one more pairing in a multi-pairing. The (p) means that precomputation is used.
+ +**+Timings for Type-1 pairings G1 X G1 = GT+** + +These pairing friendly curves are used, where _k_ is the embedding degree: +- SSP - Super-singular Curve over GF(_p_) (512-bit modulus _p_, _k_=2) +- SSP - Super-singular Curve over GF(_p_) (1536-bit modulus _p_, _k_=2) +- SS2 - Supersingular Curve over GF(2^_m_) (_m_=379, _k_=4) +- SS2 - Supersingular Curve over GF(2^_m_) (_m_=1223, _k_=4) + +| AES/Curve | 80/SSP | 80/SS2 | 128/SSP | 128/SSP | +|--------------|--------|--------|---------|---------| +| G1 mul | 1.49 | 0.38 | 13.57 | 2.57 | +| G1 mul (p) | 0.30 | - | 3.01 | - | +| Pairing | 3.34 | 1.18 | 40.95 | 19.00 | +| Pairing (p) | 1.65 | - | 25.22 | - | +| GT pow | 0.36 | 0.29 | 3.76 | 2.09 | +| GT Pow (p) | 0.08 | - | 0.78 | - | +| One More | 2.29 | 1.01 | 20.80 | 17.80 | +| One More (p) | 0.60 | - | 5.31 | - | + +**+Timings for Type-3 pairings G2 X G1 = GT+** + +These pairing friendly curves are used, where _k_ is the embedding degree: +- CP - Cocks-Pinch Curve over GF(_p_) (512-bit modulus _p_, _k_=2)
+- MNT - MNT Curve over GF(_p_) (160-bit modulus _p_, _k_=6)
+- BN - Barreto-Naehrig Curve over GF(_p_) (256-bit modulus _p_, k=12)
+- KSS - Kachisa-Schaefer-Scott Curve over GF(_p_) (512-bit modulus _p_, _k_=18)
+- BLS - Barreto-Lynn-Scott Curve over GF(_p_) (640-bit modulus _p_, _k_=24) + +| AES/Curve | 80/CP | 80/MNT | 128/BN | 192/KSS | 256/BLS | +|--------------|-------|--------|--------|---------|---------| +| G1 mul | 0.51 | 0.19 | 0.22 | 0.7 | 1.26 | +| G1 mul (p) | 0.1 | 0.04 | 0.07 | 0.24 | 0.43 | +| G2 mul | 0.51 | 1.15 | 0.44 | 5.53 | 16.04 | +| G2 mul(p) | 0.1 | 0.35 | 0.19 | 2.81 | 5.44 | +| Pairing | 1.14 | 1.9 | 2.32 | 20.55 | 33.91 | +| Pairing (p) | 0.58 | 0.69 | 2.09 | 18.05 | 30.45 | +| GT pow | 0.12 | 0.24 | 0.95 | 6.2 | 24.87 | +| GT pow (p) | 0.03 | 0.08 | 0.43 | 2.73 | 6.47 | +| One More | 0.81 | 1.57 | 0.75 | 4.65 | 6.59 | +| One More (p) | 0.23 | 0.34 | 0.41 | 2.38 | 3.42Ę | diff --git a/miracl/docs/miracl-explained/elliptic-curves.md b/miracl/docs/miracl-explained/elliptic-curves.md new file mode 100644 index 0000000..295ddec --- /dev/null +++ b/miracl/docs/miracl-explained/elliptic-curves.md @@ -0,0 +1,88 @@ +* [What Is Miracl](README.md) +* [Security Advisory](security-advisory.md) +* [Benchmarks](benchmarks.md) +* [Miracl Standard Curves](miracl-standard-curves.md) +* [IEEE 1363](ieee-1363.md) +* Elliptic Curves +* [Licensing](licensing.md) +* Reference Manual + * [Low Level Routines](reference-manual/low-level-routines.md) + * [Advanced Arithmetic Routines](reference-manual/advanced-arithmetic-routines.md) + * [Montgomery Arithmetic Routines](reference-manual/montgomery-arithmetic-routines.md) + * [ZZn2 Arithmetic Routines](reference-manual/zzn2-arithmetic-routines.md) + * [Encryption Routines](reference-manual/encryption-routines.md) + * [Elliptic Curve Routines](reference-manual/elliptic-curve-routines.md) + * [Floating Slash Routines](reference-manual/floating-slash-routines.md) + * [Structure Reference](reference-manual/structure-reference.md) + + +Elliptic Curves +--- + +These curves use the standard Weierstrass parameterisation, and are of the form: + +**y2 = x3 +Ax +B mod p** + +...where p is a prime congruent to 3 mod 4, and A is fixed at -3. A quarter of all randomly generated curves can be transformed into this form.The former condition makes it easier to find points on the curve, and the latter make calculations on the curve somewhat faster. + +The motivation is provide a set of curves which, within the limitations mentioned above, are otherwise in no way special. It is thought that by using such curves the user is safe against cryptanalytic advances, except in a circumstance where the whole premise behind Elliptic Curve cryptography collapses and a sub-exponential solution is found for the most general discrete logarithm problem in the elliptic curve setting. + +Each curve is with respect to a prime p which is n bits in length. In each case the number of points q on the curve is itself a prime. The prime p is found as the first prime congruent to 3 mod 4 which is found by incrementing a number n bits in length, formed from the first n bits of the mathematical constant pi=3.141592.... The parameter B is formed from the first n bits of the mathematical constant e=2.71828...., incremented until q is prime. + +**ssc-160** +``` +n=160 +B=993193335754933797118314178888153828594854512705 +p=1147860701762054730346201299935827782113538756127 +q=1147860701762054730346200648614608152209809891831 +``` +**ssc-192** +``` +n=192 +B=4265732895672588129268258440977714335632089762934383523494 +p=4930024174431634640599033341057067222865862716297522433299 +q=4930024174431634640599033341125441632693811654341940586403 +``` +**ssc-224** +``` +n=224 +B=18321183280385145938884990414875229336370193019939570227257813318147 +p=21174292597673270169193562049053717791882423761323585056162680913631 +q=21174292597673270169193562049053723134442099121024262551089688143309 +``` +**ssc-256** +``` +n=256 +B=78688883013276200091698248537162581920209762369847930022367595957783191893217 +p=90942894222941581070058735694432465663348344332098107489693037779484723616779 +q=90942894222941581070058735694432465663288414616171509431879910319924502217783 +``` +**ssc-288** +``` +n=288 +B=337966179100791213208996178567593129982221810838428315939365373128820605838874928979766 +p=390596756491121423614434954606695289304724084762108334731724254341779347664665278286219 +q=390596756491121423614434954606695289304724116479393090921502092797686514928150248753237 +``` +**ssc-320** +``` +n=320 +B=1451553686391976948456801799936788618707919738968947956999929796583121697128874465400872041660580 +p=1677600295053042228788960243555000810201048522356787237681776606087928304667951345024875097229491 +q=1677600295053042228788960243555000810201048522357873106251579120122685384485967275546948559607409 +``` +**ssc-384** +``` +n=384 +B=2677643936212245379258831955273195965014103242523976013961762903324499451740187144031703534071217029867094433378961 +p=30946263300823101954888425259784296108860594177929936231961025381527827855583154673559277957637088071546809309873019 +q=30946263300823101954888425259784296108860594177929936231959195086011429040851460901626189237585847628753659044398489 +``` +**ssc-512** +``` +n=512 +B=9111550163858012281440901732746538838772262590143654133938674743542107885492015390851248618042056679983385207705625699101049041930943171450852516780927629 +p=10530467723362659054861705371139847026313999328372313651398671272025951445569024729948471343061931586610942824229083371331823229156399790385588443550959087 +q=10530467723362659054861705371139847026313999328372313651398671272025951445569144524507377363887941433449823713742916287342504795006316114468040283111710577 +``` +These curves may be used freely without restriction. diff --git a/miracl/docs/miracl-explained/ieee-1363.md b/miracl/docs/miracl-explained/ieee-1363.md new file mode 100644 index 0000000..9bb193c --- /dev/null +++ b/miracl/docs/miracl-explained/ieee-1363.md @@ -0,0 +1,42 @@ +* [What Is Miracl](README.md) +* [Security Advisory](security-advisory.md) +* [Benchmarks](benchmarks.md) +* [Miracl Standard Curves](miracl-standard-curves.md) +* IEEE 1363 +* [Elliptic Curves](elliptic-curves.md) +* [Licensing](licensing.md) +* Reference Manual + * [Low Level Routines](reference-manual/low-level-routines.md) + * [Advanced Arithmetic Routines](reference-manual/advanced-arithmetic-routines.md) + * [Montgomery Arithmetic Routines](reference-manual/montgomery-arithmetic-routines.md) + * [ZZn2 Arithmetic Routines](reference-manual/zzn2-arithmetic-routines.md) + * [Encryption Routines](reference-manual/encryption-routines.md) + * [Elliptic Curve Routines](reference-manual/elliptic-curve-routines.md) + * [Floating Slash Routines](reference-manual/floating-slash-routines.md) + * [Structure Reference](reference-manual/structure-reference.md) + + +IEEE 1363 +--- + +The IEEE P1363 standard for Public key Cryptography [P1363](http://grouper.ieee.org/groups/1363/) is now complete. A fully multi-threaded IEEE 1363 "wrapper" for MIRACL is available which implements all the cryptographic primitives in this popular standard. It also supports point compression for elliptic curves, and precomputation for faster Digital Signature. GF(p) and GF(2m) curves are treated separately. The implemented primitives (some from P1363a) are: + +| DLSVDP-DH | DLSVDP-DHC | DLSVDP-MQV | DLSVDP-MQVC | +|--------------|--------------|------------|-------------| +| DLSP-NR | DLVP-NR | DLSP-DSA | DLVP-DSA | +| ECSVDP-DH | ECSVDP-DHC | ECSVDP-MQV | ECSVDP-MQVC | +| ECSP-NR | ECVP-NR | ECSP-DSA | ECVP-DSA | +| IFEP-RSA | IFDP-RSA | IFSP-RSA1 | IFVP-RSA1 | +| IFSP-RSA2 | IFVP-RSA2 | IFSP-RW | IFVP-RW | +| DLPSP-NR2/PV | DLSP-NR2 | DLVP-NR2 | DLSP-PV | +| DLVP-PV | ECPSP-NR2/PV | ECSP-NR2 | ECVP-NR2 | +| ECSP-PV | ECVP-PV | | | + +The following message encoding and auxiliary functions are also implemented (some from P1363a): + +| MGF1 | EMSA1/2/3/4 (PSS) | EMSR1/2/3 (PSS-R) | +|-------------|-------------------|-------------------| +| EME1 (OAEP) | KDF1 | KDF2 | +| MAC1 (HMAC) | AES_CBC_IV0 | | + +Full instructions for evaluation and deployment can be found at the head of the [p1363.c](https://github.com/CertiVox/MIRACL/blob/master/source/p1363/p1363.c) file. These include full instructions for the creation of a Win32/.NET compatible IEEE 1363 Dynamic Link Library (DLL), so that IEEE 1363 functionality can be easily integrated into your Win32/.NET application. A test program implements instances of signature and encryption schemes ECDSA, IFSSA, IFSSR, DLSSR, DLSSR-PV and ECIES. diff --git a/miracl/docs/miracl-explained/images/logos.png b/miracl/docs/miracl-explained/images/logos.png new file mode 100644 index 0000000..a7a1920 Binary files /dev/null and b/miracl/docs/miracl-explained/images/logos.png differ diff --git a/miracl/docs/miracl-explained/images/miracl.png b/miracl/docs/miracl-explained/images/miracl.png new file mode 100644 index 0000000..ccd1c46 Binary files /dev/null and b/miracl/docs/miracl-explained/images/miracl.png differ diff --git a/miracl/docs/miracl-explained/licensing.md b/miracl/docs/miracl-explained/licensing.md new file mode 100644 index 0000000..e2ecda8 --- /dev/null +++ b/miracl/docs/miracl-explained/licensing.md @@ -0,0 +1,37 @@ +* [What Is Miracl](README.md) +* [Security Advisory](security-advisory.md) +* [Benchmarks](benchmarks.md) +* [Miracl Standard Curves](miracl-standard-curves.md) +* [IEEE 1363](ieee-1363.md) +* [Elliptic Curves](elliptic-curves.md) +* Licensing +* Reference Manual + * [Low Level Routines](reference-manual/low-level-routines.md) + * [Advanced Arithmetic Routines](reference-manual/advanced-arithmetic-routines.md) + * [Montgomery Arithmetic Routines](reference-manual/montgomery-arithmetic-routines.md) + * [ZZn2 Arithmetic Routines](reference-manual/zzn2-arithmetic-routines.md) + * [Encryption Routines](reference-manual/encryption-routines.md) + * [Elliptic Curve Routines](reference-manual/elliptic-curve-routines.md) + * [Floating Slash Routines](reference-manual/floating-slash-routines.md) + * [Structure Reference](reference-manual/structure-reference.md) + + +Licensing +--- + +MIRACL has been under continuous development since 1988. It is currently licensed to hundreds of leading companies in the United States, Brazil, Britain, Germany, France, Switzerland, South Africa and Australia. Its cryptographic runtimes can be found in chips, operating systems and software applications in industries ranging from defense and intelligence to financial services and software as a service companies. + +## What's the license for MIRACL? + +MIRACL licenses are offered according to a dual licensing scheme. The FOSS license applicable to cryptographic implementations is the Affero GPL (AGPL) License, version 3. MIRACL is offered as a standard commercial license with any subscription to the CertiVox Key Management Service. Companies that are not comfortable with AGPL and are using MIRACL without a subscription to the CertiVox Key Management Service can acquire a commercial license for use of the software from by contacting . + +## Why is AGPL sometimes incompatible with commercial software? + +From a purely theoretical viewpoint, there is no incompatibility between AGPL and commercial applications. One may be running a commercial service while making the source code open and available to third-parties. Of course, things are likely different in practice. AGPL employs so-called 'strong copyleft' – for example: the demand that all the software linked against free software (free in GNU/FSF sense) is also free software and freely available. GNU Public License is the most famous of such 'strong copyleft' FOSS licenses. The GPL copyleft clause triggers when an application is distributed outside of company boundaries. The GPL license was created at a time when the web did not exist, let alone the possibility to use applications remotely through a web browser. Because of this, companies could deploy GPL code commercially on a web server without betraying the letter, but arguably betraying the spirit of the GPL. This is called the ASP loophole. This is the context in which Affero was designed. The basic idea is that making AGPL software available through a web server constitutes distribution, and this is enough to trigger the strong copyleft provisions that many are already familiar with because of GPL. In other words, all of the software that links to the AGPL library must also be released with a compatible Free or Open-Source license. Commercial companies or applications developed that are deployed in the financial services, national defense or intelligence industries are unlikely to want to have to disclose and distribute the source code with which they use MIRACL. If that is the case, closed source licenses are available that do not require the company, application or organization to disclose the source code with which it uses MIRACL. This is called selling/buying a GPL exception in GNU parlance (others simply call this 'dual licensing'). + +## If I use the AGPL license, will I need to open-source my code? + +Yes, you will. Exactly like regular GPL, linking your code to GPL code creates derivative work (in the copyright sense of the term) and this is enough to trigger the 'copyleft' provisions. FSF is adamant on this interpretation and so is CertiVox. +Q: What's the price of a commercial license and / or support from CertiVox? + +CertiVox issues a commercial license for MIRACL when a subscription to the CertiVox Key Management Service is issued. Additionally, CertiVox will offer enhanced developer support for MIRACL, which will optionally include cryptographic design consulting. CertiVox will publish publicly available pricing for both in the next few weeks. If you need a commercial license and / or support immediately, please contact . diff --git a/miracl/docs/miracl-explained/miracl-standard-curves.md b/miracl/docs/miracl-explained/miracl-standard-curves.md new file mode 100644 index 0000000..20d1fc3 --- /dev/null +++ b/miracl/docs/miracl-explained/miracl-standard-curves.md @@ -0,0 +1,88 @@ +* [What Is Miracl](README.md) +* [Security Advisory](security-advisory.md) +* [Benchmarks](benchmarks.md) +* Miracl Standard Curves +* [IEEE 1363](ieee-1363.md) +* [Elliptic Curves](elliptic-curves.md) +* [Licensing](licensing.md) +* Reference Manual + * [Low Level Routines](reference-manual/low-level-routines.md) + * [Advanced Arithmetic Routines](reference-manual/advanced-arithmetic-routines.md) + * [Montgomery Arithmetic Routines](reference-manual/montgomery-arithmetic-routines.md) + * [ZZn2 Arithmetic Routines](reference-manual/zzn2-arithmetic-routines.md) + * [Encryption Routines](reference-manual/encryption-routines.md) + * [Elliptic Curve Routines](reference-manual/elliptic-curve-routines.md) + * [Floating Slash Routines](reference-manual/floating-slash-routines.md) + * [Structure Reference](reference-manual/structure-reference.md) + + +MIRACL Standard Curves +--- + +These curves use the standard Weierstrass parameterisation, and are of the form: + +**y2 = x3 +Ax +B mod p** + +...where *p* is a prime congruent to 3 mod 4, and A is fixed at -3. A quarter of all randomly generated curves can be transformed into this form.The former condition makes it easier to find points on the curve, and the latter make calculations on the curve somewhat faster. + +The motivation is provide a set of curves which, within the limitations mentioned above, are otherwise in no way special. It is thought that by using such curves the user is safe against cryptanalytic advances, except in a circumstance where the whole premise behind Elliptic Curve cryptography collapses and a sub-exponential solution is found for the most general discrete logarithm problem in the elliptic curve setting. + +Each curve is with respect to a prime p which is n bits in length. In each case the number of points q on the curve is itself a prime. The prime p is found as the first prime congruent to 3 mod 4 which is found by incrementing a number n bits in length, formed from the first n bits of the mathematical constant pi=3.141592.... The parameter B is formed from the first n bits of the mathematical constant e=2.71828...., incremented until q is prime. + +**ssc-160** +``` +n=160 +B=993193335754933797118314178888153828594854512705 +p=1147860701762054730346201299935827782113538756127 +q=1147860701762054730346200648614608152209809891831 +``` +**ssc-192** +``` +n=192 +B=4265732895672588129268258440977714335632089762934383523494 +p=4930024174431634640599033341057067222865862716297522433299 +q=4930024174431634640599033341125441632693811654341940586403 +``` +**ssc-224** +``` +n=224 +B=18321183280385145938884990414875229336370193019939570227257813318147 +p=21174292597673270169193562049053717791882423761323585056162680913631 +q=21174292597673270169193562049053723134442099121024262551089688143309 +``` +**ssc-256** +``` +n=256 +B=78688883013276200091698248537162581920209762369847930022367595957783191893217 +p=90942894222941581070058735694432465663348344332098107489693037779484723616779 +q=90942894222941581070058735694432465663288414616171509431879910319924502217783 +``` +**ssc-288** +``` +n=288 +B=337966179100791213208996178567593129982221810838428315939365373128820605838874928979766 +p=390596756491121423614434954606695289304724084762108334731724254341779347664665278286219 +q=390596756491121423614434954606695289304724116479393090921502092797686514928150248753237 +``` +**ssc-320** +``` +n=320 +B=1451553686391976948456801799936788618707919738968947956999929796583121697128874465400872041660580 +p=1677600295053042228788960243555000810201048522356787237681776606087928304667951345024875097229491 +q=1677600295053042228788960243555000810201048522357873106251579120122685384485967275546948559607409 +``` +**ssc-384** +``` +n=384 +B=26776439362122453792588319552731959650141032425239760139617629033244994517401871440317035340712170298670944533378961 +p=30946263300823101954888425259784296108860594177929936231961025381527827855583154673559277957637088071546809309873019 +q=30946263300823101954888425259784296108860594177929936231959195086011429040851460901626189237585847628753659044398489 +``` +**ssc-512** +``` +n=512 +B=9111550163858012281440901732746538838772262590143654133938674743542107885492015390851248618042056679983385207705625699101049041930943171450852516780927629 +p=10530467723362659054861705371139847026313999328372313651398671272025951445569024729948471343061931586610942824229083371331823229156399790385588443550959087 +q=10530467723362659054861705371139847026313999328372313651398671272025951445569144524507377363887941433449823713742916287342504795006316114468040283111710577 +``` +These curves may be used freely without restriction. diff --git a/miracl/docs/miracl-explained/reference-manual/advanced-arithmetic-routines.md b/miracl/docs/miracl-explained/reference-manual/advanced-arithmetic-routines.md new file mode 100644 index 0000000..fbb0998 --- /dev/null +++ b/miracl/docs/miracl-explained/reference-manual/advanced-arithmetic-routines.md @@ -0,0 +1,637 @@ +* [What Is Miracl](../README.md) +* [Security Advisory](../security-advisory.md) +* [Benchmarks](../benchmarks.md) +* [Miracl Standard Curves](../miracl-standard-curves.md) +* [IEEE 1363](../ieee-1363.md) +* [Elliptic Curves](../elliptic-curves.md) +* [Licensing](../licensing.md) +* Reference Manual + * [Low Level Routines](low-level-routines.md) + * Advanced Arithmetic Routines + * [Montgomery Arithmetic Routines](montgomery-arithmetic-routines.md) + * [ZZn2 Arithmetic Routines](zzn2-arithmetic-routines.md) + * [Encryption Routines](encryption-routines.md) + * [Elliptic Curve Routines](elliptic-curve-routines.md) + * [Floating Slash Routines](floating-slash-routines.md) + * [Structure Reference](structure-reference.md) + + +Advanced Arithmetic Routines +--- + +In these routines a big parameter can also be used wherever a flash is specified, but not vice versa. Further information may be gleaned from the (lightly) commented source code. An asterisk after +the name indicates that the function does not take a mip parameter if MR_GENERIC_MT is defined in +mirdef.h. + +## void bigdig (int n, int b, big x) + +Generates a big random number of given length. Uses the built-in simple random number generator initialised +by irand(). + +**Parameters:** + +←n
+←b
+→x A big random number n digits long to base b + +**Precondition:** + +The base b must be printable, that is 2 <= b <= 256 + +**Example:** +``` +// This generates a 100 decimal digit random number +bigdig(100, 10, x); +``` +## void bigrand (big w, big x) + +Generates a big random number. Uses the built-in simple random number generator initialised by irand(). + +**Parameters:** + +←w
+→x A big random number in the range 0 <= x < w + +## void brick_end* (brick * b) + +Cleans up after an application of the Comb method. + +**Parameters:** + +←b A pointer to the current instance. + +## BOOL brick_init (brick * b, big g, big n, int window, int nb) + +Initialises an instance of the Comb method for modular exponentiation with precomputation. Internally +memory is allocated for 2w big numbers which will be precomputed and stored. For bigger w more space +is required, but the exponentiation is quicker. Try w = 8. + +**Parameters:** + +←→b A pointer to the current instance
+←g The fixed generator
+←n The modulus
+←window The window size w
+←nb The maximum number of bits to be used in the exponent + +**Returns:** + +TRUE if successful, otherwise FALSE + +> If MR_STATIC is defined in mirdef.h, then the g parameter in this function is replaced by an mr_small pointer to a precomputed table. In this case the function returns a void. + +## void crt (big_chinese * c, big * u, big x) + +Applies the Chinese Remainder Theorem. + +**Parameters:** + +←c A pointer to the current instance
+←u An array of big remainders
+→x The big number which yields the given remainders u when it is divided by the big moduli specified +in a prior call to crt_init() + +**Precondition:** + +The routine crt_init() must be called first. + +## void crt_end* (big_chinese * c) + +Cleans up after an application of the Chinese Remainder Theorem. + +**Parameters:** + +←c A pointer to the current instance. + +## BOOL crt_init (big_chinese * c, int r, big * moduli) + +Initialises an instance of the Chinese Remainder Theorem. Some internal workspace is allocated. + +**Parameters:** + +→c A pointer to the current instance
+←r The number of co-prime moduli
+←moduli An array of at least two big moduli + +**Returns:** + +TRUE if successful, otherwise FALSE. + +## int egcd (big x, big y, big z) + +Calculates the Greatest Common Divisor of two big numbers. + +**Parameters:** + +←x
+←y
+←z = gcd(x,y) + +**Returns:** + +GCD as integer, if possible, otherwise MR_TOOBIG. + +## void expb2 (int n, big x) + +Calculates 2 to the power of an integer as a big. + +**Parameters:** + +←n
+→x = 2n + +**Example:** +``` +// This calculates and prints out the largest known prime number +// (on a true 32-bit computer with lots of memory!) +expb2(1398269, x); +decr(x, 1, x); +mip->IOBASE = 10; +cotnum(x, stdout); +``` +### void expint (int b, int n, big x) + +Calculates an integer to the power of an integer as a big. + +**Parameters:** + +←b
+←n
+→x = bn + +### void fft_mult (big x, big y, big z) + +Multiplies two big numbers, using the Fast Fourier Method. See [Pollard71]. + +**Parameters:** + +←x
+←y
+→z = xy + +> Should only be used on a 32-bit computer when x and y are ver large, at least 1000 decimal digits. + +### void gprime (int maxp) + +Generates all prime numbers up to a certain limit into the instance array miracl::PRIMES, terminated by +zero. This array is used internally by the routines isprime() and nxprime(). + +**Parameters:** + +←maxp A positive integer indicating the maximum prime number to be generated. If maxp = 0 the +miracl::PRIMES array is deleted. + +### int hamming (big x) + +Calculates the hamming weight of a big number (in fact the number of 1's in its binary representation). + +**Parameters:** + +←x + +**Returns:** + +Hamming weight of x. + +### mr_small invers* (mr_small x, mr_small y) + +Calculates the inverse of an integer modulus a co-prime integer. + +**Parameters:** + +←x
+←y + +**Returns:** + +x−1 (mod y) + +> Result unpredictable if x and y not co-prime. + +### BOOL isprime (big x) + +Tests whether or not a big number is prime using a probabilistic primality test. The number is assumed +to be prime if it passes this test miracl::NTRY times, where miracl::NTRY is an instance variable with a +default initialisation in routine mirsys(). + +**Parameters:** + +←x + +**Returns:** + +TRUE if x is (almost certainly) prime, otherwise FALSE + +> This routine first test divides x by the list of small primes stored in the instance array miracl::PRIMES. +> The testing of larger primes will be significantly faster in many cases if this list is increased. See +> **gprime()**. By default only the small primes less than 1000 are used. + +### int jac (mr_small x, mr_small n) + +Calculates the value of the Jacobi symbol. See [Reisel]. + +**Parameters:** + +←x
+←n + +**Returns:** + +The value of (x | n) as +1 or -1, or 0 if symbol undefined + +> See also: **jack** + +### int jack (big U, big V) + +Calculates the value of the Jacobi symbol. See [Reisel]. + +**Parameters:** + +←U
+←V + +**Returns:** + +The value of (U | V) as +1 or -1, or 0 if symbol undefined + +> See also: **jac** + +### int logb2 (big x) + +Calculates the approximate integer log to the base 2 of a big number (in fact the number of bits in it). + +**Parameters:** + +←x + +**Returns:** + +Number of bits in x + +### void lucas (big p, big r, big n, big vp, big v) + +Performs Lucas modular exponentiation. Uses Montgomery arithmetic internally. This function can be +speeded up further for particular moduli, by invoking special assembly language routines to implement +Montgomery arithmetic. See powmod(). + +**Parameters:** + +←p The base
+←r The exponent
+←n The modulus
+→vp = Vr−1(p) (mod n)
+→v = Vr(p) (mod n) + +> Only v is returned if v and vp are not distinct. The "sister" Lucas function Ur(p) can, if required, be calculated as Ur(p) * [pVr(p) − 2Vr−1(p)]/(p2 − 4) (mod n) + +**Precondition:** + +The value of n must be odd. + +### BOOL multi_inverse (int m, big * x, big n, big * w) + +Finds the modular inverses of many numbers simultaneously, exploiting Montgomery's observation that +x−1 = y(xy)−1, y−1 = x(xy)−1. This will be quicker, as modular inverses are slow to calculate, and this +way only one is required. + +**Parameters:** + +←m The number of inverses required
+←x An array of m numbers whose inverses are required
+←n The modulus
+→w The resulting array of inverses + +**Returns:** + +TRUE if successful, otherwise FALSE + +**Precondition:** + +The parameters x and w must be distinct. + +### BOOL nroot (big x, int n, big w) + +Extracts lower approximation to a root of a big number. + +**Parameters:** + +←x A big number
+←n A positive integer
+→w = [nx] + +**Returns:** + +TRUE if the root is exact, otherwise FALSE + +**Precondition:** + +The value of n must be positive. If x is negative, then n must be odd + +> See also: **sqroot, nres_sqroot** + +### BOOL nxprime (big w, big x) + +Finds next prime number. + +**Parameters:** + +←w
+←x The next prime number greater than w + +**Returns:** + +TRUE if successful, otherwise FALSE + +> See also: **nxsafeprime** + +### BOOL nxsafeprime (int type, int subset, big w, big p) + +Finds next safe prime number greater than w. A safe prime number p is defined here to be one for which +q = (p − 1)/2 (type=0) or q = (p + 1)/2 (type=1) is also prime. + +**Parameters:** + +←type The type of safe prime as above
+←subset If subset = 1, then the search is restricted so that the value of the prime q is congruent to 1 +mod 4. If subset = 3, then the search is restricted so that the value of q is congruent to 3 mod 4. +If subset = 0 then there is no condition on q: it can be either 1 or 3 mod 4
+←w
+→p + +**Returns:** + +TRUE if successful, otherwise FALSE + +> See also: **nxprime** + +### void pow_brick (brick * b, big e, big w) + +Carries out a modular exponentiation, using the precomputed values stored in the brick structure. + +**Parameters:** + +←b A pointer to the current instance
+←e A big exponent
+→w = ge (mod n), where g and n are specified in the initial call to brick_init() + +**Precondition:** + +Must be preceded by a call to brick_init(). + +### void power (big x, long n, big z, big w) + +Raises a big number to an integer power. + +**Parameters:** + +←x A big number
+←n A positive integer
+←z A big number
+→w = xn (mod z) + +**Precondition:** + +The value of n must be positive. + +### int powltr (int x, big y, big n, big w) + +Raises an int to the power of a big number modulus another big number. Uses Left-to-Right binary +method, and will be somewhat faster than powmod() for small x. Uses Montgomery arithmetic internally +if the modulus n is odd. + +**Parameters:** + +←x
+←y
+←n
+→w = xy (mod n) + +**Returns:** + +The result expressed as an integer, if possible. Otherwise the value MR_TOOBIG + +**Precondition:** + +The value of y must be positive. The parameters x and n must be distinct. + +### void powmod (big x, big y, big n, big w) + +Raises a big number to a big power modulus another big. Uses a sophisticated 5-bit sliding window technique, +which is close to optimal for popular modulus sizes (such as 512 or 1024 bits). Uses Montgomery +arithmetic internally if the modulus n is odd. + +This function can be speeded up further for particular moduli, by invoking special assembly language +routines (ir your compiler allows it). A KCM Modular Multiplier will be automatically invoked if MR_- +KCM has been defined in mirdef.h and has been set to an appropriate size. Alternatively a Comba modular +multiplier will be used if MR_COMBA is so defined, and the modulus is of the specified size. Experimental +coprocessor code will be called if MR_PENTIUM is defined. Only one of these conditionals should be +defined. + +**Parameters:** + +←x
+←y
+←n
+→w = xy (mod n) + +**Precondition:** + +The value of y must be positive. The parameters x and n must be distinct. + +### void powmod2 (big x, big y, big a, big b, big n, big w) + +Calculates the product of two modular exponentiations. This is quicker than doing two separate exponentiations, +and is useful for certain cryptographic protocols. Uses 2-bit sliding window. + +**Parameters:** + +←x
+←y
+←a
+←b
+←n
+→w = xy ab (mod n) + +**Precondition:** + +The values of y and b must be positive. The parameters n and w must be distinct. The modulus n must +be odd. + +### void powmodn (int n, big * x, big * y, big p, big w) + +Calculates the product of n modular exponentiations. This is quicker than doing n separate exponentiations, +and is useful for certain cryptographic protocols. Extra memory is allocated internally for this function. + +**Parameters:** + +←n
+←x
+←y
+←p
+→w = x[0]y[0]x[1]y[1] · · · x[n − 1]y[n−1) (mod p) + +**Precondition:** + +The values of y[ ] must be positive. The parameters p and w must be distinct. The modulus p must be +odd. The underlying number base must be a power of 2. + +### void scrt (small_chinese * c, mr_utype * u, big x) + +Applies Chinese Remainder Theorem (for small prime moduli). + +**Parameters:** + +←c A pointer to the current instance of the Chinese Remainder Theorem
+←u An array of remainders
+→x The big number which yields the given integer remainders u[ ] when it is divided by the integer +moduli specified in a prior call to scrt_init() + +**Precondition:** + +The routine scrt_init() must be called first. + +### void scrt_end* (small_chinese * c) + +Cleans up after an application of the Chinese Remainder Theorem. + +**Parameters:** + +←c A pointer to the current instance of the Chinese Remainder Theorem. + +### BOOL scrt_init (small_chinese * c, int r, mr_utype * moduli) + +Initialises an instance of the Chinese Remainder Theorem. Some internal workspace is allocated. + +**Parameters:** + +→c A pointer to the current instance
+←r The number of co-prime moduli
+←moduli An array of at least two integer moduli + +**Returns:** + +TRUE if successful, otherwise FALSE. + +### void sftbit (big x, int n, big z) + +Shifts a big integer left or right by a number of bits. + +**Parameters:** + +←x
+←n If positive shifts to the left, if negative shifts to the right
+→z = x shifted by n bits + +### mr_small smul* (mr_small x, mr_small y, mr_small n) + +Multiplies two integers mod a third. + +**Parameters:** + +←x
+←y
+←n + +**Returns:** + +xy (mod n) + +### mr_small spmd* (mr_small x, mr_small n, mr_small m) + +Raises an integer to an integer power modulo a third. + +**Parameters:** + +←x
+←n
+←m + +**Returns:** + +xn (mod m) + +### mr_small sqrmp* (mr_small x, mr_small m) + +Calculates the square root of an integer modulo an integer prime number. + +**Parameters:** + +←x
+←m A prime number + +**Returns:** + +x (mod m), or 0 if root does not exist + +**Precondition:** + +p must be prime, otherwise the result is unpredictable + +> See also: **sqroot** + +### BOOL sqroot (big x, big p, big w) + +Calculates the square root of a big integer mod a big integer prime. + +**Parameters:** + +←x
+←p
+→w =x (mod p) if the square root exists, otherwise w = 0. Note that the "other" square root +may be found by subtracting w from p + +**Returns:** + +TRUE if the square root exists, FALSE otherwise + +**Precondition:** + +The number p must be prime + +> This routine is particularly efficient if p = 3 (mod 4). + +### int trial_division (big x, big y) + +Dual purpose trial division routine. If x and y are the same big variable then trial division by the small +prime numbers in the instance array miracl::PRIMES is attempted to determine the primality status of the +big number. If x and y are distinct then, after trial division, the unfactored part of x is returned in y. + +**Parameters:** + +←x
+←→y + +**Returns:** + +If x and y are the same, then a return value of 0 means that the big number is definitely not prime, a +return value of 1 means that it definitely is prime, while a return value of 2 means that it is possibly +prime (and that perhaps further testing should be carried out). If x and y are distinct, then a return value +of 1 means that x is smooth, that it is completely factored by trial division (and y is the largest prime +factor). A return value of 2 means that the unfactored part y is possibly prime. + +### int xgcd (big x, big y, big xd, big yd, big z) + +Calculates extended Greatest Common Divisor of two big numbers. Can be used to calculate modular +inverses. Note that this routine is much slower than a mad() operation on numbers of similar size. + +**Parameters:** + +←x
+→y
+→xd
+→yd
+→z = gcd(x, y) = (x * xd) + (y * yd) + +**Returns:** + +GCD as integer, if possible, otherwise MR_TOOBIG + +**Precondition:** + +If xd and yd are not distinct, only xd is returned. The GCD is only returned if z distinct from both xd +and yd + +**Example:** +``` +xgcd(x, p, x, x, x,); // x = 1/x mod p (p is prime) +``` diff --git a/miracl/docs/miracl-explained/reference-manual/elliptic-curve-routines.md b/miracl/docs/miracl-explained/reference-manual/elliptic-curve-routines.md new file mode 100644 index 0000000..a07966e --- /dev/null +++ b/miracl/docs/miracl-explained/reference-manual/elliptic-curve-routines.md @@ -0,0 +1,637 @@ +* [What Is Miracl](../README.md) +* [Security Advisory](../security-advisory.md) +* [Benchmarks](../benchmarks.md) +* [Miracl Standard Curves](../miracl-standard-curves.md) +* [IEEE 1363](../ieee-1363.md) +* [Elliptic Curves](../elliptic-curves.md) +* [Licensing](../licensing.md) +* Reference Manual + * [Low Level Routines](low-level-routines.md) + * [Advanced Arithmetic Routines](advanced-arithmetic-routines.md) + * [Montgomery Arithmetic Routines](montgomery-arithmetic-routines.md) + * [ZZn2 Arithmetic Routines](zzn2-arithmetic-routines.md) + * [Encryption Routines](encryption-routines.md) + * Elliptic Curve Routines + * [Floating Slash Routines](floating-slash-routines.md) + * [Structure Reference](structure-reference.md) + + +Elliptic Curve Routines +--- + +In these routines a big parameter can also be used wherever a flash is specified, but not vice versa. Further information may be gleaned from the (lightly) commented source code. An asterisk after +the name indicates that the function does not take a mip parameter if MR_GENERIC_MT is defined in +mirdef.h. + +## void ebrick2_end* (ebrick2 * B) + +Cleans up after an application of the Comb for GF(2m) elliptic curves. + +**Parameters:** + +←→B A pointer to the current instance + +## BOOL ebrick2_init (ebrick2 * B, big x, big y, big a2, big a6, int m, int a, int b, int c, int window, int nb) + +Initialises an instance of the Comb method for GF(2m) elliptic curve multiplication with precomputation. +The field is defined with respect to the trinomial basis tm+ta+1 or the pentanomial basis tm+ta+tb+tc+1. +Internally memory is allocated for 2w elliptic curve points which will be precomputed and sotred. For +bigger w more space is required, but the exponentiation is quicker. Try w = 8. + +**Parameters:** + +←B A pointer to the current instance
+←x x coordinate of the fixed point
+←y y coordinate of the fixed point
+←a2 The a2 coefficient of the curve y2 + xy = x3 + a2x2 + a6
+←a6 the a6 coefficient of the curve y2 + xy = x3 + a2x2 + a6
+←m
+←a
+←b
+←c
+←window The size w of the window
+←nb The maximum number of bits to be used in the exponent + +**Returns:** + +TRUE if successful, otherwise FALSE + +> If MR_STATIC is defined in mirdef.h, then the x and y parameters in this function are replaced by a single mr_small * pointer to a precomputed table. In this case the function returns a void. + +## void ebrick_end* (ebrick * B) + +Cleans up after an application of the Comb for GF(p) elliptic curves. + +**Parameters:** + +←→B A pointer to the current instance + +## BOOL ebrick_init (ebrick * B, big x, big y, big a, big b, big n, int window, int nb) + +Initialises an instance of the Comb method for GF(p) elliptic curve multiplication with precomputation. +Internally memory is allocated for 2w elliptic curve points which will be precomputed and stored. For +bigger w more space is required, but the exponentiation is quicker. Try w = 8. + +**Parameters:** + +→B A pointer to the current instance
+←x x coordinate of the fixed point
+←y y coordinate of the fixed point
+←a The a coefficient of the curve y2 = x3 + ax + b
+←b The b coefficient of the curve y2 = x3 + ax + b
+←n The modulus
+←window The size w of the window
+←nb The maximum number of bits to be used in the exponent + +**Returns:** + +TRUE if successful, otherwise FALSE + +> If MR_STATIC is defined in mirdef.h, then the x and y parameters in this function are replaced by a single mr_small * pointer to a precomputed table. In this case the function returns a void. + +## big ecurve2_add (epoint * p, epoint * pa) + +Adds two points on a GF(2m) elliptic curve using the special rule for addition. Note that if pa = p, then a +different duplication rule is used. Addition is quicker if p is normalised. + +**Parameters:** + +←p
+←→pa = pa + p + +**Returns:** + +An ephemeral pointer to the sline slope if curve is super-singular + +**Precondition:** + +The input points must actually be on the current active curve. + +## BOOL ecurve2_init (int m, int a, int b, int c, big a2, big a6, BOOL check, int type) + +Initialises the internal parameters of the current active GF(2m) elliptic curve. The curve is assumed to be +of the form y2 + xy = x3 + Ax2 + B. The field is defined with respect to the trinomial basis tm + ta + 1 +or the pentanomial basis tm+ta+tb+tc+1. This routine can be called subsequently with the parameters +of a different curve. + +**Parameters:** + +←m
+←a
+←b
+←c
+←a2 The A coefficient on the elliptic curve equation
+←a6 The B coefficient on the elliptic curve equation
+←check If TRUE a check is made that the specified basis is irreducible. If FALSE, this basis validity +check, which is time-consuming, is supressed
+←type Either MR_PROJECTIVE or MR_AFFINE, specifying whether projective or affine coordinates +should be used internally. Normally the former is faster + +**Returns:** + +TRUE if parameters make sense, otherwise FALSE + +> Allocated memory will be freed when the current instance of MIRACL is terminated by a call to mirexit(). Only one elliptic curve, GF(p) or GF(2m) may be active within a single MIRACL instance. + +## void ecurve2_mult (big e, epoint * pa, epoint * pt) + +Multiplies a point on a GF(2m) elliptic curve by an integer. Uses the addition/subtraction method. + +**Parameters:** + +←e
+←pa
+→pt = e × pa + +**Precondition:** + +The point pa must be on the active curve. + +## void ecurve2_mult2 (big e, epoint * p, big ea, epoint * pa, epoint * pt) + +Calculates the point e × p + ea × pa on a GF(2m) elliptic curve. This is quicker than doing two separate +multiplications and an addition. Useful for certain cryptosystems. + +**Parameters:** + +←e
+←p
+←ea
+←pa
+→pt = e × p + ea × pa + +**Precondition:** + +The points p and pa must be on the active curve. + +## void ecurve2_multi_add (int m, epoint ** x, epoint ** w) + +Simultaneously adds pairs of points on the active GF(2m) curve. This is much quicker than adding them individually, but only when using affine coordinates. + +**Parameters:** + +←m
+←x
+→w w[i] = w[i] + x[i] for i = 0 to m - 1 + +> Only useful when using affine coordinates. + +> See also: **ecurve2_init** + +## void ecurve2_multn (int n, big * y, epoint ** x, epoint * w) + +Calculates the point x[0]y[0] + x[1]y[1] + . . . + x[n − 1]y[n − 1]) on a GF(2m) elliptic curve, for n >= 2. + +**Parameters:** + +←n
+←y an array of n big numbers
+←x an array of n elliptic curve points
+→w = x[0]y[0] + x[1]y[1] + . . . + x[n − 1]y[n − 1]) + +**Precondition:** + +The points must be on the active curve. The y[] values must all be positive. The underlying number +base must be a power of 2. + +## big ecurve2_sub (epoint * p, epoint * pa) + +Subtracts two points on a GF(2m) elliptic curve. Actually negates p and adds it to pa. Subtraction is quicker +if p is normalised. + +**Parameters:** + +←p
+←→ pa = pa − p + +**Returns:** + +An ephemeral pointer to the sline slope + +**Precondition:** + +The input points must actually be on the current active curve. + +## big ecurve_add (epoint * p, epoint * pa) + +Adds two points on a GF(p) elliptic curve using the special rule for addition. Note that if pa = p, then a +different duplication rule is used. Addition is quicker if p is normalised. + +**Parameters:** + +←p
+←→pa = pa + p + +**Returns:** + +An ephemeral pointer to the sline slope + +**Precondition:** + +The input points must actually be on the current active curve. + +## void ecurve_init (big a, big b, big p, int type) + +Initialises the internal parameters of the current active GF(p) elliptic curve. The curve is assumed to be +of the form y2 = x3 + Ax + B (mod p), the so-called Weierstrass model. This routine can be called +subsequently with the parameters of a different curve. + +**Parameters:** + +←a The A coefficient of the elliptic curve
+←b The B coefficient of the elliptic curve
+←p The modulus
+→type Either MR_PROJECTIVE or MR_AFFINE, specifying whether projective or affine coordinates +should be used internally. Normally the former is faster + +> Allocated memory will be freed when the current instance of MIRACL is terminated by a call to mirexit(). Only one elliptic curve, GF(p) or GF(2m) may be active within a single MIRACL instance. + +## void ecurve_mult (big e, epoint * pa, epoint * pt) + +Multiplies a point on a GF(p) elliptic curve by an integer. Uses the addition/subtraction method. + +**Parameters:** + +←e
+←pa
+→pt = e × pa + +**Precondition:** + +The point pa must be on the active curve. + +## void ecurve_mult2 (big e, epoint * p, big ea, epoint * pa, epoint * pt) + +Calculates the point e × p + ea × pa on a GF(p) elliptic curve. This is quicker than doing two separate +multiplications and an addition. Useful for certain cryptosystems. + +**Parameters:** + +←e
+←p
+←ea
+←pa
+→pt = e × p + ea × pa + +**Precondition:** + +The points p and pa must be on the active curve. + +## void ecurve_multi_add (int m, epoint ** x, epoint ** w) + +Simultaneously adds pairs of points on the active GF(p) curve. This is much quicker than adding them +individually, but only when using affine coordinates. + +**Parameters:** + +←m
+←x
+→w w[i] = w[i] + x[i] for i = 0 to m - 1 + +> Only useful when using affine coordinates. + +> See also: **ecurve_init, nres_multi_inverse** + +## void ecurve_multn (int n, big * y, epoint ** x, epoint * w) + +Calculates the point x[0]y[0] + x[1] * y[1] + . . . + x[n − 1]y[n − 1] on a GF(p) elliptic curve, for n >= 2. + +**Parameters:** + +←n
+←y An array of n big numbers
+←x An array of n elliptic curve points
+→w = x[0]y[0] + x[1]y[1] + . . . + x[n − 1]y[n − 1] + +**Precondition:** + +The points must be on the active curve. The y[] values must all be positive. The underlying number +base must be a power of 2. + +## big ecurve_sub (epoint * p, epoint * pa) + +Subtracts two points on a GF(p) elliptic curve. Actually negates p and adds it to pa. Subtraction is quicker +if p is normalised. + +**Parameters:** + +←p
+←→pa = pa − p + +**Returns:** + +An ephemeral pointer to the sline slope + +**Precondition:** + +The input points must actually be on the current active curve. + +## BOOL epoint2_comp (epoint * a, epoint * b) + +Compares two points on the current active GF(2m) elliptic curve. + +**Parameters:** + +←a
+←b + +**Returns:** + +TRUE if the points are the same, otherwise FALSE. + +## void epoint2_copy* (epoint * a, epoint * b) + +Copies one point to another on a GF(2m) elliptic curve. + +**Parameters:** + +←a
+←b = a + +## int epoint2_get (epoint * p, big x, big y) + +Normalises a point and extracts its (x,y) coordinates on the active GF(2m) elliptic curve. + +**Parameters:** + +←p
+→x
+→y + +**Returns:** + +The least significant bit of y. Note that it is possible to reconstruct a point from its x coordinate and +just the least significant bit of y. Often such a 'compressed' description of a point is useful + +**Precondition:** + +The point p must be on the active curve + +> If x and y are not distinct variables on entry then only the value of x is returned. + +**Example:** +``` +i = epoint2_get(p, x, x); // extract x coordinate and lsb of y/x +``` +## void epoint2_getxyz (epoint * p, big x, big y, big z) + +Extracts the raw (x,y,z) coordinates of a point on the active GF(2m) elliptic curve. + +**Parameters:** + +←p
+→x
+→y
+→z + +**Precondition:** + +The point p must be on the active curve + +> If any of x, y, z is NULL then that coordinate is not returned. + +## BOOL epoint2_norm (epoint * p) + +Normalises a point on the current active GF(2m) elliptic curve. This sets the z coordinate to 1. Point +addition is quicker when adding a normalised point. This function does nothing if affine coordinates are +being used (in which case there is no z coordinate). + +**Parameters:** + +←p A point on the current active elliptic curve + +**Returns:** + +TRUE if successful, otherwise FALSE. + +## BOOL epoint2_set (big x, big y, int cb, epoint * p) + +Sets a point on the current active GF(2m) elliptic curve (if possible). + +**Parameters:** + +←x The x coordinate of the point
+←y The y coordinate of the point + +←cb If x and y are not distinct variables then x only is passed to the function, and cb is taken as the +least significant bit of y. In this case the full value of y is reconstructed internally. This is known +as 'point decompression' (and is a bit time-consuming, requiring the extraction of a modular +square root)
+→p = (x,y) + +**Returns:** + +TRUE if the point exists on the current active elliptic curve, otherwise FALSE + +**Example:** +``` +p = epoint_init(); +epoint2_set(x, x, 1, p); // decompress p +``` +## BOOL epoint_comp (epoint * a, epoint * b) + +Compares two points on the current active GF(p) elliptic curve. + +**Parameters:** + +←a
+←b + +**Returns:** + +TRUE if the points are the same, otherwise FALSE. + +## void epoint_copy* (epoint * a, epoint * b) + +Copies one point to another on a GF(p) elliptic curve. + +**Parameters:** + +←a
+←b = a + +## void epoint_free* (epoint * p) + +Frees memory associated with a point on a GF(p) elliptic curve. + +**Parameters:** + +←p + +## int epoint_get (epoint * p, big x, big y) + +Normalises a point and extracts its (x,y) coordinates on the active GF(p) elliptic curve. + +**Parameters:** + +←p
+→x
+→y + +**Returns:** + +The least significant bit of y. Note that it is possible to reconstruct a point from its x coordinate and +just the least significant bit of y. Often such a 'compressed' description of a point is useful + +**Precondition:** + +The point p must be on the active curve + +> If x and y are not distinct variables on entry then only the value of x is returned. + +**Example:** +``` +i = epoint_get(p, x, x); // extract x coordinate and lsb of y +``` +## void epoint_getxyz (epoint * p, big x, big y, big z) + +Extracts the raw (x,y,z) coordinates of a point on the active GF(p) elliptic curve. + +**Parameters:** + +←p
+→x
+→y
+→z + +**Precondition:** + +The point p must be on the active curve + +> If any of x, y, z is NULL then that coordinate is not returned. + +## epoint* epoint_init (void) + +Assigns memory to a point on a GF(p) elliptic curve, and initialises it to the 'point at infinity' + +**Returns:** + +A pointer to an elliptic curve point (in fact a pointer to a structure allocated from the heap) + +> It is the C programmer's responsibility to ensure that all elliptic curve points initialised by a call to this function are ultimately freed by a call to epoint_free(). If not a memory leak will result. + +## epoint* epoint_init_mem (char * mem, int index) + +Initialises memory for an elliptic curve point from a pre-allocated byte array mem. This array may be +created from the heap by a call to ecp_memalloc(), or in some other way. This is quicker than multiple +calls to epoint_init(). + +**Parameters:** + +←mem
+←index An index into mem. Each index should be unique + +**Returns:** + +An initialised elliptic curve point + +**Precondition:** + +Sufficient memory must have been allocated and pointed to by mem. + +## BOOL epoint_norm (epoint * p) + +Normalises a point on the current active GF(p) elliptic curve. This sets the z coordinate to 1. Point addition is quicker when adding a normalised point. This function does nothing if affine coordinates are being used (in which case there is no z coordinate). + +**Parameters:** + +←p A point on the current active elliptic curve + +**Returns:** + +TRUE if successful, otherwise FALSE. + +## BOOL epoint_set (big x, big y, int cb, epoint * p) + +Sets a point on the current active GF(p) elliptic curve (if possible). + +**Parameters:** + +←x The x coordinate of the point
+←y The y coordinate of the point
+←cb If x and y are not distinct variables then x only is passed to the function, and cb is taken as the +least significant bit of y. In this case the full value of y is reconstructed internally. This is known +as 'point decompression' (and is a bit time-consuming, requiring the extraction of a modular +square root)
+→p = (x,y) + +**Returns:** + +TRUE if the point exists on the current active elliptic curve, otherwise FALSE + +**Example:** +``` +p = epoint_init(); +epoint_set(x, x, 1, p); // decompress p +``` +## BOOL epoint_x (big x) + +Tests to see if the parameter x is a valid coordinate of a point on the curve. It is faster to test an x coordinate +first in this way, rather than trying to directly set it on the curve by calling epoint_set(), as it avoids an +expensive modular square root. + +**Parameters:** + +←x The integer coordinate x + +**Returns:** + +TRUE if x is the coordinate of a curve point, otherwise FALSE. + +## int mul2_brick (ebrick2 * B, big e, big x, big y) + +Carries out a GF(2m) elliptic curve multiplication using the precomputed values stored in the ebrick structure. + +**Parameters:** + +←B A pointer to the current instance
+←e A big exponent
+→x The x coordinate of e × G, where G is specified in the initial call to ebrick2_init()
+→y The y coordinate of e × G, where G is specified in the initial call to ebrick2_init() + +**Returns:** + +The least significant bit of y + +> If x and y are not distinct variables, only x is returned. + +**Precondition:** + +Must be preceded by a call to ebrick2_init(). + +## int mul_brick (ebrick * B, big e, big x, big y) + +Carries out a GF(p) elliptic curve multiplication using the precomputed values stored in the ebrick structure. + +**Parameters:** + +←B A pointer to the current instance
+←e A big exponent
+→x The x coordinate of eG (mod n), where G and n are specified in the initial call to ebrick_init()
+→y The y coordinate of eG (mod n), where G and n are specified in the initial call to ebrick_init() + +**Returns:** + +The least significant bit of y + +> If x and y are not distinct variables, only x is returned. + +**Precondition:** + +Must be preceded by a call to ebrick_init(). + +## BOOL point_at_infinity* (epoint * p) + +Tests if an elliptic curve point is the 'point at infinity'. + +**Parameters:** + +←p An elliptic curve point + +**Returns:** + +TRUE if p is the point at infinity, otherwise FALSE + +**Precondition:** + +The point must be initialised. diff --git a/miracl/docs/miracl-explained/reference-manual/encryption-routines.md b/miracl/docs/miracl-explained/reference-manual/encryption-routines.md new file mode 100644 index 0000000..bda1677 --- /dev/null +++ b/miracl/docs/miracl-explained/reference-manual/encryption-routines.md @@ -0,0 +1,293 @@ +* [What Is Miracl](../README.md) +* [Security Advisory](../security-advisory.md) +* [Benchmarks](../benchmarks.md) +* [Miracl Standard Curves](../miracl-standard-curves.md) +* [IEEE 1363](../ieee-1363.md) +* [Elliptic Curves](../elliptic-curves.md) +* [Licensing](../licensing.md) +* Reference Manual + * [Low Level Routines](low-level-routines.md) + * [Advanced Arithmetic Routines](advanced-arithmetic-routines.md) + * [Montgomery Arithmetic Routines](montgomery-arithmetic-routines.md) + * [ZZn2 Arithmetic Routines](zzn2-arithmetic-routines.md) + * Encryption Routines + * [Elliptic Curve Routines](elliptic-curve-routines.md) + * [Floating Slash Routines](floating-slash-routines.md) + * [Structure Reference](structure-reference.md) + + +Encryption Routines +--- + +In these routines a big parameter can also be used wherever a flash is specified, but not vice versa. Further information may be gleaned from the (lightly) commented source code. An asterisk after +the name indicates that the function does not take a mip parameter if MR_GENERIC_MT is defined in +mirdef.h. + +## mr_unsign32 aes_decrypt* (aes * a, char * buff) + +Decrypts a 16 or n byte input buffer in situ. If the mode of operation is as a block cipher (MR_ECB or +MR_CBC) then 16 bytes will be decrypted. If the mode of operation is as a stream cipher (MR_CFBn, +MR_OFBn or MR_PCFBn) then n bytes will be decrypted. + +**Parameters:** + +←a Pointer to an initialised instance of an aes structured defined in miracl.h
+←→buff Pointer to the buffer of bytes to be decrypted + +**Returns:** + +If MR_CFBn and MR_PCFBn modes then n byte(s) that were shifted off the end of the input register +as result of decrypting the n input byte(s), otherwise 0. + +**Precondition:** + +Must be preceded by call to aes_init() + +## mr_unsign32 aes_encrypt* (aes * a, char * buff) + +Encrypts a 16 or n byte input buffer in situ. If the mode of operation is as a block cipher (MR_ECB or +MR_CBC) then 16 bytes will be encrypted. If the mode of operation is as a stream cipher (MR_CFBn, +MR_OFBn or MR_PCFBn) then n bytes will be encrypted. + +**Parameters:** + +←a Pointer to an initialised instance of an aes structure defined in miracl.h
+←→buff Pointer to the buffer of bytes to be encrypted + +**Returns:** + +In MR_CFBn and MR_PCFBn modes the n byte(s) that were shifted off the end of the input register +as result of encrypting the n input byte(s), otherwise 0. + +**Precondition:** + +Must be preceded by a call to aes_init(). + +## void aes_end* (aes * a) + +Ends an AES encryption session, and de-allocates the memory associated with it. The internal session key +data is destroyed. + +**Parameters:** + +←→a Pointer to an initialised instance of an aes structured defined in miracl.h + +## void aes_getreg* (aes * a, char * ir) + +Reads the current contents of the input chaining register associated with this instance of the AES. This is the register initialised by the IV in the calls to aes_init() and aes_reset(). + +**Parameters:** + +←a Pointer to an instance of the aes structured, defined in miracl.h
+→ir A character array to hold the extracted 16-byte data + +**Precondition:** + +Must be preceded by a call to aes_init(). + +## BOOL aes_init* (aes * a, int mode, int nk, char * key, char * iv) + +Initialises an Encryption/Decryption session using the Advanced Encryption Standard (AES). This is a +block cipher system that encrypts data in 128-bit blocks using a key of 128, 192 or 256 bits. See [Stinson] for more background on block ciphers. + +**Parameters:** + +→a Pointer to an instance of the aes structure defined in miracl.h
+←mode The mode of operation to be used: MR_ECB (Electronic Code Book), MR_CBC (Cipher +Block Chaining), MR_CFBn (Cipher Feed-Back where n is 1, 2 or 4), MR_PCFBn (error Propagating +Cipher Feed-Back where n is 1, 2 or 4) or MR_OFBn (Output Feed-Back where n is 1, +2, 4, 8 or 16). The value of n indicates the number of bytes to be processed in each application. +For more information on Modes of Operation, see [Stinson]. MR_PCFBn is an invention of our +own [Scott93]
+←nk The size of the key in bytes. It can be either 16, 24 or 32
+←key A pointer to the key
+←iv A pointer to the Initialisation Vector (IV). A 16-byte initialisation vector should be specified for +all modes other than MR_ECB, in which case it can be NULL + +**Returns:** + +TRUE if successful, otherwise FALSE. + +## void aes_reset* (aes * a, int mode, char * iv) + +Resets the AES structure. + +**Parameters:** + +←a Pointer to an instance of the aes structure defined in miracl.h
+←mode an Indication of the new mode of operation
+←iv A pointer to a (possibly new) initialisation vector + +## void shs256_hash* (sha256 * sh, char hash[32]) + +Generates a 32 byte (256 bit) hash value into the provided array. + +**Parameters:** + +←sh Pointer to the current instance
+→hash Pointer to array to be filled + +## void shs256_init* (sha256 * sh) + +Initialises an instance of the Secure Hash Algorithm (SHA-256). Must be called before new use. + +**Parameters:** + +→sh Pointer to an instance of a structure defined in miracl.h + +## void shs256_process* (sha256 * sh, int byte) + +Processes a single byte. Typically called many times to provide input to the hashing process. The hash +value of all the processed bytes can be retrieved by a subsequent call to shs256_hash(). + +**Parameters:** + +←sh Pointer to the current instance
+←byte Character to be processed + +## void shs384_hash* (sha384 * sh, char hash[48]) + +Generates a 48 byte (384 bit) hash value into the provided array. + +**Parameters:** + +←sh Pointer to the current instance
+→hash Pointer to array to be filled + +## void shs384_init* (sha384 * sh) + +Initialises an instance of the Secure Hash Algorithm (SHA-384). Must be called before new use. + +**Parameters:** + +! sh Pointer to an instance of a structure defined in miracl.h + +**Precondition:** + +The SHA-384 algorithm is only available if 64-bit data-type is defined. + +## void shs384_process* (sha384 * sh, int byte) + +Processes a single byte. Typically called many times to provide input to the hashing process. The hash +value of all the processed bytes can be retrieved by a subsequent call to shs384_hash(). + +**Parameters:** + +←sh Pointer to the current instance
+←byte Character to be processed + +## void shs512_hash* (sha512 * sh, char hash[64]) + +Generates a 64 byte (512 bit) hash value into the provided array. + +**Parameters:** + +←sh Pointer to the current instance
+→hash Pointer to array to be filled + +## void shs512_init* (sha512 * sh) + +Initialises an instance of the Secure Hash Algorithm (SHA-512). Must be called before new use. + +**Parameters:** + +→sh Pointer to an instance of a structure defined in miracl.h. + +**Precondition:** + +The SHA-512 algorithm is only available if 64-bit data-type is defined. + +## void shs512_process* (sha512 * sh, int byte) + +Processes a single byte. Typically called many times to provide input to the hashing process. The hash +value of all the processed bytes can be retrieved by a subsequent call to shs512_hash(). + +**Parameters:** + +←sh Pointer to the current instance
+←byte Character to be processed + +## void shs_hash* (sha * sh, char hash[20]) + +Generates a twenty byte (160 bit) hash value into the provided array. + +**Parameters:** + +←sh Pointer to the current instance
+→hash Pointer to array to be filled + +## void shs_init* (sha * sh) + +Initialises an instance of the Secure Hash Algorithm (SHA-1). Must be called before new use. + +**Parameters:** + +→sh Pointer to an instance of a structure defined in miracl.h + +## void shs_process* (sha * sh, int byte) + +Processes a single byte. Typically called many times to provide input to the hashing process. The hash +value of all the processed bytes can be retrieved by a subsequent call to shs_hash(). + +**Parameters:** + +←sh Pointer to the current instance
+←byte Character to be processed + +## void strong_bigdig (csprng * rng, int n, int b, big x) + +Generates a big random number of given length from the cryptographically strong generator rng. + +**Parameters:** + +←rng A pointer to the random number generator
+←n
+←b
+→x Big random number n digits long to base b + +**Precondition:** + +The base b must be printable, that is 2 <= b <= 256 + +## void strong_bigrand (csprng * rng, big w, big x) + +Generates a cryptographically strong random big number x using the random number generator rng wuch +that 0 <= x < w + +**Parameters:** + +←rng A pointer to the current instance
+←w
+→x + +## void strong_init* (csprng * rng, int rawlen, char * raw, mr_unsign32 tod) + +Initialises the cryptographically strong random number generator rng. The array raw (of length rawlen) +and the time-of-day value tod are the two sources used together to seed the generator. The former might be provided from random keystrokes, the latter from an internal clock. Subsequent calls to strong_rng() will provide random bytes. + +**Parameters:** + +→rng
+←rawlen
+←raw An array of length rawlen
+←tod A 32-bit time-of-day value + +## void strong_kill* (csprng * rng) + +Kills the internal state of the random number generator rng + +**Parameters:** + +←rng A pointer to a random number generator + +## int strong_rng* (csprng * rng) + +Generates a sequence of cryptographically strong random bytes. + +**Parameters:** + +←rng A pointer to a random number generator + +**Returns:** + +A random byte. diff --git a/miracl/docs/miracl-explained/reference-manual/floating-slash-routines.md b/miracl/docs/miracl-explained/reference-manual/floating-slash-routines.md new file mode 100644 index 0000000..4d3084e --- /dev/null +++ b/miracl/docs/miracl-explained/reference-manual/floating-slash-routines.md @@ -0,0 +1,446 @@ +* [What Is Miracl](../README.md) +* [Security Advisory](../security-advisory.md) +* [Benchmarks](../benchmarks.md) +* [Miracl Standard Curves](../miracl-standard-curves.md) +* [IEEE 1363](../ieee-1363.md) +* [Elliptic Curves](../elliptic-curves.md) +* [Licensing](../licensing.md) +* Reference Manual + * [Low Level Routines](low-level-routines.md) + * [Advanced Arithmetic Routines](advanced-arithmetic-routines.md) + * [Montgomery Arithmetic Routines](montgomery-arithmetic-routines.md) + * [ZZn2 Arithmetic Routines](zzn2-arithmetic-routines.md) + * [Encryption Routines](encryption-routines.md) + * [Elliptic Curve Routines](elliptic-curve-routines.md) + * Floating Slash Routines + * [Structure Reference](structure-reference.md) + + +Floating Slash Routines +--- + +In these routines a big parameter can also be used wherever a flash is specified, but not vice versa. Further information may be gleaned from the (lightly) commented source code. An asterisk after +the name indicates that the function does not take a mip parameter if MR_GENERIC_MT is defined in +mirdef.h. + +## void build (flash x, int(*)(_MIPT_ big, int) gen) + +Uses supplied generator of regular continued fraction expansion to build up a flash number x, rounded if +necessary. + +**Parameters:** + +→x The flash number created
+←gen The generator function + +**Example:** +``` +int phi(flash w, int n) +{ +// rcf generator for golden ratio // +return 1; +} +... +build(x, phi); +... +// This will calculate the golden ratio (1 + sqrt(5)) / 2 in x -- very quickly! +``` +## void dconv (double d, flash w) + +Converts a double to flash format. + +**Parameters:** + +←d
+→w The flash equivalent of d + +## void denom (flash x, big y) + +Extracts the denominator of a flash number. + +**Parameters:** + +←x
+→y The denominator of x + +## void facos (flash x, flash y) + +Calculates arc-cosine of a flash number, using fasin(). + +**Parameters:** + +←x
+→y = arccos(x) + +**Precondition:** + +|x| must be less than or equal to 1. + +## void facosh (flash x, flash y) + +Calculates hyperbolic arc-cosine of a flash number. + +**Parameters:** + +←x
+→y = arccosh(x) + +**Precondition:** + +|x| must be greater than or equal to 1. + +## void fadd (flash x, flash y, flash z) + +Adds two flash numbers. + +**Parameters:** + +←x
+←y
+→z = x + y + +## void fasin (flash x, flash y) + +Calculates arc-sin of a flash number, using fatan(). + +**Parameters:** + +←x
+→y = arcsin(x) + +**Precondition:** + +|x| must be less than or equal to 1. + +## void fasinh (flash x, flash y) + +Calculates hyperbolic arc-sin of a flash number. + +**Parameters:** + +←x
+→y = arcsinh(x) + +## void fatan (flash x, flash y) + +Calculates the arc-tangent of a flash number, using an O(n2.5) method based on Newton's iteration. + +**Parameters:** + +←x
+→y = arctan(x) + +### void fatanh (flash x, flash y) + +Calculates the hyperbolic arc-tangent of a flash number. + +**Parameters:** + +←x
+→y = arctanh(x) + +**Precondition:** + +x2 must be less than 1 + +### int fcomp (flash x, flash y) + +Compares two flash numbers. + +**Parameters:** + +←x
+←y + +**Returns:** + +-1 if y > x, +1 if x > y and 0 if x = y + +### void fconv (int n, int d, flash x) + +Converts a simple fraction to flash format. + +**Parameters:** + +←n
+←d
+→x = n/d + +### void fcos (flash x, flash y) + +Calculates cosine of a given flash angle, using ftan(). + +**Parameters:** + +←x
+→y = cos(x) + +### void fcosh (flash x, flash y) + +Calculates hyperbolic cosine of a given flash angle. + +**Parameters:** + +←x
+→y = cosh(x) + +### void fdiv (flash x, flash y, flash z) + +Divides two flash numbers. + +**Parameters:** + +←x
+←y
+→z = x/y + +### double fdsize (flash w) + +Converts a flash number to double format. + +**Parameters:** + +←w + +**Returns:** + +The value of the parameter x as a double + +**Precondition:** + +The value of x must be representable as a double. + +### void fexp (flash x, flash y) + +Calculates the exponential of a flash number using O(n2.5) method. + +**Parameters:** + +←x
+→y = ex + +### void fincr (flash x, int n, int d, flash y) + +Add a simple fraction to a flash number. + +**Parameters:** + +←x
+←n
+←d
+→y = x + n/d + +**Example:** +``` +// This subtracts two-thirds from the value of x +fincr(x, -2, 3, x); +``` +### void flog (flash x, flash y) + +Calculates the natural log of a flash number using O(n2.5) method. + +**Parameters:** + +←x
+→y = log(x) + +### void flop (flash x, flash y, int * op, flash z) + +Performs primitive flash operation. Used internally. See source listing comments for more details. + +**Parameters:** + +←x
+←y
+←op
+→z = Fn(x,y), where the function performed depends on the parameter op. + +### void fmodulo (flash x, flash y, flash z) + +Finds the remainder when one flash number is divided by another. + +**Parameters:** + +←x
+←y
+→z = x (mod y) + +### void fmul (flash x, flash y, flash z) + +Multiplies two flash numbers. + +**Parameters:** + +←x
+←y
+→z = xy + +### void fpack (big n, big d, flash x) + +Forms a flash number from big numerator and denominator. + +**Parameters:** + +←n
+←d
+→x = n/d + +**Precondition:** + +The denominator must be non-zero. Flash variable x and big variable d must be distinct. The resulting +flash variable must not be too big for the representation. + +### void fpi (flash pi) + +Calculates π using Gauss-Legendre O(n2 log n) method. Note that on subsequent calls to this routine, π is +immediately available, as it is stored internally. (This routine is disappointingly slow. There appears to be +no simple way to calculate a rational approximation to π quickly). + +**Parameters:** + +→pi =π + +> Internally allocated memory is freed when the current MIRACL instance is ended by a call to mirexit(). + +### void fpmul (flash x, int n, int d, flash y) + +Multiplies a flash number by a simple fraction. + +**Parameters:** + +←x
+←n
+←d
+→y = xn/d + +### void fpower (flash x, int n, flash w) + +Raises a flash number to an integer power. + +**Parameters:** + +←x
+←n
+→w = xn + +### void fpowf (flash x, flash y, flash z) + +Raises a flash number to a flash power. + +**Parameters:** + +←x
+←y
+→z = xy + +### void frand (flash x) + +Generates a random flash number. + +**Parameters:** + +→x A flash random number in the range 0 < x < 1 + +### void frecip (flash x, flash y) + +Calculates reciprocal of a flash number. + +**Parameters:** + +←x
+→y = 1/x + +### BOOL froot (flash x, int n, flash w) + +Calculates n-th root of a flash number using Newton's O(n2) method. + +**Parameters:** + +←x
+←n
+→w = nx + +**Returns:** + +TRUE for exact root, otherwise FALSE. + +### void fsin (flash x, flash y) + +Calculates sine of a given flash angle. Uses ftan(). + +**Parameters:** + +←x
+→y = sin(x) + +### void fsinh (flash x, flash y) + +Calculates hyperbolic sine of a given flash angle. + +**Parameters:** + +←x
+→y = sinh(x) + +### void fsub (flash x, flash y, flash z) + +Subtracts two flash numbers. + +**Parameters:** + +←x
+←y
+→z = x − y + +### void ftan (flash x, flash y) + +Calculates the tan of a given flash angle, using an O(n2.5) method. + +**Parameters:** + +←x
+→y = tan(x) + +### void ftanh (flash x, flash y) + +Calculates the hyperbolic tan of a given flash angle. + +**Parameters:** + +←x
+→y = tanh(x) + +### void ftrunc (flash x, big y, flash z) + +Separates a flash number to a big number and a flash remainder. + +**Parameters:** + +←x
+→y = int(x)
+→z The fractional remainder. If y is the same as z, only int(x) is returned + +### void mround (big num, big den, flash z) + +Forms a rounded flash number from big numerator and denominator. If rounding takes place the instance +variable EXACT is set to FALSE. EXACT Is initialised to TRUE in routine mirsys(). This routine is used +internally. + +**Parameters:** + +←num
+←den
+→z = R(num/dem)--- the flash number num/dem is rounded if necessary to fit the representation + +**Precondition:** + +The denominator must be non-zero. + +### void numer (flash x, big y) + +Extracts the numerator of a flash number. + +**Parameters:** + +←x
+→y the numerator of x diff --git a/miracl/docs/miracl-explained/reference-manual/low-level-routines.md b/miracl/docs/miracl-explained/reference-manual/low-level-routines.md new file mode 100644 index 0000000..ce62b2a --- /dev/null +++ b/miracl/docs/miracl-explained/reference-manual/low-level-routines.md @@ -0,0 +1,880 @@ +* [What Is Miracl](../README.md) +* [Security Advisory](../security-advisory.md) +* [Benchmarks](../benchmarks.md) +* [Miracl Standard Curves](../miracl-standard-curves.md) +* [IEEE 1363](../ieee-1363.md) +* [Elliptic Curves](../elliptic-curves.md) +* [Licensing](../licensing.md) +* Reference Manual + * Low Level Routines + * [Advanced Arithmetic Routines](advanced-arithmetic-routines.md) + * [Montgomery Arithmetic Routines](montgomery-arithmetic-routines.md) + * [ZZn2 Arithmetic Routines](zzn2-arithmetic-routines.md) + * [Encryption Routines](encryption-routines.md) + * [Elliptic Curve Routines](elliptic-curve-routines.md) + * [Floating Slash Routines](floating-slash-routines.md) + * [Structure Reference](structure-reference.md) + + +Low Level Routines +--- + +In these routines a big parameter can also be used wherever a flash is specified, but not vice versa. Further information may be gleaned from the (lightly) commented source code. An asterisk after +the name indicates that the function does not take a mip parameter if MR_GENERIC_MT is defined in +mirdef.h. + +## void absol* (flash x, flash y) + +Gives absolute value of a big or flash number. + +**Parameters:** + +←|x The number whose absolute value is to be computed
+→y = |x| + +## void add (big x, big y, big z) + +Adds two big numbers. + +**Parameters:** + +←x
+→y
+→z = x + y + +**Example:** +``` +add(x, x, x); // This doubles the value of x +``` +## int big_to_bytes (int max, big x, char * ptr, BOOL justify) + +Converts a positive big number into a binary octet string. Error checking is carried out to ensure that the +function does not write beyond the limits of ptr if `max > 0`. If `max = 0`, no checking is carried out. If `max > 0 and justify = TRUE`, the output is right-justified, otherwise leading zeros are supressed. + +**Parameters:** + +←max Maximum number of octets to be written in ptr
+←x The original big number
+→ptr Destination of the binary octet string
+→justify If TRUE, the output is right-justified, otherwise leading zeros are supressed. + +**Returns:** + +The number of bytes generated in ptr. If justify = TRUE then the return value is max. + +**Precondition:** + +max must be greater than 0 if justify = TRUE + +## void bigbits (int n, big x) + +Generates a big random number of given length. Uses the built-in simple random number generator initialised +by irand(). + +**Parameters:** + +←n The desired length of the random big number
+→x The random number + +## mr_small brand (void) + +Generates random integer number. + +**Returns:** + +A random integer number. + +**Precondition:** + +First use must be preceded by an initial call to irand(). + +> This generator is not cryptographically strong. For cryptographic applications, use the strong_rng() routine. + +## void bytes_to_big (int len, char * ptr, big x) + +Converts a binary octet string to a big number. Binary to big conversion. + +**Parameters:** + +←len Length of ptr
+←ptr Byte array of the binary octet string
+→x Big result + +**Example:** +``` +#include +#include "miracl.h" + +int main() +{ +int i, len; +miracl *mip = mirsys(100, 0); +big x, y; +char b[200]; // b needs space allocated to it +x = mirvar(0); // all big variables need to be "mirvar"ed +y = mirvar(0); + +expb2(100, x); +incr(x, 3, x); // x = 2^100 + 3 + +len = big_to_bytes(200, x, b, FALSE); +// Now b contains big number x in raw binary +// It is len bytes in length + +// now print out the raw binary number b in hex +for (i = 0; i < len; i++) printf("%02x", b[i]); +printf("n"); + +// now convert it back to big format, and print it out again +bytes_to_big(len, b, y); +mip->IOBASE = 16; +cotnum(y, stdout); + +return 0; +} +``` +## int cinnum (flash x, FILE * filep) + +Inputs a flash/big number from the keyboard or a file, using as number base the current value of the instance variable miracl::IOBASE. Flash numbers can be entered using either a slash '/' to indicate numerator and denominator, or with a radix point. + +**Parameters:** + +→x Big/flash number + +←filep File descriptor. For input from the keyboard specify stdin, otherwise as the descriptor of +some other opened file. + +> To force input of a fixed number of bytes, set the instance variable miracl::INPLEN to the required number, just before calling cinnum(). + +**Example:** +``` +mip->IOBASE = 256; +mip->INPLEN = 14; // this inputs 14 bytes from fp and +cinnum(x, fp); // converts them into big number x +``` +## int cinstr (flash x, char * string) + +Inputs a flash/big number from a character string, using as number base the current value of the instance +variable miracl::IOBASE. Flash numbers can be input using a slash '/' to indicate numerator and denominator, +or with a radix point. + +**Parameters:** + +→x
+←string + +**Returns:** + +The number of input characters. + +**Example:** +``` +// input large hex number into big x +mip->IOBASE = 16; +cinstr(x, "AF12398065BFE4C96DB723A"); +``` +## int compare* (big x, big y) + +Compares two big numbers. + +**Parameters:** + +←x
+→y + +**Returns:** + ++1 if x > y; 0 if x = y; -1 if x < y + +## void convert (int n, big x) + +Converts an integer number to big number format. + +**Parameters:** + +←n
+→x + +## void copy* (flash x, flash y) + +Copies a big/flash number to another. + +**Parameters:** + +←x
+→y= x + +**Parameters:**If x and y are the same variable, no operation is performed. + +## int cotnum (flash x, FILE * filep) + +Outputs a big/flash number to the screen or to a file, using as number base the value currently assigned to +the instance variable miracl::IOBASE. A flash number will be converted to radix-point representation if +the instance variable miracl::RPOINT = ON. Otherwise it will output as a fraction. + +**Parameters:** + +←x Big/flash number to be output
+→filep File descriptor. If stdout then output will be to the screen, otherwise to the file opened with +descriptor filep. + +**Returns:** + +Number of output characters. + +**Example:** +``` +// This outputs x in hex, to the file associated with fp +mip->IOBASE = 16; +cotnum(x, fp); +``` +## int cotstr (flash x, char * string) + +Outputs a big/flash number to the specified string, using as number base the value currently assigned to the +instance variable miracl::IOBASE. A flash number will be converted to radix-point representation if the +instance variable miracl::RPOINT = ON. Otherwise it will be output as a fraction. + +**Parameters:** + +←x
+→string + +**Returns:** + +Number of output characters. + +> There is nothing to prevent this routine from overflowing the limits of the user supplied +> character array string, causing obscure runtime problems. It is the programmer's responsibility to +> ensure that string is big enough to contain the number output to it. Alternatively use the internally +> declared instance string miracl::IOBUFF, which is of size miracl::IOBSIZ. If this array overflows a +> MIRACL error will be flagged. + +## void decr (big x, int n, big z) + +Decrements a big number by an integer amount. + +**Parameters:** + +←x
+←n
+→z = x − n + +## void divide (big x, big y, big z) + +Divides one big number by another: z = x/y, x = x (mod y). The quotient only is returned if x and z +are the same, the remainder only if y and z are the same. + +**Parameters:** + +←→x
+→y
+→z + +**Precondition:** + +Parameters x and y must be different, and y must be non-zero. + +> See also: **normalise()** + +## BOOL divisible (big x, big y) + +Tests a big number for divisibility by another. + +**Parameters:** + +←x
+→y + +**Returns:** + +TRUE if y divides x exactly, otherwise FALSE. + +**Precondition:** + +The parameter y must be non-zero. + +## void* ecp_memalloc (int num) + +Reserves space for a number elliptic curve points in one heap access. Individual points can subsequently +be initialised from this memory by calling epoint_init_mem(). + +**Parameters:** + +←num The number of elliptic curve points to reserve space for. + +**Returns:** + +A pointer to the allocated memory. + +## void ecp_memkill (char * mem, int num) + +Deletes and sets to zero the memory previously allocated by ecp_memalloc(). + +**Parameters:** + +→mem Pointer to the memory to be erased and deleted
+←num The size of the memory in elliptic curve points + +**Precondition:** + +Must be preceded by a call to ecp_memalloc(). + +## int exsign* (flash x) + +Extracts the sign of a big/flash number. + +**Parameters:** + +←x A big/flash number + +**Returns:** + +The sign of x, i.e. -1 if x is negative, +1 if x is zero or positive. + +## miracl* get_mip () + +Gets the current Miracl Instance Pointer. + +**Returns:** + +The mip (Miracl Instance Pointer) for the current thread. + +**Precondition:** + +This function does not exist if MR_GENERIC_MT is defined. + +## int getdig (big x, int i) + +Extracts a digit from a big number. + +**Parameters:** + +←x A big number
+→i The position of the digit to be extracted from x + +**Returns:** + +The value of the requested digit. + +> Returns rubbish if required digit does not exist. + +## unsigned int igcd* (unsigned int x, unsigned int y) + +Calculates the Greatest Common Divisor of two integers using Euclid's Method. + +**Parameters:** + +←x
+←y + +**Returns:** + +The GCD of x and y. + +## void incr (big x, int n, big z) + +Increments a big number. + +**Parameters:** + +←x
+←n
+→z = x + n + +**Example:** +``` +incr(x, 2, x); // This increments x by 2 +``` +## BOOL init_big_from_rom (big x, int len, const mr_small * rom, int romsize, int * romptr) + +Initialises a big variable from ROM memory. + +**Parameters:** + +→rx A big number
+←len Length of the big number in computer words
+←rom Address of ROM memory which stores up to romsize computer words
+←romsize
+←→romptr A pointer into ROM. This pointer is incremented internally as ROM memory is accessed +to fill x + +**Returns:** + +TRUE if successful, or FALSE if an attempt is made to read beyond the end of the ROM. + +## BOOL init_point_from_rom (epoint * P, int len, const mr_small * rom, int romsize, int * romptr) + +Initialises an elliptic curve point from ROM memory. + +**Parameters:** + +→P An elliptic curve point
+←len Length of the two big coordinates of P, in computer words
+←rom Address of ROM memory which stores up to romsize computer words
+←romsize
+←→romptr A pointer into ROM. This pointer is incremented internally as ROM memory is accessed +to fill P + +**Returns:** + +TRUE if successful, or FALSE if an attempt is made to read beyond the end of the ROM. + +## int innum (flash x, FILE * filep) + +Inputs a big/flash number from a file or the keyboard, using as number base the value specified in the +initial call to mirsys(). Flash numbers can be entered using either a slash '/' to indicate numerator and +denominator, or with a radix point. + +**Parameters:** + +→x A big/flash number
+←filep A file descriptor. For input from the keyboard specify stdin, otherwise the descriptor of +some other opened file. + +**Returns:** + +The number of characters input. + +**Precondition:** + +The number base specified in mirsys() must be less than or equal to 256. If not use cinnum() instead. + +> For fastest inputting of ASCII text to a big number, and if a full-width base is possible, use mirsys(...,256) initially. This has the same effect as specifying mirsys(...,0), except that now ASCII bytes may be input directly via innum(x, fp) without the time-consuming change of base implicit in the use of cinnum(). + +## void insign* (int s, flash x) + +Forces a big/flash number to a particular sign. + +**Parameters:** + +←s The sign the big/flash is to take
+→x = s|x| + +**Example:** +``` +insign(PLUS, x); // force x to be positive +``` +## int instr (flash x, char * string) + +Inputs a big or flash number from a character string, using as number base the value specified in the +initial call to mirsys(). Flash numbers can be entered using either a slash '/' to indicate numerator and +denominator, or with a radix point. + +**Parameters:** + +→x
+←string + +**Returns:** + +The number of characters input. + +**Precondition:** + +The number base specified in mirsys() must be less than or equal to 256. If not use cinstr() instead. + +## void irand (mr_unsign32 seed) + +Initialises internal random number system. Long integer types are used internally to yield a generator with +maximum period. + +**Parameters:** + +←seed A seed used to start off the random number generator. + +## void lgconv (long n, big x) + +Converts a long integer to big number format. + +**Parameters:** + +←n
+→x +## void mad (big x, big y, big z, big w, big q, big r) + +Multiplies, adds and divides big numbers. The initial product is stored in a double-length internal variable +to avoid the possibility of overflow at this stage. + +**Parameters:** + +←x
+←y
+←z
+←w
+→q = (xy + z)/w
+→r The remainder + +> If w and q are not distinct variables then only the remainder is returned; if q and r are not distinct then only the quotient is returned. The addition of z is not done if x and z (or y and z) are the same. + +**Precondition:** + +Parameters w and r must be distinct. The value of w must not be zero. + +**Example:** +``` +mad(x, x, x, w, x, x,); // x = x^2 / w +``` +## void* memalloc (int num) + +Reserves space for big/flash variables in one heap access. Individual big/flash variables can subsequently +be initialised from this memory by calling mirvar_mem(). + +**Parameters:** + +←num The number of big/flash variables to reserve space for. + +**Returns:** + +A pointer to the allocated memory + +## void memkill (char * mem, int len) + +Deletes and sets to zero the memory previously allocated by memalloc(). + +**Parameters:** + +→mem A pointer to the memory to be erased and deleted
+←len The size of that memory in bigs + +**Precondition:** + +Must be preceded by a call to memalloc() + +## void mirexit (void) + +Cleans up after the current instance of MIRACL, and frees all internal variables. A subsequent call to +mirsys() will re-initialise the MIRACL system. + +**Precondition:** + +Must be called after mirsys(). + +## void mirkill* (big x) + +Securely kills off a big/flash number by zeroising it, and freeing its memory. + +**Parameters:** + +←x. + +## miracl* mirsys (int nd, mr_small nb) + +Initialises the MIRACL system for the current program thread, as described below. Must be called before +attempting to use any other MIRACL routines + +1. The error tracing mechanism is initialised. +2. The number of computer words to use for each big/flash number is calculated from nd and nb. +3. Sixteen big work variables (four of them double length) are initialised. +4. Certain instance variables are given default initial values. +5. The random number generator is started by calling irand(0L). + +**Parameters:** + +←nd The number of digits to use for each big/flash variable. If negative, it is taken as indicating the +size of big/flash numbers in 8-bit bytes
+→nb The number base + +**Returns:** + +The Miracl Instance Pointer, via which all instance variables can be accessed, or NULL if there was +not enough memory to create an instance + +**Precondition:** + +The number base nb should normally be greater than 1 and less than or equal to MAXBASE. A base of +0 implies that the 'full-width' number base should be used. The number of digits nd must be less than +a certain maximum, depending on the underlying type mr_utype and on whether or not MR_FLASH +is defined + +**Example:** +``` +// This initialises the MIRACL system to use 500 decimal digits for each +// big or flash number +miracl *mip = mirsys(500, 10); +``` +## flash mirvar (int iv) + +Initialises a big/flash variable by reserving a suitable number of memory locations for it. This memory may +be released by a subsequent call to the function mirkill(). + +**Parameters:** + +←iv An integer initial value for the big/flash number + +**Returns:** + +A pointer to the reserved memory + +**Example:** +``` +flash x; +x = mirvar(8); // Creates a flash variable x = 8 +``` +## flash mirvar_mem (char * mem, int index) + +Initialises memory for a big/flash variable from a pre-allocated byte array mem. This array may be created +from the heap by a call to memalloc(), or in some other way. This is quicker than multiple calls to mirvar(). + +**Parameters:** + +←mem A pointer to the pre-allocated array
+←index An index into that array. Each index should be unique + +**Returns:** + +An initialised big/flash variable + +**Precondition:** + +Sufficient memory must have been allocated and pointed to by mem. + +## void multiply (big x, big y, big z) + +Multiplies two big numbers. + +**Parameters:** + +←x
+←y
+→z = xy + +## void negify* (flash x, flash y) + +Negates a big/flash number. + +**Parameters:** + +←x
+→y = - x + +> negify(x,x) is valid and sets x = - x + +## mr_small normalise (big x, big y) + +Multiplies a big number such that its most significant word is greater than half the number base. If such +a number is used as a divisor by divide(), the division will be carried out faster. If many divisions by the +same divisor are required, it makes sense to normalise the divisor just once beforehand. + +**Parameters:** + +←x
+→y = nx + +**Returns:** + +n, the normalising multiplier + +> Use with care. Used internally. + +## int numdig (big x) + +Determines the number of digits in a big number. + +**Parameters:** + +←x + +**Returns:** + +The number of digits in x. + +## int otnum (flash x, FILE * filep) + +Outputs a big/flash number to the screen or to a file, using as number base the value specified in the initial +call to mirsys(). A flash number will be converted to radix-point representation if the instance variable +miracl::RPOINT = ON. Otherwise it will be output as a fraction. + +**Parameters:** + +←x A big/flash number
+←filep A file descriptor. If stdout then output will be to the screen, otherwise to the file opened with descriptor filep + +**Returns:** + +Number of output characters + +**Precondition:** + +The number base specified in mirsys() must be less than or equal to 256. If not, use cotnum() instead. + +## int otstr (flash x, char * string) + +Outputs a big or flash number to the specified string, using as number base the value specified in the initial +call to mirsys(). A flash number will be converted to radix-point representation if the instance variable +miracl::RPOINT = ON. Otherwise it will be output as a fraction. + +**Parameters:** + +←x A big/flash number
+→string A representation of x + +**Returns:** + +Number of output characters + +**Precondition:** + +The number base specified in mirsys() must be less than or equal to 256. If not, use cotstr() instead + +> There is nothing to prevent this routine from overflowing the limits of the user supplied +> character array string, causing obscure runtime problems. It is the programmer's responsibility to +> ensure that string is big enough to contain the number output to it. Alternatively use the internally +> declared instance string miracl::IOBUFF, which is of size miracl::IOBSIZ. If this array overflows a +> MIRACL error will be flagged. + +## void premult (big x, int n, big z) + +Multiplies a big number by an integer. + +**Parameters:** + +←x
+←n
+→z = nx + +## void putdig (int n, big x, int i) + +Sets a digit of a big number to a given value. + +**Parameters:** + +←n The new value for the digit
+→x A big number
+←i A digit position + +**Precondition:** + +The digit indicated must exist. + +## int remain (big x, int n) + +Finds the integer remainder, when a big number is divided by an integer. + +**Parameters:** + +←x
+←n + +**Returns:** + +The integer remainder. + +## void set_io_buffer_size (int len) + +Sets the size of the input/output buffer. By default this is set to 1024, but programs that need to handle very +large numbers may require a larger I/O buffer. + +**Parameters:** + +←len The size of I/O buffer required + +> Destroys the current contents of the I/O buffer. + +## void set_user_function (BOOL(*)(void) user) + +Supplies a user-specified function, which is periodically called during some of the more time-consuming +MIRACL functions, particularly those involved in modular exponentiation and in finding large prime numbers. +The supplied function must take no parameters and return a BOOL value. Normally this should be +TRUE. If FALSE then MIRACL will attempt to abort its current operation. In this case the function should +continue to return FALSE until control is returned to the calling program. The user-supplied function +should normally include only a few instructions, and no loops, otherwise it may adversely impact the speed +of MIRACL functions + +Once MIRACL is initialised, this function may be called multiple times with a new supplied function. If +no longer required, call with a NULL parameter. + +**Parameters:** + +←user A pointer to a user-supplied function, or NULL if not required + +**Example:** +``` +// Windows Message Pump +static BOOL idle() +{ +MSG msg; +if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) +{ +if (msg.message != WM_QUIT) +{ +if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) +{ +// do a Message Pump +TranslateMessage(&msg); +DispatchMessage(&msg); +} +} +else +return FALSE; +} +return TRUE; +} +... +set_user_function(idle); +``` +## int size* (big x) + +Tries to convert big number to a simple integer. Also useful for testing the sign of big/flash variable as in: +if (size(x) < 0) ... + +**Parameters:** + +←x A big number + +**Returns:** + +The value of x as an integer. If this is not possible (because x is too big) it returns the value plus or +minus MR_TOOBIG. + +## int subdiv (big x, int n, big z) + +Divides a big number by an integer + +**Parameters:** + +←x
+←n
+→z = x/n + +**Returns:** + +The integer remainder + +**Precondition:** + +The value of n must not be zero. + +## BOOL subdivisible (big x, int n) + +Tests a big number for divisibility by an integer. + +**Parameters:** + +←x
+←n + +**Returns:** + +TRUE if n divides x exactly, otherwise FALSE + +**Precondition:** + +The value of n must not be zero. + +## void subtract (big x, big y, big z) + +Subtracts two big numbers. + +**Parameters:** + +←x
+←y
+→z = x − y + +## void zero* (flash x) + +Sets a big/flash number to zero. + +**Parameters:** + +→x diff --git a/miracl/docs/miracl-explained/reference-manual/montgomery-arithmetic-routines.md b/miracl/docs/miracl-explained/reference-manual/montgomery-arithmetic-routines.md new file mode 100644 index 0000000..aec26d5 --- /dev/null +++ b/miracl/docs/miracl-explained/reference-manual/montgomery-arithmetic-routines.md @@ -0,0 +1,349 @@ +* [What Is Miracl](../README.md) +* [Security Advisory](../security-advisory.md) +* [Benchmarks](../benchmarks.md) +* [Miracl Standard Curves](../miracl-standard-curves.md) +* [IEEE 1363](../ieee-1363.md) +* [Elliptic Curves](../elliptic-curves.md) +* [Licensing](../licensing.md) +* Reference Manual + * [Low Level Routines](low-level-routines.md) + * [Advanced Arithmetic Routines](advanced-arithmetic-routines.md) + * Montgomery Arithmetic Routines + * [ZZn2 Arithmetic Routines](zzn2-arithmetic-routines.md) + * [Encryption Routines](encryption-routines.md) + * [Elliptic Curve Routines](elliptic-curve-routines.md) + * [Floating Slash Routines](floating-slash-routines.md) + * [Structure Reference](structure-reference.md) + + +Montgomery Arithmetic Routines +--- + +In these routines a big parameter can also be used wherever a flash is specified, but not vice versa. Further information may be gleaned from the (lightly) commented source code. An asterisk after +the name indicates that the function does not take a mip parameter if MR_GENERIC_MT is defined in +mirdef.h. + +## void nres (big x, big y) + +Converts a big number to n-residue form. + +**Parameters:** + +←x
+→y the n-residue form of x + +**Precondition:** + +Must be preceded by call to prepare_monty() + +> See also: **redc** + +## void nres_dotprod (int m, big * x, big * y, big w) + +Finds the dot product of two arrays of n-residues. So-called "lazy" reduction is used, in that the sum of +products is only reduced once with respect to the Montgomery modulus. This is quicker---nearly twice as fast. + +**Parameters:** + +←m
+←x An array of m n-residues
+←y An array of m n-residues
+→w =Σxiyi (mod n), where n is the current Montgomery modulus + +**Precondition:** + +Must be preceded by call to prepare_monty(). + +## void nres_double_modadd (big x, big y, big w) + +Adds two double length bigs modulo pR, where R = 2n and n is the smallest multiple of the word-length +of the underlying MIRACL type, such that R > p. This is required for lazy reduction. + +**Parameters:** + +←x
+←y
+→w = a + b (mod pR) + +## void nres_double_modsub (big x, big y, big w) + +Subtracts two double length bigs modulo pR, where R = 2n and n is the smallest multiple of the wordlength +of the underlying MIRACL type, such that R > p. This is required for lazy reduction. + +**Parameters:** + +←x
+←y
+→w = a − b (mod pR) + +## void nres_lazy (big a0, big a1, big b0, big b1, big r, big i) + +Uses the method of lazy reduction combined with Karatsuba's method to multiply two zzn2 variables. +Requires just 3 multiplications and two modular reductions. + +**Parameters:** + +←a0
+←a1
+←b0
+←b1
+→r = the "real part" of (a0 + a1i)(b0 + b1i)
+→i = the "imaginary part" of (a0 + a1i)(b0 + b1i) + +## void nres_lucas (big p, big r, big vp, big v) + +Modular Lucas exponentiation of an n-residue. + +**Parameters:** + +←p An n-residue
+←r A big exponent
+→vp = Vr−1(p) (mod n) where n is the current Montgomery modulus
+→v = Vr(p) (mod n) where n is the current Montgomery modulus + +> Only v is returned if v and vp are the same big variable. + +**Precondition:** + +Must be preceded by call to prepare_monty() and conversion of the first parameter to n-residue form. +Note that the exponent is not converted to n-residue form + +> See also: **lucas** + +## void nres_modadd (big x, big y, big w) + +Modular addition of two n-residues. + +**Parameters:** + +←x
+←y
+→w = x + y (mod n), where n is the current Montgomery modulus + +**Precondition:** + +Must be preceded by a call to prepare_monty(). + +## int nres_moddiv (big x, big y, big w) + +Modular division of two n-residues. + +**Parameters:** + +←x
+←y
+→w = x/y (mod n), where n is the current Montgomery modulus + +**Returns:** + +GCD of y and n as an integer, if possible, or MR_TOOBIG. Should be 1 for a valid result + +**Precondition:** + +Must be preceded by call to prepare_monty() and conversion of parameters to n-residue form. Parameters +x and y must be distinct. + +## void nres_modmult (big x, big y, big w) + +Modular multiplication of two n-residues. Note that this routine will invoke a KCM Modular Multiplier if +MR_KCM has been defined in mirdef.h and set to an appropriate size for the current modulus, or a Comba +fixed size modular multiplier if MR_COMBA is defined as exactly the size of the modulus. + +**Parameters:** + +←x
+←y
+→w = xy (mod n), where n is the current Montgomery modulus + +**Precondition:** + +Must be preceded by call to prepare_month() and conversion of parameters to n-residue form. + +### void nres_modsub (big x, big y, big w) + +Modular subtraction of two n-residues. + +**Parameters:** + +←x
+←y
+→w = x − y (mod n), where n is the current Montgomery modulus + +**Precondition:** + +Must be preceded by a call to prepare_monty(). + +### BOOL nres_multi_inverse (int m, big * x, big * w) + +Finds the modular inverses of many numbers simultaneously, exploiting Montgomery's observation that +x−1 = y(xy)−1, y−1 = x(xy)−1. This will be quicker, as modular inverses are slow to calculate, and this +way only one is required. + +**Parameters:** + +←m The number of inverses required
+←x An array of m n-residues whose inverses are wanted
+→w An array with the inverses of za x + +**Returns:** + +TRUE if successful, otherwise FALSE + +**Precondition:** + +The parameters x and w must be distinct. + +### void nres_negate (big x, big w) + +Modular negation. + +**Parameters:** + +←x An n-residue number
+→w = −x (mod n), where n is the current Montgomery modulus + +**Precondition:** + +Must be preceded by a call to prepare_monty(). + +### void nres_powltr (int x, big y, big w) + +Modular exponentiation of an n-residue. + +**Parameters:** + +←x
+←y
+→w = xy (mod n), where n is the current Montgomery modulus + +**Precondition:** + +Must be preceded by call to prepare_monty(). Note that the small integer x and the exponent are not +converted to n-residue form. + +### void nres_powmod (big x, big y, big w) + +Modular exponentiation of an n-residue. + +**Parameters:** + +←x An n-reside number, the base
+←y A big number, the exponent
+→w = xy (mod n), where n is the current Montgomery modulus + +**Precondition:** + +Must be preceded by call to prepare_monty() and conversion of the first parameter to n-residue form. +Note that the exponent is not converted to n-residue form + +> See also: **nres_powltr, nres_powmod2** + +**Example:** +``` +prepare_monty(n); +... +nres(x, y); // convert to n-residue form +nres_powmod(y, e, z); +redc(z, w); // convert back to normal form +``` +### void nres_powmod2 (big x, big y, big a, big b, big w) + +Calculates the product of two modular exponentiations involving n-residues. + +**Parameters:** + +←x An n-residue number
+←y A big integer
+←a An n-residue number
+←b A big integer
+→w = xy ab (mod n), where n is the current Montgomery modulus + +**Precondition:** + +Must be preceded by call to prepare_monty() and conversion of the appropriate parameters to n-residue +form. Note that the exponents are not converted to n-residue form + +> See also: **nres_powltr, nres_powmod** + +### void nres_powmodn (int n, big * x, big * y, big w) + +Calculates the product of n modular exponentiations involving n-residues. Extra memory is allocated +internally by this function. + +**Parameters:** + +←n The number of n-residue numbers
+←x An array of n n-residue numbers
+←y An array of n big integers
+→w = x[0]y[0]x[1]y[1] · · · x[n − 1]y[n−1) (mod p), where p is the current Montgomery modulus + +**Precondition:** + +Must be preceded by call to prepare_monty() and conversion of the appropriate parameters to n-residue +form. Note that the exponents are not converted to n-residue forms. + +### void nres_premult (big x, int k, big w) + +Multiplies an n-residue by a small integer. + +**Parameters:** + +←x
+←k
+→w = kx (mod n), where n is the current Montgomery modulus + +**Precondition:** + +Must be preceded by call to prepare_monty() and conversion of the first parameter to n-residue form. +Note that the small integer is not converted to n-residue form + +> See also: **nres_modmult** + +### BOOL nres_sqroot (big x, big w) + +Calculates the square root of an n-residue mod a prime modulus. + +**Parameters:** + +←x
+→w =x (mod n), where n is the current Montgomery modulus + +**Returns:** + +TRUE if the square root exists, otherwise FALSE + +**Precondition:** + +Must be preceded by call to prepare_monty() and conversion of the first parameter to n-residue form. + +### mr_small prepare_monty (big n) + +Prepares a Montgomery modulus for use. Each call to this function replaces the previous modulus (if any). + +**Parameters:** + +←n A big number which is to be the Montgomery modulus + +**Returns:** + +None + +**Precondition:** + +The parameter n must be positive and odd. Allocated memory is freed when the current instance of +MIRACL is terminated by a call to mirexit(). + +### void redc (big x, big y) + +Converts an n-residue back to normal form. + +**Parameters:** + +←x an n-residue
+→y the normal form of the n-residue x + +**Precondition:** + +Must be preceded by call to prepare_monty() + +> See also: **nres** diff --git a/miracl/docs/miracl-explained/reference-manual/structure-reference.md b/miracl/docs/miracl-explained/reference-manual/structure-reference.md new file mode 100644 index 0000000..66acd33 --- /dev/null +++ b/miracl/docs/miracl-explained/reference-manual/structure-reference.md @@ -0,0 +1,48 @@ +* [What Is Miracl](../README.md) +* [Security Advisory](../security-advisory.md) +* [Benchmarks](../benchmarks.md) +* [Miracl Standard Curves](../miracl-standard-curves.md) +* [IEEE 1363](../ieee-1363.md) +* [Elliptic Curves](../elliptic-curves.md) +* [Licensing](../licensing.md) +* Reference Manual + * [Low Level Routines](low-level-routines.md) + * [Advanced Arithmetic Routines](advanced-arithmetic-routines.md) + * [Montgomery Arithmetic Routines](montgomery-arithmetic-routines.md) + * [ZZn2 Arithmetic Routines](zzn2-arithmetic-routines.md) + * [Encryption Routines](encryption-routines.md) + * [Elliptic Curve Routines](elliptic-curve-routines.md) + * [Floating Slash Routines](floating-slash-routines.md) + * Structure Reference + + +MIRACL Structure Reference +--- + +## MIRACL Instance Pointer + +`#include ` + +## Field Documentation + +`BOOL ERCON` - errors by default generate an error message and immediately abort the program. Alternatively by setting mip->ERCON=TRUE error control is left to the user. + +`int ERNUM` - number of the last error that occurred. + +`BOOL EXACT` - initialised to TRUE. Set to FALSE if any rounding takes place during flash arithmetic. + +`int INPLEN` - length of input string. Must be used when inputting binary data. + +`int IOBASE` - the 'printable' number base to be used for input and output. May be changed at will within a program. Must be greater than or equal to 2 and less than or equal to 256. + +`int IOBSIZ` – size of I/O buffer. + +`char* IOBUFF` – input/output buffer. + +`int NTRY` - number of iterations used in probabilistic primality test by isprime(). Initialised to 6. + +`int* PRIMES` – pointer to a table of small prime numbers. + +`BOOL RPOINT` - if set to ON numbers are output with a radix point. Otherwise they are output as fractions (the default). + +`BOOL TRACER` - if set to ON causes debug information to be printed out, tracing the progress of all subsequent calls to MIRACL routines. Initialised to OFF. diff --git a/miracl/docs/miracl-explained/reference-manual/zzn2-arithmetic-routines.md b/miracl/docs/miracl-explained/reference-manual/zzn2-arithmetic-routines.md new file mode 100644 index 0000000..09bea56 --- /dev/null +++ b/miracl/docs/miracl-explained/reference-manual/zzn2-arithmetic-routines.md @@ -0,0 +1,544 @@ +* [What Is Miracl](../README.md) +* [Security Advisory](../security-advisory.md) +* [Benchmarks](../benchmarks.md) +* [Miracl Standard Curves](../miracl-standard-curves.md) +* [IEEE 1363](../ieee-1363.md) +* [Elliptic Curves](../elliptic-curves.md) +* [Licensing](../licensing.md) +* Reference Manual + * [Low Level Routines](low-level-routines.md) + * [Advanced Arithmetic Routines](advanced-arithmetic-routines.md) + * [Montgomery Arithmetic Routines](montgomery-arithmetic-routines.md) + * ZZn2 Arithmetic Routines + * [Encryption Routines](encryption-routines.md) + * [Elliptic Curve Routines](elliptic-curve-routines.md) + * [Floating Slash Routines](floating-slash-routines.md) + * [Structure Reference](structure-reference.md) + + +ZZn2 Arithmetic Routines +--- + +In these routines a big parameter can also be used wherever a flash is specified, but not vice versa. Further information may be gleaned from the (lightly) commented source code. An asterisk after +the name indicates that the function does not take a mip parameter if MR_GENERIC_MT is defined in +mirdef.h. + +## void zzn2_add (zzn2 * x, zzn2 * y, zzn2 * w) + +Adds two zzn2 variables. + +**Parameters:** + +←x
+←y
+→w = x + y + +## BOOL zzn2_compare* (zzn2 * x, zzn2 * y) + +Compares two zzn2 variables for equality. + +**Parameters:** + +←x
+←y + +**Returns:** + +TRUE if x = y, otherwise FALSE. + +## void zzn2_conj (zzn2 *x, zzn2 *w) + +Finds the conjugate of a zzn2. + +**Parameters:** + +←x
+→w If x = a + bi, then w = a - bi + +## void zzn2_copy* (zzn2 * x, zzn2 * w) + +Copies one zzn2 to another. + +**Parameters:** + +←x
+→w = x + +## void zzn2_from_big (big x, zzn2 * w) + +Creates a zzn2 from a big integer. This is converted internally into n-residue format. + +**Parameters:** + +←x
+→w = x + +## void zzn2_from_bigs (big x, big y, zzn2 * w) + +Creates a zzn2 from two big integers. These are converted internally into n-residue format. + +**Parameters:** + +←x
+←y
+→w = x + yi + +## void zzn2_from_int (int i, zzn2 * w) + +Converts an integer to zzn2 format. + +**Parameters:** + +←i
+→w = i + +> See also: **zzn2_from_ints** + +## void zzn2_from_ints (int i, int j, zzn2 * w) + +Creates a zzn2 from two integers. + +**Parameters:** + +←i
+←j
+→w = i + j i + +> See also: **zzn2_from_int** + +## void zzn2_from_zzn (big x, zzn2 * w) + +Creates a zzn2 from a big already in n-residue format. + +**Parameters:** + +←x
+→w = x + +### void zzn2_from_zzns (big x, big y, zzn2 * w) + +Creates a zzn2 from two bigs already in n-residue format. + +**Parameters:** + +←x
+←y
+→w = x + y i + +> See also: **zzn2_from_zzn** + +### void zzn2_imul (zzn2 * x, int y, zzn2 * w) + +Multiplies a zzn2 variable by an integer. + +**Parameters:** + +←x
+←y
+→w = xy + +### void zzn2_inv (zzn2 * w) + +In-place inversion of a zzn2 variable. + +**Parameters:** + +←→w = 1 / w + +### BOOL zzn2_isunity (zzn2 * x) + +Tests a zzn2 value for equality to one. + +**Parameters:** + +←x + +**Returns:** + +TRUE if x is one, otherwise FALSE. + +### BOOL zzn2_iszero* (zzn2 * x) + +Tests a zzn2 value for equality to zero. + +**Parameters:** + +←x + +**Returns:** + +TRUE if x is zero, otherwise FALSE. + +### void zzn2_mul (zzn2 * x, zzn2 * y, zzn2 * w) + +Multiplies two zzn2 variables. If x and y are the same variable, a faster squaring method is used. + +**Parameters:** + +←x
+←y
+→w = xy + +### void zzn2_negate (zzn2 * x, zzn2 * w) + +Negates a zzn2 + +**Parameters:** + +←x
+→w = -x + +### void zzn2_sadd (zzn2 * x, big y, zzn2 * w) + +Adds a big in n-residue format to a zzn2. + +**Parameters:** + +←x
+←y
+→w = x + y + +### void zzn2_smul (zzn2 * x, big y, zzn2 * w) + +Multiplies a zzn2 variable by a big in n-residue. + +**Parameters:** + +←x
+←y
+→w = xy + +### void zzn2_ssub (zzn2 * x, big y, zzn2 * w) + +Subtracts a big in n-residue format from a zzn2. + +**Parameters:** + +←x
+←y
+→w = x - y + +### void zzn2_sub (zzn2 * x, zzn2 * y, zzn2 * w) + +Subtracts two zzn2 variables. + +**Parameters:** + +←x
+←y
+→w = x - y + +### void zzn2_timesi (zzn2 * u) + +In-place multiplication of a zzn2 by i, the imaginary square root of the quadratic non-residue. + +**Parameters:** + +←→u If u = a + bi then on exit u = i2b + ai + +### void zzn2_zero* (zzn2 * w) + +Sets a zzn2 variable to zero. + +**Parameters:** + +→w = 0 + +## Encryption Routines + +**Functions** +- mr_unsign32 aes_decrypt* (aes *a, char *buff) +- mr_unsign32 aes_encrypt* (aes *a, char *buff) +- void aes_end* (aes *a) +- void aes_getreg* (aes *a, char *ir) +- BOOL aes_init* (aes *a, int mode, int nk, char *key, char *iv) +- void aes_reset* (aes *a, int mode, char *iv) +- void shs256_hash* (sha256 *sh, char hash[32]) +- void shs256_init* (sha256 *sh) +- void shs256_process* (sha256 *sh, int byte) +- void shs384_hash* (sha384 *sh, char hash[48]) +- void shs384_init* (sha384 *sh) +- void shs384_process* (sha384 *sh, int byte) +- void shs512_hash* (sha512 *sh, char hash[64]) +- void shs512_init* (sha512 *sh) +- void shs512_process* (sha512 *sh, int byte) +- void shs_hash* (sha *sh, char hash[20]) +- void shs_init* (sha *sh) +- void shs_process* (sha *sh, int byte) +- void strong_bigdig (csprng *rng, int n, int b, big x) +- void strong_bigrand (csprng *rng, big w, big x) +- void strong_init* (csprng *rng, int rawlen, char *raw, mr_unsign32 tod) +- void strong_kill* (csprng *rng) +- int strong_rng* (csprng *rng) + +## mr_unsign32 aes_decrypt* (aes * a, char * buff) + +Decrypts a 16 or n byte input buffer in situ. If the mode of operation is as a block cipher (MR_ECB or +MR_CBC) then 16 bytes will be decrypted. If the mode of operation is as a stream cipher (MR_CFBn, +MR_OFBn or MR_PCFBn) then n bytes will be decrypted. + +**Parameters:** + +←a Pointer to an initialised instance of an aes structured defined in miracl.h
+←→buff Pointer to the buffer of bytes to be decrypted + +**Returns:** + +If MR_CFBn and MR_PCFBn modes then n byte(s) that were shifted off the end of the input register +as result of decrypting the n input byte(s), otherwise 0 + +**Precondition:** + +Must be preceded by call to aes_init(). + +## mr_unsign32 aes_encrypt* (aes * a, char * buff) + +Encrypts a 16 or n byte input buffer in situ. If the mode of operation is as a block cipher (MR_ECB or +MR_CBC) then 16 bytes will be encrypted. If the mode of operation is as a stream cipher (MR_CFBn, +MR_OFBn or MR_PCFBn) then n bytes will be encrypted. + +**Parameters:** + +←a Pointer to an initialised instance of an aes structure defined in miracl.h
+←→buff Pointer to the buffer of bytes to be encrypted + +**Returns:** + +In MR_CFBn and MR_PCFBn modes the n byte(s) that were shifted off the end of the input register +as result of encrypting the n input byte(s), otherwise 0 + +**Precondition:** + +Must be preceded by a call to aes_init(). + +## void aes_end* (aes * a) + +Ends an AES encryption session, and de-allocates the memory associated with it. The internal session key +data is destroyed. + +**Parameters:** + +←→a Pointer to an initialised instance of an aes structured defined in miracl.h + +## void aes_getreg* (aes * a, char * ir) + +Reads the current contents of the input chaining register associated with this instance of the AES. This is +the register initialised by the IV in the calls to aes_init() and aes_reset(). + +**Parameters:** + +←a Pointer to an instance of the aes structured, defined in miracl.h
+→ir A character array to hold the extracted 16-byte data + +**Precondition:** + +Must be preceded by a call to aes_init(). + +## BOOL aes_init* (aes * a, int mode, int nk, char * key, char * iv) + +Initialises an Encryption/Decryption session using the Advanced Encryption Standard (AES). This is a +block cipher system that encrypts data in 128-bit blocks using a key of 128, 192 or 256 bits. See [Stinson] +for more background on block ciphers. + +**Parameters:** + +→a Pointer to an instance of the aes structure defined in miracl.h
+←mode The mode of operation to be used: MR_ECB (Electronic Code Book), MR_CBC (Cipher +Block Chaining), MR_CFBn (Cipher Feed-Back where n is 1, 2 or 4), MR_PCFBn (error Propagating +Cipher Feed-Back where n is 1, 2 or 4) or MR_OFBn (Output Feed-Back where n is 1, +2, 4, 8 or 16). The value of n indicates the number of bytes to be processed in each application. +For more information on Modes of Operation, see [Stinson]. MR_PCFBn is an invention of our +own [Scott93]
+←nk The size of the key in bytes. It can be either 16, 24 or 32
+←key A pointer to the key
+←iv A pointer to the Initialisation Vector (IV). A 16-byte initialisation vector should be specified for +all modes other than MR_ECB, in which case it can be NULL + +**Returns:** + +TRUE if successful, otherwise FALSE. + +## void aes_reset* (aes * a, int mode, char * iv) + +Resets the AES structure. + +**Parameters:** + +←a Pointer to an instance of the aes structure defined in miracl.h
+←mode an Indication of the new mode of operation
+←iv A pointer to a (possibly new) initialisation vector + +## void shs256_hash* (sha256 * sh, char hash[32]) + +Generates a 32 byte (256 bit) hash value into the provided array. + +**Parameters:** + +←sh Pointer to the current instance
+→hash Pointer to array to be filled + +## void shs256_init* (sha256 * sh) + +Initialises an instance of the Secure Hash Algorithm (SHA-256). Must be called before new use. + +**Parameters:** + +→sh Pointer to an instance of a structure defined in miracl.h + +## void shs256_process* (sha256 * sh, int byte) + +Processes a single byte. Typically called many times to provide input to the hashing process. The hash +value of all the processed bytes can be retrieved by a subsequent call to shs256_hash(). + +**Parameters:** + +←sh Pointer to the current instance
+←byte Character to be processed + +### void shs384_hash* (sha384 * sh, char hash[48]) + +Generates a 48 byte (384 bit) hash value into the provided array. + +**Parameters:** + +←sh Pointer to the current instance
+→hash Pointer to array to be filled + +### void shs384_init* (sha384 * sh) + +Initialises an instance of the Secure Hash Algorithm (SHA-384). Must be called before new use. + +**Parameters:** + +! sh Pointer to an instance of a structure defined in miracl.h + +**Precondition:** + +The SHA-384 algorithm is only available if 64-bit data-type is defined. + +### void shs384_process* (sha384 * sh, int byte) + +Processes a single byte. Typically called many times to provide input to the hashing process. The hash +value of all the processed bytes can be retrieved by a subsequent call to shs384_hash(). + +**Parameters:** + +←sh Pointer to the current instance
+←byte Character to be processed + +### void shs512_hash* (sha512 * sh, char hash[64]) + +Generates a 64 byte (512 bit) hash value into the provided array. + +**Parameters:** + +←sh Pointer to the current instance
+→hash Pointer to array to be filled + +### void shs512_init* (sha512 * sh) + +Initialises an instance of the Secure Hash Algorithm (SHA-512). Must be called before new use. + +**Parameters:** + +→sh Pointer to an instance of a structure defined in miracl.h + +**Precondition:** + +The SHA-512 algorithm is only available if 64-bit data-type is defined. + +### void shs512_process* (sha512 * sh, int byte) + +Processes a single byte. Typically called many times to provide input to the hashing process. The hash +value of all the processed bytes can be retrieved by a subsequent call to shs512_hash(). + +**Parameters:** + +←sh Pointer to the current instance
+←byte Character to be processed + +### void shs_hash* (sha * sh, char hash[20]) + +Generates a twenty byte (160 bit) hash value into the provided array. + +**Parameters:** + +←sh Pointer to the current instance
+→hash Pointer to array to be filled +### void shs_init* (sha * sh) + +Initialises an instance of the Secure Hash Algorithm (SHA-1). Must be called before new use. + +**Parameters:** + +→sh Pointer to an instance of a structure defined in miracl.h + +### void shs_process* (sha * sh, int byte) + +Processes a single byte. Typically called many times to provide input to the hashing process. The hash +value of all the processed bytes can be retrieved by a subsequent call to shs_hash(). + +**Parameters:** + +←sh Pointer to the current instance
+←byte Character to be processed + +### void strong_bigdig (csprng * rng, int n, int b, big x) + +Generates a big random number of given length from the cryptographically strong generator rng. + +**Parameters:** + +←rng A pointer to the random number generator
+←n
+←b
+→x Big random number n digits long to base b + +**Precondition:** + +The base b must be printable, that is 2 <= b <= 256 + +### void strong_bigrand (csprng * rng, big w, big x) + +Generates a cryptographically strong random big number x using the random number generator rng wuch +that 0 <= x < w. + +**Parameters:** + +←rng A pointer to the current instance
+←w
+→x + +### void strong_init* (csprng * rng, int rawlen, char * raw, mr_unsign32 tod) + +Initialises the cryptographically strong random number generator rng. The array raw (of length rawlen) +and the time-of-day value tod are the two sources used together to seed the generator. The former might be +provided from random keystrokes, the latter from an internal clock. Subsequent calls to strong_rng() will +provide random bytes. + +**Parameters:** + +→rng
+←rawlen
+←raw An array of length rawlen
+←tod A 32-bit time-of-day value + +### void strong_kill* (csprng * rng) + +Kills the internal state of the random number generator rng. + +**Parameters:** + +←rng A pointer to a random number generator + +### int strong_rng* (csprng * rng) + +Generates a sequence of cryptographically strong random bytes. + +**Parameters:** + +←rng A pointer to a random number generator + +**Returns:** + +A random byte. diff --git a/miracl/docs/miracl-explained/security-advisory.md b/miracl/docs/miracl-explained/security-advisory.md new file mode 100644 index 0000000..80144ba --- /dev/null +++ b/miracl/docs/miracl-explained/security-advisory.md @@ -0,0 +1,40 @@ +* [What Is Miracl](README.md) +* Security Advisory +* [Benchmarks](benchmarks.md) +* [Miracl Standard Curves](miracl-standard-curves.md) +* [IEEE 1363](ieee-1363.md) +* [Elliptic Curves](elliptic-curves.md) +* [Licensing](licensing.md) +* Reference Manual + * [Low Level Routines](reference-manual/low-level-routines.md) + * [Advanced Arithmetic Routines](reference-manual/advanced-arithmetic-routines.md) + * [Montgomery Arithmetic Routines](reference-manual/montgomery-arithmetic-routines.md) + * [ZZn2 Arithmetic Routines](reference-manual/zzn2-arithmetic-routines.md) + * [Encryption Routines](reference-manual/encryption-routines.md) + * [Elliptic Curve Routines](reference-manual/elliptic-curve-routines.md) + * [Floating Slash Routines](reference-manual/floating-slash-routines.md) + * [Structure Reference](reference-manual/structure-reference.md) + + +Security Advisory +--- + +If you found an issue with MIRACL, cryptographically or in its implementation, we would appreciate your help to make our code and services better. + +## How MIRACL approaches security issues + +- MIRACL will not take any legal or intimidating action for reporting security vulnerabilities. We ask you however to be responsible and avoid destroying, tampering or doing any action that might hamper the service or disclose private information of others. + +- We will make an effort to respond as fast as possible, and will usually acknowledge the issue within that day. However, we will need to reproduce the issue, and this can take more time. Once we do start trying to reproduce the issue, we will contact you to let you we are working on it. If we can't reproduce it, we will contact you to try to get more information. This is where we would really appreciate your help! + +- Once we figure out the issue, we'll come up with a plan to fix it. We will communicate with you our plans and keep you involved during the whole process. We know it's important to you that the issue is fixed promptly. It's important for us too. Depending on severity, turnaround is between 6 hours and 2 days. + +- Once the issue is fixed, we'll deploy the patch and inform our customers. Before publishing details about the vulnerability however, we try to wait 2-5 days to allow everyone to patch depending on the severity of the issue. + +- As soon as we can, we will publicly post details of the issue on our Blog. If you wish to be named we will contact you to ask for your approval. If you want to remain anonymous, we'll also respect that. + +- We appreciate you disclose the issue in a responsible manner. At this point we don't offer cash prices or rewards, but we usually follow-on with you and send you a reward or a freebie. + +## Contact us + +Please send all issues to . diff --git a/miracl/docs/miracl-explained/timings.doc b/miracl/docs/miracl-explained/timings.doc new file mode 100644 index 0000000..d2b360d Binary files /dev/null and b/miracl/docs/miracl-explained/timings.doc differ diff --git a/miracl/docs/miracl-user-manual/README.md b/miracl/docs/miracl-user-manual/README.md new file mode 100644 index 0000000..7d4a820 --- /dev/null +++ b/miracl/docs/miracl-user-manual/README.md @@ -0,0 +1,46 @@ +* Intro +* [Installation](installation.md) +* [The UI](the-ui.md) +* [Internal Rep](internal-rep.md) +* [Implementation](implementation.md) +* [Floating Slash Nums](floating-slash-nums.md) +* [The C++ Interface](the-cpp-interface.md) +* [Example Programs](example-progs.md) +* [The MIRACL Routines](miracl-explained/reference-manual/low-level-routines.md) +* [Instance Variables](instance-variables.md) +* [MIRACL Error Messages](miracl-error-messages.md) +* [Hardware Compiler Interface](hardware-compiler-interface.md) +* [Bibliography](bibliography.md) + + +Intro +--- + +Remember when as a naive young computer user, you received delivery of your brand new state-of-the-art micro; remember your anticipation at the prospect of the computer power now available at your fingertips; remember recalling all those articles which promised that ‘today’s microcomputers are as powerful as yesterdays mainframes’. Remember then slowly and laboriously typing in your first program, to calculate, say, 1000! (i.e. 1000 ´ 999 ´ 998... ´1) - a calculation unimaginable by hand. +``` +10 LET X=1 +20 FOR I=1 TO 1000 +30 X=X*I +40 NEXT I +50 PRINT X +60 END +RUN +``` + +After a few seconds the result appeared: + +`Too big at line 30` + +Remember your disappointment. + +Now try the MIRACL approach. MIRACL is a portable C library which implements multiprecision integer and rational data-types, and provides the routines to perform basic arithmetic on them. + +Run the program **fact** from the distribution media, and type in 1000. There is your answer - a 2568 digit number. + +Now compile and run the program **roots**, and ask it to calculate the square root of 2. Virtually instantly your computer comes back with the value correct to 100+ decimal places. Now that’s what I call computing! + +Next run the Public Key Cryptography program **enciph**. When it asks the name of a file to be enciphered press return. When it asks for an output filename, type FRED followed by return. Now type in any message, finishing with CONTROL-Z. Your message has been thoroughly enciphered in the file FRED.BLG (type it out and see). Now run ‘deciph’, and type in FRED. Press return for the requested output filename. Your original message appears on the screen. + +This type of encipherment, based as it is on the difficulty of factoring large numbers, offers much greater security and flexibility than more traditional methods. + +A useful demonstration of the power of MIRACL is given by the program **ratcalc**, a powerful scientific calculator - accurate to 36 decimal places and with the unusual ability to handle fractions directly. diff --git a/miracl/docs/miracl-user-manual/bibliography.md b/miracl/docs/miracl-user-manual/bibliography.md new file mode 100644 index 0000000..e4ef93b --- /dev/null +++ b/miracl/docs/miracl-user-manual/bibliography.md @@ -0,0 +1,105 @@ +* [Intro](README.md) +* [Installation](installation.md) +* [The UI](the-ui.md) +* [Internal Rep](internal-rep.md) +* [Implementation](implementation.md) +* [Floating Slash Nums](floating-slash-nums.md) +* [The C++ Interface](the-cpp-interface.md) +* [Example Programs](example-progs.md) +* [The MIRACL Routines](miracl-explained/reference-manual/low-level-routines.md) +* [Instance Variables](instance-variables.md) +* [MIRACL Error Messages](miracl-error-messages.md) +* [Hardware Compiler Interface](hardware-compiler-interface.md) +* Bibliography + + +Bibliography +--- + +[Blake] BLAKE, SEROUSSI, and SMART. Elliptic Curves in Cryptography, London Mathematical Society Lecture Notes Series 265, Cambridge University Press. ISBN 0 521 65374 6, July 1999. + +[Brassard] BRASSARD, G. Modern Cryptology. Lecture Notes in Computer Science, Vol. 325. Springer-Verlag 1988. + +[Brent76] BRENT, R.P. Fast Multiprecision Evaluation of Elementary Functions. J. ACM, 23, 2 (April 1976), 242-251. + +[Brent78] BRENT, R.P. A Fortran Multiprecision Arithmetic Package. ACM Trans. Math. Software 4,1 (March 1978), 57-81. + +[Brick] BRICKELL, E, et al, Fast Exponentiation with Precomputation, Proc. Eurocrypt 1992, Springer-Verlag 1993. + +[Cherry] CHERRY, L. and MORRIS, R. BC - An Arbitrary Precision Desk-Calculator Language. in ULTRIX-32 Supplementary Documents Vol. 1 General Users. Digital Equipment Corporation 1984. + +[Comba] COMBA, P.G. Exponentiation Cryptosystems on the IBM PC. IBM Systems Journal, 29,4 (1990), pp 526-538. + +[CS] CRAMER, R. and SHOUP, V. A practical public key cryptosystem provably secure against adaptive chosen ciphertext attack Proc. Crypto 1998, Springer-Verlag 1999. + +[DSS] Digital Signature Standard, Communications of the ACM, July 1992, Vol. 35 No. 7. + +[Gruen] GRUENBERGER, F. Computer Recreations. Scientific American, April 1984. + +[Jurisic] JURISIC, A and MENEZES A.H. Elliptic Curves and Cryptography, Dr. Dobbs Journal, #264, April 1997. + +[Knuth73] KNUTH, D.E. The Art of Computer Programming, Vol 1: Fundamental Algorithms. Addison-Wesley, Reading, Mass., 1973. + +[Knuth81] KNUTH, D.E. The Art of Computer Programming, Vol 2: Seminumerical Algorithms. Addison-Wesley, Reading, Mass., 1981. + +[Korn83] KORNERUP, P. and MATULA, D.W. Finite Precision Rational Arithmetic: An Arithmetic Unit. IEEE Trans. Comput., C-32, 4 (April 1983), 378-387. + +[Korn85] KORNERUP, P. and MATULA, D.W. Finite Precision Lexicographic Continued Fraction Number Systems. Proc. 7th Sym. on Comp. Arithmetic, IEEE Cat. \#85CH2146-9, 1985, 207-214. + +[LimLee] LIM, C.H. and LEE, P.J. A Key Recovery Attack on Discrete Log-based Schemes Using a Prime Order Subgroup. Advances in Cryptology, Crypto '97, Springer-Verlag 1998. + +[Marsaglia] MARSAGLIA, G.M. and ZAMAN, A. A New Class of Random Number Generators. The Annals of Applied Probability, Vol. 1, 3, 1991, 462-480. + +[Matula85] MATULA, D.W. and KORNERUP, P. Finite Precision Rational Arithmetic: Slash Number Systems. IEEE Trans. Comput., C-34, 1 (January 1985), 3-18. + +[Maurer] MAURER, U.M. and YACOBI, Y. Non-Interactive Public Key Cryptography. Advances in Cryptography, Eurocrypt '91, Springer Verlag, 1992. + +[Menezes] MENEZES, A.J. Elliptic Curve Public key Cryptosystems, Kluwer Academic Publishers, 1993. + +[HAC] Handbook of Applied Cryptography, CRC Press, 2001. + +[McCurley] McCURLEY, K.S. A Key Distribution System Equivalent to Factoring. J. Cryptology, Vol. 1. No. 2, 1988. + +[Monty85] MONTGOMERY, P. Modular Multiplication Without Trial Division. Math. Comput., 44, (April 1985), 519-521. + +[Monty87] MONTGOMERY, P. Speeding the Pollard and Elliptic Curve Methods. Math. Comput., 48, (January 1987), 243-264. + +[Morrison] MORRISON, M.A. and BRILLHART, J. A Method of Factoring and the Factorization of F7. Math. Comput., 29, 129 (January 1975), 183-205. + +[Pollard71] POLLARD, J.M. Fast Fourier Transform in a Finite Field. Math. Comput., 25, 114 (April 1971), 365-374. + +[Pollard78] POLLARD, J.M. Monte Carlo Methods for Index Computation (mod p). Math. Comp. Vol. 32, No. 143, pp 918-924, 1978. + +[Pomerance] POMERANCE, C. The Quadratic Sieve Factoring Algorithm. In Advances in Cryptology, Lecture Notes in Computer Science, Vol. 209, Springer-Verlag, 1985, 169-182. + +[Reisel] REISEL, H. Prime Numbers and Computer methods for Factorisation. Birkhauser 1987. + +[Richter] RICHTER, J. Advanced Windows. Microsoft Press. + +[RSA] RIVEST, R., SHAMIR, A. and ADLEMAN, L. A Method for obtaining Digital Signatures and Public-Key Cryptosystems. Comm. ACM, 21,2 (February 1978), 120-126. + +[Rubin] RUBIN, P. Personal Communication. + +[Sch] SCHOOF, R. Elliptic Curves Over Finite Fields and the Computation of Square Roots mod p. Math. Comp. Vol. 44, No. 170. April 1985, pp 483-494. + +[Scott89a] SCOTT, M.P.J. Fast rounding in multiprecision floating-slash arithmetic. IEEE Transactions on Computers, July 1989, 1049-1052. + +[Scott89b] SCOTT, M.P.J. On Using Full Integer Precision in C. Dublin City University Working Paper CA 0589, 1989. + +[Scott89c] SCOTT, M.P.J. Factoring Large Integers on Small Computers. National Institute for Higher Education Working Paper CA 0189, 1989. + +[Scott92] SCOTT, M.P.J. and SHAFA'AMRY, M. Implementing an Identity-based Key Exchange algorithm. Available from ftp.computing.dcu.ie /pub/crypto/ID-based_key_exchange.ps . + +[Scott93] SCOTT, M.P.J. Novel Chaining Methods for Block Ciphers, Dublin City University, School of Computer Applications Working Paper CA-1993. + +[Scott96] SCOTT, M.P.J. Comparison of methods for modular multiplication on 32-bit Intel 80x86 processors. Available from ftp.computing.dcu.ie /pub/crypto/timings.ps . + +[Shoup] SHOUP, V. A New Polynomial Factorisation Algorithm and Its Implementation. Jl. Symbolic Computation, 1996. + +[Stinson] STINSON, D.R. Cryptography, Theory and practice. CRC Press, 1995. + +[Silverman] SILVERMAN, R.D. The Multiple Polynomial Quadratic Sieve, Math. Comp. 48, 177, (January 1987), 329-339. + +[Walmsley] WALMSLEY, M., Multi-Threaded Programming in C++. Springer-Verlag 1999. + +[WeiDai] DAI , W. Personal Communication. diff --git a/miracl/docs/miracl-user-manual/docs.md b/miracl/docs/miracl-user-manual/docs.md new file mode 100644 index 0000000..9eb8cfa --- /dev/null +++ b/miracl/docs/miracl-user-manual/docs.md @@ -0,0 +1,514 @@ +Elliptic Curve Routines +--- + +In these routines a big parameter can also be used wherever a flash is specified, but not visa-versa. Further information may be gleaned from the (lightly) commented source code. An asterisk after the name indicates that the function does not take a *mip* parameter if MR_GENERIC_MT is defined in *mirdef.h* . + +## ebrick_init + +Function: + + BOOL ebrick_init(binst,x,y,a,b,n,w,nb) + + ebrick *binst; + + big x,y; + + big a,b,n; + + int w,nb; + +| Module | Description | Parameters | Return value |Restrictions| +|-----------|-----------------------|----------------------------------------------|------|------| +|mrebrick.c|Initialises an instance of the Comb method for GF(p) elliptic curve multiplication with precomputation. Internally memory is allocated for 2w elliptic curve points which will be precomputed and stored. For bigger w more space is required, but the exponentiation is quicker. Try w=8.|A pointer to the current instance binst, the fixed point G=(x,y) on the curve y2 =x3 + ax + b, the modulus n, and the maximum number of bits to be used in the exponent nb.|TRUE if all went well, FALSE if there was a problem.|Note: If MR_STATIC is defined in mirdef.h, then the x and y parameters in this function are replaced by a single mr_small * pointer to a precomputed table. In this case the function returns a void.| + +## ebrick2_init + +Function: + + BOOL ebrick2_init(binst,x,y,A,B,m,a,b,c,nb) + + ebrick2 *binst; + + big x,y; + + big A,B; + + int m,a,b,c,nb; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrec2m.c|Initialises an instance of the Comb method for GF(2m) elliptic curve multiplication with precomputation. The field is defined with respect to the trinomial basis tm+ta+1 or the pentanomial basis tm+ta+tb+tc+1. Internally memory is allocated for 2w elliptic curve points which will be precomputed and stored. For bigger w more space is required, but the exponentiation is quicker. Try w=8.|A pointer to the current instance binst, the fixed point G=(x,y) on the curve y2 + xy = x3 + Ax2 + B, the field parameters m, a, b, c, and the maximum number of bits to be used in the exponent nb. Set b = 0 for a trinomial basis.|TRUE if all went well, FALSE if there was a problem.|Note: If MR_STATIC is defined in mirdef.h, then the x and y parameters in this function are replaced by a single mr_small * pointer to a precomputed table. In this case the function returns a void.| + +## ebrick_end * + +Function: + + void ebrick_end(binst) + + ebrick *binst + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +mrebrick.c|Cleans up after an application of the Comb for GF(p) elliptic curves|A pointer to the current instance|None |None| + +## ebrick2_end * + +Function: + + void ebrick2_end(binst) + + ebrick2 *binst + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrec2m.c|Cleans up after an application of the Comb method for GF(2m) elliptic curves.|A pointer to the current instance|None |None| + +## ecurve_add + +Function: + + void ecurve_add(p,pa) + + epoint *p,*pa; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcurve.c|Adds two points on a GF(p) elliptic curve using the special rule for addition. Note that if pa=p, then a different duplication rule is used. Addition is quicker if p is normalised.|Two points on the current active curve, pa and p. On exit pa=pa+p.|None|The input points must actually be on the current active curve.| + +## ecurve2_add + +Function: + + void ecurve2_add(p,pa) + + epoint *p,*pa; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrec2m.c|Adds two points on a GF(2m) elliptic curve using the special rule for addition. Note that if pa=p, then a different duplication rule is used. Addition is quicker if p is normalised.|Two points on the current active curve, pa and p. On exit pa=pa+p.|None|The input points must actually be on the current active curve.| + +## ecurve_init + +Function: + + void ecurve_init(A,B,p,type) + + big A,B,p; + + int type; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcurve.c|Initialises the internal parameters of the current active GF(p) elliptic curve. The curve is assumed to be of the form y2 =x3 + Ax + B mod p, the so-called Weierstrass model. This routine can be called subsequently with the parameters of a different curve.|Three big numbers A, B and p. The type parameter must be either MR_PROJECTIVE or MR_AFFINE, and specifies whether projective or affine co-ordinates should be used internally. Normally the former is faster.|None|Allocated memory will be freed when the current instance of MIRACL is terminated by a call to mirexit. However only one elliptic curve, GF(p) or GF(2m) may be active within a single MIRACL instance. In addition, a call to a function like powmod will overwrite the stored modulus. This can be restored by a repeat call to ecurve_init| + +## ecurve2_init + +Function: + + BOOL ecurve2_init(m,a,b,c,A,B,check,type) + + big A,B; + + int m,a,b,c,type; + + BOOL check; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrec2m.c|Initialises the internal parameters of the current active elliptic curve. The curve is assumed to be of the form y2 + xy =x3 + Ax2 + B . The field is defined with respect to the trinomial basis tm+ta+1 or the pentanomial basis tm+ta+tb+tc+1. This routine can be called subsequently with the parameters of a different curve.|The fixed point G=(x,y) on the curve y2 + xy = x3 + Ax2 + B, the field parameters m, a, b, c. Set b = 0 for a trinomial basis. The type parameter must be either MR_PROJECTIVE or MR_AFFINE, and specifies whether projective or affine co-ordinates should be used internally. Normally the former is faster. If check is TRUE a check is made that the specified basis is irreducible. If FALSE, this basis validity check, which is time-consuming, is suppressed.|TRUE if parameters make sense, otherwise FALSE.|Allocated memory will be freed when the current instance of MIRACL is terminated by a call to mirexit. However only one elliptic curve, GF(p) or GF(2m) may be active within a single MIRACL instance.| + +## ecurve_mult + +Function: + + void ecurve_mult(k,p,pa) + + big k; + + epoint *p,*pa; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcurve.c|Multiplies a point on a GP(p) elliptic curve by an integer. Uses the addition/subtraction method.|A big number k, and two points p and pa. On exit pa=k*p.|None|The point p must be on the active curve.| + +## ecurve2_mult + +Function: + + void ecurve2_mult(k,p,pa) + + big k; + + epoint *p,*pa; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrec2m.c|Multiplies a point on a GF(2m) elliptic curve by an integer. Uses the addition/subtraction method.|A big number k, and two points p and pa. On exit pa=k*p.|None|The point p must be on the active curve.| + +## ecurve_mult2 + +Function: + + void ecurve_mult2(k1,p1,k2,p2,pa) + + big k1,k2; + + epoint *p1,*p2,*pa; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcurve.c|Calculates the point k1.p1+k2.p2 on a GF(p) elliptic curve. This is quicker than doing two separate multiplications and an addition. Useful for certain cryptosystems. (See ecsver.c for example)|Two big integers k1 and k2, and three points p1, p2 and pa. On exit pa = k1.p1+k2.p2|None|The points p1 and p2 must be on the active curve.| + +## ecurve2_mult2 + +Function: + + void ecurve2_mult2(k1,p1,k2,p2,pa) + + big k1,k2; + + epoint *p1,*p2,*pa; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrec2m.c|Calculates the point k1.p1+k2.p2 on a GF(2m) elliptic curve. This is quicker than doing two separate multiplications and an addition. Useful for certain cryptosystems. (See ecsver2.c for example)|Two big integers k1 and k2, and three points p1, p2 and pa. On exit pa = k1.p1+k2.p2|None|The points p1 and p2 must be on the active curve.| + +## ecurve_multi_add + +Function: + + void ecurve_multi_add(m,x,w) + + int m; + + epoint x,w; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcurve.c|Simultaneously adds pairs of points on the active GF(p) curve. This is much quicker than adding them individually, but only when using Affine co-ordinates.|An integer m and two arrays of points w and x. On exit w[i]=w[i]+x[i] for i =0 to m-1|None|Only useful when using Affine co-ordinates. See also: ecurve_init and nres_multi_inverse, which is used internally.| + +## ecurve2_multi_add + +Function: + + void ecurve2_multi_add(m,x,w) + + int m; + + epoint x,w; + +| Module | Description | Parameters | Return value | Restrictions |See also| +|-----------|-----------------------|----------------------------------------------|------|------| +|mrec2m.c|Simultaneously adds pairs of points on the active GF(2m) curve. This is much quicker than adding them individually, but only when using Affine co-ordinates.|An integer m and two arrays of points w and x. On exit w[i]=w[i]+x[i] for i =0 to m-1|None|Only useful when using Affine co-ordinates.|See also: ecurve2_init| + +## ecurve_multn + +Function: + + void ecurve_multn(n,k,p,pa) + + int n; + + big *k; + + epoint p; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcurve.c|Calculates the point k[0].p[0] + k[1].p[1] + … + k[n-1].p[n-1] on a GF(p) elliptic curve, for n>2.| An integer n, an array of n big numbers k[], and an array of n points. The result is returned in pa.|None|The points must be on the active curve. The k[] values must all be positive. The underlying number base must be a power of 2.| + +## ecurve2_multn + +Function: + + void ecurve2_multn(n,k,p,pa) + + int n; + + big *k; + + epoint p; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrec2m.c|Calculates the point k[0].p[0] + k[1].p[1] + … + k[n-1].p[n-1] on a GF(2m) elliptic curve, for n>2.| An integer n, an array of n big numbers k[], and an array of n points. The result is returned in pa.|None|The points must be on the active curve. The k[] values must all be positive. The underlying number base must be a power of 2.| + +## ecurve_sub + +Function: + + void ecurve_sub(p,pa) + + epoint *p,*pa; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcurve.c|Subtracts two points on a GF(p) elliptic curve. Actually negates p and adds it to pa. Subtraction is quicker if p is normalised.|Two points on the current active curve, pa and p. On exit pa = pa-p.|None|The input points must actually be on the current active curve.| + +## ecurve2_sub + +Function: + + void ecurve2_sub(p,pa) + + epoint *p,*pa; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrec2m.c|Subtracts two points on a GF(2m) elliptic curve. Actually negates p and adds it to pa. Subtraction is quicker if p is normalised.|Two points on the current active curve, pa and p. On exit pa = pa-p.|None| The input points must actually be on the current active curve. + +## epoint_comp + +Function: + + BOOL epoint_comp(p1,p2) epoint *p1,*p2; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcurve.c|Compares two points on the current active GF(p) elliptic curve.|Two points p1 and p2.|TRUE if the points are the same, otherwise FALSE. |None| + +## epoint2_comp + +Function: BOOL epoint2_comp(p1,p2) + + epoint *p1,*p2; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrec2m.c|Compares two points on the current active GF(2m) elliptic curve.|Two points p1 and p2.|TRUE if the points are the same, otherwise FALSE. |None| + +## epoint_copy * + +Function: void epoint_copy(p1,p2) + + epoint *p1,*p2; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcurve.c|Copies one point to another on a GF(p) elliptic curve.|Two points p1 and p2. On exit p2=p1.|None |None| + +## epoint2_copy * + +Function: + + void epoint2_copy(p1,p2) + + epoint *p1,*p2; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrec2m.c|Copies one point to another on a GF(2m) elliptic curve.|Two points p1 and p2. On exit p2=p1.|None |None| + +## epoint_free * + +Function: + + void epoint_free(p) epoint *p; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcore.c|Frees memory associated with a point on a GF(p) elliptic curve.|A point p.|None |None| + +## epoint_get + +Function: + + int epoint_get(p,x,y) + + epoint *p; + + big x,y; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcurve.c|Normalises a point and extracts its (x,y) co-ordinates on the active GF(p) elliptic curve.|A point p, and two big integers x and y. If x and y are not distinct variables on entry then only the value of x is returned.|The least significant bit of y. Note that it is possible to reconstruct a point from its x co-ordinate and just the least significant bit of y. Often such a "compressed" description of a point is useful. |The point p must be on the active curve. + +Example: + + i=epoint_get(p,x,x);| /* extract x co-ordinate and lsb of y */ + +## epoint_getxyz + +Function: + + void epoint_getxyz(p,x,y,z) + + epoint *p; + + big x,y,z; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcurve.c|Extracts the raw (x,y,z) co-ordinates of a point on the active GF(p) elliptic curve.|A point p, and three big integers x, y and z. If any of these is NULL that coordinate is not returned.|None| The point p must be on the active curve. + +## epoint2_get + +Function: int epoint2_get(p,x,y) + + epoint *p; + + big x,y; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrec2m.c|Normalises a point and extracts its (x,y) co-ordinates on the active GF(2m) elliptic curve.|A point p, and two big integers x and y. If x and y are not distinct variables on entry then only the value of x is returned.|The least significant bit of y/x. Note that it is possible to reconstruct a point from its x co-ordinate and just the least significant bit of y/x. Often such a "compressed" description of a point is useful.| The point p must be on the active curve. + +Example: + + i=epoint_get(p,x,x);| /* extract x co-ordinate and lsb of y/x */ + +## epoint2_getxyz + +Function: + + void epoint2_getxyz(p,x,y,z) + + epoint *p; + + big x,y,z; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcurve.c|Extracts the raw (x,y,z) co-ordinates of a point on the active GF(2m) elliptic curve.|A point p, and three big integers x, y and z. If any of these is NULL that coordinate is not returned.|None| The point p must be on the active curve. + +## epoint_init + +Function: epoint* epoint_init() + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcore.c|Assigns memory to a point on a GF(p) elliptic curve, and initialises it to the "point at infinity".|None|A point p (in fact a pointer to a structure allocated from the heap).| It is the C programmers responsibility to ensure that all elliptic curve points initialised by a call to this function, are ultimately freed by a call to epoint_free. If not a memory leak will result. + +## epoint_init_mem + +Function: + + epoint* epoint_init_mem(mem,index) + + char *mem; + + int index; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcore.c|Initialises memory for an elliptic curve point from a pre-allocated byte array mem. This array may be created from the heap by a call to ecp_memalloc, or in some other way. This is quicker than multiple calls to epoint_init|A pointer to the pre-allocated array mem, and an index into that array. Each index should be unique.|An initialised elliptic curve point.| Sufficient memory must have been allocated and pointed to by mem. + +## epoint_norm + +Function: + + BOOL epoint_norm(p) + + epoint *p; + +| Module | Description | Parameters | Return value | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcurve.c|Normalises a point on the current active GF(p) elliptic curve. This sets the z coordinate to 1. Point addition is quicker when adding a normalised point. This function does nothing if affine coordinates are being used (in which case there is no z co-ordinate)|A point on the current active elliptic curve.|TRUE if successful.| + +## epoint2_norm + +Function: + + BOOL epoint2_norm(p) + + epoint *p; + +| Module | Description | Parameters | Return value | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrec2m.c|Normalises a point on the current active GF(2m) elliptic curve. This sets the z coordinate to 1. Point addition is quicker when adding a normalised point. This function does nothing if affine coordinates are being used (in which case there is no z co-ordinate)|A point on the current active elliptic curve.|TRUE if successful.| + +## epoint_set + +Function: + + BOOL epoint_set(x,y,lsb,p) + + big x,y; + + int lsb; + + epoint *p; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcurve.c|Sets a point on the current active GF(p) elliptic curve (if possible).|The integer co-ordinates x and y of the point p. If x and y are not distinct variables then x only is passed to the function, and lsb is taken as the least significant bit of y. In this case the full value of y is reconstructed internally. This is known as "point decompression" (and is a bit time-consuming, requiring the extraction of a modular square root). On exit p=(x,y).|TRUE if the point exists on the current active point, otherwise FALSE. |None| + +Example: + + p=epoint_init(); + + epoint_set(x,x,1,p); /* decompress p */ + +## epoint2_set + +Function: + + BOOL epoint2_set(x,y,lsb,p) + + big x,y; + + int lsb; + + epoint *p; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrec2m.c|Sets a point on the current active GF(2m) elliptic curve (if possible).|The integer co-ordinates x and y of the point p. If x and y are not distinct variables then x only is passed to the function, and lsb is taken as the least significant bit of y/x. In this case the full value of y is reconstructed internally. This is known as "point decompression" (and is a bit time-consuming, requiring the extraction of a field square root). On exit p=(x,y).|TRUE if the point exists on the current active point, otherwise FALSE. |None| + +Example: + + p=epoint_init(); + + epoint2_set(x,x,1,p); /* decompress p */ + +## epoint_x + +Function: + + BOOL epoint_x(x) + + big x; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcurve.c| Tests to see if the parameter x is a valid co-ordinate of a point on the curve. It is faster to test an x co-ordinate first in this way, rather than trying to directly set it on the curve by calling epoint_set, as it avoids an expensive modular square root.|The integer coordinate x.|TRUE if x is the coordinate of a curve point, otherwise FALSE |None| + +## mul_brick + +Function: + + int mul_brick(binst,e,x,y) + + ebrick *binst; + + big e,x,y; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrebrick.c|Carries out a GF(p) elliptic curve multiplication using the precomputed values stored in the ebrick structure.|A pointer to the current instance, a big exponent e and a big number w. On exit (x,y) = e.G mod n, where G and n are specified in the initial call to ebrick_init. If x and y are not distinct variables, only x is returned.|The least significant bit of y.| Must be preceded by a call to ebrick_init. + +## mul2_brick + +Function: + + int mul2_brick(binst,e,x,y) + + ebrick2 *binst; + + big e,x,y; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrec2m.c|Carries out a GF(2m) elliptic curve multiplication using the precomputed values stored in the ebrick2 structure.|A pointer to the current instance, a big exponent e and a big number w. On exit (x,y) = e.G, where G is specified in the initial call to ebrick2_init. If x and y are not distinct variables, only x is returned.|The least significant bit of y/x.| Must be preceded by a call to ebrick2_init. + +## point_at_infinity * + +Function: + + BOOL point_at_infinity(p) + + epoint *p; + +| Module | Description | Parameters | Return value | Restrictions | +|-----------|-----------------------|----------------------------------------------|------|------| +|mrcore.c|Tests if an elliptic curve point is the "point at infinity".|An elliptic curve point p.|TRUE if p is the point-at-infinity, otherwise FALSE.| The point must be initialised. diff --git a/miracl/docs/miracl-user-manual/example-progs.md b/miracl/docs/miracl-user-manual/example-progs.md new file mode 100644 index 0000000..0779ccb --- /dev/null +++ b/miracl/docs/miracl-user-manual/example-progs.md @@ -0,0 +1,281 @@ +* [Intro](README.md) +* [Installation](installation.md) +* [The UI](the-ui.md) +* [Internal Rep](internal-rep.md) +* [Implementation](implementation.md) +* [Floating Slash Nums](floating-slash-nums.md) +* [The C++ Interface](the-cpp-interface.md) +* Example Programs +* [The MIRACL Routines](miracl-explained/reference-manual/low-level-routines.md) +* [Instance Variables](instance-variables.md) +* [MIRACL Error Messages](miracl-error-messages.md) +* [Hardware Compiler Interface](hardware-compiler-interface.md) +* [Bibliography](bibliography.md) + + +Example Programs +--- + +* [Simple Programs](#simple) +* [Factoring Programs](#factoring) +* [Discrete Logarithm Programs](#discrete) +* [Public-Key Cryptography](#cryptography) +* [Pairing-Based Cryptography](#pairing) +* ['flash' Programs](#flash) + +> The programs described here are of an experimental nature, and in many cases are not completely 'finished off'. For further information read the comments associated with the appropriate source file. + +## Simple Programs +___ +### hail.c + +This program allows you to investigate so-called hailstone numbers, as described by Gruenberger [Gruen]. The procedure is simple. Starting with any number apply the following rules: + +1. If it is odd, multiply it by 3 and add 1. +2. If it is even, divide it by 2. +3. Repeat the process, until the number becomes equal to 1, in which case stop. + +It would appear that for any initial number this process always eventually terminates, although it has not been proved that this must happen, or that the process cannot get stuck in an infinite loop. What goes up, it seems, must come down. Try the program for an initial value of 27. Then try it using much bigger numbers, like 10709980568908647 (which has interesting behaviour). + +### palin.c + +This programs allows one to investigate palindromic reversals [Gruen]. A palindromic number is one which reads the same in both directions. Start with any number and apply the following rules. + +1. Add the number to the number obtained by reversing the order of the digits. Make this the new number. +2. Stop the process when the new number is palindromic. + +It appears that for most initial numbers this process quickly terminates. Try it for 89. Then try it for 196. + +### mersenne.c + +This program attempts to generate all prime numbers of the form 2n-1. The largest known primes have always been of this form because of the efficiency of this Lucas-Lehmer test. The routine **fft_mult** is used, as it is faster for very large numbers. + +## Factoring Programs +___ +Six different Integer Factorisation programs are included, covering all modern approaches to this classical problem. For more background and information on the algorithms used, see [Scott89c]. + +### brute.c + +This program attempts to factorise a number by brute force division, using a table of small prime numbers. When attempting a difficult factorisation it makes sense to try this approach first. Factorise 12345678901234567890 using this program. Then try it on bigger random numbers. + +### brent.c + +This program attempts to factorise a number using the Brent-Pollard method. This method is faster at finding larger factors than the simple-minded brute force approach. However it will not always succeed, even for simple factorisations. Use it to factorise R17, that is 11111111111111111 (seventeen ones). Then try it on larger numbers that would not yield to the brute force approach. + +### pollard.c + +Another factoring program, which implements Pollard's (*p*-1) method, specialises in quickly finding a factor *p* of a number *N* for which (*p-1*) has itself only small factors. Phase 1 of this method will work if all these small factors are less than LIMIT1. If Phase 1 fails then Phase 2 searches for just one final larger factor less than LIMIT2. The constants LIMIT1 and LIMIT2 are set inside the program. + +### williams.c + +This program is similar to Pollards method, but can find a factor *p* of *N* for which (*p+1*) has only small factors. Again two phases are used. In fact this method is sometimes a (*p+1*) method, and sometimes a (*p-1*) method, so several attempts are made to hit on the (*p+1*) condition. The algorithm is rather more complex than that used in Pollards method, and is somewhat slower. + +### lenstra.c### + +Lenstra [Monty87] has discovered a new method of factorisation, generically similar to the Pollard and Williams methods, but potentially much more powerful. It works by randomly generating an Elliptic Curve, which can then be used to find a factor *p* of *N*, for which *p+1-d* has only small factors, where *d* depends on the particular curve chosen. If one curve fails then another can be tried, an option not possible with the Pollard/Williams methods. Again this is a two-phase method, and although it has very good asymptotic behaviour, it is much slower than the Pollard/Williams methods for each iteration. + +### qsieve.c### + +This is a sophisticated Pomerance-Silverman-Montgomery [Pomerance], [Silverman] factoring program. which factors F7 = 2128+1 + + 340282366920938463463374607431768211457 + +in less than 30 seconds, running on a 60MHz Pentium-based computer. When this number was first factored, it took 90 minutes on an IBM 360 mainframe (Morrison & Brillhart [Morrison]), albeit using a somewhat inferior algorithm. + +Its speciality is factoring all numbers (up to about sixty digits long), irrespective of the size of the factors. If the number to be factored is *N*, then the program actually works with a number *k.N*, where *k* is a small Knuth-Schroepel multiplier. The program itself works out the best value of *k* to use. Internally, the program uses a 'factor base' of small primes. The larger the number, the bigger will be this factor base. The program works by accumulating information from a number of simpler factorisations. As it progresses with these it prints out *working...n*. When it thinks it has enough information it prints out *trying*, but these tries may be premature and may not succeed. The program will always terminate before the number *n* in *working...n* reaches the size of the factor base. + +This program uses much more memory than any of the other example programs, particularly when factoring bigger numbers. The amount of memory that the program can take is limited by the values defined for MEM, MLF and SSIZE at the beginning of the program. These limit the number of primes in the factor base, the number of 'larger' primes used by the so-called large-prime variation of the algorithm, and the sieve size respectively. They should be increased if possible, or reduced if your computer has insufficient memory. See [Silverman] for more details. + +Use **qsieve** to factor 10000000000000000000000000000000009 (thirty-five digits). + +### factor.c### + +This program combines the above algorithms into a single general purpose program for factoring integers. Each method is used in turn in the attempt to extract factors. The number to be factored is given in the command line, as in **factor 11111111111**. The number can alternatively be specified as a formula, using the switch '-f', as in **factor -f (10#11-1)/9**. The symbol # here means 'to the power of' (# is used instead of ^ as the latter symbol has a special meaning for DOS on an IBM PC). Type **factor** on its own for a full description of this and other switches that can be used to control the input/output of this program. + +## Discrete Logarithm Programs +___ +Two programs implement Pollards algorithms [Pollard78] for extracting discrete logarithms. The discrete logarithm problem is to find *x* given *y*, *r* and *n* in: + +Inline image 1 + +The above is a good example of a one-way function. It is easy to calculate *y* given *x*, but apparently extremely difficult to find *x* given *y*. Pollard's algorithms however perform quite well under certain circumstances, if *x* is known to be small or if *n* is a prime *p* for which *p-1* has only small factors. + +### kangaroo.c + +This program finds *x* in the above, assuming that *x* is quite small. The value of *r* is fixed (at 16), and the modulus *n* is also fixed inside the program. Initially a 'trap' is set. Subsequently the discrete logarithm can be found (almost certainly) for any number, assuming its discrete logarithm is less than a certain upper limit. The number of steps required will be approximately the square root of this limit. + +### genprime.c + +A prime number *p* with known factorisation of *p-1* is generated by this program, for use by the *index.c* and *identity.c* programs described below. The factors of *p-1* are output to a file *prime.dat*. + +### index.c + +This program implements Pollard's rho algorithm for extracting discrete logarithms, when the modulus *n* in the above equation is a prime *p*, and when *p-1* has only relatively small factors. The number of steps required is a function of the square root of the largest of these factors. + +## Public-Key Cryptography +___ +Public Key Cryptography is a two key cryptographic system with the very desirable feature that the encoding key can be made publicly available, without weakening the strength of the cipher. The first example program demonstrates many popular public-key techniques. Then two functional Public-Key cryptography systems, whose strength appears to depend on the difficulty of factorisation, are presented. The first is the classic RSA system (Rivest, Shamir & Adleman [RSA]). This is fast to encode a message, but painfully slow at decoding. A much faster technique has been invented by Blum and Goldwasser. This probabilistic Public Key system is also stronger than RSA in some senses. For more details see [Brassard], who describes it as 'the best that academia has had to offer thus far'. For both methods the keys are constructed from 'strong' primes to enhance security. Closely associated with PK Cryptography, is the concept of the Digital Signature. A group of example programs implement the Digital Signature Standard, using classic finite fields and elliptic curves over both the fields GF(*p*) and GF(2*m*). + +### pk-demo.c + +This program carries out a 1024-bit Diffie-Hellman key exchange, and then another Diffie-Hellman type key exchange, but this time based on a 160-bit prime and an elliptic curve. Next a test string is encrypted and decrypted using the El Gamal method. The program finishes with a 1024 bit RSA encryption/decryption of the same string. For a good description of all these techniques see [Stinson]. Anyone attempting to implement a PK system using MIRACL is strongly encouraged to examine this file, and its C++ counter-part **pk-demo.cpp**. + +### bmark.c/imratio.c + +The benchmarking program *bmark.c* allows the user to quickly determine the time that will be required to implement any of the popular public key methods. It can be compiled and linked with any of the variants of the MIRACL library, as specified in *mirdef.h*, to determine which gives the best performance on a particular platform for a particular PK method. The program *imratio.c* when compiled and run calculates the significant ratios S/M, I/M and J/M, where S is the time for a modular squaring, M the time for a modular multiplication, I the time for a modular inversion, and J the time for a Jacobi symbol calculation. + +### genkey.c + +This program generates the 'public' encoding key and 'private' decoding keys that are necessary for both the original Rivest-Shamir-Adleman PK system and the superior Blum-Goldwasser method [Brassard]. These keys can take a long time to generate, as they are formed from very large prime numbers, which must be generated carefully for maximum security. + +The size of each prime in bits is set inside the program by a #define. The security of the system depends on the difficulty of factoring the encoding 'public' key, which is formed from two such large primes. The largest numbers which can be routinely factored using hundreds of powerful computers are 430 bits long (1996). So a minimum size of 512 bits for each prime gives plenty of security (for now!) + +After this program has run, the two keys are created in files PUBLIC.KEY and PRIVATE.KEY. + +### encode.c + +Messages or files may be encoded with this program, which uses the 'public' encoding key from the file PUBLIC.KEY, generated by the program *genkey*, which must have been run prior to using this program. When run, the user is prompted for a file to encipher. Either supply the name of a text file, or press return to enter a message directly from the keyboard. In the former case the encoded output is sent to a file with the same name, but with the extension .RSA. In the latter case a prompt is issued for an output filename, which must be given. Text entered from the keyboard must be terminated by a CONTROL-Z (end-of-file character). Type out the encoded file and be impressed by how indecipherable it looks. + +### decode.c + +Messages or files encoded using the RSA system may be decoded using this program, which uses the 'private' decoding key from the file PRIVATE.KEY generated by the program *genkey* which must have been run at some stage prior to using this program. + +When run, the user is prompted for the name of the file to be decoded. Type in the filename (without an extension - the program will assume the extension .RSA) and press return. Then the user is asked for an output filename. Either supply a filename or press return, in which case the decoded output will be sent straight to the screen. A problem with the RSA system becomes immediately apparent - decoding takes quite a relatively long time! This is particularly true for larger key sizes and long messages. + +### enciph.c + +This program works in an identical fashion to the program 'encode', except that it prompts for a random seed before encrypting the data. This random seed is then used internally to generate a larger random number. The encryption process depends on this random number, which means that the same data will not necessarily produce the same cipher-text, which is one of the strengths of this approach. As well as creating a file with a .BLG extension containing the encrypted data, a second small file (with the .KEY extension) is also produced. + +### deciph.c + +This program works in an identical fashion to the program 'decode'. However it has the advantage that it runs much more quickly. There will be a significant initial delay while a rather complex calculation is carried out. This uses the private key and the data in the .KEY file to recover the large random number used in the encryption process. Thereafter deciphering is as fast as encipherment. + +### dssetup.c + +A standard method for digital signature has been proposed by the American National Institute of Standards and Technology (NIST), and fully described in the Digital Signature Standard [DSS]. This program generates a prime *q*, another much larger prime *p=2nq+1*, (where *n* is random) and a generator *g*. This information is made common to all. This program generates the common information {*p,q,g*} into a file *common.dss* . + +### limlee.c + +It has been shown by Lim & Lee [LimLee] that for certain Discrete Logarithm based protocols (but not for the Digital Signature Standard) there is a weakness associated with primes of the kind generated by the *dssetup.c* program described above. To avoid these problems they recommend that *p* is of the form *p*=2.p1.p2.p3…q + 1, where the *p*i are primes greater than *q*. This program generates the values (*p,q,g*) into a file *common.dss*, and can be used in place of *dssetup.c* . It is a little slower. + +### dssgen.c + +Each user who wishes to digitally sign a computer file randomly generates their own private key *xx mod p*. The security of the system depends on the sizes of *p* and *q* (at least 512 bits and 160 bits respectively). This program generates a single public/private key pair in the files *public.dss* and *private.dss* respectively. + +### dssign.c + +This program uses the private key from *private.dss* to 'sign' a document stored in a file. First the file data is 'hashed' down to a 160 bit number using SHA, the Standard Hash Algorithm. This is also specified by the NIST and is implemented in the provided module *mrshs.c* . The 160-bit hash is duly 'signed' as described in [DSS], and the signature, in the form of two 160-bit numbers, written out to a file. This file has the same name as the document file, but with the extension *.dss* . + +### dssver.c + +This program uses the public key from *public.dss* to verify the signature associated with a file, as described in [DSS]. + +### ecsgen.c, ecsign.c, ecsver.c + +The Digital Signature technique can also be implemented using Elliptic Curves over the field GF(*p*)[Jurisic]. Common domain information in the order {*p,A,B,q,X,Y*} is extracted from the file *common.ecs* created using one of the point-counting algorithms described below. These values specify an initial point (*X,Y*) on an elliptic curve *y2=x3+Ax+B mod p* which has *q* points on it. The advantages are a much smaller public key for the same level of security. Smaller numbers can be used as the discrete logarithm problem is apparently much more difficult in the context of an elliptic curve. This in turn implies that elliptic curve arithmetic is also potentially faster. However the use of smaller numbers is somewhat offset by the more complex calculations involved. + +This set of programs has the same functionality as those described above for the standard DSS. Note however that the file extension *.ecs* is used for all the generated files. Read the comments in the source files for more information. + +### ecsgen2.c, ecsign2.c, ecsver2.cpp + +These programs provide the same functionality as those provided above, but use elliptic curves defined over the field GF(2*m*). Domain information in this case is extracted from the file *common2.ecs* in the order {*m,A,B,q,X,Y,a,b,c*}, where (*X,Y*) specifies an initial point on the elliptic curve *y2=x3+Ax2+B* defined over GF(2*m*). The parameters of a trinomial or pentanomial basis are also specified, *tm+ta+1* or *tm+ta+tb+tc+1* respectively. In the former case *b* and *c* are zero. Finally *cf.q* specifies the number of points on the curve, the product of a large prime factor *q* and a small cofactor *cf*. The latter is normally 2 or 4. The file *common2.ecs* can be created by the **schoof2** program described below. + +### cm.cpp, schoof.cpp, mueller.cpp, process.cpp, sea.cpp, schoof2.cpp + +A problem with Elliptic curve cryptography is the construction of suitable curves. This is actually much more difficult than the equivalent problem in the integer finite field as implemented by the program *dssetup.c/dssetup.cpp* . One approach is the Complex Multiplication method, as described in the Annex to the IEEE P1363 Standard Specifications for Public Key Cryptography (available from the Web). This is implemented here by the C++ program *cm.cpp* and its supporting modules *float.cpp*, *complex.cpp*, *flpoly.cpp*, *poly.cpp*, and associated header files. + +The program when run uses command line arguments. Type **cm** on its own to get instructions. For example + + cm -f 2#224-2#96+1 -o common.ecs + +generates the common information needed to implement elliptic curve cryptography into the file *common.ecs* . + +As an alternative to the CM method, a random curve can be generated, and the points on the curve directly counted. This is more time-consuming than complex multiplication, but may lead to more secure, less structured curves. The basic algorithm is due to Schoof [Sch],[Blake] and is only practical due to the use of Fast Fourier Transform methods [Shoup] for the multiplication/division of large degree polynomials. See *mrfast.c* . Its still very slow, much slower than **cm**. Type **schoof** on its own to get instructions. For example: + + schoof –f 2#192-2#64-1 –3 35317045537 + +counts the points on the curve y2 = x3 –3x +35317045537 mod 2192-264-1. + +This curve is randomly selected (actually 35317045537 is my international phone number). The answer is the prime number: + + 6277101735386680763835789423127240467907482257771524603027 + +Be prepared to wait, or…. + +Use the suite of **programs**, **mueller**, **process**, and **sea**, which together implement the superior, but more complex, Schoof-Elkies-Atkin method for point counting. See [Blake] for details. + +First of all the **mueller** program should be run, to generate the required Modular Polynomials. This needs to be done just once – ever. The greater your collection of Modular Polynomials, the greater the size of prime modulus that can be used for the elliptic curves of interest. Note that this program is particularly hard on memory resources, as well as taking a long time to run. However after an hour at most you should have enough Modular Polynomials to start experimenting. As with all these programs, simply typing the program name without parameters generates instructions for use. Also be sure to read the comments at the start of the source file, in this case *mueller.cpp* . + +Next run the **process** application, which processes the file of raw modular polynomials output by **mueller**, for use with a specified prime modulus. + +Finally run **sea** to count the points on the curve, and optionally to create a *.ecs* file as described above. + +For example: +``` +mueller 0 120 –o mueller.raw + +process –f 65112*2#144-1 –i mueller.raw –o test160.pol + +sea –3 49 –i test160.pol +``` +generates all the modular polynomials for primes from 0 to 120, and outputs them to the file *mueller.raw* . Then these polynomials are processed with respect to the prime *p* = 65112.2144-1, to create the file *test160.pol*. Finally the main **sea** application counts the points on the curve *y*2=*x*3-3x+49 mod *p*. + +This may be more complicated to use, but its much faster than **schoof**. + +Read the comments at the start of *sea.cpp* for more information. + +For elliptic curves over GF(2*m*), the program **schoof2** can be used, which is quite similar to **schoof**. It is even slower, but just about usable on contemporary hardware. For example: + + schoof2 1 52 191 9 –o common2.ecs + +counts the points on the curve *y2+xy=x3+x2+52*, over the field GF(2191). A suitable irreducible basis must also be specified, in this case *t191+t9+1*. Tables of suitable bases can be found in many documents, for example in Appendix A of the IEEE P1363 standard. See [Menezes] for a description of the method. + +For more information on building these applications see the files *cm.txt*, *schoof.txt*, *schoof2.txt* and *sea.txt*. + +### crsetup.cpp, crgen.cpp, crencode.cpp, crdecode.cpp + +Public key schemes should ideally be immune from *adaptive chosen cipher-text* attacks, whereby an attacker is able to obtain decryptions of any presented cipher-texts other than the particular one they are interested in. Recently Cramer & Shoup [CS] have come up with a Public Key encryption method that is provably immune to such powerful attacks. The program **crsetup** creates various global parameters, and **crgen** generates one set of public and private keys in the files *public.crs* and *private.crs* respectively. To encrypt an ASCII file called for example *fred.txt*, run the **crencode** program that generates a random session key, and uses it to encrypt the file. This session key is in turn encrypted by the public key and stored in the file *fred.key*. The binary encrypted file itself is stored as *fred.crs*. To decrypt the file, run the **crdecode** program, which uses the private key to recover the session key, and hence decode the text to the screen. + +A couple of points are worth highlighting. First of all the bulk encryption is carried out using a block cipher method. Such hybrid systems are standard practice, as block ciphers are much faster than public key methods. The block cipher scheme used is the new Advanced Encryption Standard block cipher, which is implemented in *mraes.c* . + +Examination of the source code *crdecode.cpp* reveals that decryption is a two-pass process. On the first pass the program determines the validity of the cipher-text, and only after that is known to be valid does the program go on to decrypt the file. So the decryption procedure will not respond at all to arbitrary bit strings concocted by an attacker. + +### brick.c, ebrick.c, ebrick2.c + +Certain Cryptographic protocols require the exponentiation of a fixed number *g*, that is the calculation of *gx mod n*, where *g* and *n* are known in advance. In this case the calculation can be substantially speeded up by a precomputation which generates a small table of *big* numbers. The method was first described by Brickell et al [Brick]. The example program *brick.c* illustrates the method. The GF(*p*) elliptic curve equivalent is provided in *ebrick.c* and the GF(2*m*) equivalent in *ebrick2.c* . In a typical application the precomputed tables might be generated using one of these programs (see commented-out code in *ebrick2.c*), which then might be transferred to ROM in an embedded program. The embedded program might use a static build of MIRACL to make use of these tables. + +### identity.c + +This is a program that allows individuals, issued with certain secret information, to establish mutual keys by performing a calculation involving only the other correspondents publicly known identity. No interchange of data is required [Maurer], and so this is called Non-Interactive Key Exchange. Note that the 'publicly known identity' might, for example, be simply an email address. For a full description see [Scott92]. This example program generates the secret data from the proffered Identity. However before this program is run, the program *genprime.c* must be run twice, to generate a pair of suitable trap-door primes. Copy the output of the program, *prime.dat*, first to *trap1.dat* and then to *trap2.dat* . The product of these primes will be used as the composite modulus used for subsequent calculations. + +### Pairing Based Cryptography +___ +A number of experimental programs are provided to implement cryptographic protocols based on *pairings*. Notably there are examples of Identity-Based Encryption (IBE) and authenticated key exchange. Read the files *pairings.txt*, *ake.txt* and *ibe.txt* for details. + +## 'flash' Programs +___ +Several programs demonstrate the use of *flash* variables. One gives an implementation of Gaussian elimination to solve a set of linear equations, involving notoriously ill-conditioned Hilbert matrices. Others show how rational arithmetic can be used to approximate real arithmetic, in, for example the calculation of roots and p. The former program detected an error in the value for the square root of 5 given in Knuth's appendix A [Knuth81]. The correct value is: + + 2.23606 79774 99789 69640 91736 68731 27623 54406 + +The error is in the tenth last digit, which is a 2, and not a 1. + +The *roots* program runs particularly fast when calculating the square roots of single precision integers, as a simple form of continued fraction generator can be used. In one test the golden ratio was calculated to 100,000 decimal places in 3 hours of CPU time on a VAX11/780. + +The 'sample' program was used to calculate p correct to 1000 decimal places, taking less than a minute on a 25MHz 80386-based IBM PC to do so. + +### roots.c + +This program calculates the square root of an input number, using Newtons method. Try using it to calculate the square root of two. The accuracy obtained depends on the size of the flash variables, specified in the initial call to **mirsys**. The tendency of flash arithmetic to prefer simple numbers can be illustrated by requesting, say, the square root of 7. The program calculates this value and then squares it, to give 7 again exactly. On your pocket calculator the same result will only be obtained if clever use is made of extra (hidden) guard digits. + +### hilbert.c + +Traditionally the inversion of 'Hilbert' matrices is regarded as a tough test for any system of arithmetic. This programs solves the set of linear equations *H.x = b*, where *H* is a Hilbert matrix and *b* is the vector [1,1,1,1,....1], using the classical Gaussian Elimination method. + +### sample.c + +This program is the same as that used by Brent [Brent78] to demonstrate some of the capabilities of his Fortran Multiprecision arithmetic package. + +### ratcalc.c + +As a comprehensive and useful demonstration of flash arithmetic this program simulates a standard full-function scientific calculator. Its unique feature (besides its 36-digit accuracy) is its ability to work directly with fractions, and to handle mixed calculations involving both fractions and decimals. By using this program the user will quickly get a feel for flash arithmetic and its capabilities. Note that this program contains some non-portable code (screen handling routines) that must be tailored to each individual computer/terminal combination. The version supplied works only on standard PCs using DOS, or a command prompt window in Windows 'NT/'98. diff --git a/miracl/docs/miracl-user-manual/floating-slash-nums.md b/miracl/docs/miracl-user-manual/floating-slash-nums.md new file mode 100644 index 0000000..3ba6563 --- /dev/null +++ b/miracl/docs/miracl-user-manual/floating-slash-nums.md @@ -0,0 +1,76 @@ +* [Intro](README.md) +* [Installation](installation.md) +* [The UI](the-ui.md) +* [Internal Rep](internal-rep.md) +* [Implementation](implementation.md) +* Floating Slash Nums +* [The C++ Interface](the-cpp-interface.md) +* [Example Programs](example-progs.md) +* [The MIRACL Routines](miracl-explained/reference-manual/low-level-routines.md) +* [Instance Variables](instance-variables.md) +* [MIRACL Error Messages](miracl-error-messages.md) +* [Hardware Compiler Interface](hardware-compiler-interface.md) +* [Bibliography](bibliography.md) + + +Floating Slash Numbers +--- + +The straightforward way to represent rational numbers is as reduced fractions, as a numerator and denominator with all common factors cancelled out. These numbers can then be added, subtracted, multiplied and divided in the obvious way and the result reduced by dividing both numerator and denominator by their Greatest Common Divisor. An efficient GCD subroutine, using Lehmers modification of the classical Euclidean algorithm for multiprecision numbers [Knuth81], is included in the MIRACL package. + +An alternative way to represent rationals would be as a finite continued fraction [Knuth81]. Every rational number *p/q* can be written as: +![Equation 1](images/equation_1.png) +or more elegantly as *p/q* = [a0/a1/a2/..../an] where the ai are positive integers, usually quite small. + +For example: +![Equation 2](images/equation_2.png) +Note that the ai elements of the above continued fraction representation are easily found as the quotients generated as a by-product when the Euclidean GCD algorithm is applied to *p* and *q*. + +As we are committed to fixed length representation of rationals, a problem arises when the result of some operation exceeds this fixed length. There is a necessity for some scheme of truncation, or rounding. While there is no obvious way to truncate a large fraction, it is a simple matter to truncate the continued fraction representation. The resulting, smaller, fraction is called a best rational approximation, or a convergent, to the original fraction. + +Consider truncating 277/642 = [0/2/3/6/1/3/3]. Simply drop the last element from the CF representation, giving [0/2/3/6/1/3] = 85/197, which is a very close approximation to 277/642 (error = 0.0018%). Chopping more terms from the CF expansion gives the successive convergents as 22/51, 19/44, 3/7, 1/2, 0/1. As the fractions get smaller, the error increases. Obviously the truncation rule for a computer implementation should be to choose the biggest convergent that fits the computer representation. + +The type of rounding described above is also called ‘Mediant rounding’. If p/q and r/s are two neighbouring representable slash numbers astride a gap, then their mediant is the unrepresentable (p+r)/(q+s). All larger fractions between p/q and the mediant will round to p/q, and those between r/s and the mediant will round to r/s. The mediant itself rounds to the ‘simpler’ of p/q and r/s. + +This is theoretically a very good way to round, much better than the rather arbitrary and base-dependent methods used in floating-point arithmetic, and is the method used here. The full theoretical basis of floating-slash arithmetic is described in detail by Matula & Kornerup [Matula85]. It should be noted that our *flash* representation is in fact a cross between the fixed- and floating-slash systems analysed by Matula & Kornerup, as our slash can only float between words, and not between bits. However the characteristics of the *flash* data type will tend to those of floating-slash, as the precision is increased. + +The MIRACL routine **mround** implements mediant rounding. If the result of an arithmetic operation is the fraction p/q, then the Euclidean GCD algorithm is applied as before to p and q. However this time the objective is not to use the algorithm to calculate the GCD per se, but to use its quotients to build successive convergents to p/q. This process is stopped when the next convergent is too large to fit the *flash* representation. The complete algorithm is given below (Kornerup & Matula [Korn83]) + +Given p³0 and q³1: + +b-2=p x-2=0 y-2=1 + +b-1=q x-1=1 y-1=0 + +Now for i=0,1,..... and for bi-1>0, find the quotient ai and remainder bi when bi-2 is divided by bi-1, such that: + +bi = -ai.bi-1 + bi-2 + +Then calculate + +xi = ai.xi-1 + xi-2 + +yi = ai.yi-1 + yi-2 + +Stop when ? is too big to fit the *flash* representation, and take ? as the rounded result. + +If applied to 277/642, this process will give the same sequence of convergents as stated earlier. + +Since this rounding procedure must be applied to the result of each arithmetic operation, and since it is potentially rather slow, a lot of effort has been made to optimise its implementation. Lehmer's idea of operating only with the most significant piece of each number for as long as possible [Knuth81] is used, so that for most of the iterations only single-precision arithmetic is needed. Special care is taken to avoid the rounded result overshooting the limits of the **flash** representation [Scott89a]. The application of the basic arithmetic routines to the calculation of elementary functions such as *log(x)*, *exp(x)*, *sin(x)*, *cos(x)*, *tan(x)* etc., uses the fast algorithms described by Brent [Brent76]. + +In many cases the result given by a program can be guaranteed to be exact. This can be checked by testing the instance variable **EXACT**, which is initialised to TRUE and is only set to FALSE if any rounding takes place. + +A disadvantage of using a *flash* type of variable to approximate real arithmetic is the non-uniformity in gap-size between representable values (Matula & Kornerup [Matula85]). + +To illustrate this consider a floating-slash system which is constrained to have the product of numerator and denominator less than 256. Observe that the first representable fraction less than 1/1 in such a system is 15/16, a gap of 1/16. The next fraction larger than 0/1 is 1/255, a gap of 1/255. In general, for a *k*-bit floating-slash system, the gap size varies from smaller than 2-k to a worst case 2-k/2. In practise this means that a real value that falls into one of the larger gaps, will be represented by a fraction which will be accurate to only half its usual precision. Fortunately such large gaps are rare, and increasingly so for higher precision, occurring only near simple fractions. However it does mean that real results can only be completely trusted to half the given decimal places. A partial solution to this problem would be to represent rationals directly as continued fractions. This gives a much better uniformity of gap-size (Kornerup & Matula [Korn85]), but would be very difficult to implement using a high level language. + +Arithmetic on *flash* data-types is undoubtedly slower than on an equivalent sized multiprecision floating-point type (e.g. [Brent78]). The advantages of the *flash* approach are its ability to exactly represent rational numbers, and do exact arithmetic on them. Even when rounding is needed, the result often works out correctly, due to the tendency of mediant-rounding to prefer a simple fraction over a complex one. For example the *roots* program (see 'Example Programs' when asked to find the square root of 2 and then square the result, comes back with the exact answer of 2, despite much internal rounding. + +Do not mix *flash* arithmetic with the built-in *double* arithmetic. They don’t mix well. If you decide to use *flash* arithmetic, use it throughout, and convert all constants at the start to type *flash*. Even better specify such constants if possible as fractions. So (in C++) it is much preferable to write: + +`x=Flash(5,8); // x=5/8` + +rather than + +`x=.625;` + diff --git a/miracl/docs/miracl-user-manual/hardware-compiler-interface.md b/miracl/docs/miracl-user-manual/hardware-compiler-interface.md new file mode 100644 index 0000000..06f860d --- /dev/null +++ b/miracl/docs/miracl-user-manual/hardware-compiler-interface.md @@ -0,0 +1,66 @@ +* [Intro](README.md) +* [Installation](installation.md) +* [The UI](the-ui.md) +* [Internal Rep](internal-rep.md) +* [Implementation](implementation.md) +* [Floating Slash Nums](floating-slash-nums.md) +* [The C++ Interface](the-cpp-interface.md) +* [Example Programs](example-progs.md) +* [The MIRACL Routines](miracl-explained/reference-manual/low-level-routines.md) +* [Instance Variables](instance-variables.md) +* [MIRACL Error Messages](miracl-error-messages.md) +* Hardware Compiler Interface +* [Bibliography](bibliography.md) + + +The Hardware/Compiler Interface +--- + +Hardware/compiler details are specified to MIRACL in this header file: *mirdef.h* . For example: +``` +/* + * MIRACL compiler/hardware definitions - mirdef.h + * This version suitable for use with most 32-bit + * computers + * + * Copyright (c) 1988-1999 Shamus Software Ltd. + */ + +#define MIRACL_32 +#define MR_LITTLE_ENDIAN + /* this may need to be changed */ + +#define mr_utype int /* the underlying type is usually int * + * but see mrmuldv.any */ + +#define mr_unsign32 unsigned long + /* 32 bit unsigned type */ + +#define MR_IBITS 32 /* number of bits in an int */ + +#define MR_LBITS 32 /* number of bits in a long */ + +#define MR_FLASH 52 /* delete this definition if integer * + * only version of MIRACL required * + * Number of bits per double mantissa */ + +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + +#define MRBITSINCHAR 8 + /* Number of bits in char type */ + +/* #define MR_NOASM * define this if using C code only * + * Note: mr_dltype MUST be defined */ + +/* #define mr_dltype long long + * double-length type */ + +/* +#define MR_STRIPPED_DOWN * define this to minimize size * + * of library - all error messages * + * lost! USE WITH CARE - see mrcore.c */ +``` + +This file must be edited if porting to a new hardware environment. Assembly language versions of the time-critical routines in *mrmuldv.any* may also have to be written, if not already provided, although in most cases the standard C version *mrmuldv.ccc* can simply be copied to *mrmuldv.c* . + +It is best where possible to use the *mirdef.h* file that is generated automatically by the interactive *config.c* program. diff --git a/miracl/docs/miracl-user-manual/images/diagram.png b/miracl/docs/miracl-user-manual/images/diagram.png new file mode 100644 index 0000000..b078113 Binary files /dev/null and b/miracl/docs/miracl-user-manual/images/diagram.png differ diff --git a/miracl/docs/miracl-user-manual/images/equation_1.png b/miracl/docs/miracl-user-manual/images/equation_1.png new file mode 100644 index 0000000..88d459d Binary files /dev/null and b/miracl/docs/miracl-user-manual/images/equation_1.png differ diff --git a/miracl/docs/miracl-user-manual/images/equation_2.png b/miracl/docs/miracl-user-manual/images/equation_2.png new file mode 100644 index 0000000..4e63c78 Binary files /dev/null and b/miracl/docs/miracl-user-manual/images/equation_2.png differ diff --git a/miracl/docs/miracl-user-manual/images/figure_4-1.png b/miracl/docs/miracl-user-manual/images/figure_4-1.png new file mode 100644 index 0000000..d9e8435 Binary files /dev/null and b/miracl/docs/miracl-user-manual/images/figure_4-1.png differ diff --git a/miracl/docs/miracl-user-manual/images/image1.png b/miracl/docs/miracl-user-manual/images/image1.png new file mode 100644 index 0000000..777a3bf Binary files /dev/null and b/miracl/docs/miracl-user-manual/images/image1.png differ diff --git a/miracl/docs/miracl-user-manual/images/image2.png b/miracl/docs/miracl-user-manual/images/image2.png new file mode 100644 index 0000000..b3c06f2 Binary files /dev/null and b/miracl/docs/miracl-user-manual/images/image2.png differ diff --git a/miracl/docs/miracl-user-manual/implementation.md b/miracl/docs/miracl-user-manual/implementation.md new file mode 100644 index 0000000..4cf12bd --- /dev/null +++ b/miracl/docs/miracl-user-manual/implementation.md @@ -0,0 +1,88 @@ +* [Intro](README.md) +* [Installation](installation.md) +* [The UI](the-ui.md) +* [Internal Rep](internal-rep.md) +* Implementation +* [Floating Slash Nums](floating-slash-nums.md) +* [The C++ Interface](the-cpp-interface.md) +* [Example Programs](example-progs.md) +* [The MIRACL Routines](miracl-explained/reference-manual/low-level-routines.md) +* [Instance Variables](instance-variables.md) +* [MIRACL Error Messages](miracl-error-messages.md) +* [Hardware Compiler Interface](hardware-compiler-interface.md) +* [Bibliography](bibliography.md) + + +Implementation +--- + +No great originality is claimed for the routines used to implement arithmetic on the big data-type. The algorithms used are faithful renditions of those described by Knuth [Knuth81]. However some effort was made to optimize the implementation for speed. At the heart of the time-consuming multiply and divide routines there is, typically, a need to multiply together a digit from each operand, add in a ‘carry’ from a previous operation, and then separate the total into a digit of the result, and a 'carry' for the next operation. To illustrate consider this base 10 multiplication: +``` + 8723536221 + + x 9 + + 78511825989 +``` +To correctly process the column with the 5 in it, we multiply 5 ´ 9 = 45, add in the ‘carry’ from the previous column (a 3), to give 48, keep the 8 as the result for this column, and carry the 4 to the next column. + +This basic primitive operation is essentially the calculation of the quotient (a.b+c)/m and its remainder. For the example above a=5, b=9, c=3 and m=10. This operation has surprisingly universal application, and since it lies at the innermost loop of the arithmetic algorithms, its efficient implementation is essential. + +There are three main difficulties with a high-level language general base implementation of this MAD (Multiply, Add and Divide) operation. + +- It will be slow. + +- Quotient and remainder are not available simultaneously as a result of the divide operation. Therefore the calculation must be essentially done twice, once to get the quotient, and once for the remainder. + +- Although the operation results in two single digit quantities, the intermediate product (a.b+c) may be double-length. Indeed such a Multiply-Add and Divide routine can be used on all occasions when a double-length quantity would be required by the basic arithmetic algorithms. Note that the C language is blessed with a ‘long’ integer data-type which may in fact be capable of temporarily storing this product. + +For these reasons it is best to implement this critical operation in the assembly language of the computer used, although a portable C version is possible. At machine-code level a transitory double-length result can often be dealt with, even if the C long data-type is not itself double-length (as is the case for most C compilers as implemented on 32-bit computers, for which *ints* and *longs* are both 32-bit quantities). For further details see the documentation in the file *mrmuldv.any* . + +A criticism of the MIRACL system might be its use of fixed length arrays for its *big* and *flash* data types. This was done to avoid the difficult and time-consuming problems of memory allocation and garbage collection, which would be needed by a variable-length representation. However it does mean that when doing a calculation on *big* integers that the results of all intermediate calculations must be less than or equal to the fixed size initially specified to **mirsys**. + +In practice, most numbers in a stable integer calculation are of more or less the same size, except when two are multiplied together in which case a double-length intermediate product is created. This is usually immediately reduced again by a subsequent divide operation. A classic example of this would be in the Pollard-Brent factoring program (see 'Example Programs'). + +Note that this is another manifestation, on a macro level, of the problem mentioned above. It would be a pity to have to specify each variable to be twice as large as necessary, just to cope with these occasional intermediate products. For this reason a special Multiply, Add and Divide routine **mad** has been included in the MIRACL library. It has proved very useful when implementing large programs (like the Pomerance-Silverman-Montgomery factoring program in 'Example Programs' on computers with limited memory. + +As well as the basic arithmetic operations, routines are also provided to: + +- Generate and test *big* prime numbers, using a probabilistic primality test [Knuth81]. +- Generate *big* and *flash* random numbers, based on the subtract-with-borrow generator [Marsaglia]. However, the basic random number generator implemented internally isn't cryptographically secure. In a real cryptographic application it would not be adequate. A Cryptographically strong generator is provided in the module *mrstrong.c* . +- Calculate powers and roots. +- Implement both the normal and extended Euclidean GCD (Greatest Common Divisor) algorithm [Knuth81]. +- Implement the ‘Chinese Remainder Theorem’ [Knuth81], and to calculate the Jacobi Symbol [Reisel]. +- Multiply extremely large numbers, using the Fast Fourier Transform method [Pollard71]. + +When performing extensive modular arithmetic, a time-critical operation is that of ‘Modular Multiplication’, that is multiplication of two numbers followed by reduction to the remainder when divided by a fixed *n*, the modulus. One obvious solution would be to use the **mad** routine described above. However Montgomery [Monty85] has proposed an alternative method. This requires that numbers are first converted to a special *n-residue* form. However, once in this form modular multiplication is somewhat faster, using a special routine that requires no division whatsoever. When the calculation is complete, the answers can be converted back to normal form. Note that modular addition and subtraction of *n-residues* proceeds as usual, using the same routines as used for normal arithmetic. Given the requirement for conversion of variables to/from *n-residue* format, Montgomery's method should only be considered when a calculation requires an extensive amount of modular arithmetic using the same modulus. It is in fact much more convenient to use in a C++ environment, which hides these difficult details. See 'The C++ Interface'. + +Montgomery arithmetic is used internally by many of the MIRACL library routines that require extensive modular arithmetic, such as the highly optimised modular exponentiation function **powmod**, and those functions which implement GF(*p*) Elliptic Curve arithmetic. Details can be found in [MIRACL Routines] (/miracl-user-manual/the-miracl-routines). + +For the fastest possible modular arithmetic, one must alas resort to assembly language, and to methods optimised for a particular modulus, or moduli of a particular size. A number of different techniques are supported and can be used. The first two methods, the Comba and KCM methods, are implemented in the files *mrcomba.c* and *mrkcm.c* respectively. These files are created from template files *mrcomba.tpl* and *mrkcm.tpl* by inserting macros defined in a *.mcs* file. This is done automatically using the supplied **m**acro **ex**pansion utility **mex**. Compile and run *config.c* on your target system to automatically create a suitable *mirdef.h* and for advice on how to proceed. Also read *kcmcomba.txt* . To get the fastest possible performance for your embedded application it is recommended that you should develop your own *x.mcs* file, if one is not already provided for your processor/compiler. + +Two other rather more experimental techniques are implemented in the files *mr87v.c* and *mr87f.c* for the Intel 80x86 family of processors only, using the Borland C++ compiler. + +If conditions are right the appropriate code will be automatically invoked by calling for example **powmod**. + +It is important to note that the four techniques described require a compiler that supports in-line assembly. Furthermore the latter two techniques have only been tested with the Borland C++ V4.5 compiler for the 80x86 family of processors. + +The first idea is to completely unravel and reorganise the program loops implicit in the multiplication and reduction process, as first advocated by [Comba] and modified by [Scott96]. See *mrcomba.tpl* . A fixed length modulus must be used and specified at compile time by defining **MR_COMBA** to the modulus size (in words) in *mirdef.h* . This works well for small to medium size moduli, particularly as used in GF(*p*) elliptic curve cryptography. For even more speed, the modular reduction algorithm can be optimised for a modulus that has a particularly simple form. This can be done by manually inserting the appropriate code into *mrcomba.tpl* . Example code for the case of a modulus *p* = 2192-264-1 is given there in the routine **comba_redc** . To invoke this special code **MR_SPECIAL** must be defined in *mirdef.h* . + +This technique can be combined with Karatsuba’s idea for fast multiplication [Knuth81] to speed up modular multiplication for larger moduli [WeiDai]. This Karatsuba-Comba-Montgomery (KCM) method is invoked by defining **MR_KCM** in *mirdef.h* . The modulus size in computer words is restricted to be equal to **MR_KCM*2n** for any positive **n** (within reason). This is a consequence of using Karatsuba’s algorithm. For example defining **MR_KCM** to be 8 on a 32-bit computer allows popular modulus sizes of 512, 1024, 2048 .... bits. + +Another alternative is to exploit the floating point co-processor (if there is one), as its multiplication instruction is often faster than that of the integer unit [Rubin]. This is the case for the original Intel Pentium processor whose embedded co-processor takes only 3 cycles to perform a multiplication, compared with the 10 required for an integer multiply, although this is not true of the Pentium Pro, II, or III. Also the co-processor has eight extra registers, and can manipulate 64-bit numbers directly. These features allow the programmer some extra flexibility, which can be used to advantage. Some experimental code has been written in the modules *mr87f.c* and *mr87v.c*, which may be exploited by defining **MR_PENTIUM** in *mirdef.h* . Use *config.c* to generate *mirdef.h* – this time the underlying type must be chosen as **double**. The module *mr87v.c* implements compact looping code, which will work with any modulus less than a certain maximum. The module *mr87f.c* unrolls the loops for more speed, but is bulkier and requires a fixed size modulus. Note that these modes of operation are incompatible with a full-width base, and work best with a number base of (usually) 228 or 229 – *config.c* will work it out for you. Note also that although this method will speed modular exponentiation on a Pentium, it may actually be slower for most other 80x86 processors, so use with care. In one test a 2048 bit number was raised to a 2048-bit power, mod a 2048 bit modulus. This took 2.4 seconds on a 60MHz Pentium. +![Diagram](images/diagram.png) +This diagram illustrates the relative timings required by each method on a Pentium Pro 200MHz processor when compiled with the Borland C 32 bit compiler. The base line “Classic” method refers to the assembly language code implemented directly in *mrarth2.c* and *mrmonty.c* . The Comba and KCM implementations use assembly language from the *ms86.mcs* file. The modulus sizes are on the **x** axis, and the scaled time in seconds on the **y** axis. Note that in the calculation of **xy mod n** it is assumed that **x**, **y** and **n** are randomly generated, all of same length in bits, and of no special form. It is assumed, for example, that the Comb optimisation technique (See [HAC] and *brick.c*) does not apply (that is **x** is a variable). The times shown are correct for the 8192 bit modulus. Times for smaller moduli are cumulatively scaled up by 8. So the times shown for a 4096 bit modulus should be divided by 8, for a 2048 bit modulus divided by 64, etc. Completely unrolled code is impracticable for the larger moduli, and hence timings for these methods are not given. + +Note that the Comba method is optimal for moduli of 512 bits and less. This implies that it will be the optimal technique for fast GF(*p*) elliptic curve implementations, and for 1024-bit RSA decryption (which requires two 512-bit exponentiations and an application of the Chinese Remainder theorem). However these conclusions are processor-dependent, and may not be globally true. Also the Comba method can generate a lot of code, and this may be an important consideration in some applications. In some circumstances (for example when the instruction cache is very small), it may in fact be advisable to take the working unrolled assembly language and carefully, manually, re-roll it. + +From Version 5.20 of MIRACL, a new data type is supported directly in C. This is called a *zzn2* type, and basically it consists of two **bigs** in *n-residue* format: +``` +typedef struct +{ + big a; + big b; +} zzn2; +``` +where *a* and *b* can be considered as the real and imaginary parts respectively. The value of a *zzn2* is *a+ib*, where *i* is the imaginary square root of a quadratic non-residue. A *zzn2* variable is a representation of an element of a quadratic extension field with respect to a prime modulus *p*. For example if *p*=3 mod 4, then *i* can be taken as √-1, and the analogy to complex numbers with their real and imaginary parts becomes clear. They are particularly useful in implementations of cryptographic pairings. For an example of use, see the example program *cardona.cpp* which solves a cubic equation. A default value for the quadratic non-residue (which depends on the modulus) is stored in the instance variable *qnr*. Only the values -1 and -2 are currently supported. + +To assist programmers generating code for a processor in a non-standard environment (e.g. an embedded controller), the code for dynamic memory allocation is always invoked from the module *mralloc.c* . By default this calls the standard C run-time functions **calloc** and **free** . However, it can easily be modified to use an alternative user-defined memory allocation mechanism. For the same reason all screen/keyboard output and input is via the standard run-time functions **fputc** and **fgetc**. By intercepting calls to these functions, I/O can be redirected to non-standard devices. diff --git a/miracl/docs/miracl-user-manual/installation.md b/miracl/docs/miracl-user-manual/installation.md new file mode 100644 index 0000000..5077a6e --- /dev/null +++ b/miracl/docs/miracl-user-manual/installation.md @@ -0,0 +1,199 @@ +* [Intro](README.md) +* Installation +* [The UI](the-ui.md) +* [Internal Rep](internal-rep.md) +* [Implementation](implementation.md) +* [Floating Slash Nums](floating-slash-nums.md) +* [The C++ Interface](the-cpp-interface.md) +* [Example Programs](example-progs.md) +* [The MIRACL Routines](miracl-explained/reference-manual/low-level-routines.md) +* [Instance Variables](instance-variables.md) +* [MIRACL Error Messages](miracl-error-messages.md) +* [Hardware Compiler Interface](hardware-compiler-interface.md) +* [Bibliography](bibliography.md) + + +Installation +--- + +* [Overview](#overview) +* [Optimising](#optimising) +* [Upgrading from Version 3](#upgrading) +* [Multi-Threaded Programming](#multi) +* [Constrained Environments](#contrained) + +## Overview + +The MIRACL library has been successfully installed on a VAX11/780, on a variety of UNIX workstations (Sun, SPARC, Next, IBM RS/6000), on an IBM PC using the Microsoft C and C++ compilers, Borland’s Turbo C and Borland C++ compilers, the Watcom C compiler and the DJGPP GNU compiler; on ARM based computers, and on an Apple Macintosh. Recently it has been implemented on Itanium and AMD 64-bit processors. + +The complete source code for each module in the MIRACL library, and for each of the example programs is provided on the distribution media. Most are written in Standard ANSI C, and should compile using any decent ANSI C compiler. Some modules contain extensive amounts of in-line assembly language, used to optimise performance for certain compiler/processor combinations. However these are invoked transparently by conditional compilation commands and will not interfere with other compilers. The batch files xxdoit.xxx contain the commands used for the creation of a library file and the example programs for several compilers. Print out and examine the appropriate file for your configuration. + +Pre-compiled libraries for immediate use with certain popular compilers may be found on the distribution media: ready-to-run versions of only some of the example programs may be included, to conserve space. + +To create a library you will need access to a compiler, a text editor, a linker, a librarian utility, and an assembler (optional). Read your compiler documentation for further details. The file *mrmuldv.any*, which contains special assembly language versions of the time-critical routines **muldiv**, **muldvd**, **muldvd2** and **muldvm** together with some portable C versions, which may need to be tailored for your configuration. These modules are particularly required if the compiler does not support a double length type which can hold the product of two word-length integers. Most modern compilers provide this support (often the double length type is called 'long long'), and in this case it is often adequate to use the standard C version of this module *mrmuldv.ccc* which can simply be copied to *mrmuldv.c*. Read this manual carefully, and the comments in *mrmuldv.any* for more details. + +The hardware/compiler specific file *mirdef.h* needs to be specified. To assist with this, five example versions of the header are supplied: *mirdef.h16* for use with a 16-bit processor, *mirdef.h32* for 32-bit processors, *mirdef.haf* if using a 32-bit processor in a 16-bit mode, and *mirdef.hpc* for pseudo 32-bit working in a 16-bit environment. Note that the full 32-bit version is fastest, but only possible if using a true 32-bit compiler with a 32-bit processor. Try *mirdef.gcc* for use with **gcc** and **g++** in a Unix environment (no assembler). + +To assist with the configuration process, a file *config.c* is provided. When compiled and run on the target processor it automatically generates a *mirdef.h* file and gives general advice on configuration. It also generates a *miracl.lst* file with a list of MIRACL modules to be included in the associated library build. Experimentation with this program is strongly encouraged. When compiling this program DO NOT use any compiler optimization. + +The *mirdef.h* file contains some optional definitions: Define **MR_NOFULLWIDTH** if you are unable to supply versions of **muldvd**, **muldvd2** and **muldvm** in *mrmuldv.c*. Define **MR_FLASH** if you wish to use flash variables in your programs. + +Either one of **MR_LITTLE_ENDIAN** or **MR_BIG_ENDIAN** must be defined. The *config.c* program automatically determines which is appropriate for your processor. + +By omitting the **MR_FLASH** definition big variables can be made much larger, and the library produced will be much smaller, leading to more compact executables. Define **MR_STRIPPED_DOWN** to omit error messages, to save even more space in production code. Use with care! + +If you don’t want any assembler, define **MR_NOASM**. This generates standard C code for the four time-critical routines, and generates it in-line. This is faster - saves on function calling overhead - and also gives an optimising compiler something to chew on. Note that if **MR_NOASM** is defined, then the *mrmuldv* module is not required in the MIRACL library. + +If using the Microsoft Visual C++ tool, some helpful advice can be found in the file *msvisual.txt*. If using the Linux operating system, check out *linux.txt*. Users of the Borland compiler should look at *borland.txt*. + +In the majority of cases where pre-built libraries or specific advice in a *.txt* file is not available, the following procedure will result in a successful build of the MIRACL library:- + +1. Compile and run *config.c* on the target processor. + +2. Rename the generated file *mirdef.tst* to *mirdef.h* + +3. If so advised by the **config** program, extract a suitable *mrmuldv.c* file from *mrmuldv.any* (or copy the standard C version *mrmuldv.ccc* to *mrmuldv.c* and use this). If it is pure assembly language it may be appropriate to name it *mrmuldv.s* or *mrmuldv.asm*. + +4. If the fast **KCM** or **Comba** methods for modular multiplication were selected (see below), compile and run the *mex.c* utility on any workstation. Use it to automatically generate either the module *mrcomba.c* or *mrkcm.c*. This will require a processor/compiler-specific *xxx.mcs* file. The compiler must support inline assembly. + +5. Make sure that all the MIRACL header files are accessible to the compiler. Typically the flag –I. or /I. allows these headers to be accessed from the current directory. + +6. Compile the MIRACL modules listed in the generated file *miracl.lst* and create a library file, typically *miracl.a* or *miracl.lib*. This might be achieved by editing *miracl.lst* into a suitable batch or make file. On UNIX it might be as simple as: +``` +gcc –I. –c –O2 mr*.c +ar rc miracl.a mr*.o +``` +7. If using the C++ MIRACL wrapper, compile the required modules, for example *zzn.cpp* and/or *big.cpp* etc. + +8. Compile and link your application code to any C++ modules it requires and to the MIRACL library. + +Remember that MIRACL is portable software. It may be ported to any computer which supports an ANSI C compiler. + +Note that MIRACL is a C library, not C++. It should always be built as a C library otherwise you might get compiler errors. To include MIRACL routines in a C program, include the header *miracl.h* at the start of the program, after including the C standard header *stdio.h* . You may also call MIRACL routines directly from a C++ program by:- +``` +extern "C" + +{ + #include "miracl.h" +} +``` +although in most cases it will be preferable to use the C++ wrapper classes described in 'The C++ Interface' section. + +## Optimising + +In the context of MIRACL this means speeding things up. A critical decision to be made when configuring MIRACL is to determine the optimal underlying type to use. Usually this will be the *int* type. In general try to define the maximum possible underlying type, as requested by *config*. If you have a 64-bit processor, you should be able to specify a 64-bit underlying type. In some circumstances it may be faster to use a floating-point **double** underlying type. + +Obviously an all-C build of MIRACL will be slowest (but still pretty fast!). It is also the easiest to start with. This requires an integer data type twice the width of the underlying type. In this context note that these days most compilers support a long long integer type which is twice the width of the int. Sometimes it is called **__int64** instead of **long long**. + +If your processor is of the extreme RISC variety and supports no integer multiplication/division instruction, or if using a very large modulus, then the Karatsuba-Montgomery-Comba technique for fast modular multiplication may well be faster for exponentiation cryptosystems. Again the *config* program will guide you through this. + +It is sometimes faster to implement the *mrmuldv* module in assembly language. This does not require the double-width data type. If you are lucky your compiler will also be supported by automatically invoked inline assembly, which will speed things up even further. See *miracl.h* to see which compilers are supported in this way. + +For the ultimate speed, use the extreme techniques implemented in *mrkcm.c*, *mrcomba.c*. See *kcmcomba.txt* for instructions on how to automatically generate these files using the supplied **mex** utility. See also 'Implementation' for more details. + +## Upgrading from Version 3 + +Version 4.0 introduces the Miracl Instance Pointer, or **mip**. Previous versions used a number of global and static variables to store internal status information. There are two problems with this. Firstly such globals have to be given obscure names to avoid clashes with other project globals. Secondly it makes multi-threaded applications much more difficult to develop. So from Version 4.0 all such variables, now referred to as instance variables, are members of a structure of type *miracl*, and must be accessed via a pointer to an instance of this structure. This global pointer is now the only static/global variable maintained by the MIRACL library. Its value is returned by the **mirsys** routine, which initialises the MIRACL library. + +C++ programmers should note the change in the name of the instance class from miracl to Miracl. The **mip** can be found by taking the address of this instance: +``` +Miracl precision=50; +. +mip=&precision; +. +etc +``` +## Multi-Threaded Programming + +From version 4.4 MIRACL offers full support for Multi-threaded programming. This comes in various flavours. + +The problem to be overcome is that MIRACL has to have access to a lot of instance specific status information via its *mip*. Ideally there should be no global variables, but MIRACL has this one pointer. Unfortunately every thread that uses MIRACL needs to have its own *mip*, pointing to its own independent status. This is a well-known issue that arises with threads. + +The first solution is to modify MIRACL so that the *mip*, instead of being a global, is passed as a parameter to every MIRACL function. The MIRACL routines can be automatically modified to support this by defining **MR_GENERIC_MT** in *mirdef.h* . Now (almost all) MIRACL routines are changed such that the *mip* is the first parameter to each function. Some simple functions are exceptions and do not require the *mip* parameter – these are marked with an asterix in 'The MIRACL Routines' section. For an example of a program modified to work with a MIRACL library built in this way, see the program *brent_mt.c* . Note however that this solution does NOT apply to programs written using the MIRACL C++ wrapper described in 'The C++ Interface' section. It only applies to C programs that access the MIRACL routines directly. + +An alternative solution is to use Keys, which are a type of thread specific “global” variable. These *Keys* are not part of the C/C++ standard, but are operating system specific extensions, implemented via special function calls. MIRACL provides support for both Microsoft Windows and Unix operating systems. In the former case these Keys are called *Thread-Local Storage*. See [Richter] for more information. For Unix MIRACL supports the POSIX standard interface for multithreading. A very useful reference for both Windows and Unix is [Walmsley]. This support for threads is implemented in the module *mrcore.c*, at the start of the file and in the initialisation routine **mirsys**. + +For Windows, define **MR_WINDOWS_MT** in *mirdef.h*, and for Unix define **MR_UNIX_MT**. In either case there are some programming implications. + +In the first place the *Key* that is to maintain the mip must be initialised and ultimately destroyed by the programs primary thread. These functions are carried out by calls to the special routines **mr_init_threading** and **mr_end_threading** respectively. + +In C++ programs these functions might be associated with the constructor and destructor of a global variable [Walmsley] – this will ensure that they are called at the appropriate time before new threads are forked off from the main thread. They must be called before any thread calls **mirsys** either explicitly, or implicitly by creating a thread-specific instance of the class Miracl. + +It is strongly recommended that program development be carried out without support for threads. Only when a program is fully tested and debugged should it be converted into a thread. + +Threaded programming may require other OS-specific measures, in terms of linking to special libraries, or access to special heap routines. In this regard it is worth pointing out that all MIRACL heap accesses are via the module *mralloc.c* . + +See the example program *threadwn.cpp* for an example of Windows C++ multithreading. Read the comments in this program – it can be compiled and run from a Windows Command prompt. Similarly see *threadux.cpp* for an example of Unix multi-threading. + +## Constrained Environments + +In version 5 of MIRACL there is new support for implementations in very small and constrained environments. Using the *config* utility it is now possible to allow various time/space trade-offs, but the main innovation is the possibility of building and using MIRACL in an environment which does not support a heap. Normally space for big variables is obtained from the heap, but by specifying in the configuration header **MR_STATIC**, a version of the library is built which will always attempt to allocate space not from the heap, but from static memory or from the stack. + +The main downside to this is that the maximum size of big variables must be set at compile time, when the library is being created. As always it is best to let the config utility guide you through the process of creating a suitable *mirdef.h* configuration header. + +For the C programmer, the allocation of memory from the stack for big variables proceeds as follows: +``` +big x,y,z; +char mem[MR_BIG_RESERVE(3)]; +memset(mem,0, MR_BIG_RESERVE(3)); +``` +This allocates space for 3 big variables on the stack, and set that memory to zero. Each individual big variable is then initialised as: +``` +x=mirvar_mem(mem,0); +y=mirvar_mem(mem,1); +z=mirvar_mem(mem,2); +``` +Allocating all the space for multiple big variables from a single chunk of memory makes sense, as it leads to a faster initialization, and also gives complete control over variable alignment, which compilers sometimes get wrong. Note that in this mode the usual big number initialization function *mirvar* is no longer available, and allocation must be implemented as described above. + +Finally this memory chunk may optionally be cleared before leaving a function by a final call to *memset(.)* – this may be important for security reasons. For an example see the program *brent.c* . + +This mechanism may be particularly useful when trying to implement a very small program using elliptic curves, which anyway require much smaller big numbers than other cryptographic techniques. To allocate memory from the stack for an elliptic curve point: +``` +epoint *x,*y,*z; +char mem[MR_ECP_RESERVE(3)]; +memset(mem,0, MR_ECP_RESERVE(3)); +``` +To initialize these points: +``` +x=epoint_init_mem(mem,0); +y=epoint_init_mem(mem,1); +z=epoint_init_mem(mem,2); +``` +Again it may be advisable to clear the memory associated with these points before exiting the function. + +This mechanism is fully supported for C++ programs as well, where it works in conjunction with the stack allocation method described in 'The C++ Interface' section. See *pk-demo.cpp* for an example of usage. + +In some extreme cases it may be desired to use only the stack for all memory allocation. This allows maximum use and re-use of memory, and avoids any fragmentation of precious RAM. This can be achieved for C programs by defining *MR_GENERIC_MT* in **mirdef.h**. See above for more details on this option. + +A typical *mirdef.h* header in this case might look like: +``` +/* + * MIRACL compiler/hardware definitions - mirdef.h + * Copyright (c) 1988-2005 Shamus Software Ltd. + */ + + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype __int64 +#define mr_unsign64 unsigned __int64 +#define MR_STATIC 7 +#define MR_ALWAYS_BINARY +#define MR_NOASM +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_SHORT_OF_MEMORY +#define MR_GENERIC_MT +#define MR_STRIPPED_DOWN +``` +For examples of programs which use this kind of header, see *ecsgen_s.c*, *ecsign_s.c* and *ecsver_s.c*, and *ecsgen2s.c*, *ecsign2s.c* and *ecsver2s*. These programs implement very small and fast ECDSA key generation, digital signature, and verification on a Pentium using Microsoft C++. See *ecdh2m.c* and *ecdhp.c* for more nice examples, which use precomputation to speed up EC Diffie-Hellman implementations. + +For small 8 and 16-bit processors, see example programs *ecdhp8.c*, *ecdhp16.c*, *ecdh2m8.c* and *ecdh2m16.c* . + +> Doing without a heap is a little problematical. Structures can no longer be of variable size, and so various features of MIRACL become unavailable in this mode. For example precomputations such as required for application of the Chinese remainder theorem are no longer supported. However in a constrained environment it could be reasonably assumed that such precomputations are carried out offline, and made available to the constrained program fixed in ROM. + +The MIRACL modules are carefully designed so that an application will only pull in the minimal number of modules from the library for any given task. This helps to keep the program size down to a minimum. However if program size is a big issue then extra savings can sometimes be made by manually deleting from the modules functions that are not needed by your particular program (the linker will complain if the function is in fact needed). diff --git a/miracl/docs/miracl-user-manual/instance-variables.md b/miracl/docs/miracl-user-manual/instance-variables.md new file mode 100644 index 0000000..834160d --- /dev/null +++ b/miracl/docs/miracl-user-manual/instance-variables.md @@ -0,0 +1,33 @@ +* [Intro](README.md) +* [Installation](installation.md) +* [The UI](the-ui.md) +* [Internal Rep](internal-rep.md) +* [Implementation](implementation.md) +* [Floating Slash Nums](floating-slash-nums.md) +* [The C++ Interface](the-cpp-interface.md) +* [Example Programs](example-progs.md) +* [The MIRACL Routines](miracl-explained/reference-manual/low-level-routines.md) +* Instance Variables +* [MIRACL Error Messages](miracl-error-messages.md) +* [Hardware Compiler Interface](hardware-compiler-interface.md) +* [Bibliography](bibliography.md) + + +Instance Variables +--- + +These variables are all member of the *miracl* structure defined in *miracl.h* . They are all accessed via the *mip* - the Miracl Instance Pointer. + +| Name | Description | +|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| BOOL EXACT; | Initialised to TRUE. Set to FALSE if any rounding takes place during *flash* arithmetic. | +| int INPLEN; | Length of input string. Must be used when inputting binary data. | +| int IOBASE; | The "printable" number base to be used for input and output. May be changed at will within a program. Must be greater than or equal to 2 and less than or equal to 256. | +| int IOBSIZ; | Size of I/O buffer. | +| BOOL ERCON; | Errors by default generate an error message and immediately abort the program. Alternatively by setting mip->ERCON=TRUE error control is left to the user. | +| int ERNUM; | Number of the last error that occurred. | +| char IOBUFF[ ]; | Input/Output buffer. | +| int NTRY; | Number of iterations used in probabilistic primality test by isprime. Initialised to 6. | +| int *PRIMES; | Pointer to a table of small prime numbers. | +| BOOL RPOINT; | If set to TRUE numbers are output with a radix point. Otherwise they are output as fractions (the default). | +| BOOL TRACER; | If set to ON, causes debug information to be printed out tracing the progress of all subsequent calls to MIRACL routines. Initialised to OFF. | diff --git a/miracl/docs/miracl-user-manual/internal-rep.md b/miracl/docs/miracl-user-manual/internal-rep.md new file mode 100644 index 0000000..6ed444c --- /dev/null +++ b/miracl/docs/miracl-user-manual/internal-rep.md @@ -0,0 +1,70 @@ +* [Intro](README.md) +* [Installation](installation.md) +* [The UI](the-ui.md) +* Internal Rep +* [Implementation](implementation.md) +* [Floating Slash Nums](floating-slash-nums.md) +* [The C++ Interface](the-cpp-interface.md) +* [Example Programs](example-progs.md) +* [The MIRACL Routines](miracl-explained/reference-manual/low-level-routines.md) +* [Instance Variables](instance-variables.md) +* [MIRACL Error Messages](miracl-error-messages.md) +* [Hardware Compiler Interface](hardware-compiler-interface.md) +* [Bibliography](bibliography.md) + + +Internal Representation +--- + +Conventional computer arithmetic facilities as provided by most computer language compilers usually provide one or two floating-point data types (e.g. single and double precision) to represent all the real numbers, together with one or more integer types to represent whole numbers. These built-in data-types are closely related to the underlying computer architecture, which is sensibly designed to work quickly with large amounts of small numbers, rather than slowly with small amounts of large numbers (given a fixed memory allocation). Floating-point allows a relatively small binary number (e.g. 32 bits) to represent real numbers to an adequate precision (e.g. 7 decimal places) over a large dynamic range. Integer types allow small whole numbers to be represented directly by their binary equivalent, or in 2's complement form if negative. Nevertheless this conventional approach to computer arithmetic has several disadvantages. + +- Floating-point and Integer data-types are incompatible. Note that the set of integers, although infinite, is a subset of the rationals (i.e. fractions), which is in turn a subset of the reals. Thus every integer has an equivalent floating-point representation. Unfortunately these two representations will in general be different. For example a small positive whole number will be represented by its binary equivalent as an integer, and as separated mantissa and exponent as a floating-point. This implies the need for conversion routines, to convert from one form to the other. + +- Most rational numbers cannot be expressed exactly (e.g. 1/3). Indeed the floating-point system can only express exactly those rationals whose denominators are multiples of the factors of the underlying radix. For example our familiar decimal system can only represent exactly those rational numbers whose denominators are multiples of 2 and 5; 1/20 is 0.05 exactly, 1/21 is 0.0476190476190..... + +- Rounding in floating-point is base-dependent and a source of obscure errors. + +- The fact that the size of integer and floating-point data types are dictated by the computer architecture, defeats the efforts of language designers to keep their languages truly portable. + +- Numbers can only be represented to a fixed machine-dependent precision. In many applications this can be a crippling disadvantage, for example in the new and growing field of Public-Key cryptography. + +- Base-dependent phenomena cannot easily be studied. For example it would be difficult to access a particular digit of a decimal number, as represented by a traditional integer data-type. + +Herein is described a set of standard C routines which manipulate multi-precision rational numbers directly, with multi-precision integers as a compatible subset. Approximate real arithmetic can also be performed. + +The two new data-types are called *big* and *flash*. The former is used to store multi-precision integers, and the latter stores multi-precision fractions as numerator and denominator in ‘floating-slash’ form. Both take the form of a fixed length array of digits, with sign and length information encoded in a separate 32-bit integer. The data type defined as **mr_small** used to store the number digits will be one of the built in types, for example int, long or even double. This is referred to as the “underlying type”. + +Both new types can be introduced into the syntax of the C language by the C statements: +``` +struct bigtype +{ + mr_unsign32 L; + mr_small *d; + +}; + +typedef struct bigtype *big; +typedef struct bigtype *flash; +``` + +Now *big* and *flash* variables can be declared just like any built-in data type, for example: +``` +big x,y[10],z[10][10]; +``` +Observe that a *big* is just a pointer. The memory needed for each *big* or *flash* number instance is taken from the heap (or from the stack). Therefore each *big* or *flash* number must be initialised before use, and the required memory assigned to it. + +Note that the user of these data-types is not concerned with this internal representation; the library routines allow *big* and *flash* numbers to be manipulated directly. + +The structure of *big* and *flash* numbers is illustrated in figure (4.1). + +These structures combine ease of use with representational efficiency. A denominator of length zero (d=0), implies an actual denominator of one; and similarly a numerator of length zero (n=0) implies a numerator of one. Zero itself is uniquely defined as the number whose first element is zero (i.e. n=d=0). +![Figure 4.1](images/figure_4-1.png) +Figure 4.1: Structure of *big* and *flash* data-types where *s* is the sign of the number, *n* and *d* are the lengths of the numerator and denominator respectively, and LSW and MSW mean ‘Least significant word and ‘Most significant word’ respectively. + +Note that the slash in the *flash* data-type is not in a fixed position, and may ‘float’ depending on the relative size of numerator and denominator. + +A *flash* number is manipulated by splitting it up into separate big numerator and denominator components. A big number is manipulated by extracting and operating on each of its component integer elements. To avoid possible overflow, the numbers in each element are normally limited to a somewhat smaller range than that of the full word-length, e.g. 0 to 32767 (= 215 - 1) on a 16-bit computer. However with careful programming a full-width base of 216 can also be used, as the C language does not report a run-time error on integer overflow [Scott89b]. + +When the system is initialised the user specifies the fixed number of words (or bytes) to be assigned to all *big* or *flash* variables, and the number base to be used. Any base can be used, up to a maximum which is dependent on the word length of the computer used. If requested to use a small base *b*, the system will, for optimal efficiency, actually use base *bn*, where *n* is the largest integer such that *bn* fits in a single computer word. Programs will in general execute fastest if a full-width base is used (achieved by specifying a base of 0 in the initial call to **mirsys**). Note that this mode may be supported by extensive in-line assembly language for certain popular compiler/processor combinations, in certain time-critical routines, for example if using Borland/Turbo C with an 80x86 processor. Examine, for example, the source code in module *mrarth1.c*. + +The encoding of the sign and numerator and denominator size information into a single word is possible, as the C language has standard constructs for bit manipulation. diff --git a/miracl/docs/miracl-user-manual/miracl-error-messages.md b/miracl/docs/miracl-user-manual/miracl-error-messages.md new file mode 100644 index 0000000..24904c0 --- /dev/null +++ b/miracl/docs/miracl-user-manual/miracl-error-messages.md @@ -0,0 +1,271 @@ +* [Intro](README.md) +* [Installation](installation.md) +* [The UI](the-ui.md) +* [Internal Rep](internal-rep.md) +* [Implementation](implementation.md) +* [Floating Slash Nums](floating-slash-nums.md) +* [The C++ Interface](the-cpp-interface.md) +* [Example Programs](example-progs.md) +* [The MIRACL Routines](miracl-explained/reference-manual/low-level-routines.md) +* [Instance Variables](instance-variables.md) +* MIRACL Error Messages +* [Hardware Compiler Interface](hardware-compiler-interface.md) +* [Bibliography](bibliography.md) + + +MIRACL Error Messages +--- + +* [Number base too big for representation](#toobig) +* [Division by zero attempted](#zero) +* [Overflow - number too big](#overflow) +* [Internal result is negative](#negative) +* [Input format error](#formaterror) +* [Illegal number base](#illegalnumberbase) +* [Illegal parameter usage](#illegalparameterusage) +* [Out of space](#outofspace) +* [Even root of a negative number](#evenroot) +* [Raising integer to negative power](#negpower) +* [Integer operation attempted on flash number](#integer) +* [Flash overflow](#flashoverflow) +* [Numbers too big](#numberstoobig) +* [Log of a non-positive number](#logofpositive) +* [Flash to double conversion failure](#doubleconversion) +* [MIRACL not initialised](#notinitialised) +* [I/O buffer overflow](#bufferoverflow) +* [Illegal modulus](#illegalmodulus) +* [No modulus defined](#nomodulus) +* [Exponent too big](#exponent) +* [Number base must be power of 2](#power) +* [Specified double-length type isn't](#specified) +* [Specified basis is not irreducible](#notirreducible) + +## Number base too big for representation + +**Diagnosis** + +An attempt has been made to input or output a number using a number base that is too big. For example, outputting using a number base of 232 is clearly impossible. For efficiency, the largest possible internal number base is used, but numbers in this format should be input/output to a much smaller number base £ 256. This error typically arises when using using *innum(.)* or *otnum(.)* after *mirsys(.,0)*. + +**Response** + +Perform a change of base prior to input/output. For example set the instance variable **IOBASE** to 10, and then use *cinnum(.)* or *cotnum(.)* . To avoid the change in number base, an alternatively is to initialise MIRACL using something like *mirsys*(400,16) which uses an internal base of 16. Now Hex I/O can be performed using *innum*(.) and *otnum*(.) . This will not impact performance on a 32-bit processor as 8 Hex digits will be packed into each computer word. + +## Division by zero attempted + +**Diagnosis** + +Self-explanatory. + +**Response** + +Don't do it! + +## Overflow - Number too big + +**Diagnosis** + +A number in a calculation is too big to be stored in its fixed length allocation of memory. + +**Response** + +Specify more storage space for all *big* and *flash* variables by increasing the value of *n* in the initial call to *mirsys*(n.b); + +## Internal Result is Negative + +**Diagnosis** + +This is an internal error that should not occur using the high-level MIRACL functions. It may be caused by user-induced memory over-runs. + +**Response** + +Report to . + +## Input Format Error + +**Diagnosis** + +The number being input contains one or more illegal symbols with respect to the current I/O number base. For example, this error might occur if IOBASE is set to 10, and a Hex number is input. + +**Response** + +Re-input the number, and be careful to use only legal symbols. Note that for Hex input only upper-case A-F are permissible. + +## Illegal number base + +**Diagnosis** + +The number base specified in the call to *mirsys*(.) is illegal. For example, a number base of 1 is not allowed. + +**Response** + +Use a different number base. + +## Illegal parameter usage + +**Diagnosis** + +The parameters used in a function call are not allowed. In certain cases, certain parameters must be distinct - for example in *divide*(.) the first two parameters must refer to distinct *big* variables. + +**Response** + +Read the documentation for the function in question. + +## Out of space + +**Diagnosis** + +An attempt has been made by a MIRACL function to allocate too much heap memory. + +**Response** + +Reduce your memory requirements. Try using a smaller value of *n* in your initial call to *mirsys(n,b)*. + +## Even root of a negative number + +**Diagnosis** + +An attempt has been made to find the square root of a negative number, for example. + +**Response** + +Don't do it! + +## Raising integer to negative power + +**Diagnosis** + +Self-explanatory. + +**Response** + +Don't do it! + +## Integer operation attempted on flash number + +**Diagnosis** + +Certain functions should only be used with *big* numbers, and do not make sense for *flash* numbers. Note that this error message is often provoked by memory problems, where for example the memory allocated to a *big* variable is accidentally over-written. + +**Response** + +Don't do it! + +## Flash overflow + +**Diagnosis** + +This error is provoked by Flash overflow or underflow. The result is outside of the representable dynamic range. + +**Response** + +Use bigger *flash* numbers. Analyse your program carefully for numerical instability. + +## Numbers too big + +**Diagnosis** + +The size of *big* or *flash* numbers requested in your call to *mirsys(.)* are simply too big. The length of each *big* and *flash* is encoded into a single computer word. If there is insufficient room for this encoding, this error message occurs. + +**Response** + +Build a MIRACL library that uses a bigger "underlying type". If not using Flash arithmetic, build a library without it - this allows much bigger big numbers to be used. + +## Log of a non-positive number + +**Diagnosis** + +An attempt has been made to calculate the logarithm of a non-positive *flash* number. + +**Response** + +Don't do it! + +## Flash to double conversion failure + +**Diagnosis** + +An attempt to convert a Flash number to the standard built-in C *double* type has failed, probably because the Flash number is outside of the dynamic range that can be represented as a *double*. + +**Response** + +Don't do it! + +## I/O buffer overflow + +**Diagnosis** + +An input output operation has failed because the I/O buffer is not big enough. + +**Response** + +Allocate a bigger buffer by calling *set_io_buffer_size(.)* after calling *mirsys(.)*. + +## MIRACL not initialised - + +**Diagnosis** + +Self-explanatory + +**Response** + +Don't do it! + +## Illegal modulus + +**Diagnosis** + +The modulus specified for use internally for Montgomery reduction, is illegal. Note that this modulus must not be even. + +**Response** + +Use an odd positive modulus. + +## No modulus defined + +**Diagnosis** + +No modulus has been specified, yet a function which needs it has been called. + +**Response** + +Set a modulus for use internally + +## Exponent too big + +**Diagnosis** + +An attempt has been made to perform a calculation using a pre-computed table, for an exponent (or multiplier in the case of elliptic curves) bigger than that catered for by the pre-computed table. + +**Response** + +Re-compute the table to allow bigger exponents, or use a smaller exponent. + +## Number base must be power of 2 + +**Diagnosis** + +A small number of functions require that the number base specified in the initial call to *mirsys(.)* is a power of 2. + +**Response** + +Use another function, or specify a power-of-2 as the number base in the initial call to *mirsys(.)* + +## Specified double-length type isn't + +**Diagnosis** + +MIRACL has determined that the double length type specified in *mirdef.h* is in fact not double length. For example if the underlying type is 32-bits, the double length type should be 64 bits. + +**Response** + +Don't do it! + +## Specified basis is not irreducible + +**Diagnosis** + +The basis specified for GF(2m) arithmetic is not irreducible. + +**Response** + +Don't do it! diff --git a/miracl/docs/miracl-user-manual/the-cpp-interface.md b/miracl/docs/miracl-user-manual/the-cpp-interface.md new file mode 100644 index 0000000..f1df736 --- /dev/null +++ b/miracl/docs/miracl-user-manual/the-cpp-interface.md @@ -0,0 +1,233 @@ +* [Intro](README.md) +* [Installation](installation.md) +* [The UI](the-ui.md) +* [Internal Rep](internal-rep.md) +* [Implementation](implementation.md) +* [Floating Slash Nums](floating-slash-nums.md) +* The C++ Interface +* [Example Programs](example-progs.md) +* [The MIRACL Routines](miracl-explained/reference-manual/low-level-routines.md) +* [Instance Variables](instance-variables.md) +* [MIRACL Error Messages](miracl-error-messages.md) +* [Hardware Compiler Interface](hardware-compiler-interface.md) +* [Bibliography](bibliography.md) + +The C++ Interface +--- + +Many users of the MIRACL package would be disappointed that they have to calculate: +![Calculation](images/image1.png) +for a flash variable x by the sequence + + fmul(x,x,t); + fadd(t,x,t); + fincr(t,1,1,t); + +rather than by simply + + t=x*x+x+1; + +Someone could of course use the MIRACL library to write a special purpose C compiler which could properly interpret such an instruction (see Cherry and Morris [Cherry] for an example of this approach). However such a drastic step is not necessary. A superset of C, called C++ has gained general acceptance as the natural successor to C. The enhancements to C are mainly aimed at making it an object-oriented language. By defining *big* and *flash* variables as ‘classes’ (in C++ terminology), it is possible to ‘overload’ the usual mathematical operators, so that the compiler will automatically substitute calls to the appropriate MIRACL routines when these operators are used in conjunction with *big* or *flash* variables. Furthermore C++ is able to look after the initialisation (and ultimate elimination) of these data-types automatically, using its constructor/destructor mechanism, which is included with the class definition. This relieves the programmer from the tedium of explicitly initialising each *big* and *flash* variable by repeated calls to **mirvar** . Indeed once the classes are properly defined and set up, it is as simple to work with the new data-types as with the built-in *double* and *int* types. Using C++ also helps shield the user from the internal workings of MIRACL. + +The MIRACL library is interfaced to C++ via the header files *big.h*, *flash.h*, *zzn.h*, *gf2m.h*, *ecn.h* and *ec2.h* . Function implementation is in the associated files *big.cpp*, *flash.cpp*, *zzn.cpp*, *gf2m.cpp*, *ecn.cpp* and *ec2.cpp*, which must be linked into any application that requires them. The Chinese Remainder Theorem is also elegantly implemented as a class, in files *crt.h* and *crt.cpp* . See *decode.cpp* for an example of use. The Comb method for fast modular exponentiation with precomputation [HAC] is implemented in *brick.h* . See *brick.cpp* for an example of use. The GF(*p*) elliptic curve equivalents are in *ebrick.h* and *ebrick.cpp* and the GF(2m) elliptic curve equivalents in *ebrick2.h* and *ebrick2.cpp* respectively. + +## Example +``` +/* + * Program to calculate factorials. + */ + +#include +#include "big.h" /* include MIRACL system */ + +using namespace std; + +Miracl precision(500,10); // This makes sure that MIRACL + // is initialised before main() // is called + +void main() +{ /* calculate factorial of number */ + Big nf=1; /* declare "Big" variable nf */ + int n; + cout << "factorial program\n"; + cout << "input number n= \n"; + cin >> n; + + while (n>1) + nf*=(n--); /* nf=n!=n*(n-1)*(n-2)*....3*2*1 */ + + cout << "n!= \n" << nf << "\n"; +} +``` +Compare this with the C version in 'The User Interface'. Note the neat use of a dummy class *Miracl* used to set the precision of the *big* variables. Its declaration at global scope ensures that MIRACL is initialised before *main()* is called. (Note that this would not be appropriate in a multi-threaded environment.) When compiling and linking this program, don’t forget to link in the *Big* class implementation file *big.cpp* . + +Conversion to/from internal *Big* format is quite important:- + +To convert a hex character string to a *Big* +``` +Big x; +char c[100]; +... +mip->IOBASE=16; +x=c; +``` +To convert a Big to a hex character string +``` +mip->IOBASE=16; +c << x; +``` +To convert to/from pure binary, use the **from_binary( )** and **to_binary( )** friend functions. +``` +int len; +char c[100]; +... +Big x=from_binary(len,c); +// creates Big x from len bytes of binary in c +len=to_binary(x,100,c,FALSE); +// converts Big x to len bytes binary in c[100] +len=to_binary(x,100,c,TRUE); +// converts Big x to len bytes binary in c[100] +// (right justified with leading zeros) +``` +In many of the example programs, particularly the factoring programs, all the arithmetic is done *mod n*. To avoid the tedious reduction *mod n* required after each operation, a new C++ class ZZ*n* has been used, and defined in the file *zzn.h*. This class *ZZn* (for *ZZ(n)* or the ring of integers *mod n*) has its arithmetic operators defined to automatically perform the reduction. The function **modulo(n)** sets the modulus. In an analogous fashion the C++ class GF2*m* deals with elements of the field defined over GF(2m). In this case the “modulus” is set via **modulo(m,a,b,c)**, which also specifies either a trinomial basis tm + ta +1, (and set b=c=0), or a pentanomial basis tm + ta + tb + tc +1. See the [IEEE P1363](http://grouper.ieee.org/groups/1363/) documentation for details. + +Internally the ZZ*n* class uses Montgomery representation. See *zzn.h* . Note that the internal implementation of ZZ*n* is hidden from the application programmer, a classic feature of C++. Thus the awkward internals of Montgomery representation need not concern the C++ programmer. + +The class EC*n* defined in *ecn.h* makes manipulation of points on GF (*p*) elliptic curves a simple matter, again hiding all the grizzly details. The class EC2 defined in *ec2.h* does the same for GF(2m) elliptic curves. + +Almost all of MIRACL’s functionality is accessible from C++. Programming can often be done intuitively, without reference to this manual, using familiar C syntax as illustrated above. Other functions are accessed using the ‘obvious’ syntax - as in for example x=gcd(x,y);, or y=sin(x);. For more details examine the header files and example programs. + +C++ versions of most of the example programs are included in the distribution media, with the file extensions *.cpp* . + +One problem with manipulating large objects in C++ is the tendency of the compiler to generate code to create/destroy/copy multiple temporary objects. By default MIRACL obtains memory for *Big* and *Flash* variables from the heap. This can be quite time-consuming, and all such objects need ultimately to be destroyed. It would be faster to assign memory instead from the stack, especially for relative small big numbers. This can now be achieved by defining **BIGS=m** at compilation time. For example if using the Microsoft C++ compiler from the command line: + + C:miracl>cl /O2 /GX /DBIGS=50 brent.cpp big.cpp zzn.cpp miracl.lib + +Note that the value of **m** should be the same as or less than the value of **n** that is specified in the call to mirsys(**n**,0); or in Miracl precision=**n**; in the main program. + +When using finite-field arithmetic, valid numbers are always less than a certain fixed modulus. For example in the finite field mod *n*, the class defined in *zzn.h* and *zzn.cpp* might handle numbers with respect to a 512-bit modulus *n*, which is set by **modulo(n)**. In this case one can define **ZZNS=16** so that all elements are of a size 16x32=512, and are created on the stack. (This works particularly well in combination with the Comba mechanism described in 'Implementation'.) + +In a similar fashion, when working over the field GF(2283), one can define **GF2MS=9**, so that all elements in the field are stored in a fixed memory allocation of 9 words taken from the stack. + +In these latter two cases the precision **n** specified in the call to mirsys(**n**,0); or in Miracl precision=n; in the main program should be at least 2 greater than the **m** that specified in the **ZZNS=m** or **GF2MS=m** definition. + +This is not recommended for program development, or if the objects are very large. It is only relevant with C++ programs. See the comments in the sample programs *ibe_dec.cpp* and *dl.cpp* for examples of the use of this mechanism. However the benefits can often be substantial – programs may be up to twice as fast. + +Finally here is a more elaborate C++ program to implement a relatively complex cryptographic protocol. Note the convention of using capitalised variables for field elements. +``` +/* + * Gunthers's ID based key exchange - Finite field version + * See RFC 1824 + * r^r variant (with Perfect Forward Security) + */ + +#include +#include +#include "zzn.h" + +using namespace std; + +Miracl precision=100; + +char *IDa="Identity 1"; +char *IDb="Identity 2"; + +// Hash function +Big H(char *ID) +{ // hash character string to 160-bit big number + int b; + Big h; + char s[20]; + sha sh; + shs_init(&sh); + while (*ID!=0) shs_process(&sh,*ID++); + shs_hash(&sh,s); + h=from_binary(20,s); + return h; +} + +int main() +{ + int bits; + ifstream common("common.dss"); // construct file stream + Big p,q,g,x,k,ra,rb,sa,sb,ta,tb,wa,wb; + ZZn G,Y,Ra,Rb,Ua,Ub,Va,Vb,Key; + ZZn A[4]; + Big b[4]; + long seed; + miracl *mip=&precision; + cout << "Enter 9 digit random number seed = "; + cin >> seed; irand(seed); + +// get common data. Its in hex. G^q mod p = 1 + common >> bits; + mip->IOBASE=16; + common >> p >> q >> g; + mip->IOBASE=10; + modulo(p); // set modulus + + G=(ZZn)g; + + cout << "Setting up Certification Authority ... " << endl; + +// CA generates its secret and public keys + + x=rand(q); // CA secret key, 0 < x < q + Y=pow(G,x); // CA public key, Y=G^x + + cout << "Visiting CA ...." << endl; + +// Visit to CA - a + k=rand(q); + Ra=pow(G,k); + ra=(Big)Ra%q; + sa=(H(IDa)+(k*ra)%q); + sa=(sa*inverse(x,q))%q; + +// Visit to CA - b + k=rand(q); + Rb=pow(G,k); + rb=(Big)Rb%q; + sb=(H(IDb)+(k*rb)%q); + sb=(sb*inverse(x,q))%q; + + cout << "Offline calculations .... " << endl; + +// offline calculation - a + wa=rand(q); + Va=pow(G,wa); + ta=rand(q); + Ua=pow(Y,ta); + +// offline calculation - b + wb=rand(q); + Vb=pow(G,wb); + tb=rand(q); + Ub=pow(Y,tb); + +// Swap ID, R, U, V + cout << "Calculate Key ... " << endl; + +// calculate key – a +// Key = Vb^wa.Ub^sa.G^[(H(IDa)*tb)%q].Rb^[(rb*ta)%q] mod p + + rb=(Big)Rb%q; + A[0]=Vb; A[1]=Ub; A[2]=G; A[3]=Rb; + b[0]=wa; b[1]=sa; b[2]=(H(IDb)*ta)%q; b[3]=(rb*ta)%q; + + Key=pow(4,A,b); // extended exponentiation + cout << "Key= \n" << Key << endl; + +// calculate key - b + ra=(Big)Ra%q; + A[0]=Va; A[1]=Ua; A[2]=G; A[3]=Ra; + b[0]=wb; b[1]=sb; b[2]=(H(IDa)*tb)%q; b[3]=(ra*tb)%q; + + Key=pow(4,A,b); // extended exponentiation + cout << "Key= \n" << Key << endl; + return 0; +} +``` + +MIRACL has evolved quite a complex class hierarchy – see the diagram below. Where possible classes are built directly on top of the C/assembly core. Note the support for polynomials, power series and extension fields. +![Class Hierarchy](images/image2.png) diff --git a/miracl/docs/miracl-user-manual/the-ui.md b/miracl/docs/miracl-user-manual/the-ui.md new file mode 100644 index 0000000..c4d8aaa --- /dev/null +++ b/miracl/docs/miracl-user-manual/the-ui.md @@ -0,0 +1,114 @@ +* [Intro](README.md) +* [Installation](installation.md) +* The UI +* [Internal Rep](internal-rep.md) +* [Implementation](implementation.md) +* [Floating Slash Nums](floating-slash-nums.md) +* [The C++ Interface](the-cpp-interface.md) +* [Example Programs](example-progs.md) +* [The MIRACL Routines](miracl-explained/reference-manual/low-level-routines.md) +* [Instance Variables](instance-variables.md) +* [MIRACL Error Messages](miracl-error-messages.md) +* [Hardware Compiler Interface](hardware-compiler-interface.md) +* [Bibliography](bibliography.md) + + +The User Interface +--- + +An example: +``` +/* + * Program to calculate factorials. + */ + +#include +#include "miracl.h" /* include MIRACL system */ + +void main() +{ + /* calculate factorial of number */ + big nf; /* declare "big" variable nf */ + int n; + miracl *mip=mirsys(5000,10); + + /* base 10, 5000 digits per big */ + nf=mirvar(1); /* initialise big variable nf=1 */ + printf("factorial program\n"); + printf("input number n= \n"); + scanf("%d",&n); + getchar(); + while (n>1) + premult(nf,n--,nf); /* nf=n!=n*(n-1)*...2*1 */ + + printf("n!= \n"); + otnum(nf,stdout); /* output result */ +} +``` +This program can be used to quickly calculate and print out 1000! (a 2568 digit number) in less a second on a 60MHz Intel Pentium-based computer, a task first performed ‘by H.S. Uhler using a desk calculator and much patience over a period of several years’ [Knuth73]. Many other programs are described in 'Example Programs'. + +Any program that wishes to make use of the MIRACL system must have an #include "miracl.h" statement. This tells the compiler to include the C header file *miracl.h* with the main program source file before proceeding with the compilation. This file contains declarations of all the MIRACL routines available to the user. The small sub-header file *mirdef.h* contains hardware/compiler-specific details. + +In the main program the MIRACL system must be initialised by a call to the routine *mirsys*, which sets the number base and the maximum size of the *big* and *flash* variables. It also initialises the random number system, and creates several workspace *big* variables for its own internal use. The return value is the Miracl Instance Pointer, or *mip*. This pointer can be used to access various internal parameters associated with the current instance of MIRACL. For example to set the **ERCON** flag, one might write: +``` +mip->ERCON=TRUE; +``` +The initial call to **mirsys** also initialises the error tracing system which is integrated with the MIRACL package. Whenever an error is detected the sequence of routine calls down to the routine which generated the error is reported, as well as the error itself. A typical error message might be: +``` +MIRACL error from routine powltr +called from isprime +called from your program +Raising integer to a negative power +``` +Such an error report facilitates debugging, and assisted us during the development of these routines. An associated instance variable **TRACER**, initialised to OFF, if set by the user to ON, will cause a trace of the program's progress through the MIRACL routines to be output to the computer screen. + +An instance flag **ERNUM**, initialised to zero, records the number of the last internal MIRACL error to have occurred. If the flag ERCON is set to FALSE (the default), an error message is directed to *stdout* and the program aborts via a call to the system routine *exit(0)*. If your system does not supply such a routine, the programmer must provide one instead. If **ERCON** is set to TRUE no error message is emitted and instead the onus is on the programmer to detect and handle the error. In this case execution continues. The programmer may choose to deal with the error, and reset **ERNUM** to zero. However errors are usually fatal, and if **ERNUM** is non-zero all MIRACL routines called subsequently will “fall-through” and exit immediately. See *miracl.h* for a list of all possible errors. + +Every *big* or *flash* variable in the users program must be initialised by a call to the routine **mirvar**, which also allows the variable to be given an initial small integer value. + +The full set of arithmetic and number-theoretic routines declared in *miracl.h* may be used on these variables. Full flexibility is (almost always) allowed in parameter usage with these routines. For example the call **multiply(x,y,z)**, multiplies the *big* variable **x** by the big variable **y** to give the result as big variable **z**. Equally valid would be **multiply(x,y,x)**, **multiply(y,y,x)**, or **multiply(x,x,x)**. This last simply squares **x**. Note that the first parameters are by convention always (usually) the inputs to the routines. Routines are provided not only to allow arithmetic on *big* and *flash* numbers, but also to allow these variables to perform arithmetic with the built-in integer and double precision data-types. + +Conversion routines are provided to convert from one type to another. For details of each routine see the relevant documentation in the 'MIRACL Routines' section. + +Input and output to a file or I/O device is handled by the routines **innum**, **otnum cinnum** and **cotnum**. The first two use the fixed number base specified by the user in the initial call of **mirsys**. The latter pair work in conjunction with the instance variable **IOBASE** which can be assigned dynamically by the user. A simple rule is that if the program is CPU bound, or involves changes of base, then set the base initially to MAXBASE (or 0 if a full-width base is possible - see 'Internal Representation' and use **cinnum** and **cotnum**. If, on the other hand, the program is I/O bound, or needs access to individual digits of numbers (using **getdig**, **putdig** and **numdig**), use **innum** and **otnum**. + +Input and output to/from a character string is also supported in a similar fashion by the routines **instr**, **otstr**, **cinstr** and **cotstr**. The input routines can be used to set *big* or *flash* numbers to large constant values. By outputting to a string, formatting can take place prior to actual output to a file or I/O device. + +Numbers to bases up to 256 can be represented. Numbers up to base 60 use as many of the symbols 0-9, A-Z, a-x as necessary. + +A number base of 64 enforces standard base64 encoding. On output base64 numbers are padded with trailing = symbols if needed, but not otherwise formatted. On input white-space characters are skipped, and padding ignored. Do not use base64 with *flash* numbers. Do not use base64 for outputting negative numbers, as the sign is ignored. + +If the base is greater than 60 (and not 64), the symbols used are the ASCII codes 0-255. + +A base of 256 is useful when it is necessary to interpret a line of text as a large integer, as is the case for the Public Key Cryptography programs described in 'Example Programs'. The routines **big_to_bytes** and **bytes_to_big** allow for direct conversion from the internal *big* format to/from pure binary. + +Strings are normally zero-terminated. However a problem arises when using a base of 256. In this case every digit from 0 - 255 can legitimately occur in a number. So a 0 does not necessarily indicate the end of the string. On input another method must be used to indicate the number of digits in the string. + +By setting the instance variable **INPLEN** = 25 (for example), just prior to a call to **innum** or **instr**, input is terminated after 25 bytes are entered. **INPLEN** is initialised to 0, and reset to 0 by the relevant routine before it returns. + +For example, initialise MIRACL to use *bigs* of 400 bytes: +``` +miracl *mip=mirsys(400,256); +``` +Internal calculations are very efficient using this base. + +Input an ASCII string as a base 256 number. This will be zero-terminated, so no need for **INPLEN**: +``` +innum(x,stdin); +``` +Now it is required to input exactly 1024 random bits: +``` +mip->INPLEN=128; +innum(y,stdin); +``` +But we want to see output in HEX: +``` +mip->IOBASE=16; +cotnum(w,stdout); +``` +Now in base64: +``` +mip->IOBASE=64; +cotnum(w,stdout); +``` +Rational numbers may be input using either a radix point (e.g 0.3333) or as a fraction (e.g. 1/3). Either form can be used on output by setting the instance variable **RPOINT**=ON or =OFF. diff --git a/miracl/doubig.txt b/miracl/doubig.txt new file mode 100644 index 0000000..8918bbe --- /dev/null +++ b/miracl/doubig.txt @@ -0,0 +1,65 @@ + +One of the basic design "features" of MIRACL is that all big number types are +of the same size, defined either at run time, or at compile time. + +This means that all big types are of the same size, and in the vast majority +of cases this is just fine, and very efficient. + +However there are some situations where, while most of the variable should be +of size n bits, some are naturally required to be of size 2*n bits. One +way around this is to make all big variables 2*n in size, but this can +be wastful of space. + +Consider for example Elliptic curves over a quadratic extension, as suggested +by Galbraith, Lin and Scott, and as supported by functions in the module +mrecn2.c + +While all of the field variables are of a size n, the group size is of size +2*n. In this case it makes sense for the vast majority of operations on field +elements, to be on elements of size n, while allowing the much simpler group +operations to be on variables of size 2*n. + +Here is how to do it (for C programs only). + +(1) Assign space for big variables from a block of memory + +#ifndef MR_STATIC + char *mem = memalloc(_MIPP_ M); +#else + char mem[MR_BIG_RESERVE(M)]; + memset(mem, 0, MR_BIG_RESERVE(M)); +#endif + +where M are the total number of big variables required. Recall that if +MR_STATIC is defined, bigs are assigned at compile time from the stack. If it +is not defined, bigs are assigned at run time from the heap. In either +case if a double sized variable is required... + + +(2) Assign space for big variable like this... + + int j=0; + c=mirvar_mem(mip, mem, j); j+=2; + d=mirvar_mem(mip, mem, j); j+=2; + r=mirvar_mem(mip, mem, j); j+=2; + v1=mirvar_mem(mip, mem, j++); + v2=mirvar_mem(mip, mem, j++); + det=mirvar_mem(mip, mem, j); j+=2; + p=mirvar_mem(mip, mem, j++); + +Observe how space for a double big is assigned to variables c,d,r and det, with +v1,v2 and p being assigned space for a regular big. Note that the final value j +here indicates the value that should be used for M above. + +(3) Into mirdef.h, put + +#define MR_DOUBLE_BIG + +This tells MIRACL to assign double-width space to the internal work variables +w0-w7. All functions that just use these work variables will now work correctly +with the double-sized bigs. + +Note that only simple arithmetic functions can be used with these double big +variables. But that should be OK, as group operations are usually very simple. +Note also that overflow checking is turned off when MR_DOUBLE_BIG is defined, +so use this feature with extreme caution! diff --git a/miracl/double.txt b/miracl/double.txt new file mode 100644 index 0000000..5bb23f7 --- /dev/null +++ b/miracl/double.txt @@ -0,0 +1,44 @@ + +With version 4.6 it is now possible to use a floating-point "double" +as the underlying type used to store the digits of a multi-precision number. +This is fully supported by the "config" utility. + +Some new processors implement integer multiplication using the floating-point +multiplier. On processors like these it may be advantageous to +work directly with doubles. Other processors support Floating point +multiplication, but not integer multiplication. + +In many cases however this approach will NOT be optimal, and using an integer +type as the underlying type is still recommended for the majority of cases. + +To properly use a double type, the program must ideally be able to control the +"rounding" behaviour of the floating-point processor. By default this may +implement "round to nearest" which is wrong for integer arithmetic where +"round to zero" is appropriate. Since no standard C constructs exist to +control rounding, a small bit of assembly language may be required - see the +function mr_invert() in the module mrarth1.c. Note however that some compilers +like GNU C do allow control of rounding via functions declared in ieeefp.h + +The compiler must properly support the Ansi Standard "long double" type. It +should also implement the standard "modfl()" function for truncation to an +integer. + +In mirdef.h MR_FP is defined if a double type is to be used. MR_FP_ROUNDING is +defined if rounding control can be exercised. + +On the Pentium using a double is potentially optimal. See the experimental +code in mr87f.c and mr87v.c, which can be used with the Borland C +compiler/TASM macro assember combination. The floating point fmul instruction +can be executed in just 1 cycle under ideal circumstances, but it requires +some very complex code ordering to fully leverage this advantage. + +See the ZMODEXP and NISTP224 programs by D. J. Bernstein at +http://cr.yp.to/software.html for more optimal examples of this approach. + +Note that GF(2^m) arithmetic, which requires bit shifting, and logical +operations like XOR and AND, would be hopelessly inefficient using floating- +point, and so it is not supported with a double underlying type. + +See mrmuldv.any for assembly language support... + + diff --git a/miracl/edwards.txt b/miracl/edwards.txt new file mode 100644 index 0000000..b8020e1 --- /dev/null +++ b/miracl/edwards.txt @@ -0,0 +1,34 @@ +Edwards curves are now supported for ECC. + +There are some limitations. In particular the pairings programs will NOT +work with Edwards curves. However for ECC programs they will be faster +than using the standard Jacobian/Weierstrass method. + +To enable Edwards curves (and disable standard curves), simply insert + +#define MR_EDWARDS + +into mirdef.h + +and recompile the MIRACL library + +Note that the SCHOOF and SEA applications have now been modified to +accept a flag -E which now looks for curves in Edwards form. Note that +these programs must be compiled *without" setting MR_EDWARDS. (They accept +the curve in twisted inverted Edwards form, convert to Weierstrass form, +and count the points on that, before converting back to Edwards). + +An example parameter file describing an edwards curve is in the file +edwards.ecs + +If MR_EDWARDS is defined, alternative code to support edwards curves is +used in modules mrcurve.c and mrecn2.c. Note that curves over 2^m are not +affected. + +To test, proceed as above to build the MIRACL library, compile and run +the ECDSA (Elliptic Curve Digital Signature) test programs ecsgen.c, +ecsign.c and ecsver.c, and also the ebrick.c program + +Note that some programs like pk-demo.c are "hard-wired" to a non-edwards +curve, and will not work in this way. The CM program will not work with +Edwards curves. diff --git a/miracl/exe/private.key b/miracl/exe/private.key new file mode 100644 index 0000000..bb8e0f1 --- /dev/null +++ b/miracl/exe/private.key @@ -0,0 +1,2 @@ +C27702C3CEAC8ADE10BBF16EC71A250A2A0B6E24FE4A182F9B8B03069398C14FEF1AF46E462C28E16DA739C6111FE5E628838F070F3CB6CB21CCA9BC3F5AE4FB +AA68656FB5F1A828B6D3745D70E3A0FCC5480A756C02238557D1B13B2977413B51B4E56D35BA70EA629AA9F0A5E4E34DBA81B8E824A81DBD0D2295AD92B0C55B diff --git a/miracl/exe/public.key b/miracl/exe/public.key new file mode 100644 index 0000000..158420f --- /dev/null +++ b/miracl/exe/public.key @@ -0,0 +1 @@ +8172553CF6B1B47BA3AD26DBB4806BDD1C2EB8923E0CC70D980694C9BA13EE34FB0D46BF577B523C5D9026DF23452D80594C3D93F19051B67D71E897B6A20D6E5C61F01974F50EAC657CA0C6673CC96A3DADC89EBD0B720DA723D736EC91414E281528FED990E4B0E52EFA744F560BC5B8B1EE725B4209D26FF46C5F0A148C39 diff --git a/miracl/fastgf2m.txt b/miracl/fastgf2m.txt new file mode 100644 index 0000000..0290909 --- /dev/null +++ b/miracl/fastgf2m.txt @@ -0,0 +1,31 @@ + +With the introduction of Intel 32nm i5/i7 processors, there +is support for a "carry-less" multiplication, also known as +"binary polynomial" multiplication. This support is in the form +of the new 64-bit PCLMULQDQ instruction. + +In fact such an instruction is also supported by some Sun and +Mips processors. + +Support for this operation gives a big boost to the performance +of any method that uses arithmetic over GF(2^m), in particular +elliptic curve cryptography, and pairing-based crypto using +supersingular curves over GF(2^m). + +To exploit the PCLMULQDQ instruction, using the Microsoft C +compiler, use the macro file clmul.mcs with the mex utility +to create the module mrcomba2.c, and define MR_COMBA2 in mirdef.h +to the number of words required to represent m. Then link this +module into the MIRACL library, and to your application. + +For example if implementing standard elliptic curves over GF(2^283) +on a 64-bit PC, using MS C tools, then + +c:\miracl>>mex 5 clmul mrcomba2 + +to create mrcomba2.c, and include into mirdef.h + +#define MR_COMBA2 5 + +Then build a MIRACL library to include mrcomba2.c, and build and +link your application as normal, for an impressive speed boost. diff --git a/miracl/first.txt b/miracl/first.txt new file mode 100644 index 0000000..b21345c --- /dev/null +++ b/miracl/first.txt @@ -0,0 +1,65 @@ +MIRACL is a highly efficient and portable Multiprecision Integer and Rational +Arithmetic C/C++ Library. Full source code is provided. Its main area of +application is in the implementation of Public Key Cryptography systems and +protocols. Many example programs are provide. + +To access the software, download the file miracl.zip. + +If using Windows decompress all files into a single DOS directory MIRACL. + +To build the standard library in this directory using the Microsoft compiler, +first make sure that paths are set up correctly by running the Microsoft +supplied batch files vcvars32 or vcvars64 (for 32-bit or 64-bit environments +respectively), or vcvarsall to set up a named environment + +Then execute either ms32doit.bat or ms64doit.bat (for 32-bit or 64-bit builds resp.) + + +If using Linux, read the following carefully + + +------------------------------------------------ +Linux installation + +Download the MIRACL.ZIP file, and save it into an otherwise empty MIRACL directory. + +1. Unzip the MIRACL.ZIP file using the unix utility unzip + +unzip -j -aa -L miracl.zip + +The -j ignores the directory structure inside MIRACL.ZIP. The -aa converts all +text files to Unix format, and -L ensures that all filenames are lower-case. + + +2. Perform a tailored build of the MIRACL library by opening a terminal window, + and typing + +bash linux + + Alternatively if your system is 64-bit + +bash linux64 + +3. All the MIRACL applications (except RATCALC) can be then be built, as + desired. Remember to link all C applications to the miracl.a library. + C++ applications must be linked as well to one or more of big.o monty.o + elliptic.o crt.o flash.o object files etc. + Some applications (like factor.c) that require floating-point support + may also require -lm in the compile command line. + +Make sure that your Linux PATH points to the current directory, so that +executables can be run. + +Note that Linux already has (a rather pathetic) factor program. To avoid name +clashes you might rename MIRACL's "factor" program to "facter", or somesuch. + + +------------------------------------------------ + + +The manual is available in MS Word format as MANUAL.DOC + +The text file UPDATE.TXT describes the latest changes and additions + +Latest Version - V7.0.0 Last updated June 2013 + diff --git a/miracl/float.txt b/miracl/float.txt new file mode 100644 index 0000000..761e743 --- /dev/null +++ b/miracl/float.txt @@ -0,0 +1,42 @@ + +A new experimental fast multiprecison floating-point module is now available, +implemented in float.cpp and float.h. The motivation was to speed up the CM +program fir elliptic curves - see cm.txt + +A new C++ class Float is defined, which can be used instead of Flash. The +main advantage is that it uses asymptotically fast methods. If MR_KCM is +defined in mirdef.h, then Karatsuba's method is used, otherwise FFT methods +(see mrfast.c). Karatsuba is faster with precisions up to several thousands of +words, beyond that the FFT is to be preferred. + +A simple example is shown in the file fsample.cpp. Compare with sample.cpp +which uses Flash arithmetic. + +For a more useful example of use see cm.cpp, a fast replacement for the +original cm.cpp which used Flash arithmetic. To support this application +modules flpoly.h/.cpp and complex.h/.cpp have also been created, for Float +polynomials and Complex arithmetic respectively. + +There are a few restrictions:- + +1) A full width base must be used. +2) The precision of FP arithmetic must be specified by a call to + setprecision(n). The precision will be 2^n words. Miracl must be + initialised to at least 2^n+2 words per big, either by mirsys(2^n+2,0) or + Miracl precision=2^n+2; +3) The basic miracl library must support flash arithmetic - that is MR_FLASH + must be defined in mirdef.h +4) Only very basic numeric output is supported. Output attempts to print a + decimal, but if the number x is very large or very small it will be output + as x.2^n. + +See float.h for the functions currently implemented. + +Note that this class has been designed simply for raw speed. No particular +care has been taken with respect to rounding errors. The rounding method is +simple truncation. The last few digits of any calculation are probably in +error. + +A rudimentary Complex class based on Float can be found in complex.h and +complex.cpp + diff --git a/miracl/fpe.pdf b/miracl/fpe.pdf new file mode 100644 index 0000000..a62b9ea Binary files /dev/null and b/miracl/fpe.pdf differ diff --git a/miracl/free/read.txt b/miracl/free/read.txt new file mode 100644 index 0000000..70cd236 --- /dev/null +++ b/miracl/free/read.txt @@ -0,0 +1,9 @@ +IBM PC MIRACL APPLICATIONS + + +RATCALC - Freeware Rational Calculator. +FACTOR - Freeware General Purpose Factoring Program + +Note: These are 32-bit applications that run in a Windows '95/NT +command prompt window. They will not work on a 64-bit OS + diff --git a/miracl/include/MIRDEF.AMD b/miracl/include/MIRDEF.AMD new file mode 100644 index 0000000..389cfbb --- /dev/null +++ b/miracl/include/MIRDEF.AMD @@ -0,0 +1,13 @@ +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype long +#define MR_IBITS 32 +#define MR_LBITS 64 +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned long +#define MR_FLASH 52 +#define MR_ALWAYS_BINARY +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_COMBA 8 + diff --git a/miracl/include/MIRDEF.SPR b/miracl/include/MIRDEF.SPR new file mode 100644 index 0000000..90548ea --- /dev/null +++ b/miracl/include/MIRDEF.SPR @@ -0,0 +1,16 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + + +#define MIRACL 32 +#define MR_BIG_ENDIAN +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_dltype long long +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned long long +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + +#define MR_NOASM diff --git a/miracl/include/big.h b/miracl/include/big.h new file mode 100644 index 0000000..bbc2b25 --- /dev/null +++ b/miracl/include/big.h @@ -0,0 +1,451 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * + * MIRACL C++ Header file big.h + * + * AUTHOR : N.Coghlan + * Modified by M.Scott + * + * PURPOSE : Definition of class Big + * + * Bigs are normally created on the heap, but by defining BIGS=m + * on the compiler command line, Bigs are instead mostly created from the + * stack. Note that m must be same or less than the n in the main program + * with for example + * + * Miracl precison(n,0); + * + * where n is the (fixed) size in words of each Big. + * + * This may be faster, as C++ tends to create and destroy lots of + * temporaries. Especially recommended if m is small. Do not use + * for program development + * + * However Bigs created from a string are always allocated from the heap. + * This is useful for creating large read-only constants which are larger + * than m. + * + * NOTE:- I/O conversion + * + * To convert a hex character string to a Big + * + * Big x; + * char c[100]; + * + * mip->IOBASE=16; + * x=c; + * + * To convert a Big to a hex character string + * + * mip->IOBASE=16; + * c << x; + * + * To convert to/from pure binary, see the from_binary() + * and to_binary() friend functions. + * + * int len; + * char c[100]; + * ... + * Big x=from_binary(len,c); // creates Big x from len bytes of binary in c + * + * len=to_binary(x,100,c,FALSE); // converts Big x to len bytes binary in c[100] + * len=to_binary(x,100,c,TRUE); // converts Big x to len bytes binary in c[100] + * // (right justified with leading zeros) + */ + +#ifndef BIG_H +#define BIG_H + +#include +//#include +#include + +#include "mirdef.h" + +#ifdef MR_CPP +#include "miracl.h" +#else +extern "C" +{ + #include "miracl.h" +} +#endif + +#ifndef MR_NO_STANDARD_IO +#include +using std::istream; +using std::ostream; +#endif + +#ifndef MIRACL_CLASS +#define MIRACL_CLASS + +#ifdef __cplusplus +#ifdef MR_GENERIC_MT +#error "The generic method isn't supported for C++, its C only" +#endif +#endif + +class Miracl +{ /* dummy class to initialise MIRACL - MUST be called before any Bigs * + * are created. This could be a problem for static/global data declared * + * in modules other than the main module */ + miracl *mr; +public: + Miracl(int nd,mr_small nb=0) + {mr=mirsys(nd,nb); +#ifdef MR_FLASH +mr->RPOINT=TRUE; +#endif +} + miracl *operator&() {return mr;} + ~Miracl() {mirexit();} +}; + +#endif + +/* +#ifdef BIGS +#define MR_INIT_BIG memset(mem,0,mr_big_reserve(1,BIGS)); fn=(big)mirvar_mem_variable(mem,0,BIGS); +#else +#define MR_INIT_BIG mem=(char *)memalloc(1); fn=(big)mirvar_mem(mem,0); +#endif +*/ + +#ifdef BIGS +#define MR_INIT_BIG fn=&b; b.w=a; b.len=0; for (int i=0;ilen=1; fn->w[0]=s; return *this;} + Big& operator=(const Big& b) {copy(b.fn,fn); return *this;} + Big& operator=(big& b) {copy(b,fn); return *this;} + Big& operator=(big* b) {fn=*b; return *this;} +#ifndef MR_SIMPLE_IO +#ifdef MR_SIMPLE_BASE + Big& operator=(char* s){instr(fn,s);return *this;} +#else + Big& operator=(char* s){cinstr(fn,s);return *this;} +#endif +#endif + Big& operator++() {incr(fn,1,fn); return *this;} + Big& operator--() {decr(fn,1,fn); return *this;} + Big& operator+=(int i) {incr(fn,i,fn); return *this;} + Big& operator+=(const Big& b){add(fn,b.fn,fn); return *this;} + + Big& operator-=(int i) {decr(fn,i,fn); return *this;} + Big& operator-=(const Big& b) {subtract(fn,b.fn,fn); return *this;} + + Big& operator*=(int i) {premult(fn,i,fn); return *this;} + Big& operator*=(const Big& b) {multiply(fn,b.fn,fn); return *this;} + + Big& operator/=(int i) {subdiv(fn,i,fn); return *this;} + Big& operator/=(const Big& b) {divide(fn,b.fn,fn); return *this;} + + Big& operator%=(int i) {convert(subdiv(fn,i,fn),fn); return *this;} + Big& operator%=(const Big& b) {divide(fn,b.fn,b.fn); return *this;} + + Big& operator<<=(int i) {sftbit(fn,i,fn); return *this;} + Big& operator>>=(int i) {sftbit(fn,-i,fn); return *this;} + + Big& shift(int n) {mr_shift(fn,n,fn); return *this;} + + mr_small& operator[](int i) {return fn->w[i];} + + void negate() const; + BOOL iszero() const; + BOOL isone() const; + int get(int index) { int m; m=getdig(fn,index); return m; } + void set(int index,int n) { putdig(n,fn,index);} + int len() const; + + big getbig() const; + + friend class Flash; + + friend Big operator-(const Big&); + + friend Big operator+(const Big&,int); + friend Big operator+(int,const Big&); + friend Big operator+(const Big&,const Big&); + + friend Big operator-(const Big&, int); + friend Big operator-(int,const Big&); + friend Big operator-(const Big&,const Big&); + + friend Big operator*(const Big&, int); + friend Big operator*(int,const Big&); + friend Big operator*(const Big&,const Big&); + + friend BOOL fmth(int n,const Big&,const Big&,Big&); // fast mult - top half + + friend Big operator/(const Big&,int); + friend Big operator/(const Big&,const Big&); + + friend int operator%(const Big&, int); + friend Big operator%(const Big&, const Big&); + + friend Big operator<<(const Big&, int); + friend Big operator>>(const Big&, int); + + friend BOOL operator<=(const Big& b1,const Big& b2) + {if (mr_compare(b1.fn,b2.fn)<=0) return TRUE; else return FALSE;} + friend BOOL operator>=(const Big& b1,const Big& b2) + {if (mr_compare(b1.fn,b2.fn)>=0) return TRUE; else return FALSE;} + friend BOOL operator==(const Big& b1,const Big& b2) + {if (mr_compare(b1.fn,b2.fn)==0) return TRUE; else return FALSE;} + friend BOOL operator!=(const Big& b1,const Big& b2) + {if (mr_compare(b1.fn,b2.fn)!=0) return TRUE; else return FALSE;} + friend BOOL operator<(const Big& b1,const Big& b2) + {if (mr_compare(b1.fn,b2.fn)<0) return TRUE; else return FALSE;} + friend BOOL operator>(const Big& b1,const Big& b2) + {if (mr_compare(b1.fn,b2.fn)>0) return TRUE; else return FALSE;} + + friend Big from_binary(int,char *); + + friend int to_binary(const Big& b,int max,char *ptr,BOOL justify=FALSE) + { + return big_to_bytes(max,b.fn,ptr,justify); + } + //friend int to_binary(const Big&,int,char *,BOOL justify=FALSE); + friend Big modmult(const Big&,const Big&,const Big&); + friend Big mad(const Big&,const Big&,const Big&,const Big&,Big&); + friend Big norm(const Big&); + friend Big sqrt(const Big&); + friend Big root(const Big&,int); + friend Big gcd(const Big&,const Big&); + friend void set_zzn3(int cnr,Big& sru) {get_mip()->cnr=cnr; nres(sru.fn,get_mip()->sru);} + friend int recode(const Big& e,int t,int w,int i) {return recode(e.fn,t,w,i);} + +#ifndef MR_FP + friend Big land(const Big&,const Big&); // logical AND + friend Big lxor(const Big&,const Big&); // logical XOR +#endif + friend Big pow(const Big&,int); // x^m + friend Big pow(const Big&, int, const Big&); // x^m mod n + friend Big pow(int, const Big&, const Big&); // x^m mod n + friend Big pow(const Big&, const Big&, const Big&); // x^m mod n + friend Big pow(const Big&, const Big&, const Big&, const Big&, const Big&); + // x^m.y^k mod n + friend Big pow(int,Big *,Big *,Big); // x[0]^m[0].x[1].m[1]... mod n + + friend Big luc(const Big& b1,const Big& b2, const Big& b3, Big *b4=NULL) + { + Big z; if (b4!=NULL) lucas(b1.fn,b2.fn,b3.fn,b4->fn,z.fn); + else lucas(b1.fn,b2.fn,b3.fn,z.fn,z.fn); + return z; + } + //friend Big luc(const Big& ,const Big&, const Big&, Big *b4=NULL); + friend Big moddiv(const Big&,const Big&,const Big&); + friend Big inverse(const Big&, const Big&); + friend void multi_inverse(int,Big*,const Big&,Big *); +#ifndef MR_NO_RAND + friend Big rand(const Big&); // 0 < rand < parameter + friend Big rand(int,int); // (digits,base) e.g. (32,16) + friend Big randbits(int); // n random bits + friend Big strong_rand(csprng *,const Big&); + friend Big strong_rand(csprng *,int,int); +#endif + friend Big abs(const Big&); +// This next only works if MIRACL is using a binary base... + friend int bit(const Big& b,int i) {return mr_testbit(b.fn,i);} + friend int bits(const Big& b) {return logb2(b.fn);} + friend int ham(const Big& b) {return hamming(b.fn);} + friend int jacobi(const Big& b1,const Big& b2) {return jack(b1.fn,b2.fn);} + friend int toint(const Big& b) {return size(b.fn);} + friend BOOL prime(const Big& b) {return isprime(b.fn);} + friend Big nextprime(const Big&); + friend Big nextsafeprime(int type,int subset,const Big&); + friend Big trial_divide(const Big& b); + friend BOOL small_factors(const Big& b); + friend BOOL perfect_power(const Big& b); + friend Big sqrt(const Big&,const Big&); + + friend void ecurve(const Big&,const Big&,const Big&,int); + friend BOOL ecurve2(int,int,int,int,const Big&,const Big&,BOOL,int); + friend BOOL is_on_curve(const Big&); + friend void modulo(const Big&); + friend BOOL modulo(int,int,int,int,BOOL); + friend Big get_modulus(void); + friend int window(const Big& x,int i,int* nbs,int *nzs,int window_size=5) + { + return mr_window(x.fn,i,nbs,nzs,window_size); + } + + + //friend int window(const Big&,int,int*,int*,int window_size=5); + friend int naf_window(const Big& x,const Big& x3,int i,int* nbs,int* nzs,int store=11) + { + return mr_naf_window(x.fn,x3.fn,i,nbs,nzs,store); + } + + + //friend int naf_window(const Big&,const Big&,int,int*,int*,int store=11); + friend void jsf(const Big&,const Big&,Big&,Big&,Big&,Big&); + +/* Montgomery stuff */ + + friend Big nres(const Big&); + friend Big redc(const Big&); +/* + friend Big nres_negate(const Big&); + friend Big nres_modmult(const Big&,const Big&); + friend Big nres_premult(const Big&,int); + friend Big nres_pow(const Big&,const Big&); + friend Big nres_pow2(const Big&,const Big&,const Big&,const Big&); + friend Big nres_pown(int,Big *,Big *); + friend Big nres_luc(const Big&,const Big&,Big *b3=NULL); + friend Big nres_sqrt(const Big&); + friend Big nres_modadd(const Big&,const Big&); + friend Big nres_modsub(const Big&,const Big&); + friend Big nres_moddiv(const Big&,const Big&); +*/ +/* these are faster.... */ +/* + friend void nres_modmult(Big& a,const Big& b,Big& c) + {nres_modmult(a.fn,b.fn,c.fn);} + friend void nres_modadd(Big& a,const Big& b,Big& c) + {nres_modadd(a.fn,b.fn,c.fn);} + friend void nres_modsub(Big& a,const Big& b,Big& c) + {nres_modsub(a.fn,b.fn,c.fn);} + friend void nres_negate(Big& a,Big& b) + {nres_negate(a.fn,b.fn);} + friend void nres_premult(Big& a,int b,Big& c) + {nres_premult(a.fn,b,c.fn);} + friend void nres_moddiv(Big & a,const Big& b,Big& c) + {nres_moddiv(a.fn,b.fn,c.fn);} +*/ + friend Big shift(const Big&b,int n); + friend int length(const Big&b); + + +/* Note that when inputting text as a number the CR is NOT * + * included in the text, unlike C I/O which does include CR. */ + +#ifndef MR_NO_STANDARD_IO + + friend istream& operator>>(istream&, Big&); + friend ostream& operator<<(ostream&, const Big&); + friend ostream& otfloat(ostream&,const Big&,int); + +#endif + +// output Big to a String + friend char * operator<<(char * s,const Big&); + + ~Big() { + // zero(fn); +#ifndef BIGS + mr_free(fn); +#endif + } +}; + +extern BOOL modulo(int,int,int,int,BOOL); +extern Big get_modulus(void); +extern Big rand(int,int); +extern Big strong_rand(csprng *,int,int); +extern Big from_binary(int,char *); +//extern int to_binary(const Big&,int,char *,BOOL); + +using namespace std; + +#endif + diff --git a/miracl/include/brick.h b/miracl/include/brick.h new file mode 100644 index 0000000..bf06b4b --- /dev/null +++ b/miracl/include/brick.h @@ -0,0 +1,36 @@ +/* + * MIRACL C++ Header file brick.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class Brick + * Comb method for fast exponentiation with + * precomputation + * NOTE : Must be used in conjunction with big.cpp + * + */ + +#ifndef BRICK_H +#define BRICK_H + +#include "big.h" + +class Brick +{ + BOOL created; + brick b; +public: + Brick(Big g,Big n,int window,int nb) + {brick_init(&b,g.getbig(),n.getbig(),window,nb); created=TRUE;} + + Brick(brick *bb) { b=*bb; created=FALSE; } + + brick *get(void) {return &b;} + + Big pow(Big &e) {Big w; pow_brick(&b,e.getbig(),w.getbig()); return w;} + + ~Brick() {if (created) brick_end(&b);} +}; + +#endif + diff --git a/miracl/include/crt.h b/miracl/include/crt.h new file mode 100644 index 0000000..65e7ea2 --- /dev/null +++ b/miracl/include/crt.h @@ -0,0 +1,39 @@ +/* + * MIRACL C++ Header file crt.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class Crt (Chinese Remainder Thereom) + * NOTE : Must be used in conjunction with big.cpp + * Can be used with either Big or utype moduli + */ + +#ifndef CRT_H +#define CRT_H + +#include "big.h" + +#define MR_CRT_BIG 0 +#define MR_CRT_SMALL 1 + +class Crt +{ + big_chinese bc; + small_chinese sc; + int type; +public: + Crt(int,Big *); + Crt(int,mr_utype *); + + Big eval(Big *); + Big eval(mr_utype *); + + ~Crt() + { /* destructor */ + if (type==MR_CRT_BIG) crt_end(&bc); + if (type==MR_CRT_SMALL) scrt_end(&sc); + } +}; + +#endif + diff --git a/miracl/include/ebrick.h b/miracl/include/ebrick.h new file mode 100644 index 0000000..f87effd --- /dev/null +++ b/miracl/include/ebrick.h @@ -0,0 +1,37 @@ +/* + * MIRACL C++ Header file ebrick.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class EBrick + * Brickell et al's method for fast exponentiation with + * precomputation - elliptic curve version GF(p) + * NOTE : Must be used in conjunction with big.cpp + * + */ + +#ifndef EBRICK_H +#define EBRICK_H + +#include "big.h" + +class EBrick +{ + BOOL created; + ebrick B; +public: + EBrick(Big x,Big y,Big a,Big b,Big n,int window,int nb) + {ebrick_init(&B,x.getbig(),y.getbig(),a.getbig(),b.getbig(),n.getbig(),window,nb); + created=TRUE;} + + EBrick(ebrick *b) {B=*b; created=FALSE;} /* set structure */ + + ebrick *get(void) {return &B;} /* get address of structure */ + + int mul(Big &e,Big &x,Big &y) {int d=mul_brick(&B,e.getbig(),x.getbig(),y.getbig()); return d;} + + ~EBrick() {if (created) ebrick_end(&B);} +}; + +#endif + diff --git a/miracl/include/ebrick2.h b/miracl/include/ebrick2.h new file mode 100644 index 0000000..1bd6b6a --- /dev/null +++ b/miracl/include/ebrick2.h @@ -0,0 +1,36 @@ +/* + * MIRACL C++ Header file ebrick2.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class EBrick2 + * Brickell et al's method for fast exponentiation with + * precomputation - elliptic curve version GF(2^m) + * NOTE : Must be used in conjunction with big.cpp + */ + +#ifndef EBRICK2_H +#define EBRICK2_H + +#include "big.h" + +class EBrick2 +{ + BOOL created; + ebrick2 B; +public: + EBrick2(Big x,Big y,Big a2,Big a6,int m,int a,int b,int c,int window,int nb) + {ebrick2_init(&B,x.getbig(),y.getbig(),a2.getbig(),a6.getbig(),m,a,b,c,window,nb); + created=TRUE;} + + EBrick2(ebrick2 *b) {B=*b; created=FALSE;} /* set structure */ + + ebrick2 *get(void) {return &B;} /* get address of structure */ + + int mul(Big &e,Big &x,Big &y) {int d=mul2_brick(&B,e.getbig(),x.getbig(),y.getbig()); return d;} + + ~EBrick2() {if (created) ebrick2_end(&B);} +}; + +#endif + diff --git a/miracl/include/ec2.h b/miracl/include/ec2.h new file mode 100644 index 0000000..32f6a83 --- /dev/null +++ b/miracl/include/ec2.h @@ -0,0 +1,146 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ec2.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class EC2 (Arithmetic on an Elliptic Curve, + * over GF(2^m) + * + * NOTE : Must be used in conjunction with ec2.cpp and big.cpp + * The active curve is set dynamically (via the Big ecurve2() + * routine) - so beware the pitfalls implicit in declaring + * static or global EC2's (which are initialised before the + * curve is set!). Uninitialised data is OK + */ + +#ifndef EC2_H +#define EC2_H + +#include +#include "big.h" + +#ifdef GF2MS +#define MR_INIT_EC2 memset(mem,0,mr_ecp_reserve(1,GF2MS)); p=(epoint *)epoint_init_mem_variable(mem,0,GF2MS); +#else +#define MR_INIT_EC2 mem=(char *)ecp_memalloc(1); p=(epoint *)epoint_init_mem(mem,0); +#endif + +class EC2 +{ + epoint *p; +#ifdef GF2MS + char mem[mr_ecp_reserve(1,GF2MS)]; +#else + char *mem; +#endif + +public: + EC2() { MR_INIT_EC2} + + EC2(const Big &x,const Big& y) {MR_INIT_EC2 + epoint2_set(x.getbig(),y.getbig(),0,p); } + + // This next constructor restores a point on the curve from "compressed" + // data, that is the full x co-ordinate, and the LSB of y/x (0 or 1) + + EC2(const Big& x,int cb) {MR_INIT_EC2 + epoint2_set(x.getbig(),x.getbig(),cb,p); } + + EC2(const EC2 &b) {MR_INIT_EC2 epoint2_copy(b.p,p);} + + epoint *get_point() const; + + EC2& operator=(const EC2& b) {epoint2_copy(b.p,p);return *this;} + + EC2& operator+=(const EC2& b) {ecurve2_add(b.p,p); return *this;} + EC2& operator-=(const EC2& b) {ecurve2_sub(b.p,p); return *this;} + + // Multiplication of a point by an integer. + + EC2& operator*=(const Big& k) {ecurve2_mult(k.getbig(),p,p); return *this;} + big add(const EC2& b) {return ecurve2_add(b.p,p); } + // returns line slope as a big + big sub(const EC2& b) {return ecurve2_sub(b.p,p); } + + void clear() {epoint2_set(NULL,NULL,0,p);} + BOOL set(const Big& x,const Big& y) {return epoint2_set(x.getbig(),y.getbig(),0,p);} + int get(Big& x,Big& y) const; + BOOL iszero() const; + // This gets the point in compressed form. Return value is LSB of y-coordinate + int get(Big& x) const; + + void getx(Big &x) const; + void getxy(Big &x,Big& y) const; + void getxyz(Big &x,Big &y,Big& z) const; + + // point compression + + // This sets the point from compressed form. cb is LSB of y/x + + BOOL set(const Big& x,int cb=0) {return epoint2_set(x.getbig(),x.getbig(),cb,p);} + + friend EC2 operator-(const EC2&); + friend void multi_add(int,EC2 *,EC2 *); + + friend EC2 mul(const Big&, const EC2&, const Big&, const EC2&); + friend EC2 mul(int, const Big *, EC2 *); + + friend void normalise(EC2 &e) {epoint2_norm(e.p);} + + friend BOOL operator==(const EC2& a,const EC2& b) + {return epoint2_comp(a.p,b.p);} + friend BOOL operator!=(const EC2& a,const EC2& b) + {return (!epoint2_comp(a.p,b.p));} + + friend EC2 operator*(const Big &,const EC2&); + +#ifndef MR_NO_STANDARD_IO + + friend ostream& operator<<(ostream&,const EC2&); + +#endif + + ~EC2() + { +#ifndef GF2MS + mr_free(mem); +#endif + } +}; + +#endif + diff --git a/miracl/include/ecn.h b/miracl/include/ecn.h new file mode 100644 index 0000000..df2f3b0 --- /dev/null +++ b/miracl/include/ecn.h @@ -0,0 +1,159 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * + * MIRACL C++ Header file ecn.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class ECn (Arithmetic on an Elliptic Curve, + * mod n) + * + * NOTE : Must be used in conjunction with ecn.cpp and big.cpp + * The active curve is set dynamically (via the Big ecurve() + * routine) - so beware the pitfalls implicit in declaring + * static or global ECn's (which are initialised before the + * curve is set!). Uninitialised data is OK + * + */ + +#ifndef ECN_H +#define ECN_H + +#include +#include "big.h" + +#ifdef ZZNS +#define MR_INIT_ECN memset(mem,0,mr_ecp_reserve(1,ZZNS)); p=(epoint *)epoint_init_mem_variable(mem,0,ZZNS); +#else +#define MR_INIT_ECN mem=(char *)ecp_memalloc(1); p=(epoint *)epoint_init_mem(mem,0); +#endif + +class ECn +{ + epoint *p; +#ifdef ZZNS + char mem[mr_ecp_reserve(1,ZZNS)]; +#else + char *mem; +#endif +public: + ECn() {MR_INIT_ECN } + + ECn(const Big &x,const Big& y) {MR_INIT_ECN + epoint_set(x.getbig(),y.getbig(),0,p); } + + // This next constructor restores a point on the curve from "compressed" + // data, that is the full x co-ordinate, and the LSB of y (0 or 1) + +#ifndef MR_SUPPORT_COMPRESSION + ECn(const Big& x,int cb) {MR_INIT_ECN + epoint_set(x.getbig(),x.getbig(),cb,p); } +#endif + + ECn(const ECn &b) {MR_INIT_ECN epoint_copy(b.p,p);} + + epoint *get_point() const; + int get_status() {return p->marker;} + ECn& operator=(const ECn& b) {epoint_copy(b.p,p);return *this;} + + ECn& operator+=(const ECn& b) {ecurve_add(b.p,p); return *this;} + + int add(const ECn&,big *,big *ex1=NULL,big *ex2=NULL) const; + // returns line slope as a big + int sub(const ECn&,big *,big *ex1=NULL,big *ex2=NULL) const; + + ECn& operator-=(const ECn& b) {ecurve_sub(b.p,p); return *this;} + + // Multiplication of a point by an integer. + + ECn& operator*=(const Big& k) {ecurve_mult(k.getbig(),p,p); return *this;} + + void clear() {epoint_set(NULL,NULL,0,p);} + BOOL set(const Big& x,const Big& y) {return epoint_set(x.getbig(),y.getbig(),0,p);} +#ifndef MR_AFFINE_ONLY +// use with care if at all + void setz(const Big& z) {nres(z.getbig(),p->Z); p->marker=MR_EPOINT_GENERAL;} +#endif + BOOL iszero() const; + int get(Big& x,Big& y) const; + + // This gets the point in compressed form. Return value is LSB of y-coordinate + int get(Big& x) const; + + // get raw coordinates + void getx(Big &x) const; + void getxy(Big &x,Big &y) const; + void getxyz(Big &x,Big &y,Big &z) const; + + // point compression + + // This sets the point from compressed form. cb is LSB of y coordinate +#ifndef MR_SUPPORT_COMPRESSION + BOOL set(const Big& x,int cb=0) {return epoint_set(x.getbig(),x.getbig(),cb,p);} +#endif + friend ECn operator-(const ECn&); + friend void multi_add(int,ECn *,ECn *); + friend void double_add(ECn&,ECn&,ECn&,ECn&,big&,big&); + + friend ECn mul(const Big&, const ECn&, const Big&, const ECn&); + friend ECn mul(int, const Big *, ECn *); + + friend void normalise(ECn &e) {epoint_norm(e.p);} + friend void multi_norm(int,ECn *); + + friend BOOL operator==(const ECn& a,const ECn& b) + {return epoint_comp(a.p,b.p);} + friend BOOL operator!=(const ECn& a,const ECn& b) + {return (!epoint_comp(a.p,b.p));} + + friend ECn operator*(const Big &,const ECn&); + +#ifndef MR_NO_STANDARD_IO + + friend ostream& operator<<(ostream&,const ECn&); + +#endif + + ~ECn() { +#ifndef ZZNS + mr_free(mem); +#endif + } + +}; + +#endif + diff --git a/miracl/include/ecnzzn.h b/miracl/include/ecnzzn.h new file mode 100644 index 0000000..4f7a028 --- /dev/null +++ b/miracl/include/ecnzzn.h @@ -0,0 +1,22 @@ +// +// Utility functions to force an ECn to be created from 2 or 3 ZZn +// And to extract an ECn into ZZns +// + +#ifndef ECNZZN_H +#define ECNZZN_H + +#include "zzn.h" +#include "ecn.h" + +#ifndef MR_AFFINE_ONLY + +extern void force(ZZn&,ZZn&,ZZn&,ECn&); +extern void extract(ECn&,ZZn&,ZZn&,ZZn&); + +#endif + +extern void force(ZZn&,ZZn&,ECn&); +extern void extract(ECn&,ZZn&,ZZn&); + +#endif diff --git a/miracl/include/flash.h b/miracl/include/flash.h new file mode 100644 index 0000000..bac7750 --- /dev/null +++ b/miracl/include/flash.h @@ -0,0 +1,163 @@ +/* + * MIRACL C++ Header file flash.h + * + * AUTHOR : N.Coghlan + * Modified by M.Scott + * + * PURPOSE : Definition of class Flash + * + */ + +#ifndef FLASH_H +#define FLASH_H + +#include "big.h" + +#ifdef MR_FLASH + +#ifdef BIGS +#define MR_FINIT_BIG fn=&b; b.w=a; b.len=0; for (int i=0;i=(const Flash& f1, const Flash& f2) + {if (fcomp(f1.fn,f2.fn) >= 0) return TRUE; else return FALSE;} + friend BOOL operator==(const Flash& f1, const Flash& f2) + {if (fcomp(f1.fn,f2.fn) == 0) return TRUE; else return FALSE;} + friend BOOL operator!=(const Flash& f1, const Flash& f2) + {if (fcomp(f1.fn,f2.fn) != 0) return TRUE; else return FALSE;} + friend BOOL operator<(const Flash& f1, const Flash& f2) + {if (fcomp(f1.fn,f2.fn) < 0) return TRUE; else return FALSE;} + friend BOOL operator>(const Flash& f1, const Flash& f2) + {if (fcomp(f1.fn,f2.fn) > 0) return TRUE; else return FALSE;} + + friend Flash inverse(const Flash&); + friend Flash pi(void); + friend Flash cos(const Flash&); + friend Flash sin(const Flash&); + friend Flash tan(const Flash&); + + friend Flash acos(const Flash&); + friend Flash asin(const Flash&); + friend Flash atan(const Flash&); + + friend Flash cosh(const Flash&); + friend Flash sinh(const Flash&); + friend Flash tanh(const Flash&); + + friend Flash acosh(const Flash&); + friend Flash asinh(const Flash&); + friend Flash atanh(const Flash&); + + friend Flash log(const Flash&); + friend Flash exp(const Flash&); + friend Flash pow(const Flash&,const Flash&); + friend Flash sqrt(const Flash&); + friend Flash nroot(const Flash&,int); + friend Flash fabs(const Flash&); + + friend double todouble(const Flash& f) { return fdsize(f.fn);} + +#ifndef MR_NO_STANDARD_IO + + friend istream& operator>>(istream&, Flash&); + friend ostream& operator<<(ostream&, const Flash&); + +#endif + + +#ifdef BIGS + ~Flash() { } +#else + ~Flash() {mirkill(fn);} +#endif +}; + +extern Flash pi(void); + +#endif +#endif + diff --git a/miracl/include/floating.h b/miracl/include/floating.h new file mode 100644 index 0000000..5ab7c5f --- /dev/null +++ b/miracl/include/floating.h @@ -0,0 +1,94 @@ +/* + * MIRACL C++ Header file float.h + * + * AUTHOR : M.Scott + * + * PURPOSE : Definition of class Float + * + */ + +#ifndef FLOAT_H +#define FLOAT_H + +#include +#include "big.h" + +extern void setprecision(int); + +class Float +{ + int e; // exponent + Big m; // mantissa +public: + Float() { } + Float(int i) {m=i; e=1;} + Float(const Float& f) {e=f.e; m=f.m; } + Float(const Big &b) {m=b; e=length(b);} + Float(const Big &b,int ex) {m=b; e=ex;} + Float(double); + + Big trunc(Float *rem=NULL); + void negate() const; + BOOL iszero() const; + BOOL isone() const; + int sign() const; + Float& operator=(double); + BOOL add(const Float&); + Float& operator+=(const Float&); + BOOL sub(const Float&); + Float& operator-=(const Float&); + Float& operator*=(const Float&); + Float& operator*=(int); + Float& operator/=(const Float&); + Float& operator/=(int); + Float& operator=(const Float&); + + friend Float reciprocal(const Float&); + friend double todouble(const Float&); + friend Float makefloat(int,int); + friend Float operator-(const Float&); + friend Float operator+(const Float&,const Float&); + friend Float operator-(const Float&,const Float&); + friend Float operator*(const Float&,const Float&); + friend Float operator*(const Float&,int); + friend Float operator*(int,const Float&); + friend Float operator/(const Float&,const Float&); + friend Float operator/(const Float&,int); + friend Float sqrt(const Float&); + friend Float nroot(const Float&,int); + friend Float exp(const Float&); + friend Float sin(const Float&); + friend Float cos(const Float&); + friend Float pow(const Float&,int); + friend Float fpi(void); + + friend Big trunc(const Float&); + friend int norm(int,Float&); + friend Float fabs(const Float&); + + /* relational ops */ + friend int fcomp(const Float&,const Float&); + + friend BOOL operator<=(const Float& f1, const Float& f2) + {if (fcomp(f1,f2) <= 0) return TRUE; else return FALSE;} + friend BOOL operator>=(const Float& f1, const Float& f2) + {if (fcomp(f1,f2) >= 0) return TRUE; else return FALSE;} + friend BOOL operator==(const Float& f1, const Float& f2) + {if (fcomp(f1,f2) == 0) return TRUE; else return FALSE;} + friend BOOL operator!=(const Float& f1, const Float& f2) + {if (fcomp(f1,f2) != 0) return TRUE; else return FALSE;} + friend BOOL operator<(const Float& f1, const Float& f2) + {if (fcomp(f1,f2) < 0) return TRUE; else return FALSE;} + friend BOOL operator>(const Float& f1, const Float& f2) + {if (fcomp(f1,f2) > 0) return TRUE; else return FALSE;} + + friend ostream& operator<<(ostream&,const Float&); + + ~Float() { } +}; + +extern Float fpi(void); +extern Float makefloat(int,int); + +#endif + diff --git a/miracl/include/gf2m.h b/miracl/include/gf2m.h new file mode 100644 index 0000000..cd95f65 --- /dev/null +++ b/miracl/include/gf2m.h @@ -0,0 +1,171 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file gf2m.h + * + * AUTHOR : M.Scott + * + * PURPOSE : Definition of class GF2m (Arithmetic in the field GF(2^m) + * + * NOTE: : The field basis is set dynamically via the modulo() routine. + * Must be used with big.h and big.cpp + */ + +#ifndef GF2M_H +#define GF2M_H + +#include "big.h" + +/* +#ifdef GF2MS +#define MR_INIT_GF2M memset(mem,0,mr_big_reserve(1,GF2MS)); fn=(big)mirvar_mem_variable(mem,0,GF2MS); +#define MR_CLONE_GF2M(x) fn->len=x->len; for (int i=0;iw[i]=x->w[i]; +#define MR_ZERO_GF2M {fn->len=0; for (int i=0;iw[i]=0;} +#else +#define MR_INIT_GF2M mem=(char *)memalloc(1); fn=(big)mirvar_mem(mem,0); +#define MR_CLONE_GF2M(x) copy(x,fn); +#define MR_ZERO_GF2M zero(fn); +#endif +*/ + + +#ifdef GF2MS +#define MR_INIT_GF2M fn=&b; b.w=a; b.len=GF2MS; +#define MR_CLONE_GF2M(x) b.len=x->len; for (int i=0;iw[i]; +#define MR_ZERO_GF2M {b.len=0; for (int i=0;i GF2m */ + GF2m(big& c) {MR_INIT_GF2M MR_CLONE_GF2M(c)} + GF2m(const GF2m& c) {MR_INIT_GF2M MR_CLONE_GF2M(c.fn)} + GF2m(char *s) {MR_INIT_GF2M cinstr(fn,s); reduce2(fn,fn);} + + GF2m& operator=(const GF2m& c) {MR_CLONE_GF2M(c.fn) return *this;} + GF2m& operator=(big c) {MR_CLONE_GF2M(c) return *this;} + + GF2m& operator=(int i) {if (i==0) MR_ZERO_GF2M else {convert(i,fn); reduce2(fn,fn);} return *this;} + GF2m& operator=(const Big& b) { reduce2(b.getbig(),fn); return *this; } + GF2m& operator=(char *s) { cinstr(fn,s); reduce2(fn,fn); return *this;} + GF2m& operator++() {incr2(fn,1,fn); return *this; } + + GF2m& operator+=(const GF2m& c) + { +#ifdef GF2MS + for (int i=0;iw[i]^=c.fn->w[i]; + fn->len=GF2MS; + if (fn->w[GF2MS-1]==0) mr_lzero(fn); +#else + add2(fn,c.fn,fn); +#endif + return *this; + } + + GF2m& operator+=(int i) {incr2(fn,i,fn); return *this; } + GF2m& operator*=(const GF2m& b) {modmult2(fn,b.fn,fn); return *this;} + GF2m& square() {modsquare2(fn,fn); return *this;} + GF2m& inverse() {inverse2(fn,fn); return *this;} + BOOL quadratic(GF2m& b) {return quad2(fn,b.fn);} + int degree() {return degree2(fn);} + + BOOL iszero() const; + BOOL isone() const; + operator Big() {return (Big)fn;} /* GF2m -> Big */ + friend big getbig(GF2m& z) {return z.fn;} + friend int trace(GF2m & z) {return trace2(z.fn);} + + GF2m& operator/=(const GF2m&); + + friend GF2m operator+(const GF2m&,const GF2m&); + friend GF2m operator+(const GF2m&,int); + friend GF2m operator*(const GF2m&,const GF2m&); + friend GF2m operator/(const GF2m&,const GF2m&); + + friend BOOL operator==(const GF2m& b1,const GF2m& b2) + { if (mr_compare(b1.fn,b2.fn)==0) return TRUE; else return FALSE;} + friend BOOL operator!=(const GF2m& b1,const GF2m& b2) + { if (mr_compare(b1.fn,b2.fn)!=0) return TRUE; else return FALSE;} + + friend GF2m square(const GF2m&); + friend GF2m inverse(const GF2m&); + friend GF2m pow(const GF2m&,int); + friend GF2m sqrt(const GF2m&); + friend GF2m halftrace(const GF2m&); + friend GF2m quad(const GF2m&); +#ifndef MR_NO_RAND + friend GF2m random2(void); +#endif + friend GF2m gcd(const GF2m&,const GF2m&); + + friend void kar2x2(const GF2m*,const GF2m*,GF2m*); + friend void kar3x3(const GF2m*,const GF2m*,GF2m*); + + friend int degree(const GF2m& x) {return degree2(x.fn);} + + ~GF2m() + { + // zero(fn); +#ifndef GF2MS + mr_free(fn); +#endif + } +}; +#ifndef MR_NO_RAND +extern GF2m random2(void); +#endif +#endif diff --git a/miracl/include/miracl.h b/miracl/include/miracl.h new file mode 100644 index 0000000..558d19c --- /dev/null +++ b/miracl/include/miracl.h @@ -0,0 +1,1563 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ + +#ifndef MIRACL_H +#define MIRACL_H + +/* + * main MIRACL header - miracl.h. + */ + +#include "mirdef.h" + +/* Some modifiable defaults... */ + +/* Use a smaller buffer if space is limited, don't be so wasteful! */ + +#ifdef MR_STATIC +#define MR_DEFAULT_BUFFER_SIZE 260 +#else +#define MR_DEFAULT_BUFFER_SIZE 1024 +#endif + +/* see mrgf2m.c */ + +#ifndef MR_KARATSUBA +#define MR_KARATSUBA 2 +#endif + +#ifndef MR_DOUBLE_BIG + +#ifdef MR_KCM + #ifdef MR_FLASH + #define MR_SPACES 32 + #else + #define MR_SPACES 31 + #endif +#else + #ifdef MR_FLASH + #define MR_SPACES 28 + #else + #define MR_SPACES 27 + #endif +#endif + +#else + +#ifdef MR_KCM + #ifdef MR_FLASH + #define MR_SPACES 44 + #else + #define MR_SPACES 43 + #endif +#else + #ifdef MR_FLASH + #define MR_SPACES 40 + #else + #define MR_SPACES 39 + #endif +#endif + +#endif + +/* To avoid name clashes - undefine this */ + +/* #define compare mr_compare */ + +#ifdef MR_AVR +#include +#endif + +/* size of bigs and elliptic curve points for memory allocation from stack or heap */ + +#define MR_ROUNDUP(a,b) ((a)-1)/(b)+1 + +#define MR_SL sizeof(long) + +#ifdef MR_STATIC + +#define MR_SIZE (((sizeof(struct bigtype)+(MR_STATIC+2)*sizeof(mr_utype))-1)/MR_SL+1)*MR_SL +#define MR_BIG_RESERVE(n) ((n)*MR_SIZE+MR_SL) + +#ifdef MR_AFFINE_ONLY +#define MR_ESIZE (((sizeof(epoint)+MR_BIG_RESERVE(2))-1)/MR_SL+1)*MR_SL +#else +#define MR_ESIZE (((sizeof(epoint)+MR_BIG_RESERVE(3))-1)/MR_SL+1)*MR_SL +#endif +#define MR_ECP_RESERVE(n) ((n)*MR_ESIZE+MR_SL) + +#define MR_ESIZE_A (((sizeof(epoint)+MR_BIG_RESERVE(2))-1)/MR_SL+1)*MR_SL +#define MR_ECP_RESERVE_A(n) ((n)*MR_ESIZE_A+MR_SL) + + +#endif + +/* useful macro to convert size of big in words, to size of required structure */ + +#define mr_size(n) (((sizeof(struct bigtype)+((n)+2)*sizeof(mr_utype))-1)/MR_SL+1)*MR_SL +#define mr_big_reserve(n,m) ((n)*mr_size(m)+MR_SL) + +#define mr_esize_a(n) (((sizeof(epoint)+mr_big_reserve(2,(n)))-1)/MR_SL+1)*MR_SL +#define mr_ecp_reserve_a(n,m) ((n)*mr_esize_a(m)+MR_SL) + +#ifdef MR_AFFINE_ONLY +#define mr_esize(n) (((sizeof(epoint)+mr_big_reserve(2,(n)))-1)/MR_SL+1)*MR_SL +#else +#define mr_esize(n) (((sizeof(epoint)+mr_big_reserve(3,(n)))-1)/MR_SL+1)*MR_SL +#endif +#define mr_ecp_reserve(n,m) ((n)*mr_esize(m)+MR_SL) + + +/* if basic library is static, make sure and use static C++ */ + +#ifdef MR_STATIC + #ifndef BIGS + #define BIGS MR_STATIC + #endif + #ifndef ZZNS + #define ZZNS MR_STATIC + #endif + #ifndef GF2MS + #define GF2MS MR_STATIC + #endif +#endif + +#ifdef __ia64__ +#if MIRACL==64 +#define MR_ITANIUM +#include +#endif +#endif + +#ifdef _M_X64 +#ifdef _WIN64 +#if MIRACL==64 +#define MR_WIN64 +#include +#endif +#endif +#endif + +#ifndef MR_NO_FILE_IO +#include +#endif + /* error returns */ + +#define MR_ERR_BASE_TOO_BIG 1 +#define MR_ERR_DIV_BY_ZERO 2 +#define MR_ERR_OVERFLOW 3 +#define MR_ERR_NEG_RESULT 4 +#define MR_ERR_BAD_FORMAT 5 +#define MR_ERR_BAD_BASE 6 +#define MR_ERR_BAD_PARAMETERS 7 +#define MR_ERR_OUT_OF_MEMORY 8 +#define MR_ERR_NEG_ROOT 9 +#define MR_ERR_NEG_POWER 10 +#define MR_ERR_BAD_ROOT 11 +#define MR_ERR_INT_OP 12 +#define MR_ERR_FLASH_OVERFLOW 13 +#define MR_ERR_TOO_BIG 14 +#define MR_ERR_NEG_LOG 15 +#define MR_ERR_DOUBLE_FAIL 16 +#define MR_ERR_IO_OVERFLOW 17 +#define MR_ERR_NO_MIRSYS 18 +#define MR_ERR_BAD_MODULUS 19 +#define MR_ERR_NO_MODULUS 20 +#define MR_ERR_EXP_TOO_BIG 21 +#define MR_ERR_NOT_SUPPORTED 22 +#define MR_ERR_NOT_DOUBLE_LEN 23 +#define MR_ERR_NOT_IRREDUC 24 +#define MR_ERR_NO_ROUNDING 25 +#define MR_ERR_NOT_BINARY 26 +#define MR_ERR_NO_BASIS 27 +#define MR_ERR_COMPOSITE_MODULUS 28 +#define MR_ERR_DEV_RANDOM 29 + + /* some useful definitions */ + +#define forever for(;;) + +#define mr_abs(x) ((x)<0? (-(x)) : (x)) + +#ifndef TRUE + #define TRUE 1 +#endif +#ifndef FALSE + #define FALSE 0 +#endif + +#define OFF 0 +#define ON 1 +#define PLUS 1 +#define MINUS (-1) + +#define M1 (MIRACL-1) +#define M2 (MIRACL-2) +#define M3 (MIRACL-3) +#define M4 (MIRACL-4) +#define TOPBIT ((mr_small)1<= MR_IBITS +#define MR_TOOBIG (1<<(MR_IBITS-2)) +#else +#define MR_TOOBIG (1<<(MIRACL-1)) +#endif + +#ifdef MR_FLASH +#define MR_EBITS (8*sizeof(double) - MR_FLASH) + /* no of Bits per double exponent */ +#define MR_BTS 16 +#define MR_MSK 0xFFFF + +#endif + +/* Default Hash function output size in bytes */ +#define MR_HASH_BYTES 32 + +/* Marsaglia & Zaman Random number generator */ +/* constants alternatives */ +#define NK 37 /* 21 */ +#define NJ 24 /* 6 */ +#define NV 14 /* 8 */ + +/* Use smaller values if memory is precious */ + +#ifdef mr_dltype + +#ifdef MR_LITTLE_ENDIAN +#define MR_BOT 0 +#define MR_TOP 1 +#endif +#ifdef MR_BIG_ENDIAN +#define MR_BOT 1 +#define MR_TOP 0 +#endif + +union doubleword +{ + mr_large d; + mr_small h[2]; +}; + +#endif + +/* chinese remainder theorem structures */ + +typedef struct { +big *C; +big *V; +big *M; +int NP; +} big_chinese; + +typedef struct { +mr_utype *C; +mr_utype *V; +mr_utype *M; +int NP; +} small_chinese; + +/* Cryptographically strong pseudo-random number generator */ + +typedef struct { +mr_unsign32 ira[NK]; /* random number... */ +int rndptr; /* ...array & pointer */ +mr_unsign32 borrow; +int pool_ptr; +char pool[MR_HASH_BYTES]; /* random pool */ +} csprng; + +/* secure hash Algorithm structure */ + +typedef struct { +mr_unsign32 length[2]; +mr_unsign32 h[8]; +mr_unsign32 w[80]; +} sha256; + +typedef sha256 sha; + +#ifdef mr_unsign64 + +typedef struct { +mr_unsign64 length[2]; +mr_unsign64 h[8]; +mr_unsign64 w[80]; +} sha512; + +typedef sha512 sha384; + +typedef struct { +mr_unsign64 length; +mr_unsign64 S[5][5]; +int rate,len; +} sha3; + +#endif + +/* Symmetric Encryption algorithm structure */ + +#define MR_ECB 0 +#define MR_CBC 1 +#define MR_CFB1 2 +#define MR_CFB2 3 +#define MR_CFB4 5 +#define MR_PCFB1 10 +#define MR_PCFB2 11 +#define MR_PCFB4 13 +#define MR_OFB1 14 +#define MR_OFB2 15 +#define MR_OFB4 17 +#define MR_OFB8 21 +#define MR_OFB16 29 + +typedef struct { +int Nk,Nr; +int mode; +mr_unsign32 fkey[60]; +mr_unsign32 rkey[60]; +char f[16]; +} aes; + +/* AES-GCM suppport. See mrgcm.c */ + +#define GCM_ACCEPTING_HEADER 0 +#define GCM_ACCEPTING_CIPHER 1 +#define GCM_NOT_ACCEPTING_MORE 2 +#define GCM_FINISHED 3 +#define GCM_ENCRYPTING 0 +#define GCM_DECRYPTING 1 + +typedef struct { +mr_unsign32 table[128][4]; /* 2k bytes */ +MR_BYTE stateX[16]; +MR_BYTE Y_0[16]; +mr_unsign32 counter; +mr_unsign32 lenA[2],lenC[2]; +int status; +aes a; +} gcm; + + /* Elliptic curve point status */ + +#define MR_EPOINT_GENERAL 0 +#define MR_EPOINT_NORMALIZED 1 +#define MR_EPOINT_INFINITY 2 + +#define MR_NOTSET 0 +#define MR_PROJECTIVE 0 +#define MR_AFFINE 1 +#define MR_BEST 2 +#define MR_TWIST 8 + +#define MR_OVER 0 +#define MR_ADD 1 +#define MR_DOUBLE 2 + +/* Twist type */ + +#define MR_QUADRATIC 2 +#define MR_CUBIC_M 0x3A +#define MR_CUBIC_D 0x3B +#define MR_QUARTIC_M 0x4A +#define MR_QUARTIC_D 0x4B +#define MR_SEXTIC_M 0x6A +#define MR_SEXTIC_D 0x6B + + +/* Fractional Sliding Windows for ECC - how much precomputation storage to use ? */ +/* Note that for variable point multiplication there is an optimal value + which can be reduced if space is short. For fixed points its a matter of + how much ROM is available to store precomputed points. + We are storing the k points (P,3P,5P,7P,...,[2k-1].P) */ + +/* These values can be manually tuned for optimal performance... */ + +#ifdef MR_SMALL_EWINDOW +#define MR_ECC_STORE_N 3 /* point store for ecn variable point multiplication */ +#define MR_ECC_STORE_2M 3 /* point store for ec2m variable point multiplication */ +#define MR_ECC_STORE_N2 3 /* point store for ecn2 variable point multiplication */ +#else +#define MR_ECC_STORE_N 8 /* 8/9 is close to optimal for 256 bit exponents */ +#define MR_ECC_STORE_2M 9 +#define MR_ECC_STORE_N2 8 +#endif + +/*#define MR_ECC_STORE_N2_PRECOMP MR_ECC_STORE_N2 */ + /* Might want to make this bigger.. */ + +/* If multi-addition is of m points, and s precomputed values are required, this is max of m*s (=4.10?) */ +#define MR_MAX_M_T_S 64 + +/* Elliptic Curve epoint structure. Uses projective (X,Y,Z) co-ordinates */ + +typedef struct { +int marker; +big X; +big Y; +#ifndef MR_AFFINE_ONLY +big Z; +#endif +} epoint; + + +/* Structure for Comb method for finite * + field exponentiation with precomputation */ + +typedef struct { +#ifdef MR_STATIC + const mr_small *table; +#else + mr_small *table; +#endif + big n; + int window; + int max; +} brick; + +/* Structure for Comb method for elliptic * + curve exponentiation with precomputation */ + +typedef struct { +#ifdef MR_STATIC + const mr_small *table; +#else + mr_small *table; +#endif + big a,b,n; + int window; + int max; +} ebrick; + +typedef struct { +#ifdef MR_STATIC + const mr_small *table; +#else + mr_small *table; +#endif + big a6,a2; + int m,a,b,c; + int window; + int max; +} ebrick2; + +typedef struct +{ + big a; + big b; +} zzn2; + +typedef struct +{ + zzn2 a; + zzn2 b; + BOOL unitary; +} zzn4; + +typedef struct +{ + int marker; + zzn2 x; + zzn2 y; +#ifndef MR_AFFINE_ONLY + zzn2 z; +#endif + +} ecn2; + +typedef struct +{ + big a; + big b; + big c; +} zzn3; + +typedef struct +{ + zzn2 a; + zzn2 b; + zzn2 c; +} zzn6_3x2; + +/* main MIRACL instance structure */ + +/* ------------------------------------------------------------------------*/ + +typedef struct { +mr_small base; /* number base */ +mr_small apbase; /* apparent base */ +int pack; /* packing density */ +int lg2b; /* bits in base */ +mr_small base2; /* 2^mr_lg2b */ +BOOL (*user)(void); /* pointer to user supplied function */ + +int nib; /* length of bigs */ +#ifndef MR_STRIPPED_DOWN +int depth; /* error tracing ..*/ +int trace[MR_MAXDEPTH]; /* .. mechanism */ +#endif +BOOL check; /* overflow check */ +BOOL fout; /* Output to file */ +BOOL fin; /* Input from file */ +BOOL active; + +#ifndef MR_NO_FILE_IO + +FILE *infile; /* Input file */ +FILE *otfile; /* Output file */ + +#endif + + +#ifndef MR_NO_RAND +mr_unsign32 ira[NK]; /* random number... */ +int rndptr; /* ...array & pointer */ +mr_unsign32 borrow; +#endif + + /* Montgomery constants */ +mr_small ndash; +big modulus; +big pR; +BOOL ACTIVE; +BOOL MONTY; + + /* Elliptic Curve details */ +#ifndef MR_NO_SS +BOOL SS; /* True for Super-Singular */ +#endif +#ifndef MR_NOKOBLITZ +BOOL KOBLITZ; /* True for a Koblitz curve */ +#endif +#ifndef MR_AFFINE_ONLY +int coord; +#endif +int Asize,Bsize; + +int M,AA,BB,CC; /* for GF(2^m) curves */ + +/* +mr_small pm,mask; +int e,k,Me,m; for GF(p^m) curves */ + + +#ifndef MR_STATIC + +int logN; /* constants for fast fourier fft multiplication */ +int nprimes,degree; +mr_utype *prime,*cr; +mr_utype *inverse,**roots; +small_chinese chin; +mr_utype const1,const2,const3; +mr_small msw,lsw; +mr_utype **s1,**s2; /* pre-computed tables for polynomial reduction */ +mr_utype **t; /* workspace */ +mr_utype *wa; +mr_utype *wb; +mr_utype *wc; + +#endif + +BOOL same; +BOOL first_one; +BOOL debug; + +big w0; /* workspace bigs */ +big w1,w2,w3,w4; +big w5,w6,w7; +big w8,w9,w10,w11; +big w12,w13,w14,w15; +big sru; +big one; + +#ifdef MR_KCM +big big_ndash; +big ws,wt; +#endif + +big A,B; + +/* User modifiables */ + +#ifndef MR_SIMPLE_IO +int IOBSIZ; /* size of i/o buffer */ +#endif +BOOL ERCON; /* error control */ +int ERNUM; /* last error code */ +int NTRY; /* no. of tries for probablistic primality testing */ +#ifndef MR_SIMPLE_IO +int INPLEN; /* input length */ +#ifndef MR_SIMPLE_BASE +int IOBASE; /* base for input and output */ + +#endif +#endif +#ifdef MR_FLASH +BOOL EXACT; /* exact flag */ +BOOL RPOINT; /* =ON for radix point, =OFF for fractions in output */ +#endif +#ifndef MR_STRIPPED_DOWN +BOOL TRACER; /* turns trace tracker on/off */ +#endif + +#ifdef MR_STATIC +const int *PRIMES; /* small primes array */ +#ifndef MR_SIMPLE_IO +char IOBUFF[MR_DEFAULT_BUFFER_SIZE]; /* i/o buffer */ +#endif +#else +int *PRIMES; /* small primes array */ +#ifndef MR_SIMPLE_IO +char *IOBUFF; /* i/o buffer */ +#endif +#endif + +#ifdef MR_FLASH +int workprec; +int stprec; /* start precision */ + +int RS,RD; +double D; + +double db,n,p; +int a,b,c,d,r,q,oldn,ndig; +mr_small u,v,ku,kv; + +BOOL last,carryon; +flash pi; + +#endif + +#ifdef MR_FP_ROUNDING +mr_large inverse_base; +#endif + +#ifndef MR_STATIC +char *workspace; +#else +char workspace[MR_BIG_RESERVE(MR_SPACES)]; +#endif + +int TWIST; /* set to twisted curve */ +int qnr; /* a QNR -1 for p=3 mod 4, -2 for p=5 mod 8, 0 otherwise */ +int cnr; /* a cubic non-residue */ +int pmod8; +int pmod9; +BOOL NO_CARRY; +} miracl; + +/* ------------------------------------------------------------------------*/ + + +#ifndef MR_GENERIC_MT + +#ifdef MR_WINDOWS_MT +#define MR_OS_THREADS +#endif + +#ifdef MR_UNIX_MT +#define MR_OS_THREADS +#endif + +#ifdef MR_OPENMP_MT +#define MR_OS_THREADS +#endif + + +#ifndef MR_OS_THREADS + +extern miracl *mr_mip; /* pointer to MIRACL's only global variable */ + +#endif + +#endif + +#ifdef MR_GENERIC_MT + +#ifdef MR_STATIC +#define MR_GENERIC_AND_STATIC +#endif + +#define _MIPT_ miracl *, +#define _MIPTO_ miracl * +#define _MIPD_ miracl *mr_mip, +#define _MIPDO_ miracl *mr_mip +#define _MIPP_ mr_mip, +#define _MIPPO_ mr_mip + +#else + +#define _MIPT_ +#define _MIPTO_ void +#define _MIPD_ +#define _MIPDO_ void +#define _MIPP_ +#define _MIPPO_ + +#endif + +/* Preamble and exit code for MIRACL routines. * + * Not used if MR_STRIPPED_DOWN is defined */ + +#ifdef MR_STRIPPED_DOWN +#define MR_OUT +#define MR_IN(N) +#else +#define MR_OUT mr_mip->depth--; +#define MR_IN(N) mr_mip->depth++; if (mr_mip->depthtrace[mr_mip->depth]=(N); if (mr_mip->TRACER) mr_track(_MIPPO_); } +#endif + +/* Function definitions */ + +/* Group 0 - Internal routines */ + +extern void mr_berror(_MIPT_ int); +extern mr_small mr_shiftbits(mr_small,int); +extern mr_small mr_setbase(_MIPT_ mr_small); +extern void mr_track(_MIPTO_ ); +extern void mr_lzero(big); +extern BOOL mr_notint(flash); +extern int mr_lent(flash); +extern void mr_padd(_MIPT_ big,big,big); +extern void mr_psub(_MIPT_ big,big,big); +extern void mr_pmul(_MIPT_ big,mr_small,big); +#ifdef MR_FP_ROUNDING +extern mr_large mr_invert(mr_small); +extern mr_small imuldiv(mr_small,mr_small,mr_small,mr_small,mr_large,mr_small *); +extern mr_small mr_sdiv(_MIPT_ big,mr_small,mr_large,big); +#else +extern mr_small mr_sdiv(_MIPT_ big,mr_small,big); +extern void mr_and(big,big,big); +extern void mr_xor(big,big,big); +#endif +extern void mr_shift(_MIPT_ big,int,big); +extern miracl *mr_first_alloc(void); +extern void *mr_alloc(_MIPT_ int,int); +extern void mr_free(void *); +extern void set_user_function(_MIPT_ BOOL (*)(void)); +extern void set_io_buffer_size(_MIPT_ int); +extern int mr_testbit(_MIPT_ big,int); +extern void mr_addbit(_MIPT_ big,int); +extern int recode(_MIPT_ big ,int ,int ,int ); +extern int mr_window(_MIPT_ big,int,int *,int *,int); +extern int mr_window2(_MIPT_ big,big,int,int *,int *); +extern int mr_naf_window(_MIPT_ big,big,int,int *,int *,int); + +extern int mr_fft_init(_MIPT_ int,big,big,BOOL); +extern void mr_dif_fft(_MIPT_ int,int,mr_utype *); +extern void mr_dit_fft(_MIPT_ int,int,mr_utype *); +extern void fft_reset(_MIPTO_); + +extern int mr_poly_mul(_MIPT_ int,big*,int,big*,big*); +extern int mr_poly_sqr(_MIPT_ int,big*,big*); +extern void mr_polymod_set(_MIPT_ int,big*,big*); +extern int mr_poly_rem(_MIPT_ int,big *,big *); + +extern int mr_ps_big_mul(_MIPT_ int,big *,big *,big *); +extern int mr_ps_zzn_mul(_MIPT_ int,big *,big *,big *); + +extern mr_small muldiv(mr_small,mr_small,mr_small,mr_small,mr_small *); +extern mr_small muldvm(mr_small,mr_small,mr_small,mr_small *); +extern mr_small muldvd(mr_small,mr_small,mr_small,mr_small *); +extern void muldvd2(mr_small,mr_small,mr_small *,mr_small *); + +extern flash mirvar_mem_variable(char *,int,int); +extern epoint* epoint_init_mem_variable(_MIPT_ char *,int,int); + +/* Group 1 - General purpose, I/O and basic arithmetic routines */ + +extern unsigned int igcd(unsigned int,unsigned int); +extern unsigned long lgcd(unsigned long,unsigned long); +extern mr_small sgcd(mr_small,mr_small); +extern unsigned int isqrt(unsigned int,unsigned int); +extern unsigned long mr_lsqrt(unsigned long,unsigned long); +extern void irand(_MIPT_ mr_unsign32); +extern mr_small brand(_MIPTO_ ); +extern void zero(flash); +extern void convert(_MIPT_ int,big); +extern void uconvert(_MIPT_ unsigned int,big); +extern void lgconv(_MIPT_ long,big); +extern void ulgconv(_MIPT_ unsigned long,big); +extern void tconvert(_MIPT_ mr_utype,big); + +#ifdef mr_dltype +extern void dlconv(_MIPT_ mr_dltype,big); +#endif + +extern flash mirvar(_MIPT_ int); +extern flash mirvar_mem(_MIPT_ char *,int); +extern void mirkill(big); +extern void *memalloc(_MIPT_ int); +extern void memkill(_MIPT_ char *,int); +extern void mr_init_threading(void); +extern void mr_end_threading(void); +extern miracl *get_mip(void ); +extern void set_mip(miracl *); +#ifdef MR_GENERIC_AND_STATIC +extern miracl *mirsys(miracl *,int,mr_small); +#else +extern miracl *mirsys(int,mr_small); +#endif +extern miracl *mirsys_basic(miracl *,int,mr_small); +extern void mirexit(_MIPTO_ ); +extern int exsign(flash); +extern void insign(int,flash); +extern int getdig(_MIPT_ big,int); +extern int numdig(_MIPT_ big); +extern void putdig(_MIPT_ int,big,int); +extern void copy(flash,flash); +extern void negify(flash,flash); +extern void absol(flash,flash); +extern int size(big); +extern int mr_compare(big,big); +extern void add(_MIPT_ big,big,big); +extern void subtract(_MIPT_ big,big,big); +extern void incr(_MIPT_ big,int,big); +extern void decr(_MIPT_ big,int,big); +extern void premult(_MIPT_ big,int,big); +extern int subdiv(_MIPT_ big,int,big); +extern BOOL subdivisible(_MIPT_ big,int); +extern int remain(_MIPT_ big,int); +extern void bytes_to_big(_MIPT_ int,const char *,big); +extern int big_to_bytes(_MIPT_ int,big,char *,BOOL); +extern mr_small normalise(_MIPT_ big,big); +extern void multiply(_MIPT_ big,big,big); +extern void fft_mult(_MIPT_ big,big,big); +extern BOOL fastmultop(_MIPT_ int,big,big,big); +extern void divide(_MIPT_ big,big,big); +extern BOOL divisible(_MIPT_ big,big); +extern void mad(_MIPT_ big,big,big,big,big,big); +extern int instr(_MIPT_ flash,char *); +extern int otstr(_MIPT_ flash,char *); +extern int cinstr(_MIPT_ flash,char *); +extern int cotstr(_MIPT_ flash,char *); +extern epoint* epoint_init(_MIPTO_ ); +extern epoint* epoint_init_mem(_MIPT_ char *,int); +extern void* ecp_memalloc(_MIPT_ int); +void ecp_memkill(_MIPT_ char *,int); +BOOL init_big_from_rom(big,int,const mr_small *,int ,int *); +BOOL init_point_from_rom(epoint *,int,const mr_small *,int,int *); + +#ifndef MR_NO_FILE_IO + +extern int innum(_MIPT_ flash,FILE *); +extern int otnum(_MIPT_ flash,FILE *); +extern int cinnum(_MIPT_ flash,FILE *); +extern int cotnum(_MIPT_ flash,FILE *); + +#endif + +/* Group 2 - Advanced arithmetic routines */ + +extern mr_small smul(mr_small,mr_small,mr_small); +extern mr_small spmd(mr_small,mr_small,mr_small); +extern mr_small invers(mr_small,mr_small); +extern mr_small sqrmp(mr_small,mr_small); +extern int jac(mr_small,mr_small); + +extern void gprime(_MIPT_ int); +extern int jack(_MIPT_ big,big); +extern int egcd(_MIPT_ big,big,big); +extern int xgcd(_MIPT_ big,big,big,big,big); +extern int invmodp(_MIPT_ big,big,big); +extern int logb2(_MIPT_ big); +extern int hamming(_MIPT_ big); +extern void expb2(_MIPT_ int,big); +extern void bigbits(_MIPT_ int,big); +extern void expint(_MIPT_ int,int,big); +extern void sftbit(_MIPT_ big,int,big); +extern void power(_MIPT_ big,long,big,big); +extern void powmod(_MIPT_ big,big,big,big); +extern void powmod2(_MIPT_ big,big,big,big,big,big); +extern void powmodn(_MIPT_ int,big *,big *,big,big); +extern int powltr(_MIPT_ int,big,big,big); +extern BOOL double_inverse(_MIPT_ big,big,big,big,big); +extern BOOL multi_inverse(_MIPT_ int,big*,big,big*); +extern void lucas(_MIPT_ big,big,big,big,big); +extern BOOL nroot(_MIPT_ big,int,big); +extern BOOL sqroot(_MIPT_ big,big,big); +extern void bigrand(_MIPT_ big,big); +extern void bigdig(_MIPT_ int,int,big); +extern int trial_division(_MIPT_ big,big); +extern BOOL isprime(_MIPT_ big); +extern BOOL nxprime(_MIPT_ big,big); +extern BOOL nxsafeprime(_MIPT_ int,int,big,big); +extern BOOL crt_init(_MIPT_ big_chinese *,int,big *); +extern void crt(_MIPT_ big_chinese *,big *,big); +extern void crt_end(big_chinese *); +extern BOOL scrt_init(_MIPT_ small_chinese *,int,mr_utype *); +extern void scrt(_MIPT_ small_chinese*,mr_utype *,big); +extern void scrt_end(small_chinese *); +#ifndef MR_STATIC +extern BOOL brick_init(_MIPT_ brick *,big,big,int,int); +extern void brick_end(brick *); +#else +extern void brick_init(brick *,const mr_small *,big,int,int); +#endif +extern void pow_brick(_MIPT_ brick *,big,big); +#ifndef MR_STATIC +extern BOOL ebrick_init(_MIPT_ ebrick *,big,big,big,big,big,int,int); +extern void ebrick_end(ebrick *); +#else +extern void ebrick_init(ebrick *,const mr_small *,big,big,big,int,int); +#endif +extern int mul_brick(_MIPT_ ebrick*,big,big,big); +#ifndef MR_STATIC +extern BOOL ebrick2_init(_MIPT_ ebrick2 *,big,big,big,big,int,int,int,int,int,int); +extern void ebrick2_end(ebrick2 *); +#else +extern void ebrick2_init(ebrick2 *,const mr_small *,big,big,int,int,int,int,int,int); +#endif +extern int mul2_brick(_MIPT_ ebrick2*,big,big,big); + +/* Montgomery stuff */ + +extern mr_small prepare_monty(_MIPT_ big); +extern void kill_monty(_MIPTO_ ); +extern void nres(_MIPT_ big,big); +extern void redc(_MIPT_ big,big); + +extern void nres_negate(_MIPT_ big,big); +extern void nres_modadd(_MIPT_ big,big,big); +extern void nres_modsub(_MIPT_ big,big,big); +extern void nres_lazy(_MIPT_ big,big,big,big,big,big); +extern void nres_complex(_MIPT_ big,big,big,big); +extern void nres_double_modadd(_MIPT_ big,big,big); +extern void nres_double_modsub(_MIPT_ big,big,big); +extern void nres_premult(_MIPT_ big,int,big); +extern void nres_modmult(_MIPT_ big,big,big); +extern int nres_moddiv(_MIPT_ big,big,big); +extern void nres_dotprod(_MIPT_ int,big *,big *,big); +extern void nres_powmod(_MIPT_ big,big,big); +extern void nres_powltr(_MIPT_ int,big,big); +extern void nres_powmod2(_MIPT_ big,big,big,big,big); +extern void nres_powmodn(_MIPT_ int,big *,big *,big); +extern BOOL nres_sqroot(_MIPT_ big,big); +extern void nres_lucas(_MIPT_ big,big,big,big); +extern BOOL nres_double_inverse(_MIPT_ big,big,big,big); +extern BOOL nres_multi_inverse(_MIPT_ int,big *,big *); +extern void nres_div2(_MIPT_ big,big); +extern void nres_div3(_MIPT_ big,big); +extern void nres_div5(_MIPT_ big,big); + +extern void shs_init(sha *); +extern void shs_process(sha *,int); +extern void shs_hash(sha *,char *); + +extern void shs256_init(sha256 *); +extern void shs256_process(sha256 *,int); +extern void shs256_hash(sha256 *,char *); + +#ifdef mr_unsign64 + +extern void shs512_init(sha512 *); +extern void shs512_process(sha512 *,int); +extern void shs512_hash(sha512 *,char *); + +extern void shs384_init(sha384 *); +extern void shs384_process(sha384 *,int); +extern void shs384_hash(sha384 *,char *); + +extern void sha3_init(sha3 *,int); +extern void sha3_process(sha3 *,int); +extern void sha3_hash(sha3 *,char *); + +#endif + +extern BOOL aes_init(aes *,int,int,char *,char *); +extern void aes_getreg(aes *,char *); +extern void aes_ecb_encrypt(aes *,MR_BYTE *); +extern void aes_ecb_decrypt(aes *,MR_BYTE *); +extern mr_unsign32 aes_encrypt(aes *,char *); +extern mr_unsign32 aes_decrypt(aes *,char *); +extern void aes_reset(aes *,int,char *); +extern void aes_end(aes *); + +extern void gcm_init(gcm *,int,char *,int,char *); +extern BOOL gcm_add_header(gcm *,char *,int); +extern BOOL gcm_add_cipher(gcm *,int,char *,int,char *); +extern void gcm_finish(gcm *,char *); + +extern void FPE_encrypt(int ,aes *,mr_unsign32 ,mr_unsign32 ,char *,int); +extern void FPE_decrypt(int ,aes *,mr_unsign32 ,mr_unsign32 ,char *,int); + +extern void strong_init(csprng *,int,char *,mr_unsign32); +extern int strong_rng(csprng *); +extern void strong_bigrand(_MIPT_ csprng *,big,big); +extern void strong_bigdig(_MIPT_ csprng *,int,int,big); +extern void strong_kill(csprng *); + +/* special modular multipliers */ + +extern void comba_mult(big,big,big); +extern void comba_square(big,big); +extern void comba_redc(_MIPT_ big,big); +extern void comba_modadd(_MIPT_ big,big,big); +extern void comba_modsub(_MIPT_ big,big,big); +extern void comba_double_modadd(_MIPT_ big,big,big); +extern void comba_double_modsub(_MIPT_ big,big,big); +extern void comba_negate(_MIPT_ big,big); +extern void comba_add(big,big,big); +extern void comba_sub(big,big,big); +extern void comba_double_add(big,big,big); +extern void comba_double_sub(big,big,big); + +extern void comba_mult2(_MIPT_ big,big,big); + +extern void fastmodmult(_MIPT_ big,big,big); +extern void fastmodsquare(_MIPT_ big,big); + +extern void kcm_mul(_MIPT_ big,big,big); +extern void kcm_sqr(_MIPT_ big,big); +extern void kcm_redc(_MIPT_ big,big); + +extern void kcm_multiply(_MIPT_ int,big,big,big); +extern void kcm_square(_MIPT_ int,big,big); +extern BOOL kcm_top(_MIPT_ int,big,big,big); + +/* elliptic curve stuff */ + +extern BOOL point_at_infinity(epoint *); + +extern void mr_jsf(_MIPT_ big,big,big,big,big,big); + +extern void ecurve_init(_MIPT_ big,big,big,int); +extern int ecurve_add(_MIPT_ epoint *,epoint *); +extern int ecurve_sub(_MIPT_ epoint *,epoint *); +extern void ecurve_double_add(_MIPT_ epoint *,epoint *,epoint *,epoint *,big *,big *); +extern void ecurve_multi_add(_MIPT_ int,epoint **,epoint **); +extern void ecurve_double(_MIPT_ epoint*); +extern int ecurve_mult(_MIPT_ big,epoint *,epoint *); +extern void ecurve_mult2(_MIPT_ big,epoint *,big,epoint *,epoint *); +extern void ecurve_multn(_MIPT_ int,big *,epoint**,epoint *); + +extern BOOL epoint_x(_MIPT_ big); +extern BOOL epoint_set(_MIPT_ big,big,int,epoint*); +extern int epoint_get(_MIPT_ epoint*,big,big); +extern void epoint_getxyz(_MIPT_ epoint *,big,big,big); +extern BOOL epoint_norm(_MIPT_ epoint *); +extern BOOL epoint_multi_norm(_MIPT_ int,big *,epoint **); +extern void epoint_free(epoint *); +extern void epoint_copy(epoint *,epoint *); +extern BOOL epoint_comp(_MIPT_ epoint *,epoint *); +extern void epoint_negate(_MIPT_ epoint *); + +extern BOOL ecurve2_init(_MIPT_ int,int,int,int,big,big,BOOL,int); +extern big ecurve2_add(_MIPT_ epoint *,epoint *); +extern big ecurve2_sub(_MIPT_ epoint *,epoint *); +extern void ecurve2_multi_add(_MIPT_ int,epoint **,epoint **); +extern void ecurve2_mult(_MIPT_ big,epoint *,epoint *); +extern void ecurve2_mult2(_MIPT_ big,epoint *,big,epoint *,epoint *); +extern void ecurve2_multn(_MIPT_ int,big *,epoint**,epoint *); + +extern epoint* epoint2_init(_MIPTO_ ); +extern BOOL epoint2_set(_MIPT_ big,big,int,epoint*); +extern int epoint2_get(_MIPT_ epoint*,big,big); +extern void epoint2_getxyz(_MIPT_ epoint *,big,big,big); +extern int epoint2_norm(_MIPT_ epoint *); +extern void epoint2_free(epoint *); +extern void epoint2_copy(epoint *,epoint *); +extern BOOL epoint2_comp(_MIPT_ epoint *,epoint *); +extern void epoint2_negate(_MIPT_ epoint *); + +/* GF(2) stuff */ + +extern BOOL prepare_basis(_MIPT_ int,int,int,int,BOOL); +extern int parity2(big); +extern BOOL multi_inverse2(_MIPT_ int,big *,big *); +extern void add2(big,big,big); +extern void incr2(big,int,big); +extern void reduce2(_MIPT_ big,big); +extern void multiply2(_MIPT_ big,big,big); +extern void modmult2(_MIPT_ big,big,big); +extern void modsquare2(_MIPT_ big,big); +extern void power2(_MIPT_ big,int,big); +extern void sqroot2(_MIPT_ big,big); +extern void halftrace2(_MIPT_ big,big); +extern BOOL quad2(_MIPT_ big,big); +extern BOOL inverse2(_MIPT_ big,big); +extern void karmul2(int,mr_small *,mr_small *,mr_small *,mr_small *); +extern void karmul2_poly(_MIPT_ int,big *,big *,big *,big *); +extern void karmul2_poly_upper(_MIPT_ int,big *,big *,big *,big *); +extern void gf2m_dotprod(_MIPT_ int,big *,big *,big); +extern int trace2(_MIPT_ big); +extern void rand2(_MIPT_ big); +extern void gcd2(_MIPT_ big,big,big); +extern int degree2(big); + +/* zzn2 stuff */ + +extern BOOL zzn2_iszero(zzn2 *); +extern BOOL zzn2_isunity(_MIPT_ zzn2 *); +extern void zzn2_from_int(_MIPT_ int,zzn2 *); +extern void zzn2_from_ints(_MIPT_ int,int,zzn2 *); +extern void zzn2_copy(zzn2 *,zzn2 *); +extern void zzn2_zero(zzn2 *); +extern void zzn2_negate(_MIPT_ zzn2 *,zzn2 *); +extern void zzn2_conj(_MIPT_ zzn2 *,zzn2 *); +extern void zzn2_add(_MIPT_ zzn2 *,zzn2 *,zzn2 *); +extern void zzn2_sub(_MIPT_ zzn2 *,zzn2 *,zzn2 *); +extern void zzn2_smul(_MIPT_ zzn2 *,big,zzn2 *); +extern void zzn2_mul(_MIPT_ zzn2 *,zzn2 *,zzn2 *); +extern void zzn2_sqr(_MIPT_ zzn2 *,zzn2 *); +extern void zzn2_inv(_MIPT_ zzn2 *); +extern void zzn2_timesi(_MIPT_ zzn2 *); +extern void zzn2_powl(_MIPT_ zzn2 *,big,zzn2 *); +extern void zzn2_from_zzns(big,big,zzn2 *); +extern void zzn2_from_bigs(_MIPT_ big,big,zzn2 *); +extern void zzn2_from_zzn(big,zzn2 *); +extern void zzn2_from_big(_MIPT_ big, zzn2 *); +extern void zzn2_sadd(_MIPT_ zzn2 *,big,zzn2 *); +extern void zzn2_ssub(_MIPT_ zzn2 *,big,zzn2 *); +extern void zzn2_div2(_MIPT_ zzn2 *); +extern void zzn2_div3(_MIPT_ zzn2 *); +extern void zzn2_div5(_MIPT_ zzn2 *); +extern void zzn2_imul(_MIPT_ zzn2 *,int,zzn2 *); +extern BOOL zzn2_compare(zzn2 *,zzn2 *); +extern void zzn2_txx(_MIPT_ zzn2 *); +extern void zzn2_txd(_MIPT_ zzn2 *); +extern BOOL zzn2_sqrt(_MIPT_ zzn2 *,zzn2 *); +extern BOOL zzn2_qr(_MIPT_ zzn2 *); +extern BOOL zzn2_multi_inverse(_MIPT_ int,zzn2 *,zzn2 *); + + +/* zzn3 stuff */ + +extern void zzn3_set(_MIPT_ int,big); +extern BOOL zzn3_iszero(zzn3 *); +extern BOOL zzn3_isunity(_MIPT_ zzn3 *); +extern void zzn3_from_int(_MIPT_ int,zzn3 *); +extern void zzn3_from_ints(_MIPT_ int,int,int,zzn3 *); +extern void zzn3_copy(zzn3 *,zzn3 *); +extern void zzn3_zero(zzn3 *); +extern void zzn3_negate(_MIPT_ zzn3 *,zzn3 *); +extern void zzn3_powq(_MIPT_ zzn3 *,zzn3 *); +extern void zzn3_add(_MIPT_ zzn3 *,zzn3 *,zzn3 *); +extern void zzn3_sub(_MIPT_ zzn3 *,zzn3 *,zzn3 *); +extern void zzn3_smul(_MIPT_ zzn3 *,big,zzn3 *); +extern void zzn3_mul(_MIPT_ zzn3 *,zzn3 *,zzn3 *); +extern void zzn3_inv(_MIPT_ zzn3 *); +extern void zzn3_timesi(_MIPT_ zzn3 *); +extern void zzn3_timesi2(_MIPT_ zzn3 *); +extern void zzn3_powl(_MIPT_ zzn3 *,big,zzn3 *); +extern void zzn3_from_zzns(big,big,big,zzn3 *); +extern void zzn3_from_bigs(_MIPT_ big,big,big,zzn3 *); +extern void zzn3_from_zzn(big,zzn3 *); +extern void zzn3_from_zzn_1(big,zzn3 *); +extern void zzn3_from_zzn_2(big,zzn3 *); +extern void zzn3_from_big(_MIPT_ big, zzn3 *); +extern void zzn3_sadd(_MIPT_ zzn3 *,big,zzn3 *); +extern void zzn3_ssub(_MIPT_ zzn3 *,big,zzn3 *); +extern void zzn3_div2(_MIPT_ zzn3 *); +extern void zzn3_imul(_MIPT_ zzn3 *,int,zzn3 *); +extern BOOL zzn3_compare(zzn3 *,zzn3 *); + +/* zzn4 stuff */ + +extern BOOL zzn4_iszero(zzn4 *); +extern BOOL zzn4_isunity(_MIPT_ zzn4 *); +extern void zzn4_from_int(_MIPT_ int,zzn4 *); +extern void zzn4_copy(zzn4 *,zzn4 *); +extern void zzn4_zero(zzn4 *); +extern void zzn4_negate(_MIPT_ zzn4 *,zzn4 *); +extern void zzn4_powq(_MIPT_ zzn2 *,zzn4 *); +extern void zzn4_add(_MIPT_ zzn4 *,zzn4 *,zzn4 *); +extern void zzn4_sub(_MIPT_ zzn4 *,zzn4 *,zzn4 *); +extern void zzn4_smul(_MIPT_ zzn4 *,zzn2 *,zzn4 *); +extern void zzn4_sqr(_MIPT_ zzn4 *,zzn4 *); +extern void zzn4_mul(_MIPT_ zzn4 *,zzn4 *,zzn4 *); +extern void zzn4_inv(_MIPT_ zzn4 *); +extern void zzn4_timesi(_MIPT_ zzn4 *); +extern void zzn4_tx(_MIPT_ zzn4 *); +extern void zzn4_from_zzn2s(zzn2 *,zzn2 *,zzn4 *); +extern void zzn4_from_zzn2(zzn2 *,zzn4 *); +extern void zzn4_from_zzn2h(zzn2 *,zzn4 *); +extern void zzn4_from_zzn(big,zzn4 *); +extern void zzn4_from_big(_MIPT_ big , zzn4 *); +extern void zzn4_sadd(_MIPT_ zzn4 *,zzn2 *,zzn4 *); +extern void zzn4_ssub(_MIPT_ zzn4 *,zzn2 *,zzn4 *); +extern void zzn4_div2(_MIPT_ zzn4 *); +extern void zzn4_conj(_MIPT_ zzn4 *,zzn4 *); +extern void zzn4_imul(_MIPT_ zzn4 *,int,zzn4 *); +extern void zzn4_lmul(_MIPT_ zzn4 *,big,zzn4 *); +extern BOOL zzn4_compare(zzn4 *,zzn4 *); + +/* ecn2 stuff */ + +extern BOOL ecn2_iszero(ecn2 *); +extern void ecn2_copy(ecn2 *,ecn2 *); +extern void ecn2_zero(ecn2 *); +extern BOOL ecn2_compare(_MIPT_ ecn2 *,ecn2 *); +extern void ecn2_norm(_MIPT_ ecn2 *); +extern void ecn2_get(_MIPT_ ecn2 *,zzn2 *,zzn2 *,zzn2 *); +extern void ecn2_getxy(ecn2 *,zzn2 *,zzn2 *); +extern void ecn2_getx(ecn2 *,zzn2 *); +extern void ecn2_getz(_MIPT_ ecn2 *,zzn2 *); +extern void ecn2_rhs(_MIPT_ zzn2 *,zzn2 *); +extern BOOL ecn2_set(_MIPT_ zzn2 *,zzn2 *,ecn2 *); +extern BOOL ecn2_setx(_MIPT_ zzn2 *,ecn2 *); +extern void ecn2_setxyz(_MIPT_ zzn2 *,zzn2 *,zzn2 *,ecn2 *); +extern void ecn2_negate(_MIPT_ ecn2 *,ecn2 *); +extern BOOL ecn2_add3(_MIPT_ ecn2 *,ecn2 *,zzn2 *,zzn2 *,zzn2 *); +extern BOOL ecn2_add2(_MIPT_ ecn2 *,ecn2 *,zzn2 *,zzn2 *); +extern BOOL ecn2_add1(_MIPT_ ecn2 *,ecn2 *,zzn2 *); +extern BOOL ecn2_add(_MIPT_ ecn2 *,ecn2 *); +extern BOOL ecn2_sub(_MIPT_ ecn2 *,ecn2 *); +extern BOOL ecn2_add_sub(_MIPT_ ecn2 *,ecn2 *,ecn2 *,ecn2 *); +extern int ecn2_mul2_jsf(_MIPT_ big,ecn2 *,big,ecn2 *,ecn2 *); +extern int ecn2_mul(_MIPT_ big,ecn2 *); +extern void ecn2_psi(_MIPT_ zzn2 *,ecn2 *); +extern BOOL ecn2_multi_norm(_MIPT_ int ,zzn2 *,ecn2 *); +extern int ecn2_mul4_gls_v(_MIPT_ big *,int,ecn2 *,big *,ecn2 *,zzn2 *,ecn2 *); +extern int ecn2_muln_engine(_MIPT_ int,int,int,int,big *,big *,big *,big *,ecn2 *,ecn2 *,ecn2 *); +extern void ecn2_precomp_gls(_MIPT_ int,BOOL,ecn2 *,zzn2 *,ecn2 *); +extern int ecn2_mul2_gls(_MIPT_ big *,ecn2 *,zzn2 *,ecn2 *); +extern void ecn2_precomp(_MIPT_ int,BOOL,ecn2 *,ecn2 *); +extern int ecn2_mul2(_MIPT_ big,int,ecn2 *,big,ecn2 *,ecn2 *); +#ifndef MR_STATIC +extern BOOL ecn2_brick_init(_MIPT_ ebrick *,zzn2 *,zzn2 *,big,big,big,int,int); +extern void ecn2_brick_end(ebrick *); +#else +extern void ebrick_init(ebrick *,const mr_small *,big,big,big,int,int); +#endif +extern void ecn2_mul_brick_gls(_MIPT_ ebrick *B,big *,zzn2 *,zzn2 *,zzn2 *); +extern void ecn2_multn(_MIPT_ int,big *,ecn2 *,ecn2 *); +extern void ecn2_mult4(_MIPT_ big *,ecn2 *,ecn2 *); +/* Group 3 - Floating-slash routines */ + +#ifdef MR_FLASH +extern void fpack(_MIPT_ big,big,flash); +extern void numer(_MIPT_ flash,big); +extern void denom(_MIPT_ flash,big); +extern BOOL fit(big,big,int); +extern void build(_MIPT_ flash,int (*)(_MIPT_ big,int)); +extern void mround(_MIPT_ big,big,flash); +extern void flop(_MIPT_ flash,flash,int *,flash); +extern void fmul(_MIPT_ flash,flash,flash); +extern void fdiv(_MIPT_ flash,flash,flash); +extern void fadd(_MIPT_ flash,flash,flash); +extern void fsub(_MIPT_ flash,flash,flash); +extern int fcomp(_MIPT_ flash,flash); +extern void fconv(_MIPT_ int,int,flash); +extern void frecip(_MIPT_ flash,flash); +extern void ftrunc(_MIPT_ flash,big,flash); +extern void fmodulo(_MIPT_ flash,flash,flash); +extern void fpmul(_MIPT_ flash,int,int,flash); +extern void fincr(_MIPT_ flash,int,int,flash); +extern void dconv(_MIPT_ double,flash); +extern double fdsize(_MIPT_ flash); +extern void frand(_MIPT_ flash); + +/* Group 4 - Advanced Flash routines */ + +extern void fpower(_MIPT_ flash,int,flash); +extern BOOL froot(_MIPT_ flash,int,flash); +extern void fpi(_MIPT_ flash); +extern void fexp(_MIPT_ flash,flash); +extern void flog(_MIPT_ flash,flash); +extern void fpowf(_MIPT_ flash,flash,flash); +extern void ftan(_MIPT_ flash,flash); +extern void fatan(_MIPT_ flash,flash); +extern void fsin(_MIPT_ flash,flash); +extern void fasin(_MIPT_ flash,flash); +extern void fcos(_MIPT_ flash,flash); +extern void facos(_MIPT_ flash,flash); +extern void ftanh(_MIPT_ flash,flash); +extern void fatanh(_MIPT_ flash,flash); +extern void fsinh(_MIPT_ flash,flash); +extern void fasinh(_MIPT_ flash,flash); +extern void fcosh(_MIPT_ flash,flash); +extern void facosh(_MIPT_ flash,flash); +#endif + + +/* Test predefined Macros to determine compiler type, and hopefully + selectively use fast in-line assembler (or other compiler specific + optimisations. Note I am unsure of Microsoft version numbers. So I + suspect are Microsoft. + + Note: It seems to be impossible to get the 16-bit Microsoft compiler + to allow inline 32-bit op-codes. So I suspect that INLINE_ASM == 2 will + never work with it. Pity. + +#define INLINE_ASM 1 -> generates 8086 inline assembly +#define INLINE_ASM 2 -> generates mixed 8086 & 80386 inline assembly, + so you can get some benefit while running in a + 16-bit environment on 32-bit hardware (DOS, Windows + 3.1...) +#define INLINE_ASM 3 -> generate true 80386 inline assembly - (Using DOS + extender, Windows '95/Windows NT) + Actually optimised for Pentium + +#define INLINE_ASM 4 -> 80386 code in the GNU style (for (DJGPP) + +Small, medium, compact and large memory models are supported for the +first two of the above. + +*/ + +/* To allow for inline assembly */ + +#ifdef __GNUC__ + #define ASM __asm__ __volatile__ +#endif + +#ifdef __TURBOC__ + #define ASM asm +#endif + +#ifdef _MSC_VER + #define ASM _asm +#endif + +#ifndef MR_NOASM + +/* Win64 - inline the time critical function */ +#ifndef MR_NO_INTRINSICS + #ifdef MR_WIN64 + #define muldvd(a,b,c,rp) (*(rp)=_umul128((a),(b),&(tm)),*(rp)+=(c),tm+=(*(rp)<(c)),tm) + #define muldvd2(a,b,c,rp) (tr=_umul128((a),(b),&(tm)),tr+=(*(c)),tm+=(tr<(*(c))),tr+=(*(rp)),tm+=(tr<(*(rp))),*(rp)=tr,*(c)=tm) + #endif + +/* Itanium - inline the time-critical functions */ + + #ifdef MR_ITANIUM + #define muldvd(a,b,c,rp) (tm=_m64_xmahu((a),(b),(c)),*(rp)=_m64_xmalu((a),(b),(c)),tm) + #define muldvd2(a,b,c,rp) (tm=_m64_xmalu((a),(b),(*(c))),*(c)=_m64_xmahu((a),(b),(*(c))),tm+=*(rp),*(c)+=(tm<*(rp)),*(rp)=tm) + #endif +#endif +/* + +SSE2 code. Works as for itanium - but in fact it is slower than the regular code so not recommended +Would require a call to emmintrin.h or xmmintrin.h, and an __m128i variable tm to be declared in effected +functions. But it works! + + #define muldvd(a,b,c,rp) (tm=_mm_add_epi64(_mm_mul_epu32(_mm_cvtsi32_si128((a)),_mm_cvtsi32_si128((b))),_mm_cvtsi32_si128((c))),*(rp)=_mm_cvtsi128_si32(tm),_mm_cvtsi128_si32(_mm_shuffle_epi32(tm,_MM_SHUFFLE(3,2,0,1))) ) + #define muldvd2(a,b,c,rp) (tm=_mm_add_epi64(_mm_add_epi64(_mm_mul_epu32(_mm_cvtsi32_si128((a)),_mm_cvtsi32_si128((b))),_mm_cvtsi32_si128(*(c))),_mm_cvtsi32_si128(*(rp))),*(rp)=_mm_cvtsi128_si32(tm),*(c)=_mm_cvtsi128_si32( _mm_shuffle_epi32(tm,_MM_SHUFFLE(3,2,0,1)) ) +*/ + +/* Borland C/Turbo C */ + + #ifdef __TURBOC__ + #ifndef __HUGE__ + #if defined(__COMPACT__) || defined(__LARGE__) + #define MR_LMM + #endif + + #if MIRACL==16 + #define INLINE_ASM 1 + #endif + + #if __TURBOC__>=0x410 + #if MIRACL==32 +#if defined(__SMALL__) || defined(__MEDIUM__) || defined(__LARGE__) || defined(__COMPACT__) + #define INLINE_ASM 2 + #else + #define INLINE_ASM 3 + #endif + #endif + #endif + #endif + #endif + +/* Microsoft C */ + + #ifdef _MSC_VER + #ifndef M_I86HM + #if defined(M_I86CM) || defined(M_I86LM) + #define MR_LMM + #endif + #if _MSC_VER>=600 + #if _MSC_VER<1200 + #if MIRACL==16 + #define INLINE_ASM 1 + #endif + #endif + #endif + #if _MSC_VER>=1000 + #if _MSC_VER<1500 + #if MIRACL==32 + #define INLINE_ASM 3 + #endif + #endif + #endif + #endif + #endif + +/* DJGPP GNU C */ + + #ifdef __GNUC__ + #ifdef i386 + #if MIRACL==32 + #define INLINE_ASM 4 + #endif + #endif + #endif + +#endif + + + +/* + The following contribution is from Tielo Jongmans, Netherlands + These inline assembler routines are suitable for Watcom 10.0 and up + + Added into miracl.h. Notice the override of the original declarations + of these routines, which should be removed. + + The following pragma is optional, it is dangerous, but it saves a + calling sequence +*/ + +/* + +#pragma off (check_stack); + +extern unsigned int muldiv(unsigned int, unsigned int, unsigned int, unsigned int, unsigned int *); +#pragma aux muldiv= \ + "mul edx" \ + "add eax,ebx" \ + "adc edx,0" \ + "div ecx" \ + "mov [esi],edx" \ + parm [eax] [edx] [ebx] [ecx] [esi] \ + value [eax] \ + modify [eax edx]; + +extern unsigned int muldvm(unsigned int, unsigned int, unsigned int, unsigned int *); +#pragma aux muldvm= \ + "div ebx" \ + "mov [ecx],edx" \ + parm [edx] [eax] [ebx] [ecx] \ + value [eax] \ + modify [eax edx]; + +extern unsigned int muldvd(unsigned int, unsigned int, unsigned int, unsigned int *); +#pragma aux muldvd= \ + "mul edx" \ + "add eax,ebx" \ + "adc edx,0" \ + "mov [ecx],eax" \ + "mov eax,edx" \ + parm [eax] [edx] [ebx] [ecx] \ + value [eax] \ + modify [eax edx]; + +*/ + + +#endif + + diff --git a/miracl/include/mirdef b/miracl/include/mirdef new file mode 100644 index 0000000..80cddc9 --- /dev/null +++ b/miracl/include/mirdef @@ -0,0 +1,30 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * This version suitable for use with most 32-bit computers + * e.g. 80386+ PC, VAX, ARM etc. Assembly language versions of muldiv, + * muldvm, muldvd and muldvd2 will be necessary. See mrmuldv.any + * + * Also suitable for DJGPP GNU C Compiler + * ... but change __int64 to long long + */ + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN /* This may need to be changed */ +#define mr_utype int + /* the underlying type is usually int * + * but see mrmuldv.any */ +#define mr_unsign32 unsigned int + /* 32 bit unsigned type */ +#define MR_IBITS 32 /* bits in int */ +#define MR_LBITS 32 /* bits in long */ +#define MR_FLASH 52 + /* delete this definition if integer * + * only version of MIRACL required */ + /* Number of bits per double mantissa */ + +#define mr_dltype __int64 /* ... or long long for Unix/Linux */ +#define mr_unsign64 unsigned __int64 + +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + + diff --git a/miracl/include/mirdef.arm b/miracl/include/mirdef.arm new file mode 100644 index 0000000..cb7daf6 --- /dev/null +++ b/miracl/include/mirdef.arm @@ -0,0 +1,22 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN + +/* or perhaps +#define MR_BIG_ENDIAN +*/ + +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype long long +#define mr_unsign64 unsigned long long +#define MR_NOASM +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + + diff --git a/miracl/include/mirdef.ash b/miracl/include/mirdef.ash new file mode 100644 index 0000000..1f07378 --- /dev/null +++ b/miracl/include/mirdef.ash @@ -0,0 +1,22 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype __int64 +#define mr_unsign64 unsigned __int64 +#define MR_STATIC 12 +#define MR_ALWAYS_BINARY +#define MR_NOASM +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_SHORT_OF_MEMORY +#define MR_AFFINE_ONLY +#define MR_NOSUPPORT_COMPRESSION diff --git a/miracl/include/mirdef.atm b/miracl/include/mirdef.atm new file mode 100644 index 0000000..92f0940 --- /dev/null +++ b/miracl/include/mirdef.atm @@ -0,0 +1,48 @@ +/* + mirdef.h file for Atmeg128 + +*/ + +#define MR_LITTLE_ENDIAN +#define MIRACL 8 +#define mr_utype char /* wordlength of processor */ +#define MR_IBITS 16 /* number of bits in int */ +#define MR_LBITS 32 /* number of bits in long */ +#define mr_unsign32 unsigned long /* unsigned 32-bit type */ +#define mr_dltype short /* double-length type (twice the number of bits of mr_utype) */ +#define MR_STATIC 21 /* 21*8 > 163 bits */ +#define MR_ALWAYS_BINARY +#define MR_NOASM /* no assembly language */ +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT /* multi-threaded */ +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_SHORT_OF_MEMORY +#define MR_NO_STANDARD_IO /* no printf support */ +#define MR_NO_FILE_IO /* no file support */ + +/* + +Delete the lines + +printf("Alice's Key= "); +otnum(mip,key,stdout); + + and + +printf("Bob's Key= "); +otnum(mip,key,stdout); + +from ecdh2m8.c + +Build a library from only + + mrcore.c + mrarth0.c + mrarth1.c + mrbits.c + mrecgf2m.c + +To find out basic RAM requirement, watch sizeof(miracl) + +*/ diff --git a/miracl/include/mirdef.bfp b/miracl/include/mirdef.bfp new file mode 100644 index 0000000..c1fe402 --- /dev/null +++ b/miracl/include/mirdef.bfp @@ -0,0 +1,24 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * + * This version of mirdef.h is for use with the Borland C compiler + * It uses a double underlying type, and using fast floating-point + * arithmetic (include mr87f.c in the library build) + * This will be fast for 512-bit arithmetic + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype double +#define mr_dltype long double +#define MR_NOFULLWIDTH +#define MR_FP +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned __int64 +#define MR_FP_ROUNDING +#define MR_FLASH 52 +#define MR_PENTIUM 18 +#define MAXBASE 536870912.0 + diff --git a/miracl/include/mirdef.bpp b/miracl/include/mirdef.bpp new file mode 100644 index 0000000..7ae0428 --- /dev/null +++ b/miracl/include/mirdef.bpp @@ -0,0 +1,21 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN + +/* or perhaps +#define MR_BIG_ENDIAN +*/ + +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype long long +#define mr_unsign64 unsigned long long +#define MR_NOASM +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + + diff --git a/miracl/include/mirdef.bs b/miracl/include/mirdef.bs new file mode 100644 index 0000000..4bda131 --- /dev/null +++ b/miracl/include/mirdef.bs @@ -0,0 +1,14 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype __int64 +#define mr_unsign64 unsigned __int64 +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define MR_FLASH 52 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 diff --git a/miracl/include/mirdef.ccc b/miracl/include/mirdef.ccc new file mode 100644 index 0000000..5eef371 --- /dev/null +++ b/miracl/include/mirdef.ccc @@ -0,0 +1,29 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * + * For typical 32-bit C-Only MIRACL library + */ + + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN + +/* or for most non-Intel processors +#define MR_BIG_ENDIAN +*/ + +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype __int64 + +/* or for gcc and most Unix +#define mr_dltype long long +*/ + +#define MR_NOASM +#define MR_FLASH 52 + +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + diff --git a/miracl/include/mirdef.cm b/miracl/include/mirdef.cm new file mode 100644 index 0000000..7d17b7b --- /dev/null +++ b/miracl/include/mirdef.cm @@ -0,0 +1,16 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype __int64 +#define mr_unsign64 unsigned __int64 +#define MR_FLASH 52 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_KCM 16 +#define MR_BITSINCHAR 8 diff --git a/miracl/include/mirdef.gcc b/miracl/include/mirdef.gcc new file mode 100644 index 0000000..f305095 --- /dev/null +++ b/miracl/include/mirdef.gcc @@ -0,0 +1,33 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * + * This version is suitable for use with the GCC compiler + * in a C/C++ only unix environment. + * Remove mrmuldv.c from the build + * + * For MS C on a PC, change BIG_ENDIAN to LITTLE_ENDIAN + * and "long long" to "__int64" + * + * Assembly language routines for the mrmuldv module will + * probably speed things up, so in most cases the generic + * mirdef.h32 file is appropriate + * + * NOT recommended for Linux on PCs - read linux.txt + * + * NOTE:- Read comments in miracl.mak unix make file + */ + + +#define MIRACL 32 +#define MR_BIG_ENDIAN /* This may need to be changed */ +#define mr_utype int +#define mr_unsign32 unsigned int +#define mr_dltype long long +#define mr_unsign64 unsigned long long +#define MR_IBITS 32 +#define MR_LBITS 32 +#define MR_NOASM +#define MR_FLASH 52 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + + diff --git a/miracl/include/mirdef.gen b/miracl/include/mirdef.gen new file mode 100644 index 0000000..22b1e8f --- /dev/null +++ b/miracl/include/mirdef.gen @@ -0,0 +1,17 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype __int64 +#define mr_unsign64 unsigned __int64 +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 16 +#define MR_BITSINCHAR 8 + diff --git a/miracl/include/mirdef.gfp b/miracl/include/mirdef.gfp new file mode 100644 index 0000000..9457a5c --- /dev/null +++ b/miracl/include/mirdef.gfp @@ -0,0 +1,20 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype __int64 +#define mr_unsign64 unsigned __int64 +#define MR_STATIC 16 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_NOASM +#define MR_BITSINCHAR 8 + diff --git a/miracl/include/mirdef.h b/miracl/include/mirdef.h new file mode 100644 index 0000000..80cddc9 --- /dev/null +++ b/miracl/include/mirdef.h @@ -0,0 +1,30 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * This version suitable for use with most 32-bit computers + * e.g. 80386+ PC, VAX, ARM etc. Assembly language versions of muldiv, + * muldvm, muldvd and muldvd2 will be necessary. See mrmuldv.any + * + * Also suitable for DJGPP GNU C Compiler + * ... but change __int64 to long long + */ + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN /* This may need to be changed */ +#define mr_utype int + /* the underlying type is usually int * + * but see mrmuldv.any */ +#define mr_unsign32 unsigned int + /* 32 bit unsigned type */ +#define MR_IBITS 32 /* bits in int */ +#define MR_LBITS 32 /* bits in long */ +#define MR_FLASH 52 + /* delete this definition if integer * + * only version of MIRACL required */ + /* Number of bits per double mantissa */ + +#define mr_dltype __int64 /* ... or long long for Unix/Linux */ +#define mr_unsign64 unsigned __int64 + +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + + diff --git a/miracl/include/mirdef.h16 b/miracl/include/mirdef.h16 new file mode 100644 index 0000000..ac7de51 --- /dev/null +++ b/miracl/include/mirdef.h16 @@ -0,0 +1,28 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * This version suitable for use with most 16-bit computers + * e.g. old IBM PCs. + */ + +#define MIRACL 16 + +#define MR_LITTLE_ENDIAN /* This may need to be changed */ +#define mr_utype int + /* the underlying type is usually int * + * but see mrmuldv.any */ +#define mr_dltype long + /* double length type */ +#define mr_unsign32 unsigned long + /* 32 bit unsigned type */ +#define MR_IBITS 16 /* bits in int */ +#define MR_LBITS 32 /* bits in long */ +#define MR_FLASH 52 + /* delete this definition if integer * + * only version of MIRACL required */ + /* Number of bits per double mantissa */ + +/* #define MR_NOASM * define this if using C code ONLY * + * mr_dltype must be defined */ + +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + diff --git a/miracl/include/mirdef.h32 b/miracl/include/mirdef.h32 new file mode 100644 index 0000000..80cddc9 --- /dev/null +++ b/miracl/include/mirdef.h32 @@ -0,0 +1,30 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * This version suitable for use with most 32-bit computers + * e.g. 80386+ PC, VAX, ARM etc. Assembly language versions of muldiv, + * muldvm, muldvd and muldvd2 will be necessary. See mrmuldv.any + * + * Also suitable for DJGPP GNU C Compiler + * ... but change __int64 to long long + */ + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN /* This may need to be changed */ +#define mr_utype int + /* the underlying type is usually int * + * but see mrmuldv.any */ +#define mr_unsign32 unsigned int + /* 32 bit unsigned type */ +#define MR_IBITS 32 /* bits in int */ +#define MR_LBITS 32 /* bits in long */ +#define MR_FLASH 52 + /* delete this definition if integer * + * only version of MIRACL required */ + /* Number of bits per double mantissa */ + +#define mr_dltype __int64 /* ... or long long for Unix/Linux */ +#define mr_unsign64 unsigned __int64 + +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + + diff --git a/miracl/include/mirdef.h64 b/miracl/include/mirdef.h64 new file mode 100644 index 0000000..02dd531 --- /dev/null +++ b/miracl/include/mirdef.h64 @@ -0,0 +1,14 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype long +#define mr_unsign64 unsigned long +#define MR_IBITS 32 +#define MR_LBITS 64 +#define mr_unsign32 unsigned int +#define MR_FLASH 52 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 diff --git a/miracl/include/mirdef.haf b/miracl/include/mirdef.haf new file mode 100644 index 0000000..ca388e3 --- /dev/null +++ b/miracl/include/mirdef.haf @@ -0,0 +1,32 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * This version suitable for use some 32-bit compilers + * which don't have a 64-bit type and for which assembly language versions + * of muldiv, muldvd, muldvm and muldvd2 are not available. + * See mrmuldv.any for details. + * This mode of operation is not recommended. + * + */ + +#define MIRACL 16 +#define MR_LITTLE_ENDIAN /* This may need to be changed */ + +#define mr_utype short + /* the underlying type is usually int * + * but see mrmuldv.any */ +#define mr_dltype long + /* double length type */ +#define mr_unsign32 unsigned int + /* 32 bit unsigned type */ +#define MR_IBITS 32 /* bits in int */ +#define MR_LBITS 32 /* bits in long */ +#define MR_FLASH 52 + /* delete this definition if integer * + * only version of MIRACL required */ + /* Number of bits per double mantissa */ + +#define MR_NOASM /* define this if using C code only * + * mr_dltype must be defined */ + +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + diff --git a/miracl/include/mirdef.hio b/miracl/include/mirdef.hio new file mode 100644 index 0000000..f6aee23 --- /dev/null +++ b/miracl/include/mirdef.hio @@ -0,0 +1,28 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * This version suitable for use with most 32-bit computers + * e.g. 80386+ PC, VAX, ARM etc. Assembly language versions of muldiv, + * muldvm, muldvd and muldvd2 will be necessary. See mrmuldv.any + * + * NOTE: This is for Integer-Only builds of the MIRACL library + * This will be slightly faster if flash arithmetic is not needed. + * + * Also suitable for DJGPP GNU C Compiler + * ... but change __int64 to long long + */ + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN /* This may need to be changed */ +#define mr_utype int + /* the underlying type is usually int * + * but see mrmuldv.any */ +#define mr_unsign32 unsigned int + /* 32 bit unsigned type */ +#define MR_IBITS 32 /* Bits in int */ +#define MR_LBITS 32 /* Bits in long */ + +#define mr_dltype __int64 /* ... or long long */ +#define mr_unsign64 unsigned __int64 + +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + diff --git a/miracl/include/mirdef.hpc b/miracl/include/mirdef.hpc new file mode 100644 index 0000000..3c4cb20 --- /dev/null +++ b/miracl/include/mirdef.hpc @@ -0,0 +1,27 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * This version suitable for use with computer such as IBM PC in which + * 32-bit longs can be manipulated directly, typically if the PC is + * 80386 based. + * + * Suitable assembly language versions of muldiv, muldvm, muldvd and muldvd2 + * will be necessary. See mrmuldv.any for details + */ + +#define MIRACL 32 + /* pseudo 32-bit working */ +#define MR_LITTLE_ENDIAN /* This may need to be changed */ +#define mr_utype long + /* the underlying type is usually int * + * but see mrmuldv.any */ +#define mr_unsign32 unsigned long + /* 32-bit unsigned type */ +#define MR_IBITS 16 /* bits in int */ +#define MR_LBITS 32 /* bits in long */ +#define MR_FLASH 52 + /* delete this definition if integer * + * only version of MIRACL required */ + /* Number of bits per double mantissa */ + +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + diff --git a/miracl/include/mirdef.hpp b/miracl/include/mirdef.hpp new file mode 100644 index 0000000..4ce88d5 --- /dev/null +++ b/miracl/include/mirdef.hpp @@ -0,0 +1,16 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * For C++ build of library + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype long +#define mr_unsign64 unsigned long +#define MR_IBITS 32 +#define MR_LBITS 64 +#define mr_unsign32 unsigned int +#define MR_FLASH 52 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_CPP diff --git a/miracl/include/mirdef.ibe b/miracl/include/mirdef.ibe new file mode 100644 index 0000000..ead4fc1 --- /dev/null +++ b/miracl/include/mirdef.ibe @@ -0,0 +1,17 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype __int64 +#define mr_unsign64 unsigned __int64 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_GENERIC_MT +#define MR_COMBA 16 +#define MR_BITSINCHAR 8 + diff --git a/miracl/include/mirdef.kep b/miracl/include/mirdef.kep new file mode 100644 index 0000000..4bdd0c9 --- /dev/null +++ b/miracl/include/mirdef.kep @@ -0,0 +1,23 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 8 +#define mr_utype char +#define MR_IBITS 16 /**/ +#define MR_LBITS 32 +#define mr_unsign32 unsigned long +#define mr_dltype int /**/ +#define mr_qltype long +#define MR_STATIC 128 +#define MR_ALWAYS_BINARY +#define MR_NOASM +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_KCM 16 +#define MR_BITSINCHAR 8 +#define MR_NO_STANDARD_IO +#define MR_NO_FILE_IO + diff --git a/miracl/include/mirdef.lnx b/miracl/include/mirdef.lnx new file mode 100644 index 0000000..5a3b465 --- /dev/null +++ b/miracl/include/mirdef.lnx @@ -0,0 +1,29 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * This version suitable for use with most 32-bit computers + * e.g. 80386+ PC, VAX, ARM etc. Assembly language versions of muldiv, + * muldvm, muldvd and muldvd2 will be necessary. See mrmuldv.any + * + * Suitable for Unix/Linux and for DJGPP GNU C Compiler + */ + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN /* This may need to be changed */ +#define mr_utype int + /* the underlying type is usually int * + * but see mrmuldv.any */ +#define mr_unsign32 unsigned int + /* 32 bit unsigned type */ +#define MR_IBITS 32 /* bits in int */ +#define MR_LBITS 32 /* bits in long */ +#define MR_FLASH 52 + /* delete this definition if integer * + * only version of MIRACL required */ + /* Number of bits per double mantissa */ + +#define mr_dltype long long /* ... or __int64 for Windows */ +#define mr_unsign64 unsigned long long + +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + + diff --git a/miracl/include/mirdef.mgw b/miracl/include/mirdef.mgw new file mode 100644 index 0000000..9214af7 --- /dev/null +++ b/miracl/include/mirdef.mgw @@ -0,0 +1,15 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype long long +#define mr_unsign64 unsigned long long +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define MR_FLASH 52 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 + diff --git a/miracl/include/mirdef.mgwn b/miracl/include/mirdef.mgwn new file mode 100644 index 0000000..54fa13a --- /dev/null +++ b/miracl/include/mirdef.mgwn @@ -0,0 +1,15 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype long long +#define mr_unsign64 unsigned long long +#define MR_IBITS 32 +#define MR_LBITS 64 +#define mr_unsign32 unsigned int +#define MR_FLASH 52 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 + diff --git a/miracl/include/mirdef.mik b/miracl/include/mirdef.mik new file mode 100644 index 0000000..06df66d --- /dev/null +++ b/miracl/include/mirdef.mik @@ -0,0 +1,20 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_dltype long long +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned long long +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 6 +#define MR_STATIC 6 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT + diff --git a/miracl/include/mirdef.mip b/miracl/include/mirdef.mip new file mode 100644 index 0000000..0abc350 --- /dev/null +++ b/miracl/include/mirdef.mip @@ -0,0 +1,17 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * Mips Version + */ + +#define MIRACL 32 +#define MR_BIG_ENDIAN /* This may need to be changed */ +#define mr_utype int +#define mr_unsign32 unsigned int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_dltype long long +#define mr_unsign64 unsigned long long +#define MR_ALWAYS_BINARY +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 16 +#define MR_BITSINCHAR 8 diff --git a/miracl/include/mirdef.mmm b/miracl/include/mirdef.mmm new file mode 100644 index 0000000..9aeba3d --- /dev/null +++ b/miracl/include/mirdef.mmm @@ -0,0 +1,30 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * This version suitable for use with most 32-bit computers + * e.g. 80386+ PC, VAX, ARM etc. Assembly language versions of muldiv, + * muldvm, muldvd and muldvd2 will be necessary. See mrmuldv.any + * + * Also suitable for DJGPP GNU C Compiler + * ... but change __int64 to long long + */ + +#define MIRACL 32 +#define MR_BIG_ENDIAN /* This may need to be changed */ +#define mr_utype int + /* the underlying type is usually int * + * but see mrmuldv.any */ +#define mr_unsign32 unsigned int + /* 32 bit unsigned type */ +#define MR_IBITS 32 /* bits in int */ +#define MR_LBITS 32 /* bits in long */ +#define MR_ALWAYS_BINARY + /* delete this definition if integer * + * only version of MIRACL required */ + /* Number of bits per double mantissa */ + +#define mr_dltype long long /* ... or long long for Unix/Linux */ +#define mr_unsign64 unsigned long long +#define MR_KCM 16 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + + diff --git a/miracl/include/mirdef.ol b/miracl/include/mirdef.ol new file mode 100644 index 0000000..0b57778 --- /dev/null +++ b/miracl/include/mirdef.ol @@ -0,0 +1,19 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define MR_STRIPPED_DOWN +#define mr_dltype __int64 +#define mr_unsign64 unsigned __int64 +#define MR_GENERIC_MT +#define MR_NOASM +#define MR_COMBA 16 +#define MR_BITSINCHAR 8 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + diff --git a/miracl/include/mirdef.pic b/miracl/include/mirdef.pic new file mode 100644 index 0000000..4273bdd --- /dev/null +++ b/miracl/include/mirdef.pic @@ -0,0 +1,28 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * This version suitable for use with most 32-bit computers + * e.g. 80386+ PC, VAX, ARM etc. Assembly language versions of muldiv, + * muldvm, muldvd and muldvd2 will be necessary. See mrmuldv.any + * + * Also suitable for DJGPP GNU C Compiler + * ... but change __int64 to long long + */ + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN /* This may need to be changed */ +#define mr_utype int + /* the underlying type is usually int * + * but see mrmuldv.any */ +#define mr_unsign32 unsigned int + /* 32 bit unsigned type */ +#define MR_IBITS 32 /* bits in int */ +#define MR_LBITS 32 /* bits in long */ + +#define mr_dltype long long /* ... or long long for Unix/Linux */ +#define mr_unsign64 unsigned long long +#define MR_NOASM + + +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + + diff --git a/miracl/include/mirdef.ppc b/miracl/include/mirdef.ppc new file mode 100644 index 0000000..d3ec71c --- /dev/null +++ b/miracl/include/mirdef.ppc @@ -0,0 +1,15 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_BIG_ENDIAN +#define MIRACL 64 +#define mr_utype long +#define MR_IBITS 32 +#define MR_LBITS 64 +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned long +#define MR_ALWAYS_BINARY +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_COMBA 8 diff --git a/miracl/include/mirdef.scr b/miracl/include/mirdef.scr new file mode 100644 index 0000000..d12f6f3 --- /dev/null +++ b/miracl/include/mirdef.scr @@ -0,0 +1,12 @@ +#define MIRACL 32 +#define MR_LITTLE_ENDIAN +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned __int64 +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MR_NO_STANDARD_IO +#define MR_KCM 16 +#define MAXBASE ((mr_utype)1<<(MIRACL-1)) diff --git a/miracl/include/mirdef.sjc b/miracl/include/mirdef.sjc new file mode 100644 index 0000000..add804f --- /dev/null +++ b/miracl/include/mirdef.sjc @@ -0,0 +1,31 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + * This version suitable for use with most 32-bit computers + * e.g. 80386+ PC, VAX, ARM etc. Assembly language versions of muldiv, + * muldvm, muldvd and muldvd2 will be necessary. See mrmuldv.any + * + * Also suitable for DJGPP GNU C Compiler + * ... but change __int64 to long long + */ + +#define MIRACL 32 +#define MR_BIG_ENDIAN /* This may need to be changed */ +#define mr_utype int + /* the underlying type is usually int * + * but see mrmuldv.any */ +#define mr_unsign32 unsigned int +#define MR_NOASM + /* 32 bit unsigned type */ +#define MR_IBITS 32 /* bits in int */ +#define MR_LBITS 32 /* bits in long */ +#define MR_ALWAYS_BINARY + /* delete this definition if integer * + * only version of MIRACL required */ + /* Number of bits per double mantissa */ + +#define mr_dltype long long /* ... or long long for Unix/Linux */ +#define mr_unsign64 unsigned long long + +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + + diff --git a/miracl/include/mirdef.tst b/miracl/include/mirdef.tst new file mode 100644 index 0000000..e69de29 diff --git a/miracl/include/mirdef.w64 b/miracl/include/mirdef.w64 new file mode 100644 index 0000000..66b573c --- /dev/null +++ b/miracl/include/mirdef.w64 @@ -0,0 +1,15 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype __int64 +#define mr_unsign64 unsigned __int64 +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define MR_FLASH 52 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 + diff --git a/miracl/include/mirdef.wpp b/miracl/include/mirdef.wpp new file mode 100644 index 0000000..359bafa --- /dev/null +++ b/miracl/include/mirdef.wpp @@ -0,0 +1,15 @@ +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype __int64 +#define mr_unsign64 unsigned __int64 +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define MR_FLASH 52 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_CPP diff --git a/miracl/include/zzn.h b/miracl/include/zzn.h new file mode 100644 index 0000000..850df10 --- /dev/null +++ b/miracl/include/zzn.h @@ -0,0 +1,219 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * + * MIRACL C++ Header file zzn.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class ZZn (Arithmetic mod n), using + * Montgomery's Method for modular multiplication + * NOTE : Must be used in conjunction with zzn.cpp + * The modulus n is always set dynamically (via the modulo() + * routine) - so beware the pitfalls implicit in declaring + * static or global ZZn's (which are initialised before n is + * set!). Uninitialised data is OK + */ + +#ifndef ZZN_H +#define ZZN_H + +#include "big.h" + +/* + +#ifdef ZZNS +#define MR_INIT_ZZN memset(mem,0,mr_big_reserve(1,ZZNS)); fn=(big)mirvar_mem_variable(mem,0,ZZNS); +#define MR_CLONE_ZZN(x) fn->len=x->len; for (int i=0;iw[i]=x->w[i]; +#define MR_ZERO_ZZN {fn->len=0; for (int i=0;iw[i]=0;} +#else +#define MR_INIT_ZZN mem=(char *)memalloc(1); fn=(big)mirvar_mem(mem,0); +#define MR_CLONE_ZZN(x) copy(x,fn); +#define MR_ZERO_ZZN zero(fn); +#endif + +*/ + +#ifdef ZZNS +#ifdef MR_COMBA +#define UZZNS ZZNS +#else +#define UZZNS ZZNS+1 // one extra required in case of carry overflow in addition +#endif +#endif + +#ifdef ZZNS +#define MR_INIT_ZZN fn=&b; b.w=a; b.len=UZZNS; +#define MR_CLONE_ZZN(x) b.len=x->len; for (int i=0;iw[i]; +#define MR_ZERO_ZZN {b.len=0; for (int i=0;i ZZn */ + ZZn(big& c) {MR_INIT_ZZN MR_CLONE_ZZN(c);} + ZZn(const ZZn& c) {MR_INIT_ZZN MR_CLONE_ZZN(c.fn);} + ZZn(char* s) {MR_INIT_ZZN cinstr(fn,s); nres(fn,fn);} + + ZZn& operator=(const ZZn& c) {MR_CLONE_ZZN(c.fn) return *this;} + ZZn& operator=(big c) {MR_CLONE_ZZN(c) return *this; } + + ZZn& operator=(int i) {if (i==0) MR_ZERO_ZZN else {convert(i,fn); nres(fn,fn);} return *this;} + ZZn& operator=(char* s){cinstr(fn,s); nres(fn,fn); return *this;} + + +/* Use fast in-line code */ + + ZZn& operator++() + {nres_modadd(fn,get_mip()->one,fn);return *this;} + ZZn& operator--() + {nres_modsub(fn,get_mip()->one,fn);return *this;} + ZZn& operator+=(int i) + {ZZn inc=i; nres_modadd(fn,inc.fn,fn);return *this;} + ZZn& operator-=(int i) + {ZZn dec=i; nres_modsub(fn,dec.fn,fn); return *this;} + ZZn& operator+=(const ZZn& b) + {nres_modadd(fn,b.fn,fn); return *this;} + ZZn& operator-=(const ZZn& b) + {nres_modsub(fn,b.fn,fn); return *this;} + ZZn& operator*=(const ZZn& b) + {nres_modmult(fn,b.fn,fn); return *this;} + ZZn& operator*=(int i) + {nres_premult(fn,i,fn); return *this;} + + ZZn& negate() + {nres_negate(fn,fn); return *this;} + + BOOL iszero() const; + + operator Big() {Big c; redc(fn,c.getbig()); return c;} /* ZZn -> Big */ + friend big getbig(ZZn& z) {return z.fn;} + + ZZn& operator/=(const ZZn& b) {nres_moddiv(fn,b.fn,fn); return *this;} + ZZn& operator/=(int); + + friend ZZn operator-(const ZZn&); + friend ZZn operator+(const ZZn&,int); + friend ZZn operator+(int, const ZZn&); + friend ZZn operator+(const ZZn&, const ZZn&); + + friend ZZn operator-(const ZZn&, int); + friend ZZn operator-(int, const ZZn&); + friend ZZn operator-(const ZZn&, const ZZn&); + + friend ZZn operator*(const ZZn&,int); + friend ZZn operator*(int, const ZZn&); + friend ZZn operator*(const ZZn&, const ZZn&); + + friend ZZn operator/(const ZZn&, int); + friend ZZn operator/(int, const ZZn&); + friend ZZn operator/(const ZZn&, const ZZn&); + + friend BOOL operator==(const ZZn& b1,const ZZn& b2) + { if (mr_compare(b1.fn,b2.fn)==0) return TRUE; else return FALSE;} + friend BOOL operator!=(const ZZn& b1,const ZZn& b2) + { if (mr_compare(b1.fn,b2.fn)!=0) return TRUE; else return FALSE;} + + friend ZZn one(void); + friend ZZn pow( const ZZn&, const Big&); + friend ZZn pow( const ZZn&,int); + friend ZZn powl(const ZZn&, const Big&); + friend ZZn pow( const ZZn&, const Big&, const ZZn&, const Big&); + friend ZZn pow( int,ZZn *,Big *); + friend int jacobi(const ZZn&); +#ifndef MR_NO_RAND + friend ZZn randn(void); // random number < modulus +#endif + friend BOOL qr(const ZZn&); // test for quadratic residue + friend BOOL qnr(const ZZn&); // test for quadratic non-residue + friend ZZn getA(void); // get A parameter of elliptic curve + friend ZZn getB(void); // get B parameter of elliptic curve + + friend ZZn sqrt(const ZZn&); // only works if modulus is prime + + friend ZZn luc( const ZZn& b1, const Big& b2, ZZn* b3=NULL) + { + ZZn z; if (b3!=NULL) nres_lucas(b1.fn,b2.getbig(),b3->fn,z.fn); + else nres_lucas(b1.fn,b2.getbig(),z.fn,z.fn); + return z; + } + + //friend ZZn luc( const ZZn&, const Big&, ZZn* b3=NULL); + + big getzzn(void) const; + +#ifndef MR_NO_STANDARD_IO + friend ostream& operator<<(ostream&,const ZZn&); +#endif + + + ~ZZn() + { + // MR_ZERO_ZZN // slower but safer +#ifndef ZZNS + mr_free(fn); +#endif + } +}; +#ifndef MR_NO_RAND +extern ZZn randn(void); +#endif +extern ZZn getA(void); +extern ZZn getB(void); +extern ZZn one(void); + +#endif + diff --git a/miracl/itanium.txt b/miracl/itanium.txt new file mode 100644 index 0000000..9d3b644 --- /dev/null +++ b/miracl/itanium.txt @@ -0,0 +1,96 @@ + +Itanium processor now fully supported using Intel C/C++ Compiler + +Use a header file like + +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype long +#define MR_IBITS 32 +#define MR_LBITS 64 +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned long +#define MR_FLASH 52 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define BITSINCHAR 8 + +and create file mrmuldv.c from Itanium source code in mrmuldv.any + +Note that this mrmuldv.c file only implements muldiv(.) and muldvm(.) +The other two functions - the time critical ones - muldvd(.) and muldvd2(.) +are inlined - see miracl.h + +Note that the above header file assumes an LP64-compatible compiler. +For an LLP64 compiler, change mr_utype to a 64-bit "long long" or __int64 + +There is also a macro file itanium.mcs - see kcmcomba.txt and makemcs.txt + + +To build the miracl library, extract below into a file "itanium" and execute + +bash itanium + + +------------------------------- + +rm miracl.a +icc -I. -c -O3 mrcore.c +icc -I. -c -O3 mrarth0.c +icc -I. -c -O3 mrarth1.c +icc -I. -c -O3 mrarth2.c +icc -I. -c -O3 mralloc.c +icc -I. -c -O3 mrsmall.c +icc -I. -c -O3 mrio1.c +icc -I. -c -O3 mrio2.c +icc -I. -c -O3 mrgcd.c +icc -I. -c -O3 mrjack.c +icc -I. -c -O3 mrxgcd.c +icc -I. -c -O3 mrarth3.c +icc -I. -c -O3 mrbits.c +icc -I. -c -O3 mrrand.c +icc -I. -c -O3 mrprime.c +icc -I. -c -O3 mrcrt.c +icc -I. -c -O3 mrscrt.c +icc -I. -c -O3 mrmonty.c +icc -I. -c -O3 mrpower.c +icc -I. -c -O3 mrcurve.c +icc -I. -c -O3 mrfast.c +icc -I. -c -O3 mrzzn2.c +icc -I. -c -O3 mrzzn2b.c +icc -I. -c -O3 mrzzn3.c +icc -I. -c -O3 mrecn2.c +icc -I. -c -O3 mrshs.c +icc -I. -c -O3 mrshs256.c +icc -I. -c -O3 mrshs512.c +icc -I. -c -O3 mraes.c +icc -I. -c -O3 mrgcm.c +icc -I. -c -O3 mrlucas.c +icc -I. -c -O3 mrstrong.c +icc -I. -c -O3 mrbrick.c +icc -I. -c -O3 mrebrick.c +icc -I. -c -O3 mrec2m.c +icc -I. -c -O3 mrgf2m.c +icc -I. -c -O3 mrflash.c +icc -I. -c -O3 mrfrnd.c +icc -I. -c -O3 mrdouble.c +icc -I. -c -O3 mrround.c +icc -I. -c -O3 mrbuild.c +icc -I. -c -O3 mrflsh1.c +icc -I. -c -O3 mrpi.c +icc -I. -c -O3 mrflsh2.c +icc -I. -c -O3 mrflsh3.c +icc -I. -c -O3 mrflsh4.c +icc -I. -c -O3 mrmuldv.c +ar rc miracl.a mrcore.o mrarth0.o mrarth1.o mrarth2.o mralloc.o mrsmall.o mrgcm.o +ar r miracl.a mrio1.o mrio2.o mrjack.o mrgcd.o mrxgcd.o mrarth3.o mrbits.o mrzzn2b.o +ar r miracl.a mrrand.o mrprime.o mrcrt.o mrscrt.o mrmonty.o mrcurve.o mrzzn2.o mrzzn3.o +ar r miracl.a mrpower.o mrfast.o mrshs.o mrshs256.o mraes.o mrlucas.o mrstrong.o mrecn2.o +ar r miracl.a mrflash.o mrfrnd.o mrdouble.o mrround.o mrbuild.o +ar r miracl.a mrflsh1.o mrpi.o mrflsh2.o mrflsh3.o mrflsh4.o +ar r miracl.a mrbrick.o mrebrick.o mrgf2m.o mrec2m.o mrshs512.o mrmuldv.o +icc -I. -O3 factor.c miracl.a -lm -o factor +rm mr*.o + +---------------------------------------------------- + + diff --git a/miracl/kcmcomba.txt b/miracl/kcmcomba.txt new file mode 100644 index 0000000..2039b2c --- /dev/null +++ b/miracl/kcmcomba.txt @@ -0,0 +1,104 @@ +In embedded applications on low-powered processors, performance is a big +issue. Using either the KCM or Comba methods as described here can increase +speeds 4-fold. + +To use the super-fast KCM (for 2048-bit RSA 1024-bit DH and DSS) and Comba +(for 1024 bit RSA and GF(p) Elliptic curves) methods you will need to create +the file mrkcm.c or the file mrcomba.c for inclusion in the MIRACL library. +This is done by inserting 'macros' from a ?.mcs file into the template files +mrkcm.tpl, or mrcomba.tpl. This is done automatically using the MEX utility. + +A c.mcs file is supplied, which contains C macros. Also c1.mcs which uses +an alternate approach. See also cs.mcs (read the comments at the top). +If a quad-length type is available (mr_qltype defined in mirdef.h), +use c2.mcs + +However the best performance is usually achieved by +using assembly language macros. This requires your compiler to support in-line +assembly. For example the file ms86.mcs inserts Pentium assembly language +macros for use with Microsoft or Borland compilers. The file gcc386.mcs does +the same for the gcc compiler. If your PC supports SSE2 extensions, for +example if it is a Pentium 4, then instead use either sse2.mcs or gccsse2.mcs +(see sse2.txt). The file arm.mcs does the same for the popular 32-bit ARM +processor. Other .mcs files for other processors/compilers may be available. +See makemcs.txt for instructions for creating your own. + +New! The files c.mcs and arm.mcs now allow "interleaved" multiplication steps +to facilitate improved processor scheduling - see makemcs.txt. + +The macro expansion is carried out automatically by the supplied program +MEX.C. You must compile and run this program. If you use the config.c +utility it will advise you on the parameters to use. Note that although +config.c should be compiled and run on the target processor, mex.c can be +compiled and run on any workstation. + +For example + +c:>mex 6 ms86 mrcomba + +creates a file mrcomba.c from mrcomba.tpl and ms86.mcs. The Comba method will +then be optimised for a modulus of 6*32 = 192 bits on a Pentium computer. +Typically this might be used for an implementation of elliptic curves over +GF(p) for p a 192 bit prime. Note that the code generated in mrcomba.c or +mrkcm.c may benefit to a small extent from some manual post-optimisation. +Re-ordering instructions may help for certain processors. + +c:>mex 16 ms86 mrkcm + +creates a file mrkcm.c from mrkcm.tpl and ms86.mcs. The KCM method will then +be optimised for moduli of sizes 512, 1024, 2048 bits etc. Typically this +might be used for a fast implementation of RSA, DSS or Diffie-Hellman. + +For the Comba method only it is possible to implement special modular +reduction methods for a modulus p of a particular form. Two types of special +modulus are supported, Generalised Mersenne Primes, and Pseudo-Mersenne +Primes. To make use of this feature MR_SPECIAL must be defined in mirdef.h. + +Generalised Mersenne Primes are also known as Solinas primes. These are of a +form like for example 2#224-2#96+1. Note that the exponents are multiples of +a 32-bit word length. Many of the NIST recommended primes are of this form. +In the file mrcomba.tpl code can be found to implement fast reduction with +respect to many different GM primes, and for many different word lengths. +If the particular one you want is not there, it is not hard to implement it +yourself by manually editing the file mrcomba.tpl + +Pseudo Mersenne Primes are also known as Crandall Primes. These are of a form +like for example 2^160-57, where 160 is a multiple of the word length, and the +constant 57 is small enough to fit into one computer word. Moduli of this +form are automatically supported if you define MR_PSEUDO_MERSENNE in mirdef.h + +As always it is best to use config.c, which guides you through all of this. + + +You will find it valuable to run through this whole process on a standard PC +using perhaps the Microsoft C/C++ compiler, just to get familiar with the +config.c and mex.c utilities. + +If you are embarking on an embedded project using a processor for which a +.mcs file does not exist, you will have to write your own, or be content with +the C macros. Note that this approach is likely to be optimal only on +processors that support an unsigned multiply instruction. +This is probably the case with the majority of embedded processors (e.g. ARM, +68000 variants etc). It is also important that the compiler support inline +assembly, via something like + +asm(" "); + +or + +__asm + +{ +} + +constructs in C. However other approaches are possible, for example using C +"intrinsics" works well for the itanium - see itanium.mcs + +To write your own .mcs file, use c.mcs or arm.mcs as models. For more +background read the article ftp.computing.dcu.ie/pub/crypto/timings.doc + +The macro-expansion mechanism has been designed to make it as easy as +possible for the developer to write optimal code for best performance. +See makemcs.txt + + diff --git a/miracl/lib/bc32doit.bat b/miracl/lib/bc32doit.bat new file mode 100644 index 0000000..2b53e5d --- /dev/null +++ b/miracl/lib/bc32doit.bat @@ -0,0 +1,108 @@ +rem MIRACL - IBM PC/MS-DOS Version 4.0 +rem This batch files creates 80386 version of miracl.lib from its component +rem parts using the 32-bit Borland C++ V4.02 (or greater) compiler BCC32 +rem +rem Read your compiler documentation for further information +rem +rem Invoke as "bc32doit" from a command prompt (MS-DOS) window. It is assumed +rem that paths have been correctly set up to the compiler, librarian, linker +rem and assembler. Make sure that the compiler can find the MIRACL header +rem files mirdef.h/miracl.h/big.h etc. +rem The simplest way to do this is to put them into the \bcXX\include\ +rem directory where the standard C header files such as stdio.h are kept. +rem +rem Provided mainly as a guide for creating a batch file tailored +rem specifically to your own configuration. +rem +rem Note - the module mrmuldv.c is not needed if MR_NOASM is defined +rem Note - one of the modules mrkcm.c mrcomba.c mr87v.c or mr87f.c may be +rem required to implement special methods for modular exponentiation +rem Note - If config.c was used to generate mirdef.h - then only those modules +rem listed in miracl.lst should be included in the library build +rem Note - If building C only version (MR_NOASM), remove the -B flag, as +rem this invokes the assembler TASM +rem +rem Compile MIRACL modules +copy mirdef.h32 mirdef.h +bcc32 -c -O2 mrcore.c +bcc32 -c -O2 mrarth0.c +bcc32 -c -O2 -B mrarth1.c +bcc32 -c -O2 -B mrarth2.c +bcc32 -c -O2 mralloc.c +bcc32 -c -O2 mrsmall.c +bcc32 -c -O2 mrio1.c +bcc32 -c -O2 mrio2.c +bcc32 -c -O2 mrgcd.c +bcc32 -c -O2 mrjack.c +bcc32 -c -O2 mrxgcd.c +bcc32 -c -O2 mrarth3.c +bcc32 -c -O2 mrbits.c +bcc32 -c -O2 mrrand.c +bcc32 -c -O2 mrprime.c +bcc32 -c -O2 mrcrt.c +bcc32 -c -O2 -B mrscrt.c +bcc32 -c -O2 -B mrmonty.c +bcc32 -c -O2 mrpower.c +bcc32 -c -O2 mrsroot.c +bcc32 -c -O2 mrcurve.c +bcc32 -c -O2 -B mrfast.c +bcc32 -c -O2 mrshs.c +bcc32 -c -O2 mrshs256.c +bcc32 -c -O2 mrshs512.c +bcc32 -c -O2 mrsha3.c +bcc32 -c -O2 mrfpe.c +bcc32 -c -O2 mraes.c +bcc32 -c -O2 mrgcm.c +bcc32 -c -O2 mrstrong.c +bcc32 -c -O2 mrlucas.c +bcc32 -c -O2 mrzzn2.c +bcc32 -c -O2 mrzzn2b.c +bcc32 -c -O2 mrzzn3.c +bcc32 -c -O2 mrzzn4.c +bcc32 -c -O2 mrbrick.c +bcc32 -c -O2 mrebrick.c +bcc32 -c -O2 mrec2m.c +bcc32 -c -O2 mrecn2.c +bcc32 -c -O2 mrgf2m.c +bcc32 -c -O2 mrflash.c +bcc32 -c -O2 mrfrnd.c +bcc32 -c -O2 mrdouble.c +bcc32 -c -O2 mrround.c +bcc32 -c -O2 mrbuild.c +bcc32 -c -O2 mrflsh1.c +bcc32 -c -O2 mrpi.c +bcc32 -c -O2 mrflsh2.c +bcc32 -c -O2 mrflsh3.c +bcc32 -c -O2 mrflsh4.c +rem bcc32 -c -O2 -B mrkcm.c +rem +rem Assemble mrmuldv.c ; be careful to use correct version from mrmuldv.any +copy mrmuldv.c32 mrmuldv.c +bcc32 -c -B mrmuldv.c +rem +rem Create library 'miracl.lib' +del miracl.lib +tlib miracl +tlib miracl +mrflsh4+mrflsh3+mrflsh2+mrpi+mrflsh1 +tlib miracl +mrdouble+mrflash+mrfrnd+mrround+mrbuild +tlib miracl +mrio2+mrio1+mrrand+mrprime+mrcrt+mrscrt+mrfast+mrbits +tlib miracl +mrjack+mrxgcd+mrgcd+mrarth3+mrarth2+mrpower+mrsroot +tlib miracl +mrmonty+mralloc+mrarth1+mrarth0+mrsmall+mrcore+mrmuldv +tlib miracl +mrcurve+mrshs+mraes+mrlucas+mrstrong+mrbrick+mrshs256+mrgcm+mrfpe+mrsha3 +tlib miracl +mrshs512+mrebrick+mrec2m+mrgf2m+mrzzn2+mrzzn3+mrecn2+mrzzn2b+mrzzn4 +rem tlib miracl +mrkcm +del mr*.obj +bcc32 -c -O2 big +bcc32 -c -O2 crt +bcc32 -c -O2 zzn +bcc32 -c -O2 ecn +bcc32 -c -O2 ec2 +bcc32 brent big.obj zzn.obj miracl.lib +bcc32 pk-demo big.obj crt.obj ecn.obj miracl.lib +bcc32 bmark.c miracl.lib +bcc32 -c -O2 flash +bcc32 sample flash.obj miracl.lib +bcc32 ecsgen ecn.obj big.obj miracl.lib +bcc32 ecsign ecn.obj big.obj miracl.lib +bcc32 ecsver ecn.obj big.obj miracl.lib + diff --git a/miracl/lib/bcldoit.bat b/miracl/lib/bcldoit.bat new file mode 100644 index 0000000..af44a0b --- /dev/null +++ b/miracl/lib/bcldoit.bat @@ -0,0 +1,100 @@ +rem MIRACL - IBM PC/MS-DOS Version 4.0 +rem This batch files creates the large memory model version of miracl.lib +rem from its component parts using the Borland C++ V3.1 (or greater) compiler +rem Also included are the commands to create some of the example programs +rem Use with typically mirdef.h16 +rem +rem Read your compiler documentation for further information +rem +rem Invoke as "bcldoit". It is assumed that paths have been correctly set up to +rem the compiler, librarian and linker. +rem +rem Provided mainly as a guide for creating a batch file tailored +rem specifically to your own configuration. +rem +rem Note - the module mrmuldv.c is not needed if MR_NOASM is defined +rem +rem Compile MIRACL modules +bcc -ml -c -O mrcore.c +bcc -ml -c -O mrarth0.c +bcc -ml -c -O mrarth1.c +bcc -ml -c -O mrarth2.c +bcc -ml -c -O mralloc.c +bcc -ml -c -O mrsmall.c +bcc -ml -c -O mrio1.c +bcc -ml -c -O mrio2.c +bcc -ml -c -O mrgcd.c +bcc -ml -c -O mrjack.c +bcc -ml -c -O mrxgcd.c +bcc -ml -c -O mrarth3.c +bcc -ml -c -O mrbits.c +bcc -ml -c -O mrrand.c +bcc -ml -c -O mrprime.c +bcc -ml -c -O mrcrt.c +bcc -ml -c -O mrscrt.c +bcc -ml -c -O mrmonty.c +bcc -ml -c -O mrpower.c +bcc -ml -c -O mrsroot.c +bcc -ml -c -O mrcurve.c +bcc -ml -c -O mrfast.c +bcc -ml -c -O mrlucas.c +bcc -ml -c -O mrzzn2.c +bcc -ml -c -O mrzzn3.c +bcc -ml -c -O mrzzn4.c +bcc -ml -c -O mrecn2.c +bcc -ml -c -O mrshs.c +bcc -ml -c -O mrshs256.c +bcc -ml -c -O mrfpe.c +bcc -ml -c -O mraes.c +bcc -ml -c -O mrgcm.c +bcc -ml -c -O mrstrong.c +bcc -ml -c -O mrbrick.c +bcc -ml -c -O mrebrick.c +bcc -ml -c -O mrec2m.c +bcc -ml -c -O mrgf2m.c +bcc -ml -c -O mrflash.c +bcc -ml -c -O mrfrnd.c +bcc -ml -c -O mrdouble.c +bcc -ml -c -O mrround.c +bcc -ml -c -O mrbuild.c +bcc -ml -c -O mrflsh1.c +bcc -ml -c -O mrpi.c +bcc -ml -c -O mrflsh2.c +bcc -ml -c -O mrflsh3.c +bcc -ml -c -O mrflsh4.c +rem +rem Assemble mrmuldv.c - use inline assembly version +bcc -ml -c mrmuldv.c +rem +rem Create library 'miracl.lib' +del miracl.lib +tlib miracl +tlib miracl +mrflsh4+mrflsh3+mrflsh2+mrpi+mrflsh1+mrfrnd+mrround+mrbuild +tlib miracl +mrdouble+mrflash +tlib miracl +mrio2+mrio1+mrrand+mrprime+mrcrt+mrscrt+mrfast+mrgcm+mrfpe +tlib miracl +mrjack+mrxgcd+mrgcd+mrarth3+mrarth2+mrpower+mrsroot+mrbits+mrecn2 +tlib miracl +mrmonty+mralloc+mrarth1+mrarth0+mrsmall+mrcore+mrmuldv+mrzzn2+mrzzn3+mrzzn4 +tlib miracl +mrcurve+mrshs+mrshs256+mraes+mrlucas+mrstrong+mrbrick+mrebrick+mrec2m+mrgf2m +del mr*.obj +rem +rem Compile and link C++ versions of example programs where possible +bcc -ml -c big +bcc -ml -c zzn +bcc -ml -c crt +bcc -ml brute big.obj miracl.lib +bcc -ml brent big.obj zzn.obj miracl.lib +bcc -ml pollard big.obj zzn.obj miracl.lib +bcc -ml genkey big.obj miracl.lib +bcc -ml encode big.obj miracl.lib +bcc -ml decode crt.obj big.obj miracl.lib +bcc -ml enciph.c miracl.lib +bcc -ml deciph.c miracl.lib +bcc -ml palin big.obj miracl.lib +bcc -ml dssetup big.obj miracl.lib +bcc -ml dssign big.obj miracl.lib +bcc -ml dssver big.obj miracl.lib +bcc -ml dssgen big.obj miracl.lib +bcc -ml -c flash +bcc -ml sample flash.obj miracl.lib +bcc -ml ratcalc.c miracl.lib + diff --git a/miracl/lib/bcxdoit.bat b/miracl/lib/bcxdoit.bat new file mode 100644 index 0000000..a72f8df --- /dev/null +++ b/miracl/lib/bcxdoit.bat @@ -0,0 +1,88 @@ +rem MIRACL - IBM PC/MS-DOS Version 4.0 +rem This batch files creates large memory model 80386 version of miracl.lib +rem from its component parts using the Borland C++ V3.1 (or greater) compiler +rem Use typically with mirdef.hpc +rem +rem Read your compiler documentation for further information +rem +rem Invoke as "bcxdoit". It is assumed that paths have been correctly set up to +rem the compiler, librarian and linker. +rem +rem Provided mainly as a guide for creating a batch file tailored +rem specifically to your own configuration. +rem +rem Note - the module mrmuldv.c is not needed if MR_NOASM is defined +rem Note - one of the modules mrkcm.c mrcomba.c mr87v.c or mr87f.c may be +rem required to implement special methods for modular exponentiation +rem +rem Compile MIRACL modules +bcc -ml -c -3 -O mrcore.c +bcc -ml -c -3 -O mrarth0.c +bcc -ml -c -3 -O -B mrarth1.c +bcc -ml -c -3 -O -B mrarth2.c +bcc -ml -c -3 -O mralloc.c +bcc -ml -c -3 -O mrsmall.c +bcc -ml -c -3 -O mrio1.c +bcc -ml -c -3 -O mrio2.c +bcc -ml -c -3 -O mrgcd.c +bcc -ml -c -3 -O mrjack.c +bcc -ml -c -3 -O mrxgcd.c +bcc -ml -c -3 -O mrarth3.c +bcc -ml -c -3 -O mrbits.c +bcc -ml -c -3 -O mrrand.c +bcc -ml -c -3 -O mrprime.c +bcc -ml -c -3 -O mrcrt.c +bcc -ml -c -3 -O mrscrt.c +bcc -ml -c -3 -O -B mrmonty.c +bcc -ml -c -3 -O mrpower.c +bcc -ml -c -3 -O mrsroot.c +bcc -ml -c -3 -O mrcurve.c +bcc -ml -c -3 -O mrfast.c +bcc -ml -c -3 -O mrshs.c +bcc -ml -c -3 -O mrshs256.c +bcc -ml -c -3 -O mrfpe.c +bcc -ml -c -3 -O mraes.c +bcc -ml -c -3 -O mrgcm.c +bcc -ml -c -3 -O mrlucas.c +bcc -ml -c -3 -O mrzzn2.c +bcc -ml -c -3 -O mrzzn3.c +bcc -ml -c -3 -O mrzzn4.c +bcc -ml -c -3 -O mrecn2.c +bcc -ml -c -3 -O mrstrong.c +bcc -ml -c -3 -O mrbrick.c +bcc -ml -c -3 -O mrebrick.c +bcc -ml -c -3 -O mrec2m.c +bcc -ml -c -3 -O mrgf2m.c +bcc -ml -c -3 -O mrflash.c +bcc -ml -c -3 -O mrfrnd.c +bcc -ml -c -3 -O mrdouble.c +bcc -ml -c -3 -O mrround.c +bcc -ml -c -3 -O mrbuild.c +bcc -ml -c -3 -O mrflsh1.c +bcc -ml -c -3 -O mrpi.c +bcc -ml -c -3 -O mrflsh2.c +bcc -ml -c -3 -O mrflsh3.c +bcc -ml -c -3 -O mrflsh4.c +rem +rem Assemble mrmuldv.c ; use inline assembly version +bcc -ml -c -3 -B mrmuldv.c +rem tasm -ml mrmuldv.c +rem +rem Create library 'miracl.lib' +del miracl.lib +tlib miracl +tlib miracl +mrflsh4+mrflsh3+mrflsh2+mrpi+mrflsh1 +tlib miracl +mrdouble+mrflash+mrfrnd+mrround+mrbuild +tlib miracl +mrio2+mrio1+mrrand+mrprime+mrcrt+mrscrt+mrfast+mrgcm+mrfpe +tlib miracl +mrjack+mrxgcd+mrgcd+mrarth3+mrarth2+mrpower+mrsroot+mrbits+mrecn2 +tlib miracl +mrmonty+mralloc+mrarth1+mrarth0+mrsmall+mrcore+mrmuldv+mrzzn2+mrzzn3+mrzzn4 +tlib miracl +mrcurve+mrshs+mrshs256+mraes+mrlucas+mrstrong+mrbrick+mrebrick+mrgf2m+mrec2m +del mr*.obj +bcc -ml -c -3 -O big +bcc -ml -c -3 -O crt +bcc -ml -c -3 -O zzn +rem compile a couple of example programs +bcc -ml brent big.obj zzn.obj miracl.lib +bcc -ml -c -3 -O flash +bcc -ml sample flash.obj miracl.lib + diff --git a/miracl/lib/gcdoit.bat b/miracl/lib/gcdoit.bat new file mode 100644 index 0000000..9b7d8e4 --- /dev/null +++ b/miracl/lib/gcdoit.bat @@ -0,0 +1,95 @@ +rem MIRACL - IBM PC/MS-DOS Version 4.0 +rem This batch files creates 80386 version of miracl.lib from its component +rem parts using the 32-bit DJGPP C/C++ V2.01 (or greater) compiler GCC +rem +rem Read your compiler documentation for further information +rem +rem Invoke as "gcdoit". It is assumed that paths have been correctly set up to +rem the compiler, librarian and linker. +rem +rem Provided mainly as a guide for creating a batch file tailored +rem specifically to your own configuration. +rem +rem Note - the module mrmuldv.c is not needed if MR_NOASM is defined +rem Note - the inline assember and the optimizer don't seem to co-exist +rem happily +rem +rem Use with mirdef.h32 - but ensure 64-bit type is defined as long long +rem (not __int64) +rem +rem Compile MIRACL modules +del miracl.a +copy mirdef.lnx mirdef.h +gcc -c -O2 mrcore.c +gcc -c -O2 mrarth0.c +gcc -c -O2 mrarth1.c +gcc -c -O2 mrarth2.c +gcc -c -O2 mralloc.c +gcc -c -O2 mrsmall.c +gcc -c -O2 mrio1.c +gcc -c -O2 mrio2.c +gcc -c -O2 mrgcd.c +gcc -c -O2 mrjack.c +gcc -c -O2 mrxgcd.c +gcc -c -O2 mrarth3.c +gcc -c -O2 mrbits.c +gcc -c -O2 mrrand.c +gcc -c -O2 mrprime.c +gcc -c -O2 mrcrt.c +gcc -c -O2 mrscrt.c +gcc -c -O2 mrmonty.c +gcc -c -O2 mrpower.c +gcc -c -O2 mrsroot.c +gcc -c -O2 mrcurve.c +gcc -c -O2 mrfast.c +gcc -c -O2 mrshs.c +gcc -c -O2 mrshs256.c +gcc -c -O2 mrshs512.c +gcc -c -O2 mrsha3.c +gcc -c -O2 mrfpe.c +gcc -c -O2 mraes.c +gcc -c -O2 mrgcm.c +gcc -c -O2 mrlucas.c +gcc -c -O2 mrzzn2.c +gcc -c -O2 mrzzn2b.c +gcc -c -O2 mrzzn3.c +gcc -c -O2 mrzzn4.c +gcc -c -O2 mrstrong.c +gcc -c -O2 mrbrick.c +gcc -c -O2 mrebrick.c +gcc -c -O2 mrec2m.c +gcc -c -O2 mrecn2.c +gcc -c -O2 mrgf2m.c +gcc -c -O2 mrflash.c +gcc -c -O2 mrfrnd.c +gcc -c -O2 mrdouble.c +gcc -c -O2 mrround.c +gcc -c -O2 mrbuild.c +gcc -c -O2 mrflsh1.c +gcc -c -O2 mrpi.c +gcc -c -O2 mrflsh2.c +gcc -c -O2 mrflsh3.c +gcc -c -O2 mrflsh4.c +as mrmuldv.gpp -o mrmuldv.o + +rem gcc -c -O2 -fomit-frame-pointer mrcomba.c + +ar rc miracl.a mrcore.o mrarth0.o mrarth1.o mrarth2.o mralloc.o mrsmall.o mrgcm.o mrfpe.o mrsha3.o +ar r miracl.a mrio1.o mrio2.o mrjack.o mrgcd.o mrxgcd.o mrarth3.o mrbits.o mrzzn2.o mrzzn3.o mrzzn4.o +ar r miracl.a mrrand.o mrprime.o mrcrt.o mrscrt.o mrmonty.o mrcurve.o mrpower.o mrsroot.o +ar r miracl.a mrfast.o mrshs.o mraes.o mrlucas.o mrstrong.o mrbrick.o mrecn2.o +ar r miracl.a mrshs256.o mrshs512.o mrmuldv.o mrebrick.o mrgf2m.o mrec2m.o mrzzn2b.o +ar r miracl.a mrdouble.o mrround.o mrbuild.o mrflsh1.o mrpi.o mrflsh2.o mrflsh3.o mrflsh4.o mrflash.o mrfrnd.o + +del mr*.o +gpp -c -O2 big.cpp +gpp -c -O2 zzn.cpp +gpp -c -O2 ecn.cpp +gpp -c -O2 ec2.cpp +gpp brent.cpp big.o zzn.o miracl.a -o brent.exe +gpp -c -O2 flash.cpp +gpp sample.cpp flash.o miracl.a -o sample.exe +gpp ecsgen.cpp ecn.o big.o miracl.a -o ecsgen.exe +gpp ecsign.cpp ecn.o big.o miracl.a -o ecsign.exe +gpp ecsver.cpp ecn.o big.o miracl.a -o ecsver.exe + diff --git a/miracl/lib/linux b/miracl/lib/linux new file mode 100644 index 0000000..b2e58ea --- /dev/null +++ b/miracl/lib/linux @@ -0,0 +1,81 @@ +rm *.exe +rm miracl.a +cp mirdef.lnx mirdef.h +gcc -c -m32 -O2 mrcore.c +gcc -c -m32 -O2 mrarth0.c +gcc -c -m32 -O2 mrarth1.c +gcc -c -m32 -O2 mrarth2.c +gcc -c -m32 -O2 mralloc.c +gcc -c -m32 -O2 mrsmall.c +gcc -c -m32 -O2 mrio1.c +gcc -c -m32 -O2 mrio2.c +gcc -c -m32 -O2 mrgcd.c +gcc -c -m32 -O2 mrjack.c +gcc -c -m32 -O2 mrxgcd.c +gcc -c -m32 -O2 mrarth3.c +gcc -c -m32 -O2 mrbits.c +gcc -c -m32 -O2 mrrand.c +gcc -c -m32 -O2 mrprime.c +gcc -c -m32 -O2 mrcrt.c +gcc -c -m32 -O2 mrscrt.c +gcc -c -m32 -O2 mrmonty.c +gcc -c -m32 -O2 mrpower.c +gcc -c -m32 -O2 mrsroot.c +gcc -c -m32 -O2 mrcurve.c +gcc -c -m32 -O2 mrfast.c +gcc -c -m32 -O2 mrshs.c +gcc -c -m32 -O2 mrshs256.c +gcc -c -m32 -O2 mrshs512.c +gcc -c -m32 -O2 mrsha3.c +gcc -c -m32 -O2 mrfpe.c +gcc -c -m32 -O2 mraes.c +gcc -c -m32 -O2 mrgcm.c +gcc -c -m32 -O2 mrlucas.c +gcc -c -m32 -O2 mrzzn2.c +gcc -c -m32 -O2 mrzzn2b.c +gcc -c -m32 -O2 mrzzn3.c +gcc -c -m32 -O2 mrzzn4.c +gcc -c -m32 -O2 mrecn2.c +gcc -c -m32 -O2 mrstrong.c +gcc -c -m32 -O2 mrbrick.c +gcc -c -m32 -O2 mrebrick.c +gcc -c -m32 -O2 mrec2m.c +gcc -c -m32 -O2 mrgf2m.c +gcc -c -m32 -O2 mrflash.c +gcc -c -m32 -O2 mrfrnd.c +gcc -c -m32 -O2 mrdouble.c +gcc -c -m32 -O2 mrround.c +gcc -c -m32 -O2 mrbuild.c +gcc -c -m32 -O2 mrflsh1.c +gcc -c -m32 -O2 mrpi.c +gcc -c -m32 -O2 mrflsh2.c +gcc -c -m32 -O2 mrflsh3.c +gcc -c -m32 -O2 mrflsh4.c +cp mrmuldv.gcc mrmuldv.c +gcc -c -m32 -O2 mrmuldv.c +ar rc miracl.a mrcore.o mrarth0.o mrarth1.o mrarth2.o mralloc.o mrsmall.o mrzzn2.o mrzzn3.o +ar r miracl.a mrio1.o mrio2.o mrjack.o mrgcd.o mrxgcd.o mrarth3.o mrbits.o mrecn2.o mrzzn4.o +ar r miracl.a mrrand.o mrprime.o mrcrt.o mrscrt.o mrmonty.o mrcurve.o mrsroot.o mrzzn2b.o +ar r miracl.a mrpower.o mrfast.o mrshs.o mrshs256.o mraes.o mrlucas.o mrstrong.o mrgcm.o +ar r miracl.a mrflash.o mrfrnd.o mrdouble.o mrround.o mrbuild.o +ar r miracl.a mrflsh1.o mrpi.o mrflsh2.o mrflsh3.o mrflsh4.o +ar r miracl.a mrbrick.o mrebrick.o mrec2m.o mrgf2m.o mrmuldv.o mrshs512.o mrsha3.o mrfpe.o +rm mr*.o +gcc -m32 -O2 bmark.c miracl.a -o bmark +gcc -m32 -O2 fact.c miracl.a -o fact +g++ -c -m32 -O2 big.cpp +g++ -c -m32 -O2 zzn.cpp +g++ -c -m32 -O2 ecn.cpp +g++ -c -m32 -O2 ec2.cpp +g++ -c -m32 -O2 crt.cpp +g++ -m32 -O2 mersenne.cpp big.o miracl.a -o mersenne +g++ -m32 -O2 brent.cpp big.o zzn.o miracl.a -o brent +g++ -c -m32 -O2 flash.cpp +g++ -m32 -O2 sample.cpp flash.o miracl.a -o sample +g++ -m32 -O2 ecsgen.cpp ecn.o big.o miracl.a -o ecsgen +g++ -m32 -O2 ecsign.cpp ecn.o big.o miracl.a -o ecsign +g++ -m32 -O2 ecsver.cpp ecn.o big.o miracl.a -o ecsver +g++ -m32 -O2 pk-demo.cpp ecn.o big.o miracl.a -o pk-demo +g++ -c -m32 -O2 polymod.cpp +g++ -c -m32 -O2 poly.cpp +g++ -m32 -O2 schoof.cpp polymod.o poly.o ecn.o crt.o zzn.o big.o miracl.a -o schoof diff --git a/miracl/lib/linux64 b/miracl/lib/linux64 new file mode 100644 index 0000000..46e1061 --- /dev/null +++ b/miracl/lib/linux64 @@ -0,0 +1,81 @@ +rm *.exe +rm miracl.a +cp mirdef.h64 mirdef.h +gcc -c -m64 -O2 mrcore.c +gcc -c -m64 -O2 mrarth0.c +gcc -c -m64 -O2 mrarth1.c +gcc -c -m64 -O2 mrarth2.c +gcc -c -m64 -O2 mralloc.c +gcc -c -m64 -O2 mrsmall.c +gcc -c -m64 -O2 mrio1.c +gcc -c -m64 -O2 mrio2.c +gcc -c -m64 -O2 mrgcd.c +gcc -c -m64 -O2 mrjack.c +gcc -c -m64 -O2 mrxgcd.c +gcc -c -m64 -O2 mrarth3.c +gcc -c -m64 -O2 mrbits.c +gcc -c -m64 -O2 mrrand.c +gcc -c -m64 -O2 mrprime.c +gcc -c -m64 -O2 mrcrt.c +gcc -c -m64 -O2 mrscrt.c +gcc -c -m64 -O2 mrmonty.c +gcc -c -m64 -O2 mrpower.c +gcc -c -m64 -O2 mrsroot.c +gcc -c -m64 -O2 mrcurve.c +gcc -c -m64 -O2 mrfast.c +gcc -c -m64 -O2 mrshs.c +gcc -c -m64 -O2 mrshs256.c +gcc -c -m64 -O2 mrshs512.c +gcc -c -m64 -O2 mrsha3.c +gcc -c -m64 -O2 mrfpe.c +gcc -c -m64 -O2 mraes.c +gcc -c -m64 -O2 mrgcm.c +gcc -c -m64 -O2 mrlucas.c +gcc -c -m64 -O2 mrzzn2.c +gcc -c -m64 -O2 mrzzn2b.c +gcc -c -m64 -O2 mrzzn3.c +gcc -c -m64 -O2 mrzzn4.c +gcc -c -m64 -O2 mrecn2.c +gcc -c -m64 -O2 mrstrong.c +gcc -c -m64 -O2 mrbrick.c +gcc -c -m64 -O2 mrebrick.c +gcc -c -m64 -O2 mrec2m.c +gcc -c -m64 -O2 mrgf2m.c +gcc -c -m64 -O2 mrflash.c +gcc -c -m64 -O2 mrfrnd.c +gcc -c -m64 -O2 mrdouble.c +gcc -c -m64 -O2 mrround.c +gcc -c -m64 -O2 mrbuild.c +gcc -c -m64 -O2 mrflsh1.c +gcc -c -m64 -O2 mrpi.c +gcc -c -m64 -O2 mrflsh2.c +gcc -c -m64 -O2 mrflsh3.c +gcc -c -m64 -O2 mrflsh4.c +cp mrmuldv.g64 mrmuldv.c +gcc -c -m64 -O2 mrmuldv.c +ar rc miracl.a mrcore.o mrarth0.o mrarth1.o mrarth2.o mralloc.o mrsmall.o mrzzn2.o mrzzn3.o +ar r miracl.a mrio1.o mrio2.o mrjack.o mrgcd.o mrxgcd.o mrarth3.o mrbits.o mrecn2.o mrzzn4.o +ar r miracl.a mrrand.o mrprime.o mrcrt.o mrscrt.o mrmonty.o mrcurve.o mrsroot.o mrzzn2b.o +ar r miracl.a mrpower.o mrfast.o mrshs.o mrshs256.o mraes.o mrlucas.o mrstrong.o mrgcm.o +ar r miracl.a mrflash.o mrfrnd.o mrdouble.o mrround.o mrbuild.o +ar r miracl.a mrflsh1.o mrpi.o mrflsh2.o mrflsh3.o mrflsh4.o +ar r miracl.a mrbrick.o mrebrick.o mrec2m.o mrgf2m.o mrmuldv.o mrshs512.o mrsha3.o mrfpe.o +rm mr*.o +gcc -m64 -O2 bmark.c miracl.a -o bmark +gcc -m64 -O2 fact.c miracl.a -o fact +g++ -c -m64 -O2 big.cpp +g++ -c -m64 -O2 zzn.cpp +g++ -c -m64 -O2 ecn.cpp +g++ -c -m64 -O2 ec2.cpp +g++ -c -m64 -O2 crt.cpp +g++ -m64 -O2 mersenne.cpp big.o miracl.a -o mersenne +g++ -m64 -O2 brent.cpp big.o zzn.o miracl.a -o brent +g++ -c -m64 -O2 flash.cpp +g++ -m64 -O2 sample.cpp flash.o miracl.a -o sample +g++ -m64 -O2 ecsgen.cpp ecn.o big.o miracl.a -o ecsgen +g++ -m64 -O2 ecsign.cpp ecn.o big.o miracl.a -o ecsign +g++ -m64 -O2 ecsver.cpp ecn.o big.o miracl.a -o ecsver +g++ -m64 -O2 pk-demo.cpp ecn.o big.o miracl.a -o pk-demo +g++ -c -m64 -O2 polymod.cpp +g++ -c -m64 -O2 poly.cpp +g++ -m64 -O2 schoof.cpp polymod.o poly.o ecn.o crt.o zzn.o big.o miracl.a -o schoof diff --git a/miracl/lib/linux64_cpp b/miracl/lib/linux64_cpp new file mode 100644 index 0000000..dc7ed72 --- /dev/null +++ b/miracl/lib/linux64_cpp @@ -0,0 +1,82 @@ +rm *.exe +rm miracl.a +cp mirdef.hpp mirdef.h +g++ -c -m64 -O2 mrcore.c +g++ -c -m64 -O2 mrarth0.c +g++ -c -m64 -O2 mrarth1.c +g++ -c -m64 -O2 mrarth2.c +g++ -c -m64 -O2 mralloc.c +g++ -c -m64 -O2 mrsmall.c +g++ -c -m64 -O2 mrio1.c +g++ -c -m64 -O2 mrio2.c +g++ -c -m64 -O2 mrgcd.c +g++ -c -m64 -O2 mrjack.c +g++ -c -m64 -O2 mrxgcd.c +g++ -c -m64 -O2 mrarth3.c +g++ -c -m64 -O2 mrbits.c +g++ -c -m64 -O2 mrrand.c +g++ -c -m64 -O2 mrprime.c +g++ -c -m64 -O2 mrcrt.c +g++ -c -m64 -O2 mrscrt.c +g++ -c -m64 -O2 mrmonty.c +g++ -c -m64 -O2 mrpower.c +g++ -c -m64 -O2 mrsroot.c +g++ -c -m64 -O2 mrcurve.c +g++ -c -m64 -O2 mrfast.c +g++ -c -m64 -O2 mrshs.c +g++ -c -m64 -O2 mrshs256.c +g++ -c -m64 -O2 mrshs512.c +g++ -c -m64 -O2 mrsha3.c +g++ -c -m64 -O2 mrfpe.c +g++ -c -m64 -O2 mraes.c +g++ -c -m64 -O2 mrgcm.c +g++ -c -m64 -O2 mrlucas.c +g++ -c -m64 -O2 mrzzn2.c +g++ -c -m64 -O2 mrzzn2b.c +g++ -c -m64 -O2 mrzzn3.c +g++ -c -m64 -O2 mrzzn4.c +g++ -c -m64 -O2 mrecn2.c +g++ -c -m64 -O2 mrstrong.c +g++ -c -m64 -O2 mrbrick.c +g++ -c -m64 -O2 mrebrick.c +g++ -c -m64 -O2 mrec2m.c +g++ -c -m64 -O2 mrgf2m.c +g++ -c -m64 -O2 mrflash.c +g++ -c -m64 -O2 mrfrnd.c +g++ -c -m64 -O2 mrdouble.c +g++ -c -m64 -O2 mrround.c +g++ -c -m64 -O2 mrbuild.c +g++ -c -m64 -O2 mrflsh1.c +g++ -c -m64 -O2 mrpi.c +g++ -c -m64 -O2 mrflsh2.c +g++ -c -m64 -O2 mrflsh3.c +g++ -c -m64 -O2 mrflsh4.c +cp mrmuldv.g64 mrmuldv.c +g++ -c -m64 -O2 mrmuldv.c +g++ -c -m64 -O2 big.cpp +g++ -c -m64 -O2 zzn.cpp +g++ -c -m64 -O2 ecn.cpp +g++ -c -m64 -O2 ec2.cpp +g++ -c -m64 -O2 flash.cpp +g++ -c -m64 -O2 crt.cpp +ar rc miracl.a mrcore.o mrarth0.o mrarth1.o mrarth2.o mralloc.o mrsmall.o mrzzn2.o mrzzn3.o +ar r miracl.a mrio1.o mrio2.o mrjack.o mrgcd.o mrxgcd.o mrarth3.o mrbits.o mrecn2.o mrzzn4.o +ar r miracl.a mrrand.o mrprime.o mrcrt.o mrscrt.o mrmonty.o mrcurve.o mrsroot.o mrzzn2b.o +ar r miracl.a mrpower.o mrfast.o mrshs.o mrshs256.o mraes.o mrlucas.o mrstrong.o mrgcm.o +ar r miracl.a mrflash.o mrfrnd.o mrdouble.o mrround.o mrbuild.o +ar r miracl.a mrflsh1.o mrpi.o mrflsh2.o mrflsh3.o mrflsh4.o +ar r miracl.a mrbrick.o mrebrick.o mrec2m.o mrgf2m.o mrmuldv.o mrshs512.o mrsha3.o mrfpe.o +ar r miracl.a big.o zzn.o ecn.o ec2.o flash.o crt.o +rm mr*.o +g++ -m64 -O2 bmark.c miracl.a -o bmark +g++ -m64 -O2 fact.c miracl.a -o fact +g++ -m64 -O2 mersenne.cpp miracl.a -o mersenne +g++ -m64 -O2 brent.cpp miracl.a -o brent +g++ -m64 -O2 sample.cpp miracl.a -o sample +g++ -m64 -O2 ecsgen.cpp miracl.a -o ecsgen +g++ -m64 -O2 ecsign.cpp miracl.a -o ecsign +g++ -m64 -O2 ecsver.cpp miracl.a -o ecsver +g++ -m64 -O2 pk-demo.cpp miracl.a -o pk-demo +g++ -c -m64 -O2 polymod.cpp +g++ -c -m64 -O2 poly.cpp +g++ -m64 -O2 schoof.cpp polymod.o poly.o miracl.a -o schoof diff --git a/miracl/lib/mingw.bat b/miracl/lib/mingw.bat new file mode 100644 index 0000000..2ad9296 --- /dev/null +++ b/miracl/lib/mingw.bat @@ -0,0 +1,60 @@ +copy mirdef.mgw mirdef.h +gcc -c -O2 mrcore.c +gcc -c -O2 mrarth0.c +gcc -c -O2 mrarth1.c +gcc -c -O2 mrarth2.c +gcc -c -O2 mralloc.c +gcc -c -O2 mrsmall.c +gcc -c -O2 mrio1.c +gcc -c -O2 mrio2.c +gcc -c -O2 mrgcd.c +gcc -c -O2 mrjack.c +gcc -c -O2 mrxgcd.c +gcc -c -O2 mrarth3.c +gcc -c -O2 mrbits.c +gcc -c -O2 mrrand.c +gcc -c -O2 mrprime.c +gcc -c -O2 mrcrt.c +gcc -c -O2 mrscrt.c +gcc -c -O2 mrmonty.c +gcc -c -O2 mrpower.c +gcc -c -O2 mrsroot.c +gcc -c -O2 mrcurve.c +gcc -c -O2 mrfast.c +gcc -c -O2 mrshs.c +gcc -c -O2 mrshs256.c +gcc -c -O2 mrshs512.c +gcc -c -O2 mrsha3.c +gcc -c -O2 mrfpe.c +gcc -c -O2 mraes.c +gcc -c -O2 mrgcm.c +gcc -c -O2 mrlucas.c +gcc -c -O2 mrzzn2.c +gcc -c -O2 mrzzn2b.c +gcc -c -O2 mrzzn3.c +gcc -c -O2 mrzzn4.c +gcc -c -O2 mrecn2.c +gcc -c -O2 mrstrong.c +gcc -c -O2 mrbrick.c +gcc -c -O2 mrebrick.c +gcc -c -O2 mrec2m.c +gcc -c -O2 mrgf2m.c +gcc -c -O2 mrflash.c +gcc -c -O2 mrfrnd.c +gcc -c -O2 mrdouble.c +gcc -c -O2 mrround.c +gcc -c -O2 mrbuild.c +gcc -c -O2 mrflsh1.c +gcc -c -O2 mrpi.c +gcc -c -O2 mrflsh2.c +gcc -c -O2 mrflsh3.c +gcc -c -O2 mrflsh4.c +copy mrmuldv.g64 mrmuldv.c +gcc -c -O2 mrmuldv.c +ar rc miracl.a mrcore.o mrarth0.o mrarth1.o mrarth2.o mralloc.o mrsmall.o mrzzn2.o mrzzn3.o +ar r miracl.a mrio1.o mrio2.o mrjack.o mrgcd.o mrxgcd.o mrarth3.o mrbits.o mrecn2.o mrzzn4.o +ar r miracl.a mrrand.o mrprime.o mrcrt.o mrscrt.o mrmonty.o mrcurve.o mrsroot.o mrzzn2b.o +ar r miracl.a mrpower.o mrfast.o mrshs.o mrshs256.o mraes.o mrlucas.o mrstrong.o mrgcm.o +ar r miracl.a mrbrick.o mrebrick.o mrec2m.o mrgf2m.o mrmuldv.o mrshs512.o mrsha3.o mrfpe.o +ar r miracl.a mrdouble.o mrround.o mrbuild.o mrflsh1.o mrpi.o mrflsh2.o mrflsh3.o mrflsh4.o mrflash.o mrfrnd.o + diff --git a/miracl/lib/miracl.mak b/miracl/lib/miracl.mak new file mode 100644 index 0000000..921cac1 --- /dev/null +++ b/miracl/lib/miracl.mak @@ -0,0 +1,262 @@ +# UNIX Makefile for MIRACL Software Multi-Precision Math Lib. +# +# Contributed by John Kennedy +# Updated by M.Scott 15/7/97 +# +# Notes: This is a "bare-bones" makefile for compiling +# the MIRACL libs and C demo programs on a UNIX +# system using the GNU C compiler. Please examine the CFLAGS and +# other configuration definitions to make sure they are +# appropriate for your environment. Particularly the +# CC, LIBS, and CFLAGS definitions. Also read the discussion +# below about assembly language vs. portable C lib +# support. Use with mirdef.h32 (typically) +# Some MIRACL builds might need certain extra modules included (e.g. +# mrkcm.c), and certain modules ommitted (e.g. mrmuldv.s) +# +# BEFORE running this make file, assembly mrmuldv.s (if you are +# using one), as +# +# as mrmuldv.s -o mrmuldv.o +# +# Invoke as "make -f miracl.mak" +# +# Use at your own risk! +# +# Note that this make file does not make the C++ programs. +# To build for example the pk-demo.cpp application, proceed as follows +# +# g++ -I. -c crt.cpp +# g++ -I. -c ecn.cpp +# g++ -I. -c big.cpp +# g++ -I. pk-demo.cpp crt.o ecn.o big.o -I/usr/lib miracl.a \ +# -lm -o pk-demo +# +# or perhaps that should be gpp rather than g++ +# +# +CC = gcc +AR = ar + +SHELL = /bin/sh + +#OPTIMIZE FLAGS +CFLAGS = -c -O2 -I. -I/usr/lib + + +.KEEP_STATE : + +MIRPROGS = hail factor fact genprime brick brent brute deciph decode dssetup \ + dssgen dssign dssver ecsgen ecsign ecsver enciph encode hilbert index \ +kangaroo mersenne pollard qsieve roots williams palin genkey identity sample \ +lenstra pk-demo factor + + +MIRACL = mrflsh4 mrflsh3 mrflsh2 mrpi mrflsh1 mrio2 mrio1 mrdouble mrflash \ +mrrand mrprime mrcrt mrcurve mrshs mrshs256 mrshs512 mrsha3 mrfpe mraes mrgcm mrstrong mrbrick mrebrick mrgf2m mrec2m \ +mrscrt mrfast mrjack mrfrnd mrxgcd mrgcd mrround mrbuild mrarth3 mrbits mrarth2 \ +mrlucas mrzzn2 mrzzn2b mrzzn3 mrecn2 mrmonty mrpower mrsroot mralloc mrarth1 mrarth0 mrsmall mrcore mrmuldv + +# Try one of these two .... + +LIBS = miracl.a /usr/lib/libm.a + +# LIBS = miracl.a -lm + +MIROBJS = mrflsh4.o mrflsh3.o mrflsh2.o mrpi.o mrflsh1.o mrio2.o mrio1.o \ +mrdouble.o mrflash.o mrrand.o mrprime.o mrcrt.o mrscrt.o mrfast.o mrjack.o \ +mrfrnd.o mrxgcd.o mrgcd.o mrstrong.o mrbrick.o mrebrick.o mrcurve.o mrshs256.o mrshs512.o mrfpe.o mrsha3.o mrshs.o \ +mraes.o mrgcm.o mrround.o mrbuild.o mrarth3.o mrbits.o mrarth2.o mrpower.o mrsroot.o mrec2m.o mrgf2m.o \ +mrlucas.o mrzzn2.o mrzzn2b.o mrzzn3.o mrecn2.o mrmonty.o mralloc.o mrarth1.o mrarth0.o mrsmall.o mrcore.o \ +mrmuldv.o + +# NOTE: THE ASSEMBLY SOURCE SHOULD BE PLACED IN 'mrmuldv.s'. +# IF YOU DON'T HAVE ASSEMBLY CODE, COMMENT OUT THE +# 'mrmuldv.o LINE AND DELETE THE '\' CONTINUATION CHARACTER +# ON THE LINE ABOVE. +# +# Ideally FOR A 32-BIT MACHINE LIKE A SUN SPARCstation, USE mirdef.h32 +# (but change ENDIAN definition) for mirdef.h with an assembly language +# mrmuldv.s +# +# Alternatively omit mrmuldv. This will be slower. +# +# See mrmuldv.any for advice on creating a mrmuldv.s assembly +# language module. In most cases the muldvd() function is the most +# time critical, so even if only this one can be written in assembly +# language, it will be worth it. It may be necessary then to create +# two files, mrmuldv.c for muldvm() and muldiv(), and a seperate +# mrmuldvd.s This make file will then have to modified to accomodate +# this change. +# +ALL: miracl.a $(MIRPROGS) + +miracl.a: $(MIROBJS) +# $(RM) $@ + $(AR) crv $@ $(MIROBJS) + +# +# DEPENDENCIES +# + +miracl.h: mirdef.h + +mrcore.o: mrcore.c mirdef.h miracl.h +mrarth0.o: mrarth0.c miracl.h +mrarth1.o: mrarth1.c miracl.h +mrarth2.o: mrarth2.c miracl.h +mralloc.o: mralloc.c miracl.h +mrmonty.o: mrmonty.c miracl.h +mrpower.o: mrpower.c miracl.h +mrsroot.o: mrsroot.c miracl.h +mrlucas.o: mrlucas.c miracl.h +mrzzn2.o: mrzzn2.c miracl.h +mrzzn2b.o: mrzzn2b.c miracl.h +mrzzn3.o: mrzzn3.c miracl.h +mrecn2.o: mrecn2.c miracl.h +mrsmall.o: mrsmall.c miracl.h +mrround.o: mrround.c miracl.h +mrio1.o: mrio1.c miracl.h +mrio2.o: mrio2.c miracl.h +mrgcd.o: mrgcd.c miracl.h +mrjack.o: mrjack.c miracl.h +mrxgcd.o: mrxgcd.c miracl.h +mrarth3.o: mrarth3.c miracl.h +mrbits.o: mrbits.c miracl.h +mrrand.o: mrrand.c miracl.h +mrprime.o: mrprime.c miracl.h +mrcrt.o: mrcrt.c miracl.h +mrscrt.o: mrscrt.c miracl.h +mrshs.o: mrshs.c miracl.h +mrshs256.o: mrshs256.c miracl.h +mrshs512.o: mrshs512.c miracl.h +mrsha3.o: mrsha3.c miracl.h +mrfpe.o: mrfpe.c miracl.h +mraes.o: mraes.c miracl.h +mrgcm.o: mrgcm.c miracl.h +mrstrong.o: mrstrong.c miracl.h +mrbrick.o: mrbrick.c miracl.h +mrebrick.o: mrebrick.c miracl.h +mrec2m.o: mrec2m.c miracl.h +mrgf2m.o: mrgf2m.c miracl.h +mrcurve.o: mrcurve.c miracl.h +mrfast.o: mrfast.c miracl.h +mrfrnd.o: mrfrnd.c miracl.h +mrflash.o: mrflash.c miracl.h +mrdouble.o: mrdouble.c miracl.h +mrbuild.o: mrbuild.c miracl.h +mrflsh1.o: mrflsh1.c miracl.h +mrpi.o: mrpi.c miracl.h +mrflsh2.o: mrflsh2.c miracl.h +mrflsh3.o: mrflsh3.c miracl.h +mrflsh4.o: mrflsh4.c miracl.h +mrmuldv.o: mrmuldv.s + +#DEMO PROGRAMS + +hail: hail.o miracl.h +factor: factor.o miracl.h +fact: fact.o miracl.h +palin: palin.o miracl.h +genkey: genkey.o miracl.h +genprime: genprime.o miracl.h +identity: identity.o miracl.h +sample: sample.o miracl.h +pk-demo: pk-demo.o miracl.h +brent: brent.o miracl.h +brick: brick.o miracl.h +brute: brute.o miracl.h +deciph: deciph.o miracl.h +decode: decode.o miracl.h +dssetup: dssetup.o miracl.h +dssgen: dssgen.o miracl.h +dssign: dssign.o miracl.h +dssver: dssver.o miracl.h +ecsgen: ecsgen.o miracl.h +ecsign: ecsign.o miracl.h +ecsver: ecsver.o miracl.h +enciph: enciph.o miracl.h +encode: encode.o miracl.h +hilbert: hilbert.o miracl.h +index: index.o miracl.h +kangaroo: kangaroo.o miracl.h +lenstra: lenstra.o miracl.h +mersenne: mersenne.o miracl.h +pollard: pollard.o miracl.h +qsieve: qsieve.o miracl.h +roots: roots.o miracl.h +williams: williams.o miracl.h + +hail: hail.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +palin: palin.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +identity: identity.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +factor: factor.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +fact: fact.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +genprime: genprime.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +genkey: genkey.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +lenstra: lenstra.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +pk-demo: pk-demo.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +brick: brick.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +brent: brent.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +brute: brute.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +deciph: deciph.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +decode: decode.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +dssetup: dssetup.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +dssgen: dssgen.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +dssign: dssign.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +dssver: dssver.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +ecsgen: ecsgen.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +ecsign: ecsign.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +ecsver: ecsver.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +enciph: enciph.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +encode: encode.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +hilbert: hilbert.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +sample: sample.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +index: index.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +kangaroo: kangaroo.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +mersenne: mersenne.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +pollard: pollard.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +qsieve: qsieve.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +roots: roots.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) +williams: williams.o $(LIBS) + $(CC) -o $@ $@.o $(LIBS) + + +clean: + -rm -f core a.out tags +tags: + ctags *.c *.h + + + diff --git a/miracl/lib/ms32doit.bat b/miracl/lib/ms32doit.bat new file mode 100644 index 0000000..91b7817 --- /dev/null +++ b/miracl/lib/ms32doit.bat @@ -0,0 +1,104 @@ +rem MIRACL - IBM PC/MS-DOS Version 4.0 +rem This batch files creates miracl.lib from its component parts +rem using the Microsoft 32-bit compiler, (as used in Windows '95 +rem and Windows NT), and the Microsoft LIB librarian utility +rem Also included are the commands to create some of the example programs +rem +rem Read your compiler documentation for further information +rem +rem Invoke as "ms32doit". It is assumed that paths have been correctly set up +rem to the compiler, librarian and linker. +rem +rem Provided mainly as a guide for creating a batch file tailored +rem specifically to your own configuration. +rem +rem Note - the module mrmuldv.c is not needed if MR_NOASM is defined +rem +rem NOTE - the flag /MT should be used for multithreaded applications +rem +rem Compile MIRACL modules +copy mirdef.h32 mirdef.h +cl /c /O2 /W3 mrcore.c +cl /c /O2 /W3 mrarth0.c +cl /c /O2 /W3 mrarth1.c +cl /c /O2 /W3 mrarth2.c +cl /c /O2 /W3 mralloc.c +cl /c /O2 /W3 mrsmall.c +cl /c /O2 /W3 mrio1.c +cl /c /O2 /W3 mrio2.c +cl /c /O2 /W3 mrgcd.c +cl /c /O2 /W3 mrjack.c +cl /c /O2 /W3 mrxgcd.c +cl /c /O2 /W3 mrarth3.c +cl /c /O2 /W3 mrbits.c +cl /c /O2 /W3 mrrand.c +cl /c /O2 /W3 mrprime.c +cl /c /O2 /W3 mrcrt.c +cl /c /O2 /W3 mrscrt.c +cl /c /O2 /W3 mrmonty.c +cl /c /O2 /W3 mrpower.c +cl /c /O2 /W3 mrsroot.c +cl /c /O2 /W3 mrcurve.c +cl /c /O2 /W3 mrfast.c +cl /c /O2 /W3 mrlucas.c +cl /c /O2 /W3 mrzzn2.c +cl /c /O2 /W3 mrzzn2b.c +cl /c /O2 /W3 mrzzn3.c +cl /c /O2 /W3 mrzzn4.c +cl /c /O2 /W3 mrshs.c +cl /c /O2 /W3 mrshs256.c +cl /c /O2 /W3 mrshs512.c +cl /c /O2 /W3 mrsha3.c +cl /c /O2 /W3 mrfpe.c +cl /c /O2 /W3 mraes.c +cl /c /O2 /W3 mrgcm.c +cl /c /O2 /W3 mrstrong.c +cl /c /O2 /W3 mrbrick.c +cl /c /O2 /W3 mrebrick.c +cl /c /O2 /W3 mrgf2m.c +cl /c /O2 /W3 mrec2m.c +cl /c /O2 /W3 mrecn2.c +cl /c /O2 /W3 mrflash.c +cl /c /O2 /W3 mrfrnd.c +cl /c /O2 /W3 mrdouble.c +cl /c /O2 /W3 mrround.c +cl /c /O2 /W3 mrbuild.c +cl /c /O2 /W3 mrflsh1.c +cl /c /O2 /W3 mrpi.c +cl /c /O2 /W3 mrflsh2.c +cl /c /O2 /W3 mrflsh3.c +cl /c /O2 /W3 mrflsh4.c +copy mrmuldv.c32 mrmuldv.c +cl /c /O2 /W3 mrmuldv.c + +rem +rem Create library 'miracl.lib' +del miracl.lib + +lib /OUT:miracl.lib mrflsh4.obj mrflsh3.obj mrflsh2.obj mrpi.obj mrflsh1.obj +lib /OUT:miracl.lib miracl.lib mrdouble.obj mrflash.obj mrfrnd.obj mrround.obj mrbuild.obj +lib /OUT:miracl.lib miracl.lib mrio2.obj mrio1.obj mrrand.obj mrprime.obj mrcrt.obj mrscrt.obj mrfast.obj +lib /OUT:miracl.lib miracl.lib mrjack.obj mrxgcd.obj mrgcd.obj mrarth3.obj mrarth2.obj mrpower.obj mrsroot.obj +lib /OUT:miracl.lib miracl.lib mrmonty.obj mralloc.obj mrarth1.obj mrarth0.obj mrsmall.obj mrcore.obj mrmuldv.obj +lib /OUT:miracl.lib miracl.lib mrcurve.obj mrshs.obj mraes.obj mrlucas.obj mrstrong.obj mrbrick.obj mrbits.obj +lib /OUT:miracl.lib miracl.lib mrshs256.obj mrshs512.obj mrebrick.obj mrgf2m.obj mrec2m.obj mrzzn2.obj mrzzn3.obj mrzzn4.obj +lib /OUT:miracl.lib miracl.lib mrecn2.obj mrzzn2b.obj mrgcm.obj mrfpe.obj mrsha3.obj + +del mr*.obj +rem +cl /c /O2 /W3 /GX big.cpp +cl /c /O2 /W3 /GX zzn.cpp +cl /c /O2 /W3 /GX ecn.cpp +cl /c /O2 /W3 /GX ec2.cpp +rem Compile and link example programs +cl /c /O2 /W3 /GX brute.cpp +link brute.obj big.obj miracl.lib +cl /c /O2 /W3 /GX brent.cpp +link brent.obj big.obj zzn.obj miracl.lib +cl /c /O2 /W3 /GX pk-demo.cpp +link pk-demo.obj big.obj ecn.obj miracl.lib +cl /c /O2 /W3 bmark.c +link bmark.obj miracl.lib +cl /c /O2 /W3 /GX flash.cpp + + diff --git a/miracl/lib/ms64doit.bat b/miracl/lib/ms64doit.bat new file mode 100644 index 0000000..e723aea --- /dev/null +++ b/miracl/lib/ms64doit.bat @@ -0,0 +1,101 @@ +rem MIRACL Build Batch File +rem This batch files creates miracl.lib from its component parts +rem using the Microsoft 64-bit compiler, and the Microsoft LIB librarian utility +rem Also included are the commands to create some of the example programs +rem +rem Read your compiler documentation for further information +rem +rem Invoke as "ms64doit". It is assumed that paths have been correctly set up +rem to the compiler, librarian and linker. +rem +rem Provided mainly as a guide for creating a batch file tailored +rem specifically to your own configuration. +rem +rem Note - the module mrmuldv.c is not needed if MR_NOASM is defined +rem +rem NOTE - the flag /MT should be used for multithreaded applications +rem +rem Compile MIRACL modules +copy mirdef.w64 mirdef.h +cl /c /O2 /W3 mrcore.c +cl /c /O2 /W3 mrarth0.c +cl /c /O2 /W3 mrarth1.c +cl /c /O2 /W3 mrarth2.c +cl /c /O2 /W3 mralloc.c +cl /c /O2 /W3 mrsmall.c +cl /c /O2 /W3 mrio1.c +cl /c /O2 /W3 mrio2.c +cl /c /O2 /W3 mrgcd.c +cl /c /O2 /W3 mrjack.c +cl /c /O2 /W3 mrxgcd.c +cl /c /O2 /W3 mrarth3.c +cl /c /O2 /W3 mrbits.c +cl /c /O2 /W3 mrrand.c +cl /c /O2 /W3 mrprime.c +cl /c /O2 /W3 mrcrt.c +cl /c /O2 /W3 mrscrt.c +cl /c /O2 /W3 mrmonty.c +cl /c /O2 /W3 mrpower.c +cl /c /O2 /W3 mrsroot.c +cl /c /O2 /W3 mrcurve.c +cl /c /O2 /W3 mrfast.c +cl /c /O2 /W3 mrlucas.c +cl /c /O2 /W3 mrzzn2.c +cl /c /O2 /W3 mrzzn2b.c +cl /c /O2 /W3 mrzzn3.c +cl /c /O2 /W3 mrzzn4.c +cl /c /O2 /W3 mrshs.c +cl /c /O2 /W3 mrshs256.c +cl /c /O2 /W3 mrshs512.c +cl /c /O2 /W3 mrsha3.c +cl /c /O2 /W3 mrfpe.c +cl /c /O2 /W3 mraes.c +cl /c /O2 /W3 mrgcm.c +cl /c /O2 /W3 mrstrong.c +cl /c /O2 /W3 mrbrick.c +cl /c /O2 /W3 mrebrick.c +cl /c /O2 /W3 mrgf2m.c +cl /c /O2 /W3 mrec2m.c +cl /c /O2 /W3 mrecn2.c +cl /c /O2 /W3 mrflash.c +cl /c /O2 /W3 mrfrnd.c +cl /c /O2 /W3 mrdouble.c +cl /c /O2 /W3 mrround.c +cl /c /O2 /W3 mrbuild.c +cl /c /O2 /W3 mrflsh1.c +cl /c /O2 /W3 mrpi.c +cl /c /O2 /W3 mrflsh2.c +cl /c /O2 /W3 mrflsh3.c +cl /c /O2 /W3 mrflsh4.c +copy mrmuldv.w64 mrmuldv.c +cl /c /O2 /W3 mrmuldv.c + +rem +rem Create library 'miracl.lib' +del miracl.lib + +lib /OUT:miracl.lib mrflsh4.obj mrflsh3.obj mrflsh2.obj mrpi.obj mrflsh1.obj +lib /OUT:miracl.lib miracl.lib mrdouble.obj mrflash.obj mrfrnd.obj mrround.obj mrbuild.obj +lib /OUT:miracl.lib miracl.lib mrio2.obj mrio1.obj mrrand.obj mrprime.obj mrcrt.obj mrscrt.obj mrfast.obj +lib /OUT:miracl.lib miracl.lib mrjack.obj mrxgcd.obj mrgcd.obj mrarth3.obj mrarth2.obj mrpower.obj mrsroot.obj +lib /OUT:miracl.lib miracl.lib mrmonty.obj mralloc.obj mrarth1.obj mrarth0.obj mrsmall.obj mrcore.obj mrmuldv.obj +lib /OUT:miracl.lib miracl.lib mrcurve.obj mrshs.obj mraes.obj mrlucas.obj mrstrong.obj mrbrick.obj mrbits.obj +lib /OUT:miracl.lib miracl.lib mrshs256.obj mrshs512.obj mrebrick.obj mrgf2m.obj mrec2m.obj mrzzn2.obj mrzzn3.obj mrzzn4.obj +lib /OUT:miracl.lib miracl.lib mrecn2.obj mrzzn2b.obj mrgcm.obj mrfpe.obj mrsha3.obj + +del mr*.obj +rem +cl /c /O2 /W3 /GX big.cpp +cl /c /O2 /W3 /GX zzn.cpp +cl /c /O2 /W3 /GX ecn.cpp +cl /c /O2 /W3 /GX ec2.cpp +rem Compile and link example programs +cl /c /O2 /W3 /GX brute.cpp +link brute.obj big.obj miracl.lib +cl /c /O2 /W3 /GX brent.cpp +link brent.obj big.obj zzn.obj miracl.lib +cl /c /O2 /W3 /GX pk-demo.cpp +link pk-demo.obj big.obj ecn.obj miracl.lib +cl /c /O2 /W3 bmark.c +link bmark.obj miracl.lib +cl /c /O2 /W3 /GX flash.cpp diff --git a/miracl/lib/ms64doit_cpp.bat b/miracl/lib/ms64doit_cpp.bat new file mode 100644 index 0000000..67ec476 --- /dev/null +++ b/miracl/lib/ms64doit_cpp.bat @@ -0,0 +1,102 @@ +rem MIRACL Build Batch File +rem This file builds an entirely C++ version of the library +rem This batch files creates miracl.lib from its component parts +rem using the Microsoft 64-bit compiler, and the Microsoft LIB librarian utility +rem Also included are the commands to create some of the example programs +rem +rem Read your compiler documentation for further information +rem +rem Invoke as "ms64doit_cpp". It is assumed that paths have been correctly set up +rem to the compiler, librarian and linker. +rem +rem Provided mainly as a guide for creating a batch file tailored +rem specifically to your own configuration. +rem +rem Note - the module mrmuldv.c is not needed if MR_NOASM is defined +rem +rem NOTE - the flag /MT should be used for multithreaded applications +rem +rem Compile MIRACL modules +copy mirdef.wpp mirdef.h +cl /c /O2 /W3 /Tp mrcore.c +cl /c /O2 /W3 /Tp mrarth0.c +cl /c /O2 /W3 /Tp mrarth1.c +cl /c /O2 /W3 /Tp mrarth2.c +cl /c /O2 /W3 /Tp mralloc.c +cl /c /O2 /W3 /Tp mrsmall.c +cl /c /O2 /W3 /Tp mrio1.c +cl /c /O2 /W3 /Tp mrio2.c +cl /c /O2 /W3 /Tp mrgcd.c +cl /c /O2 /W3 /Tp mrjack.c +cl /c /O2 /W3 /Tp mrxgcd.c +cl /c /O2 /W3 /Tp mrarth3.c +cl /c /O2 /W3 /Tp mrbits.c +cl /c /O2 /W3 /Tp mrrand.c +cl /c /O2 /W3 /Tp mrprime.c +cl /c /O2 /W3 /Tp mrcrt.c +cl /c /O2 /W3 /Tp mrscrt.c +cl /c /O2 /W3 /Tp mrmonty.c +cl /c /O2 /W3 /Tp mrpower.c +cl /c /O2 /W3 /Tp mrsroot.c +cl /c /O2 /W3 /Tp mrcurve.c +cl /c /O2 /W3 /Tp mrfast.c +cl /c /O2 /W3 /Tp mrlucas.c +cl /c /O2 /W3 /Tp mrzzn2.c +cl /c /O2 /W3 /Tp mrzzn2b.c +cl /c /O2 /W3 /Tp mrzzn3.c +cl /c /O2 /W3 /Tp mrzzn4.c +cl /c /O2 /W3 /Tp mrshs.c +cl /c /O2 /W3 /Tp mrshs256.c +cl /c /O2 /W3 /Tp mrshs512.c +cl /c /O2 /W3 /Tp mrsha3.c +cl /c /O2 /W3 /Tp mrfpe.c +cl /c /O2 /W3 /Tp mraes.c +cl /c /O2 /W3 /Tp mrgcm.c +cl /c /O2 /W3 /Tp mrstrong.c +cl /c /O2 /W3 /Tp mrbrick.c +cl /c /O2 /W3 /Tp mrebrick.c +cl /c /O2 /W3 /Tp mrgf2m.c +cl /c /O2 /W3 /Tp mrec2m.c +cl /c /O2 /W3 /Tp mrecn2.c +cl /c /O2 /W3 /Tp mrflash.c +cl /c /O2 /W3 /Tp mrfrnd.c +cl /c /O2 /W3 /Tp mrdouble.c +cl /c /O2 /W3 /Tp mrround.c +cl /c /O2 /W3 /Tp mrbuild.c +cl /c /O2 /W3 /Tp mrflsh1.c +cl /c /O2 /W3 /Tp mrpi.c +cl /c /O2 /W3 /Tp mrflsh2.c +cl /c /O2 /W3 /Tp mrflsh3.c +cl /c /O2 /W3 /Tp mrflsh4.c +copy mrmuldv.w64 mrmuldv.c +cl /c /O2 /W3 /Tp mrmuldv.c +cl /c /O2 /W3 /EHsc big.cpp +cl /c /O2 /W3 /EHsc zzn.cpp +cl /c /O2 /W3 /EHsc ecn.cpp +cl /c /O2 /W3 /EHsc ec2.cpp +cl /c /O2 /W3 /EHsc flash.cpp + +rem +rem Create library 'miracl.lib' +rem Note that now C++ modules can be put in here as well. +del miracl.lib + +lib /OUT:miracl.lib mrflsh4.obj mrflsh3.obj mrflsh2.obj mrpi.obj mrflsh1.obj +lib /OUT:miracl.lib miracl.lib mrdouble.obj mrflash.obj mrfrnd.obj mrround.obj mrbuild.obj +lib /OUT:miracl.lib miracl.lib mrio2.obj mrio1.obj mrrand.obj mrprime.obj mrcrt.obj mrscrt.obj mrfast.obj +lib /OUT:miracl.lib miracl.lib mrjack.obj mrxgcd.obj mrgcd.obj mrarth3.obj mrarth2.obj mrpower.obj mrsroot.obj +lib /OUT:miracl.lib miracl.lib mrmonty.obj mralloc.obj mrarth1.obj mrarth0.obj mrsmall.obj mrcore.obj mrmuldv.obj +lib /OUT:miracl.lib miracl.lib mrcurve.obj mrshs.obj mraes.obj mrlucas.obj mrstrong.obj mrbrick.obj mrbits.obj +lib /OUT:miracl.lib miracl.lib mrshs256.obj mrshs512.obj mrebrick.obj mrgf2m.obj mrec2m.obj mrzzn2.obj mrzzn3.obj mrzzn4.obj +lib /OUT:miracl.lib miracl.lib mrecn2.obj mrzzn2b.obj mrgcm.obj mrfpe.obj mrsha3.obj +lib /OUT:miracl.lib miracl.lib big.obj zzn.obj ecn.obj ec2.obj flash.obj + +del mr*.obj +rem + +rem Compile and link example programs +cl /O2 /W3 /EHsc brute.cpp miracl.lib +cl /O2 /W3 /EHsc brent.cpp miracl.lib +cl /O2 /W3 /EHsc pk-demo.cpp miracl.lib +cl /O2 /W3 /Tp bmark.c miracl.lib +cl /O2 /W3 /EHsc sample.cpp miracl.lib diff --git a/miracl/lib/msiodoit.bat b/miracl/lib/msiodoit.bat new file mode 100644 index 0000000..c593548 --- /dev/null +++ b/miracl/lib/msiodoit.bat @@ -0,0 +1,87 @@ +rem MIRACL - IBM PC/MS-DOS Version 4.0 +rem This batch files creates miracl.lib from its component parts +rem using the Microsoft 32-bit compiler, (as used in Windows '95 +rem and Windows NT), and the Microsoft LIB librarian utility +rem Also included are the commands to create some of the example programs +rem +rem Read your compiler documentation for further information +rem +rem Invoke as "msiodoit". It is assumed that paths have been correctly set up +rem to the compiler, librarian and linker. +rem +rem NOTE: This batch file will build an Intger-Only version of the MIRACL +rem library, without support for FLASH arithmetic +rem +rem Provided mainly as a guide for creating a batch file tailored +rem specifically to your own configuration. +rem +rem Note - the module mrmuldv.c is not needed if MR_NOASM is defined +rem +rem +rem Compile MIRACL modules +cl /c /O2 mrcore.c +cl /c /O2 mrarth0.c +cl /c /O2 mrarth1.c +cl /c /O2 mrarth2.c +cl /c /O2 mralloc.c +cl /c /O2 mrsmall.c +cl /c /O2 mrio1.c +cl /c /O2 mrio2.c +cl /c /O2 mrgcd.c +cl /c /O2 mrjack.c +cl /c /O2 mrxgcd.c +cl /c /O2 mrarth3.c +cl /c /O2 mrbits.c +cl /c /O2 mrrand.c +cl /c /O2 mrprime.c +cl /c /O2 mrcrt.c +cl /c /O2 mrscrt.c +cl /c /O2 mrmonty.c +cl /c /O2 mrpower.c +cl /c /O2 mrsroot.c +cl /c /O2 mrcurve.c +cl /c /O2 mrfast.c +cl /c /O2 mrlucas.c +cl /c /O2 mrzzn2.c +cl /c /O2 mrzzn3.c +cl /c /O2 mrzzn4.c +cl /c /O2 mrecn2.c +cl /c /O2 mrshs.c +cl /c /O2 mrshs256.c +cl /c /O2 mrfpe.c +cl /c /O2 mraes.c +cl /c /O2 mrgcm.c +cl /c /O2 mrstrong.c +cl /c /O2 mrbrick.c +cl /c /O2 mrebrick.c +cl /c /O2 mrec2m.c +cl /c /O2 mrgf2m.c +cl /c /O2 mrmuldv.c + +rem +rem Create library 'miracl.lib' +del miracl.lib + +lib /OUT:miracl.lib mrio2.obj mrio1.obj mrrand.obj mrprime.obj mrcrt.obj mrscrt.obj mrfast.obj mrecn2.obj mrzzn4.obj +lib /OUT:miracl.lib miracl.lib mrjack.obj mrxgcd.obj mrgcd.obj mrarth3.obj mrarth2.obj mrpower.obj mrsroot.obj +lib /OUT:miracl.lib miracl.lib mrmonty.obj mralloc.obj mrarth1.obj mrarth0.obj mrsmall.obj mrcore.obj mrmuldv.obj +lib /OUT:miracl.lib miracl.lib mrcurve.obj mrshs.obj mraes.obj mrlucas.obj mrstrong.obj mrbrick.obj mrbits.obj +lib /OUT:miracl.lib miracl.lib mrshs256.obj mrebrick.obj mrec2m.obj mrgf2m.obj mrzzn2.obj mrzzn3.obj mrgcm.obj mrfpe.obj +del mr*.obj +rem +cl /c /O2 /GX big.cpp +cl /c /O2 /GX zzn.cpp +cl /c /O2 /GX crt.cpp +cl /c /O2 /GX ecn.cpp +cl /c /O2 /GX ec2.cpp +rem Compile and link example programs +cl /c /O2 /GX brute.cpp +link brute.obj big.obj miracl.lib +cl /c /O2 /GX brent.cpp +link brent.obj big.obj zzn.obj miracl.lib +cl /c /O2 /GX pk-demo.cpp +link pk-demo.obj big.obj crt.obj ecn.obj miracl.lib +cl /c /O2 /GX bmark.c +link bmark.obj miracl.lib + + diff --git a/miracl/lib/msldoit.bat b/miracl/lib/msldoit.bat new file mode 100644 index 0000000..ae56595 --- /dev/null +++ b/miracl/lib/msldoit.bat @@ -0,0 +1,101 @@ +rem MIRACL - IBM PC/MS-DOS Version 4.0 +rem This batch files creates miracl.lib from its component parts +rem using the Microsoft 16-bit compiler, the Microsoft +rem Macro assembler and the Microsoft LIB librarian utility +rem Also included are the commands to create some of the example programs +rem +rem Read your compiler documentation for further information +rem +rem Invoke as "msldoit". It is assumed that paths have been correctly set up +rem to the compiler, macro assembler, librarian and linker. +rem +rem Provided mainly as a guide for creating a batch file tailored +rem specifically to your own configuration. +rem +rem Note - the module mrmuldv.c is not needed if MR_NOASM is defined +rem +rem Compile MIRACL modules +cl /AL /O2 /c mrcore.c +cl /AL /O2 /c mrarth0.c +cl /AL /O2 /c mrarth1.c +cl /AL /O2 /c mrarth2.c +cl /AL /O2 /c mralloc.c +cl /AL /O2 /c mrsmall.c +cl /AL /O2 /c mrio1.c +cl /AL /O2 /c mrio2.c +cl /AL /O2 /c mrgcd.c +cl /AL /O2 /c mrjack.c +cl /AL /O2 /c mrxgcd.c +cl /AL /O2 /c mrarth3.c +cl /AL /O2 /c mrbits.c +cl /AL /O2 /c mrrand.c +cl /AL /O2 /c mrprime.c +cl /AL /O2 /c mrcrt.c +cl /AL /O2 /c mrscrt.c +cl /AL /O2 /c mrmonty.c +cl /AL /O2 /c mrpower.c +cl /AL /O2 /c mrsroot.c +cl /AL /O2 /c mrcurve.c +cl /AL /O2 /c mrfast.c +cl /AL /O2 /c mrshs.c +cl /AL /O2 /c mrshs256.c +cl /AL /O2 /c mrfpe.c +cl /AL /O2 /c mraes.c +cl /AL /O2 /c mrgcm.c +cl /AL /O2 /c mrlucas.c +cl /AL /O2 /c mrzzn2.c +cl /AL /O2 /c mrzzn3.c +cl /AL /O2 /c mrzzn4.c +cl /AL /O2 /c mrecn2.c +cl /AL /O2 /c mrstrong.c +cl /AL /O2 /c mrbrick.c +cl /AL /O2 /c mrebrick.c +cl /AL /O2 /c mrgf2m.c +cl /AL /O2 /c mrec2m.c +cl /AL /O2 /c mrflash.c +cl /AL /O2 /c mrfrnd.c +cl /AL /O2 /c mrdouble.c +cl /AL /O2 /c mrround.c +cl /AL /O2 /c mrbuild.c +cl /AL /O2 /c mrflsh1.c +cl /AL /O2 /c mrpi.c +cl /AL /O2 /c mrflsh2.c +cl /AL /O2 /c mrflsh3.c +cl /AL /O2 /c mrflsh4.c +rem +rem Assemble mrmuldv.c - use inline assembly version +cl /AL /O2 /c mrmuldv.c +rem +rem Create library 'miracl.lib' +del miracl.lib +lib miracl; +lib miracl +mrflsh4+mrflsh3+mrflsh2+mrpi+mrflsh1; +lib miracl +mrdouble+mrflash+mrfrnd+mrround+mrbuild; +lib miracl +mrio2+mrio1+mrrand+mrprime+mrcrt+mrscrt+mrfast+mrgcm+mrzzn4+mrfpe; +lib miracl +mrjack+mrxgcd+mrgcd+mrarth3+mrarth2+mrebrick+mrpower+mrsroot+mrbits; +lib miracl +mrmonty+mralloc+mrarth1+mrarth0+mrsmall+mrcore+mrmuldv+mrzzn2+mrzzn3+mrecn2; +lib miracl +mrcurve+mrshs+mrshs256+mraes+mrlucas+mrstrong+mrbrick+mrec2m+mrgf2m; +del mr*.obj +rem +cl /AL /O2 /c big.cpp +cl /AL /O2 /c zzn.cpp +cl /AL /O2 /c crt.cpp +rem Compile and link example programs +cl /AL /O2 /c brute.cpp +link brute+big,,,miracl; +cl /AL /O2 /c genkey.cpp +link genkey+big,,,miracl; +cl /AL /O2 /c encode.cpp +link encode+big,,,miracl; +cl /AL /O2 /c decode.cpp +link decode+big+crt,,,miracl; +cl /AL /O2 /c brent.cpp +link brent+big+zzn,,,miracl; +cl /AL /O2 /c pollard.cpp +link pollard+big+zzn,,,miracl; +cl /AL /O2 /c pk-demo.cpp +link pk-demo+big+crt,,,miracl; +cl /AL /O2 /c flash.cpp +cl /AL /O2 /c sample.cpp +link sample+flash,,,miracl; + diff --git a/miracl/linux.txt b/miracl/linux.txt new file mode 100644 index 0000000..bfb4fa8 --- /dev/null +++ b/miracl/linux.txt @@ -0,0 +1,46 @@ +RedHat Linux 6.0+ MIRACL i386 x86-32 installation + +Also works OK for Solaris if its x386/Pentium based. + +1. Unzip the MIRACL.ZIP file using the utility unzip, into an empty directory + +unzip -j -aa -L miracl.zip + +The -j ignores the directory structure inside MIRACL.ZIP. The -aa converts all +text files to Unix format, and -L ensures that all filenames are lower-case. + + +2. Perform a tailored build of the MIRACL library by opening a terminal +window, and typing + +bash linux + +3. All the MIRACL applications (except RATCALC) can then be built, as + desired. Remember to link all C applications to the miracl.a library. + C++ applications must be linked as well to one or more of big.o zzn.o + ecn.o crt.o flash.o object files etc. + See the xxx.bat files for examples. Some applications that require + floating-point support may also require -lm in the compile command line. + + +Make sure that your Linux PATH points to the current directory, so that +executables can be run. + +Some programs may require some small changes. For example in schoof.cpp search +for the comment about "platforms". + +Note that Linux already has (a rather pathetic) factor program. To avoid name +clashes you might rename MIRACL's "factor" program to "facter", or somesuch. + + + +For a 64-bit build, on for example an AMD64 or a Core 2 processor (x86-64), use + +bash linux64 + + +IMPORTANT + +Some files might have to be changed from Windows File format, to Unix file format +in order for programs to work correctly. + diff --git a/miracl/mac.txt b/miracl/mac.txt new file mode 100644 index 0000000..965e4ae --- /dev/null +++ b/miracl/mac.txt @@ -0,0 +1,13 @@ + +Running gcc under Snow Leopard requires an under-score in front of the function names in mrmuldv.s64 + +So muldiv becomes _muldiv, etc. + + +On a MAC using GCC, use the flag + +-mdynamic-no-pic + +when compiling MIRACL assembly language modules.. + +(Thanks Augusto) diff --git a/miracl/makemcs.txt b/miracl/makemcs.txt new file mode 100644 index 0000000..1b78be3 --- /dev/null +++ b/miracl/makemcs.txt @@ -0,0 +1,396 @@ +This file offers some guidance for developers who need to create assembly +language Macros for an unsupported processor to support the Comba or KCM +methods for modular multiplication. Note that the "standard" C build of MIRACL +may be fast enough, or else the provided C macros may be sufficient. Use c.mcs +or c1.mcs, but if mr_qltype is defined in mirdef.h, use c3.mcs + +An .mcs file contains C or assembly language macros to implement some simple +operations on big number digits. On most modern Load/Store RISC processors +the optimal assembly language required is fortunately quite generic - and +that's why this approach is possible. The Instruction set need only support +unsigned multiply, add and subtract. It should also support standard indexed +addressing modes, where the effective memory address is calculated by adding +an offset to a register. The compiler should ideally support in-line assembly. + +Correct memory address offsets and label names are automatically inserted by +the mex utility. It uses the standard C function "fprintf" to expand the +macros, and hence inserts appropriate numbers where-ever %d appears in the +macro. This implies that if the symbol % should be part of assembly language +syntax, it must be replaced by %%. + +These macros when extracted by the mex.c program from the specified .mcs +file are used to implement some fast algorithms. + +MULTIPLY + + a2 a1 a0 + b2 b1 b0 + -------------- + a2.b0 a1.b0 a0.b0 + a2.b1 a1.b1 a0.b1 + a2.b2 a1.b2 a0.b2 + ------------------------------ + c4 c3 c2 c1 c0 + + +Here (a1.b0) is a partial product. As we add up each column, the result is +accumulated in a triple-precision register x|y|z. When the column is totalled +z is written to memory and 0|x|y becomes the "carry" to the next column. Note +that x will always be "small", less than the number of partial products in +the longest column. + +The algorithm for fast multi-precision multiplication multiplies a*b=c and +requires the following macros. + + MUL_START + + Push any registers if necessary, Initialise pointers to a, b and c, + and zero the triple-precision register required to accumulate the + partial products. + + STEP + + Calculate a partial product and add it to the triple-register. + The array offsets from the pointers to a and b are inserted + automatically by the mex utility. + + MFIN + + Store total for this column z, and calculate the carry for the next. + + MUL_END + + Store the left over carry in the left-most column, and pop registers + if necessary. + + +MULTUP + +Here we just need the first (lower) half of c=a*b; So we use the same +MUL_START, STEP, and MFIN macros as above. However no carry is needed from +the last column, so a simpler LAST macro is employed here. + +SQUARE + +Multiprecision squaring can be done nearly twice as fast, as partial products +appear twice in most columns, but only need to be calculated once. Observe +that if a=b in the above example then a2.b0 = a0.b2 in the third column. + +This algorithm finds c=a*a + + SQR_START + + Push registers, form pointers to a and c, zeroise triple register + + DSTEP + + Calculate a partial product and add it twice to column total in + the triple register. + + SELF + + Calculate a "diagonal element", e.g. (a1.a1) and add to total. + + SFIN + + Store total for this column z, and calculate the carry for the next + + SQR_END + + Store the left over carry in the left-most column, and pop registers + if necessary. + +REDC + +Montgomery's modular reduction algorithm calculates a%=b; It also accesses +the pre-computed variable "ndash". + + REDC_START + + Push registers, get pointers to a and b, and put ndash in a register. + Initialise the triple register x|y|z to 0|0|a[0] + + RFINU + + Multiply ndash*z and store lower half of result in a[i] for i-th + column. Multiply this number now by b[0]. Add the result to the + triple register x|y|z. Set the triple register to reflect the + "carry" to the next column 0|x|y. Add a[i+1] to the triple register. + + RFIND + + Store z into a[i]. Set triple register to reflect the "carry" + to the next column. Add a[i+1] to the triple register. + + REDC_END + + Store the left-over carry in the left-most two columns. + +This algorithm also uses the STEP macro as described above. + +ADDITION + +This algorithm does a simple element-by-element adition c=a+b, +propagating the carries. + + ADD_START + + Gets pointers to a, b and c. Adds the first two elements + c[0]=a[0]+b[0] + + ADD + + Adds-with-carry c[i]=a[i]+b[i] + + ADD_END + + If the carry flag is still set, set the variable "carry"=1, + otherwise =0 + +INCREMENT + +Very similar to the above, but this time calculates a+=b + + INC_START + + Gets pointers to a and b. Adds the first elements a[0]+=b[0] + + INC + + Adds-with-carry a[i]+=b[i] + + INC_END + + If the carry flag is still set, set the variable "carry=1", + otherwise 0 + +SUBTRACTION + +Find c=a-b, propagating borrows + + SUB_START + + Gets pointers to a, b and c. Subtracts the first two elements + c[0]=a[0]-b[0] + + SUB + + Subtracts-with-borrow c[i]=a[i]-b[i] + + SUB_END + + If there is a "borrow" outstanding, set the variable "carry"=1, + otherwise =0. **NOTE** This MAY be indicated by carry flag=1 OR + by carry flag=0 - it depends on architecture, so be careful. + +DECREMENT + +Find a-=b, propagating borrows + + DEC_START + + Gets pointers to a and b. Subtracts the first two elements + a[0]-=b[0] + + DEC + + Subtracts-with-borrow a[i]-=b[i] + + DEC_END + + If there is a "borrow" outstanding, set the variable "carry"=1, + otherwise =0. **NOTE** This MAY be indicated by carry flag=1 OR + by carry flag=0 - it depends on architecture, so be careful. + +SUMMATION + +Adds c=a+b in a "for" loop. Each time around the loop a fixed block of +digits are added. A total of n such blocks are to be added. + + KADD_START + + Initialise pointers to a, b and c. Move n into a register. Set + the carry flag to zero. Provide a label for looping back to. Note + that label numbers are automatically inserted by the mex utility. + + KASL + + Decrement the n register. If its zero jump to label at the end of + this macro. If its not, advance the pointer registers to point to + the next block, and branch back to label in KADD_START. + **NOTE** It is vitally important that this macro does NOT affect + the carry flag + + KADD_END + + If the carry flag is still set, set the variable "carry=1", + otherwise 0 + +This algorithm also uses the ADD macro. See above + + +INCREMENTATION + +Adds a+=b in a "for" loop. Each time around the loop a fixed block of +digits are added. A total of n such blocks are to be added. + + KINC_START + + Initialise pointers to a and b. Move n into a register. Set + the carry flag to zero. Provide a label for looping back to. Note + that label numbers are automatically inserted by the mex utility. + + KIDL + + Decrement the n register. If its zero jump to label at the end of + this macro. If its not, advance the pointer registers to point to + the next block, and branch back to label in KINC_START. + **NOTE** It is vitally important that this macro does NOT affect + the carry flag + + KINC_END + + If the carry flag is still set, set the variable "carry=1", + otherwise 0 + +This algorithm also uses the INC macro. See above + + +DECREMENTATION + +Subtracts a-=b in a "for" loop. Each time around the loop a fixed block of +digits are subtracted. A total of n such blocks are to be subtracted. + + KDEC_START + + Initialise pointers to a and b. Move n into a register. Set + the carry flag to that state which indicates no borrow. Provide a + label for looping back to. Note that label numbers are automatically + inserted by the mex utility. + + KDEC_END + + Set the variable "carry" to 1 if the carry flag is in that state + which reflects an outstanding "borrow", otherwise 0 + +This algorithm also uses the KIDL and DEC macros. See above. + + +NEW! - April 2002 + +Interleaved steps can be used in multiplication to allow for improved +instruction scheduling. This could be a lot faster if the multiply unit takes +more than 1 clock cycle. The idea is to expose more ILP (Instruction Level +Parallelism) for a modern pipelined (and possibly super-scaler) load-store +processor to chew on. + +In the calculation of the sum of partial products in a column, replace + + STEPM - Multiply + STEPA - Add + STEPM - Multiply + STEPA - Add + STEPM - Multiply + STEPA - Add + STEPM - Multiply + STEPA - Add + +with the interleaved + + STEP1M - Multiply 1 + + STEP2M - Multiply 2 + STEP1A - Add 1 + STEP1M - Multiply 1 + STEP2A - Add 2 + STEP2M - Multiply 2 + STEP1A - Add 1 + + STEP2A - Add 2 + +The same applies to DSTEP for squaring. + +In this way the multiply instruction gets more time to complete to its +destination registers. + +If the MEX program sees that STEP1M macro is present as well as STEP, +it will permit scheduling with the -s flag as above. Of course this requires +that there to be enough registers - STEP1x and STEP2x should ideally use +different registers. + +If this is going to help it is particularly important that the destination +registers of the multiply steps STEP1M and STEP2M be distinct. + +Many processors use hardware dynamic scheduling (like the Pentium II). +For such a processor scheduling the code like this will have little +effect. The ARM assembler re-orders the code automatically for +optimum scheduling, so again scheduling the code like this will have little +impact. + +Some example *.mcs files in this format are included - see c.mcs and +arm.mcs for example. + +This idea could be extended in a fairly obvious way, for example + + STEP1M - Multiply 1 + STEP2M - Multiply 2 + STEP3M - Multiply 3 + + STEP1A - Add 1 + STEP1M - Multiply 1 + STEP2A - Add 2 + STEP2M - Multiply 2 + STEP3A - Add 3 + STEP3M - Multiply 3 + STEP1A - Add 1 + STEP1M - Multiply 1 + + STEP2A - Add 2 + STEP3A - Add 3 + STEP1A - Add 1 + +This is currently NOT supported, it would require a relatively simple +modification to mex.c + +This might be justified in the case of a very deeply pipelined multiplier. +The idea would be that Multiply 1, 2, and 3 might all be active +simultaneously. + + + +New features 12/10/2007 + +NEW: PMUL, PMUL_START and PMUL_END macros to support fast reduction for +pseudo mersenne prime moduli. + + +PMULT + +When reducing modulo p=2^m-d, where m is a multiple of the word length and +d is single precision, we have the useful identity 2^m=d mod p. The product +of two field elements can be considered as 2^m.U+L, where U is the upper +half of the product, and L is the lower half. Therefore the reduced value +is 2^m.U+L mod p = dU+L. The dU component can in turn be considered as +2^m.x+Y, where x will be single precision. So the final result is d.x+Y+L. +Finally a couple of subtractions of p might be required to get a result +less than p. The function PMULT calculates d.x and Y + + PMUL_START + + Initialises pointers to the top half of the product a[], and arrays + to hold d.x (b[]) and Y (c[]). Moves d to a register. + + PMUL + + Sets c[i]=a[i]*d and propagates carries. Sets b[i]=0 + + PMUL_END + + Sets b[0] (and b[1]) to d.x + +NEW: Macros to support Hybrid method - see http://eprint.iacr.org/2007/299 +Basically a 2x2 or 4x4 block of partial products are calculated together +which reduces memory accesses. Uses more registers. + + + diff --git a/miracl/managed.txt b/miracl/managed.txt new file mode 100644 index 0000000..8b8e408 --- /dev/null +++ b/miracl/managed.txt @@ -0,0 +1,206 @@ + +It is possible to create a version of the MIRACL library which consists of +Microsoft Studio compatible "managed code", for .NET applications. + +In managed code (aka C++/CLI), the MIRACL modules must be compiled as C++ +code into an Intermediate Language (IL), which is not native assembly +language. This IL is compatible with code generated by other languages like +C# and Java, supports portability and enhanced runtime error checking and +heap management. Using sophisticated Just-In-Time compilation techniques, +this IL can itself be compiled "on-the fly" into native machine code, and +hence runs surprisingly fast. + +To generate managed code the compiler flags /clr and /TP must be used. +However modules containing in-line assembly or using compiler intrinsics +cannot be compiled to IL, and are instead compiled directly to native +machine code. This is not necessarily a problem, as IL and native assembly +language modules can be mixed. + +Since MIRACL modules must be compiled as C++ and not as C, it is important +to define MR_CPP in mirdef.h to ensure that MIRACL C++ modules are aware +that the MIRACL library now uses C++ function calling conventions. + +A 100% managed code build of miracl will NOT be as fast as one compiled +directly to native machine code. + +The .NET framework supports mixing of languages, so one may want for +example to use MIRACL functionality with C#. The best way to proceed +is to build a C++ DLL, and link to C# using (from the command line) + +csc your_program.cs /r:miracl_based_code.dll + +To communicate between C++ and C#, you need to use a supported type. +For cryptographic keys and the like a byte array is best. So on the C# side + +byte[] KEY = new byte[32]; + +On the C++ side, declare the function parameter like + +array^ KEY + +Also on the C# side + +String ID="Alice"; + +The C++ parameter in this case is + +String^ ID + +You can use the MIRACL big_to_bytes() and bytes_to_big() functions to convert +from the internal MIRACL structures to simple byte arrays. + +To build a 100% managed code (no flash arithmetic) version of MIRACL, +proceed as follows: + +Copy this to mirdef.h + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype __int64 +#define mr_unsign64 unsigned __int64 +#define MR_ALWAYS_BINARY +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_NOASM +#define MR_BITSINCHAR 8 +#define MR_CPP + +Build the library using this batch file + +----------------------------------------------------------- +rem Compile MIRACL modules +cl /clr /TP /c /O2 /W3 mrcore.c +cl /clr /TP /c /O2 /W3 mrarth0.c +cl /clr /TP /c /O2 /W3 mrarth1.c +cl /clr /TP /c /O2 /W3 mrarth2.c +cl /clr /TP /c /O2 /W3 mralloc.c +cl /clr /TP /c /O2 /W3 mrsmall.c +cl /clr /TP /c /O2 /W3 mrio1.c +cl /clr /TP /c /O2 /W3 mrio2.c +cl /clr /TP /c /O2 /W3 mrgcd.c +cl /clr /TP /c /O2 /W3 mrjack.c +cl /clr /TP /c /O2 /W3 mrxgcd.c +cl /clr /TP /c /O2 /W3 mrarth3.c +cl /clr /TP /c /O2 /W3 mrbits.c +cl /clr /TP /c /O2 /W3 mrrand.c +cl /clr /TP /c /O2 /W3 mrprime.c +cl /clr /TP /c /O2 /W3 mrcrt.c +cl /clr /TP /c /O2 /W3 mrscrt.c +cl /clr /TP /c /O2 /W3 mrmonty.c +cl /clr /TP /c /O2 /W3 mrpower.c +cl /clr /TP /c /O2 /W3 mrsroot.c +cl /clr /TP /c /O2 /W3 mrcurve.c +cl /clr /TP /c /O2 /W3 mrfast.c +cl /clr /TP /c /O2 /W3 mrlucas.c +cl /clr /TP /c /O2 /W3 mrzzn2.c +cl /clr /TP /c /O2 /W3 mrzzn2b.c +cl /clr /TP /c /O2 /W3 mrzzn3.c +cl /clr /TP /c /O2 /W3 mrshs.c +cl /clr /TP /c /O2 /W3 mrshs256.c +cl /clr /TP /c /O2 /W3 mrshs512.c +cl /clr /TP /c /O2 /W3 mraes.c +cl /clr /TP /c /O2 /W3 mrgcm.c +cl /clr /TP /c /O2 /W3 mrstrong.c +cl /clr /TP /c /O2 /W3 mrbrick.c +cl /clr /TP /c /O2 /W3 mrebrick.c +cl /clr /TP /c /O2 /W3 mrgf2m.c +cl /clr /TP /c /O2 /W3 mrec2m.c +cl /clr /TP /c /O2 /W3 mrecn2.c + +rem +rem Create library 'miracl.lib' +del miracl.lib + +lib /OUT:miracl.lib mrio2.obj mrio1.obj mrrand.obj mrprime.obj mrcrt.obj mrscrt.obj mrfast.obj +lib /OUT:miracl.lib miracl.lib mrjack.obj mrxgcd.obj mrgcd.obj mrarth3.obj mrarth2.obj mrpower.obj mrsroot.obj +lib /OUT:miracl.lib miracl.lib mrmonty.obj mralloc.obj mrarth1.obj mrarth0.obj mrsmall.obj mrcore.obj mrgcm.obj +lib /OUT:miracl.lib miracl.lib mrcurve.obj mrshs.obj mraes.obj mrlucas.obj mrstrong.obj mrbrick.obj mrbits.obj +lib /OUT:miracl.lib miracl.lib mrshs256.obj mrshs512.obj mrebrick.obj mrgf2m.obj mrec2m.obj mrzzn2.obj mrzzn3.obj +lib /OUT:miracl.lib miracl.lib mrecn2.obj mrzzn2b.obj + +del mr*.obj + +rem compile one example program + +cl /O2 /clr pk-demo.cpp big.cpp ecn.cpp miracl.lib +-------------------------------------------------------------- + +For a 64-bit build use this as mirdef.h + +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype __int64 +#define mr_unsign64 unsigned __int64 +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_ALWAYS_BINARY +#define MR_CPP +#define MR_NO_INTRINSICS + +and build using this batch file + +--------------------------------------------------------------- + +cl /clr /TP /c /O2 /W3 mrcore.c +cl /clr /TP /c /O2 /W3 mrarth0.c +cl /clr /TP /c /O2 /W3 mrarth1.c +cl /clr /TP /c /O2 /W3 mrarth2.c +cl /clr /TP /c /O2 /W3 mralloc.c +cl /clr /TP /c /O2 /W3 mrsmall.c +cl /clr /TP /c /O2 /W3 mrio1.c +cl /clr /TP /c /O2 /W3 mrio2.c +cl /clr /TP /c /O2 /W3 mrgcd.c +cl /clr /TP /c /O2 /W3 mrjack.c +cl /clr /TP /c /O2 /W3 mrxgcd.c +cl /clr /TP /c /O2 /W3 mrarth3.c +cl /clr /TP /c /O2 /W3 mrbits.c +cl /clr /TP /c /O2 /W3 mrrand.c +cl /clr /TP /c /O2 /W3 mrprime.c +cl /clr /TP /c /O2 /W3 mrcrt.c +cl /clr /TP /c /O2 /W3 mrscrt.c +cl /clr /TP /c /O2 /W3 mrmonty.c +cl /clr /TP /c /O2 /W3 mrpower.c +cl /clr /TP /c /O2 /W3 mrsroot.c +cl /clr /TP /c /O2 /W3 mrcurve.c +cl /clr /TP /c /O2 /W3 mrfast.c +cl /clr /TP /c /O2 /W3 mrlucas.c +cl /clr /TP /c /O2 /W3 mrzzn2.c +cl /clr /TP /c /O2 /W3 mrzzn2b.c +cl /clr /TP /c /O2 /W3 mrzzn3.c +cl /clr /TP /c /O2 /W3 mrshs.c +cl /clr /TP /c /O2 /W3 mrshs256.c +cl /clr /TP /c /O2 /W3 mrshs512.c +cl /clr /TP /c /O2 /W3 mraes.c +cl /clr /TP /c /O2 /W3 mrgcm.c +cl /clr /TP /c /O2 /W3 mrstrong.c +cl /clr /TP /c /O2 /W3 mrbrick.c +cl /clr /TP /c /O2 /W3 mrebrick.c +cl /clr /TP /c /O2 /W3 mrgf2m.c +cl /clr /TP /c /O2 /W3 mrec2m.c +cl /clr /TP /c /O2 /W3 mrecn2.c +copy mrmuldv.w64 mrmuldv.c +cl /clr /TP /c /O2 /W3 mrmuldv.c + +rem +rem Create library 'miracl.lib' +del miracl.lib + +lib /OUT:miracl.lib mrio2.obj mrio1.obj mrrand.obj mrprime.obj mrcrt.obj mrscrt.obj mrfast.obj mrmuldv.obj +lib /OUT:miracl.lib miracl.lib mrjack.obj mrxgcd.obj mrgcd.obj mrarth3.obj mrarth2.obj mrpower.obj mrsroot.obj +lib /OUT:miracl.lib miracl.lib mrmonty.obj mralloc.obj mrarth1.obj mrarth0.obj mrsmall.obj mrcore.obj +lib /OUT:miracl.lib miracl.lib mrcurve.obj mrshs.obj mraes.obj mrlucas.obj mrstrong.obj mrbrick.obj mrbits.obj +lib /OUT:miracl.lib miracl.lib mrshs256.obj mrshs512.obj mrebrick.obj mrgf2m.obj mrec2m.obj mrzzn2.obj mrzzn3.obj +lib /OUT:miracl.lib miracl.lib mrecn2.obj mrzzn2b.obj mrgcm.obj + +del mr*.obj +rem + +cl /O2 /clr pk-demo.cpp big.cpp ecn.cpp miracl.lib + +------------------------------------------------------------------ diff --git a/miracl/manual.doc b/miracl/manual.doc new file mode 100644 index 0000000..9ffd8df Binary files /dev/null and b/miracl/manual.doc differ diff --git a/miracl/mex.c b/miracl/mex.c new file mode 100644 index 0000000..6af662f --- /dev/null +++ b/miracl/mex.c @@ -0,0 +1,1076 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* mex.c + * + * Updated to allow emission of scheduled code. + * + * Macro EXpansion program. + * Expands Macros from a .mcs file into a .tpl file to create a .c file + * + */ + +#include +#include +#include + +typedef int BOOL; +#define FALSE 0 +#define TRUE 1 + +/* Define Algorithms */ + +#define MULTIPLY 0 +#define MULTUP 1 +#define SQUARE 2 +#define REDC 3 +#define ADDITION 4 +#define INCREMENT 5 +#define SUBTRACTION 6 +#define DECREMENT 7 +#define SUMMATION 8 +#define INCREMENTATION 9 +#define DECREMENTATION 10 +#define MULTIPLY2 11 +#define ADDITION2 12 +#define SUBTRACTION2 13 +#define PMULT 14 +#define DOUBLEIT 15 + + +/* Define Macros */ + +#define MUL_START 0 +#define STEP 1 +#define STEP1M 2 +#define STEP1A 3 +#define STEP2M 4 +#define STEP2A 5 +#define MFIN 6 +#define MUL_END 7 +#define LAST 8 +#define SQR_START 9 +#define DSTEP 10 +#define DSTEP1M 11 +#define DSTEP1A 12 +#define DSTEP2M 13 +#define DSTEP2A 14 +#define SELF 15 +#define SFIN 16 +#define SQR_END 17 +#define REDC_START 18 +#define RFINU 19 +#define RFIND 20 +#define REDC_END 21 +#define ADD_START 22 +#define ADD 23 +#define ADD_END 24 +#define SUB_START 25 +#define SUB 26 +#define SUB_END 27 +#define INC_START 28 +#define INC 29 +#define INC_END 30 +#define DEC_START 31 +#define DEC 32 +#define DEC_END 33 +#define KADD_START 34 +#define KASL 35 +#define KADD_END 36 +#define KINC_START 37 +#define KIDL 38 +#define KINC_END 39 +#define KDEC_START 40 +#define KDEC_END 41 +#define STEPB 42 +#define STEPB1M 43 +#define STEPB1A 44 +#define STEPB2M 45 +#define STEPB2A 46 +#define H2_MUL_START 47 +#define H2_STEP 48 +#define H2_MFIN 49 +#define H2_MUL_END 50 +#define H2_SQR_START 51 +#define H2_DSTEP 52 +#define H2_SELF 53 +#define H2_SFIN 54 +#define H2_SQR_END 55 +#define H4_MUL_START 56 +#define H4_STEP 57 +#define H4_MFIN 58 +#define H4_MUL_END 59 +#define H4_SQR_START 60 +#define H4_DSTEP 61 +#define H4_SELF 62 +#define H4_SFIN 63 +#define H4_SQR_END 64 +#define H2_LAST 65 +#define H4_LAST 66 +#define PMUL_START 67 +#define PMUL 68 +#define PMUL_END 69 +#define MULB_START 70 +#define MULB_END 71 +#define MBFIN 72 +#define H2_MULB_START 73 +#define H2_MULB_END 74 +#define H2_MBFIN 75 +#define H2_STEPB 76 +#define H4_MULB_START 77 +#define H4_MULB_END 78 +#define H4_MBFIN 79 +#define H4_STEPB 80 +#define H2_REDC_START 81 +#define H2_RFINU 82 +#define H2_RFIND 83 +#define H2_REDC_END 84 +#define H4_REDC_START 85 +#define H4_RFINU 86 +#define H4_RFIND 87 +#define H4_REDC_END 88 +#define DOUBLE_START 89 +#define DOUBLE 90 +#define DOUBLE_END 91 +#define LAST_ONE 92 + +BOOL scheduled; +int hybrid,hybrid_b,pmp,hybrid_r; + +int PARAM; +char *macro[LAST_ONE]; /* macro text */ + +char *functions[]={(char *)"MULTIPLY",(char *)"MULTUP",(char *)"SQUARE",(char *)"REDC",(char *)"ADDITION",(char *)"INCREMENT", + (char *)"SUBTRACTION",(char *)"DECREMENT",(char *)"SUMMATION",(char *)"INCREMENTATION", + (char *)"DECREMENTATION",(char *)"MULTIPLY2",(char *)"ADDITION2",(char *)"SUBTRACTION2",(char *)"PMULT",(char *)"DOUBLEIT",NULL}; + +char *names[]={(char *)"MUL_START",(char *)"STEP",(char *)"STEP1M",(char *)"STEP1A",(char *)"STEP2M", + (char *)"STEP2A",(char *)"MFIN",(char *)"MUL_END",(char *)"LAST",(char *)"SQR_START",(char *)"DSTEP", + (char *)"DSTEP1M",(char *)"DSTEP1A",(char *)"DSTEP2M",(char *)"DSTEP2A",(char *)"SELF", + (char *)"SFIN",(char *)"SQR_END",(char *)"REDC_START",(char *)"RFINU",(char *)"RFIND", + (char *)"REDC_END",(char *)"ADD_START",(char *)"ADD",(char *)"ADD_END",(char *)"SUB_START",(char *)"SUB", + (char *)"SUB_END",(char *)"INC_START",(char *)"INC",(char *)"INC_END",(char *)"DEC_START",(char *)"DEC", + (char *)"DEC_END",(char *)"KADD_START",(char *)"KASL",(char *)"KADD_END",(char *)"KINC_START",(char *)"KIDL", + (char *)"KINC_END",(char *)"KDEC_START",(char *)"KDEC_END",(char *)"STEPB",(char *)"STEPB1M",(char *)"STEPB1A",(char *)"STEPB2M",(char *)"STEPB2A", + (char *)"H2_MUL_START",(char *)"H2_STEP",(char *)"H2_MFIN",(char *)"H2_MUL_END", + (char *)"H2_SQR_START",(char *)"H2_DSTEP",(char *)"H2_SELF",(char *)"H2_SFIN",(char *)"H2_SQR_END", + (char *)"H4_MUL_START",(char *)"H4_STEP",(char *)"H4_MFIN",(char *)"H4_MUL_END", + (char *)"H4_SQR_START",(char *)"H4_DSTEP",(char *)"H4_SELF",(char *)"H4_SFIN",(char *)"H4_SQR_END",(char *)"H2_LAST",(char *)"H4_LAST", + (char *)"PMUL_START",(char *)"PMUL",(char *)"PMUL_END",(char *)"MULB_START",(char *)"MULB_END",(char *)"MBFIN", + (char *)"H2_MULB_START",(char *)"H2_MULB_END",(char *)"H2_MBFIN",(char *)"H2_STEPB", + (char *)"H4_MULB_START",(char *)"H4_MULB_END",(char *)"H4_MBFIN",(char *)"H4_STEPB", + (char *)"H2_REDC_START",(char *)"H2_RFINU",(char *)"H2_RFIND",(char *)"H2_REDC_END", + (char *)"H4_REDC_START",(char *)"H4_RFINU",(char *)"H4_RFIND",(char *)"H4_REDC_END", + (char *)"DOUBLE_START",(char *)"DOUBLE",(char *)"DOUBLE_END",NULL}; + +BOOL white(char c) +{ + if (c==' ' || c=='\n' || c=='\r' || c=='\t') return TRUE; + else return FALSE; +} + +int skip(char *c,int i) +{ + while (white(c[i])) i++; + return i; +} + +int which(char *name,char *names[]) +{ + int ipt=0; + while (names[ipt]!=NULL) + { + if (strcmp(name,names[ipt])==0) return ipt; + ipt++; + } + return -1; +} + +void m_prologue(FILE *dotc,int k,int m) +{ + fprintf(dotc,macro[STEP1M],k,m); +} + +void m_epilogue(FILE *dotc,int x) +{ + if (x==1) fprintf(dotc,macro[STEP1A]); + else fprintf(dotc,macro[STEP2A]); +} + +void m_schedule(FILE *dotc,int x,int k,int m) +{ + if (x==1) + { + fprintf(dotc,macro[STEP2M],k,m); + fprintf(dotc,macro[STEP1A]); + } + else + { + fprintf(dotc,macro[STEP1M],k,m); + fprintf(dotc,macro[STEP2A]); + } +} + +void m_prologue2(FILE *dotc,int k,int m) +{ + fprintf(dotc,macro[STEPB1M],k,m); +} + +void m_epilogue2(FILE *dotc,int x) +{ + if (x==1) fprintf(dotc,macro[STEPB1A]); + else fprintf(dotc,macro[STEPB2A]); +} + +void m_schedule2(FILE *dotc,int x,int k,int m) +{ + if (x==1) + { + fprintf(dotc,macro[STEPB2M],k,m); + fprintf(dotc,macro[STEPB1A]); + } + else + { + fprintf(dotc,macro[STEPB1M],k,m); + fprintf(dotc,macro[STEPB2A]); + } +} + +void s_prologue(FILE *dotc,int k,int m) +{ + fprintf(dotc,macro[DSTEP1M],k,m); +} + +void s_epilogue(FILE *dotc,int x) +{ + if (x==1) fprintf(dotc,macro[DSTEP1A]); + else fprintf(dotc,macro[DSTEP2A]); +} + +void s_schedule(FILE *dotc,int x,int k,int m) +{ + if (x==1) + { + fprintf(dotc,macro[DSTEP2M],k,m); + fprintf(dotc,macro[DSTEP1A]); + } + else + { + fprintf(dotc,macro[DSTEP1M],k,m); + fprintf(dotc,macro[DSTEP2A]); + } +} + +/* Insert functions into template file */ + +void insert(int index,FILE *dotc) +{ + int i,k,m,n,x,inc; + switch (index) + { + case PMULT: + if (!pmp) break; + fprintf(dotc,macro[PMUL_START]); + for (i=0;i4) + { + printf("Bad arguments\n"); + printf("mex <.mcs file> <.tpl file>\n"); + printf("Use flag -s for scheduled code\n"); + printf("Examples:\n"); + printf("mex 6 ms86 mrcomba\n"); + printf("mex -s 8 c mrkcm\n"); + exit(0); + } + ip=0; + scheduled=FALSE; + if (strcmp(argv[0],"-s")==0) + { + ip=1; + scheduled=TRUE; + } + + PARAM=atoi(argv[ip]); + if (PARAM<2 || PARAM>40) + { + printf("Invalid parameter\n"); + exit(0); + } + strcpy(fname,argv[ip+1]); + strcat(fname,".mcs"); + macros=fopen(fname,"rt"); + if (macros==NULL) + { + printf("Macro file %s not found\n",fname); + exit(0); + } + + strcpy(tmpl,argv[ip+2]); + strcat(tmpl,".tpl"); + templat=fopen(tmpl,"rt"); + if (templat==NULL) + { + printf("Template file %s file not found\n",tmpl); + exit(0); + } + strcpy(tmpl,argv[ip+2]); + strcat(tmpl,".c"); + dotc=fopen(tmpl,"wt"); + if (dotc==NULL) + { + printf("Unable to open %s for output\n",tmpl); + exit(0); + } + + for (i=0;i +#include + +void _mon_putc (char c) +{ + while (U1STAbits.UTXBF); + U1TXREG = c; +} + +At the very start of the main() program add + + U1MODEbits.UARTEN = 0x01; + U1STAbits.UTXEN = 0x01; + +This magic is required to redirect printf() to UART1 + +Click on Debugger->Settings and the UART1 IO Tab. Enable UART1 IO +and redirect the output to a window. + +Click on Project->Build options->project and the Linker Tab. +Create a heap of 65536 bytes and a stack of 1024 bytes + +Build and Run the program. You should see the output in the Output Window, +SIM Uart1 Tab + +The PIC32 uses a MIPS core. This architecture does not support a carry flag +and so Assembly language implementation will not be much faster than +C generated code. + +To run the application ecdhp32.c, add the same "magic" as before +to redirect printf to UART1. + +Use as mirdef.h + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN +#define mr_utype int +#define mr_unsign32 unsigned int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_dltype long long +#define mr_unsign64 unsigned long long +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 5 +#define MR_STATIC 5 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MR_PSEUDO_MERSENNE +#define MR_SPECIAL +#define MR_NOASM + +And build the library from the command line + +mex 5 c mrcomba +pic32-gcc -c -g mrcore.c +pic32-gcc -c -g mrarth0.c +pic32-gcc -c -g mrarth1.c +pic32-gcc -c -g mrarth2.c +pic32-gcc -c -g mrsmall.c +pic32-gcc -c -g mrio1.c +pic32-gcc -c -g mrjack.c +pic32-gcc -c -g mrbits.c +pic32-gcc -c -g mrxgcd.c +pic32-gcc -c -g mrmonty.c +pic32-gcc -c -g mrsroot.c +pic32-gcc -c -g mrcurve.c +pic32-gcc -c -g mrlucas.c +pic32-gcc -c -g mrebrick.c +pic32-gcc -c -g mrcomba.c + +pic32-ar -rc miracl.a mrcore.o mrarth0.o mrarth1.o mrarth2.o mrsmall.o +pic32-ar -r miracl.a mrio1.o mrjack.o mrxgcd.o +pic32-ar -r miracl.a mrmonty.o mrcurve.o +pic32-ar -r miracl.a mrebrick.o mrsroot.o mrlucas.o +pic32-ar -r miracl.a mrbits.o mrcomba.o +del mr*.o + +This time no heap is required. + +Note that -O2 optimization causes a problem. However introducing +each individual optimization from + +http://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Optimize-Options.html + +works fine. + +Note that -O2 optimization works OK with MicroChip's newer MPLAB-X tool, +which uses a more up-to-date version 4.5 of the GCC compiler. diff --git a/miracl/powerpc.txt b/miracl/powerpc.txt new file mode 100644 index 0000000..e506f0d --- /dev/null +++ b/miracl/powerpc.txt @@ -0,0 +1,76 @@ + +64-bit PowerPC G5 processor now fully supported using GCC Compiler + +Use a header file like + +#define MR_BIG_ENDIAN +#define MIRACL 64 +#define mr_utype long +#define MR_IBITS 32 +#define MR_LBITS 64 +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned long +#define MR_ALWAYS_BINARY +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 + +and use assembly language file mrmuldv.ppc renamed to mrmuldv.c +Or extract it from mrmuldv.any + +To build the miracl library, extract below into a file "powerpc" and execute + +bash powerpc + +------------------------------- + +rm miracl.a +gcc -m64 -c -O2 mrcore.c +gcc -m64 -c -O2 mrarth0.c +gcc -m64 -c -O2 mrarth1.c +gcc -m64 -c -O2 mrarth2.c +gcc -m64 -c -O2 mralloc.c +gcc -m64 -c -O2 mrsmall.c +gcc -m64 -c -O2 mrbits.c +gcc -m64 -c -O2 mrio1.c +gcc -m64 -c -O2 mrio2.c +gcc -m64 -c -O2 mrgcd.c +gcc -m64 -c -O2 mrjack.c +gcc -m64 -c -O2 mrxgcd.c +gcc -m64 -c -O2 mrarth3.c +gcc -m64 -c -O2 mrrand.c +gcc -m64 -c -O2 mrprime.c +gcc -m64 -c -O2 mrcrt.c +gcc -m64 -c -O2 mrscrt.c +gcc -m64 -c -O2 mrmonty.c +gcc -m64 -c -O2 mrpower.c +gcc -m64 -c -O2 mrcurve.c +gcc -m64 -c -O2 mrfast.c +gcc -m64 -c -O2 mrzzn2.c +gcc -m64 -c -O2 mrzzn2b.c +gcc -m64 -c -O2 mrzzn3.c +gcc -m64 -c -O2 mrecn2.c +gcc -m64 -c -O2 mrshs.c +gcc -m64 -c -O2 mrshs256.c +gcc -m64 -c -O2 mrshs512.c +gcc -m64 -c -O2 mraes.c +gcc -m64 -c -O2 mrgcm.c +gcc -m64 -c -O2 mrlucas.c +gcc -m64 -c -O2 mrstrong.c +gcc -m64 -c -O2 mrbrick.c +gcc -m64 -c -O2 mrebrick.c +gcc -m64 -c -O2 mrgf2m.c +gcc -m64 -c -O2 mrec2m.c +gcc -m64 -c -O2 mrmuldv.c +ar rc miracl.a mrcore.o mrarth0.o mrarth1.o mrarth2.o mralloc.o mrsmall.o mrgcm.o +ar r miracl.a mrio1.o mrio2.o mrjack.o mrgcd.o mrxgcd.o mrarth3.o mrbits.o mrzzn3.o +ar r miracl.a mrrand.o mrprime.o mrcrt.o mrscrt.o mrmonty.o mrcurve.o mrzzn2.o mrzzn2b.o +ar r miracl.a mrpower.o mrfast.o mrshs.o mrshs256.o mraes.o mrlucas.o mrstrong.o +ar r miracl.a mrbrick.o mrebrick.o mrec2m.o mrgf2m.o mrshs512.o mrmuldv.o mrecn2.o +gcc -I. -O2 -m64 brent.c miracl.a -o brent +rm mr*.o + +---------------------------------------------------- + + +There is also a macro file gccppc.mcs - see kcmcomba.txt and makemcs.txt + diff --git a/miracl/problems.txt b/miracl/problems.txt new file mode 100644 index 0000000..fd571bc --- /dev/null +++ b/miracl/problems.txt @@ -0,0 +1,87 @@ +MIRACL - Bug warnings + +The MIRACL library is written in standard C and has been tested on many +combinations of computer and compiler. It should work on any system which +supports C as defined by Kernighan and Richie. The author is interested to +hear of any problems that arise with other configurations. + +**** NOTE: If upgrading an old version of MIRACL, make sure to replace all old +files with new ones. In particular make sure to replace headers, such as +MIRACL.H. Newer versions of this header may have extensions to the "miracl" +structure. If an old MIRACL.H header is inadvertently used, the offsets +within this structure will be wrong, and all sorts of obscure run-time errors +will ensue. + +Remember - not all compilers are perfect! MIRACL already contains work- +arounds which were necessary to circumvent bugs in certain compilers. +Some of the routines in MIRACL stretch a compiler's completeness to +the limit. + +Some drastic bugs, however, cannot be avoided. + +For example the early Microsoft C Version 5.0 (not to be confused with the +current C++ compiler), sometimes got the wrong +answer when dividing two unsigned longs. For example try dividing 4294967167 +by 71583361. It gets 60. The correct answer is 59. This problem makes it +impossible to use a full-width base using this compiler with 'mr_utypes' defined +as 'long'. This problem was fixed in version 5.1 (but think of +Star Wars - the Strategic Defence Initiative - and worry). + +Other possible problems: + +Remember that the example programs must be linked to a pre-compiled MIRACL +library, so that the MIRACL routines can be incorporated into the executables. + +Most 32-bit compilers now support a 64-bit type. But unfortunately some call +it "long long", while others call it "__int64". Make sure the right name is +used in mirdef.h + +C programs need only be linked to the MIRACL library. + +But note that C++ programs need also to be linked to at least one or more of +the object files created by compiling big.cpp, zzn.cpp, crt.cpp, +ecn.cpp or flash.cpp. See the xxDOIT.BAT files for examples. + +When using RATCALC.EXE on an IBM PC or compatible, be sure to set up your +system to use US Code Page 437, otherwise certain graphics characters will +appear incorrectly on the screen. See your DOS documentation for details. + +Remember to include stdio.h BEFORE including miracl.h in your C programs. +Similarly include I/O libraries before big.h, number.h or flash.h in C++ +programs. This is important as certain types (such as FILE *) need to be +defined before the MIRACL headers are included. + +Most user problems arise due to building the MIRACL library with the wrong +MIRDEF.H file, or by inclusion of the wrong assembly language routines +from mrmuldv.any. Be careful. Only use MIRDEF.H32 if you have both a true 32- +bit CPU *AND* a true 32-bit compiler. + +The "fast" code for modular arithmetic is NOT included in +the precompiled libraries. To use this code the individual module e.g. +mrkcm.c must be seperately created using the mex utility, compiled and linked +in. Note also that only one of these methods can be used at a time. +Whenever possible use config.c to generate a valid MIRDEF.H + +Early versions of the GCC compiler did not seem to like the generated mrcomba.c and +mrkcm.c files. If it objects switch off optimization - the inline assembly is +optimized enough. Or try -fomit-frame-pointer + +If using MIRACL on a computer which does not support a +fullwidth number base, remember to (a) #define MR_NOFULLWIDTH in +mirdef.h, and (b) use mirsys(...,MAXBASE) instead of mirsys(...,0) in all +your programs. + +Try using the config.c program to automatically generate a mirdef.h +file for you. + +If you have any other problems with MIRACL, please let us know. Email to +mscott@indigo.ie + +DISCLAIMER + +In no event will the Authors be liable to you for any damages, including +any lost profits, lost savings or other incidental or consequential +damages arising out of the use of or inability to use these programs, +even if the Authors have been advised of the possibility of such damages, +or for any claim by any other party. + diff --git a/miracl/readme.txt b/miracl/readme.txt new file mode 100644 index 0000000..81ddd13 --- /dev/null +++ b/miracl/readme.txt @@ -0,0 +1,448 @@ +IMPORTANT! See UPDATE.TXT for latest changes + +Then read FIRST.TXT + +The distribution media contains the following files + + README.TXT - This file + FIRST.TXT - Read this next + MSVISUAL.TXT - Microsoft Visual C++ V6.0 quick-start instructions + VC2005.TXT - Microsoft Visual C++ V8.0 quick-start instructions + BORLAND.TXT - Borland C quick-start instructions + ARM.TXT - ARM processor advice + SPARC.TXT - SPARC processor advice + ITANIUM.TXT - ITANIUM processor advice + FASTGF2M.TXT - How to speed up methods based on the field GF(2^m) + WIN64.TXT - 64-bit Windows advice + DEVCPP.TXT - DEV-CPP quick-start instructions + TEXASDSP.TXT - Texas C6713 DSP advice + AMD64.TXT - AMD64 processor advice + SSE2.TXT - SSE2 extensions advice + PIC32.TXT - PIC32 processor advice + POWERPC.TXT - POWERPC processor advice + LINUX.TXT - Some advice for Linux users + CYGWIN.TXT - How to install MIRACL using Cygwin + MANUAL.DOC - The Manual - read it! + PROBLEMS.TXT - Known problems with MIRACL + UPDATE.TXT - MIRACL Update History + KCMCOMBA.TXT - Using super-fast techniques + MAKEMCS.TXT - How to create your own .mcs file + DOUBLE.TXT - Using a double underlying type + FLOAT.TXT - Multiprecision floating-point + DOUBIG.TXT - How to allow "Double Precision" big types + EDWARDS.TXT - How to use Edwards curves for Elliptic curve crypto over Fp + MANAGED.TXT - How to build a "managed code" version of MIRACL for .NET applications + AESGCM.TXT - New support for AES-GCM mode of operation + BLACKFIN.TXT - For information on Analog devices Blackfin processors + CONFIG.C - Program to automatically generate a mirdef.h file + MEX.C - Program to insert fast macros into mrcomba.c/mrkcm.c + FPE.PDF - Paper on Format Preserving Encryption + +In the subdirectory SOURCE + + MRMULDV.ANY - Contains assembly language versions of muldiv,muldvm, + muldvd and muldvd2 + MRMULDV.S - Version of the above for Linux i386 GCC + MRMULDV.S64 - Version of the above for Linux x86_64 GCC + MRMULDV.W64 - Version of the above for Windows x86-64 Visual Studio + MRMULDV.GCC - GCC version of above - 32-bit + MRMULDV.G64 - GCC version of above - 64-bit + MRMULDV.C - Version of the above for Win32 + MRMULDV.CCC - Standard C version + MRMULDV.GPP - Version of the above for DJGPP GCC + MR*.C - MIRACL library source files + MRCOMBA.TPL - Template file for fast Comba method + MRCOMBA2.TPL - Template file for fast Comba method for GF2 arithmetic + MRKCM.TPL - Template file for fast KCM method + C.MCS - C macros for use with above + C1.MCS - Alternate C macros + C2.MCS - Alternate C macros + CS.MCS - Alternate C macros + CLMUL.MCS - MSC Intrinsic macros to use PCLMULQDQ instruction + GCCLMUL.MCS - GCC assembly language to support PCLMULQDQ instruction + SMARTMIP.MCS - Macros for Smartmips smart-card processor + MIPS.MCS - Macros for 32-bit Mips processor + MS86.MCS - Microsoft/Borland 80*86/Pentium macros for use with above + GCC386.MCS - GCC compiler compatible Pentium macros + ARM.MCS - ARM processor macros + GCCARM.MCS - GCC compatable version of the above + AVR.MCS - Atmel Atmega128 processor macros + MSP430.MCS - TI msp430 support (uses hardware multiplier) + BLACKFIN.MCS - Analog Devices Blackfin processor support + GCCMSP430.MCS - GCC compatable version of the above + SPARC32.MCS - 32-bit Sparc processor macros + SPARC64.MCS - 64-bit Sparc processor macros + ITANIUM.MCS - 64-bit Itanium processor macros + WIN64.MCS - 64-bit x86-64 Windows macros + AMD64.MCS - 64-bit AMD64 procesor macros + SSE2.MCS - Pentium 4 SSE2 instructions for Microsoft compiler + GCCPPC.MCS - PowerPC processor macros + GCCSSE2.MCS - Pentium 4 SSE2 instructions for GCC compiler + BMARK.C - Benchmark program for Public Key methods + IMRATIO.C - Benchmark program. Calculates S/M, I/M and J/M ratios over GF(p) + IMRATIO2.C - Benchmark program. Calculates S/M and I/M ratios over GF(2^m) + MERSENNE.C - Mersenne primes + FACT.C - Factorials + BRUTE.C - Brute-force factorisation + BRENT.C - Brent-pollard factoring + BRENT_MT.C - Example of generic Multi-Threading + HAIL.C - Hailstone numbers + PALIN.C - Palindromic numbers + GENKEY.C - Generate Public and Private keys + ENCODE.C - Encode using RSA method + DECODE.C - Decode using RSA method + ENCIPH.C - Encipher using Probabalistic method + DECIPH.C - Decipher using Probabalistic method + PK-DEMO.C - Demo of RSA/El Gamal/Diffie-Hellman/Elliptic Curve... + IDENTITY.C - ID based key exchange program + HILBERT.C - Solve special system of equations + SAMPLE.C - Example of Flash arithmetic + ROOTS.C - Square roots + POLLARD.C - Pollard's factoring method + WILLIAMS.C - William's factoring method + LENSTRA.C - Lenstra's factoring method + QSIEVE.C - The Quadratic Sieve + RATCALC.C - Rational Scientific Calculator + FACTOR.C - Factoring Program source + KANGAROO.C - Pollards Lambda method for discrete logs + INDEX.C - Pollards rho method for discrete logs + GENPRIME.C - Generates prime for above + LIMLEE.C - Lim-Lee prime generation + DSSETUP.C - Digital Signature Standard setup program + DSSGEN.C - Digital Signature Standard key generator program + DSSIGN.C - Digital Signature Standard signature program + DSSVER.C - Digital Signature Standard verification program + ECDH2M.C - Example EC Diffie-Hellman program for 32-bit constrained environments (static stack-only) + ECDH2M16.C - 16-bit version of the above + ECDH2M8.c - 8-bit version of the above + ROMAKER2.C - Program to automatically generate ROMS for above programs + ECDHP.C - ditto, over GF(p) - 32-bit + ECDHP32.C - ditto, over GF(p) - Nice ARM example (32-bits) + ECDHP8.C - ditto, over GF(p), 8-bit version + ECDHP16.C - ditto, over GF(p), 16-bit version + ROMAKER.C - Program to automatically generate ROMS for above programs + ECSGEN.C - DSS (Elliptic Curve GF(p) variation) key generator program + ECSIGN.C - DSS (Elliptic Curve GF(p) variation) signature program + ECSVER.C - DSS (Elliptic Curve GF(p) variation) verification program + ECSGEN_S.C - DSS (Elliptic Curve GF(p) variation) key generator program (static stack-only version) + ECSIGN_S.C - DSS (Elliptic Curve GF(p) variation) signature program (static stack-only version) + ECSVER_S.C - DSS (Elliptic Curve GF(p) variation) verification program (static stack-only version) + ECSGEN2.C - DSS (Elliptic Curve GF(2^m) variation) key generator program + ECSIGN2.C - DSS (Elliptic Curve GF(2^m) variation) signature program + ECSVER2.C - DSS (Elliptic Curve GF(2^m) variation) verification program + ECSGEN2S.C - DSS (Elliptic Curve GF(2^m) variation) key generator program (static stack-only version) + ECSIGN2S.C - DSS (Elliptic Curve GF(2^m) variation) signature program (static stack-only version) + ECSVER2S.C - DSS (Elliptic Curve GF(2^m) variation) verification program (static stack-only version) + BRICK.C - Brickell's method for fast exponentiation + EBRICK.C - Same for GF(p) Elliptic Curves + EBRICK2.C - Same for GF(2^m) Elliptic Curves + BIG.CPP - Big function implementations + ZZN.CPP - ZZn function implementations + ECN.CPP - ECn function implementations + ECNZZN.CPP - ECn <-> ZZn functions + EC2.CPP - EC2 function implementations + GF2M.CPP - GF(2^m) function implementations + CRT.CPP - Crt function implementations + FLASH.CPP - Flash function implementations + FLOATING.CPP - Float function implementations + PAL_ENC.CPP - Paillier Homomorphic Encryption Program + PAL_DEC.CPP - Paillier Homomorphic Decryption Program + THREADWN.CPP - Example of Windows Multi-threading + THREADUX.CPP - Example of Unix Multi-Threading + THREADMP.CPP - Example of openMP Multi-Threading + FINDBASE.CPP - Find irreducible polynomial for GF(2^m) programs + IRP.CPP - Generates code to implement irreducible polynomial + NEWBASIS.CPP - Converts from one irreducible polynomial representation to another + FACT.CPP - Example C++ source (uses BIG.H) + HAIL.CPP - " " + PALIN.CPP - " " + BRUTE.CPP - " " + MERSENNE.CPP - " " + QSIEVE.CPP - " " + GENKEY.CPP - " " + ENCODE.CPP - " " + DECODE.CPP - " " + ENCIPH.CPP - " " + DECIPH.CPP - " " + PK-DEMO.CPP - " " + LIMLEE.CPP - " " + DSSETUP.CPP - " " + DSSGEN.CPP - " " + DSSIGN.CPP - " " + DSSVER.CPP - " " + KANGAROO.CPP - " " + INDEX.CPP - " " + GENPRIME.CPP - " " + BRICK.CPP - " " + EBRICK.CPP - Example C++ source (uses ECN.H) + ECSGEN.CPP - " " + ECSIGN.CPP - " " + ECSVER.CPP - " " + EBRICK2.CPP - Example C++ source (uses EC2.H) + ECSGEN2.CPP - " " + ECSIGN2.CPP - " " + ECSVER2.CPP - " " + POLLARD.CPP - Example C++ source (uses ZZN.H) + WILLIAMS.CPP - " " + LENSTRA.CPP - " " + BRENT.CPP - " " + SAMPLE.CPP - Example C++ source (uses FLASH.H) + ROOTS.CPP - " " + HILBERT.CPP - " " + FSAMPLE.CPP - Example C++ source (uses FLOATING.H) + CARDANO.CPP - Example C++ source (uses ZZn2.H) + BP160.ECS - Brainpool 160-bit GF(p) curve + BPT160.ECS - Brainpool 160-bit GF(p) twisted curve + SECP160/192/224/256/521.ecs - Parameter files for some standard GF(p) elliptic curves + NIST163/233/283/571.ecs - Parameter files for standard GF(2^m) elliptic curves + KOB163/233/283/571.ecs - Parameter files for GF(2^m) Koblitz curves + EDWARDS.ECS - Parameter file for an Edwards GF(p) elliptic curve + + Note how readable the C++ versions of the example programs look. + + In the subdirectory SOURCE\CURVE + + CM.CPP - Complex Multiplication - creates elliptic curves + VARIABLE.H - Dummy Variable class + POLY.H - Polynomial Class definition, elements from ZZn + POLY.CPP - Polynomial Arithmetic with ZZn coefficients + POLY2.H - Polynomial Class definition, elements from GF(2^m) + POLY2.CPP - Polynomial Arithmetic with GF(2^m) coefficients + FLPOLY.H - Polynomial Class definition, float elements + FLPOLY.CPP - Polynomial arithmetic with float coefficients + COMPLEX.H - Complex Float class definition + COMPLEX.CPP - Complex Float class arithmetic + CM.TXT - How to build the CM application + POLYMOD.H - Polynomials mod a Polynomial - Class Definition + POLYMOD.CPP - ZZn Polynomial arithmetic wrt a Polynomial Modulus + POLY2MOD.H - Polynomials mod a Polynomial - Class Definition + POLY2MOD.CPP - GF(2^m) Polynomial arithmetic wrt a Polynomial Modulus + TRANS.CPP - A simple utility to convert elliptic curve to Weierstrass + SCHOOF.CPP - Schoof's method for counting points on a GF(p) elliptic curve + SCHOOF2.CPP - Schoof's method for counting points on a GF(2^m) elliptic curve + SCHOOF.TXT - How to build the schoof Application + SCHOOF2.TXT - How to build the schoof2 Application + PS_BIG.H - Power series with Big coefficients - Class Definition + PS_BIG.CPP - Power Series Arithmetic + PS_ZZN.H - Power series with ZZN coefficients - Class Definition + PS_ZZN.CPP - Power Series Arithmetic + POLYXY.H - Bivariate Polynomials - Class Definition + POLYXY.CPP - Bivariate Polynomilas - Implementation + POLY2XY.H - Bivariate Polynomials - Class Definition + POLY2XY.CPP - Bivariate Polynomilas - Implementation + MUELLER.CPP - Program to generate Modular Polynomials + PROCESS.CPP - Program to process Modular Polynomials wrt a prime modulus + SEA.CPP - Schoof-Elkies-Atkin-Mueller algorithm + SEA.TXT - How to build the MUELLER/PROCESS/SEA applications + WEIL.CPP - Calculates number of points on curve over extension field + GLV.CPP - Calculates a GLV decomposition + + In the subdirectory SOURCE\P1363 + + P1363.H - P1363 Header File + P1363.C - P1363 implementation file + TEST1363.c - test driver for P1363 implementation + RSA.C - quick start RSA application + OCTET.C - OCTET string handler + OCTET.H - OCTET header + ECDH.C - Elliptic Curve Code + ECDH.H - Elliptic Curve Header + TESTECC.C - Typical MIRACL Elliptic Curve API Implementation - thread-safe - no heap + + In the subdirectory SOURCE\CURVE\PAIRING + + BLS_SIGN.CPP - Boneh-Lynn-Shacham signature + BLS_VER.CPP - Boneh-Lynn-Shacham signature verification + GF2M4X.H - GF(2^4m) arithmetic - Header file + GF2M4X.CPP - GF(2^4m) arithmetic - Implementation file + GF2M6X.H - GF(2^6m) arithmetic - Header file + GF2M6X.CPP - GF(2^6m) arithmetic - Implementation file + GF2M12X.H - GF(2^12m) arithmetic - Header file + GF2M12X.CPP - GF(2^12m) arithmetic - Implementation file + SF2M12X.H - GF(2^12m) special extension arithmetic - Header file + SF2M12X.CPP - GF(2^12m) special extension arithmetic - Implementation file + ECN2.H - Elliptic curves over Fp2 - Header file + ECN2.CPP - Elliptic curves over Fp2 - Implementation file + ECN4.H - Elliptic curves over Fp4 - Header file + ECN4.CPP - Elliptic curves over Fp4 - Implementation file + ECN6.H - Elliptic curves over Fp6 - Header file + ECN6.CPP - Elliptic curves over Fp6 - Implementation file + ECN8.H - Elliptic curves over Fp8 - Header file + ECN8.CPP - Elliptic curves over Fp8 - Implementation file + ZZN2.H - Fp2 arithmetic - Header file + ZZN2.CPP - Fp2 arithmetic - Implementation file + ZZN3.H - Fp3 arithmetic - Header file + ZZN3.CPP - Fp3 arithmetic - Implementation file + ZZN4.H - Fp4 arithmetic - Header file + ZZN4.CPP - Fp4 arithmetic - Implementation file + ZZN8.H - Fp8 arithmetic - Header file + ZZN8.CPP - Fp8 arithmetic - Implementation file + ECN3.H/.CPP - Elliptic curves over Fp3 + ZZN6.H/.CPP - Fp6 arithmetic - 2 over 3 + ZZN6a.H/.CPP - Fp6 arithmetic - 3 over 2 + ZZN12.H/.CPP - Fp12 arithmetic - 2 over 3 over 2 + ZZN12a.H/.CPP- Fp12 arithmetic - 3 over 2 over 2 + ZZN12b.H/.CPP- Fp12 arithmetic - 2 over 2 over 3 + ZZN18.H/.CPP - Fp18 arithmetic - 3 over 2 over 3 + ZZN24.H/.CPP - Fp24 arithmetic - 3 over 2 over 2 over 2 + ZZN36.H/.CPP - Fp36 arithmetic - 3 over 2 over 2 over 3 + MNT.CPP - Program to generate MNT elliptic curves + MNT.ECS - Non-supersingular curve, k=6, created by CM from MNT output + FREEMAN.CPP - Program to generate k=10 Freeman curves + FOLKLORE.CPP - program to create pairing-friendly non-SS curves + IRRED.CPP - Finds irreducible polynomial - Experimental! + AKE.TXT - Some explanation for these programs. + AKE6MNTT.CPP - Authenticated Key Exchange, MNT k=6 curve - Experimental! 1-3-6 tower + AKE6MNTX.CPP - Authenticated Key Exchange, MNT k=6 curve - Experimental! Uses "compositum" tower. + AKE6MNTA.CPP - Authenticated Key Exchange, MNT k=6 curve - Experimental! Uses "compositum" tower. + AKE6MNTT.C - Partial C version of the above + AKE4MNTT.CPP - Authenticated Key Exchange, k=4 - Experimental! + AKE4MNTT.C - Partial C version of the above + AKE4MNTA.CPP - Authenticated Key Exchange, k=4 - Experimental! - Ate pairing + AKE4MNTT.C - Partial C version of the above + AKE6FSTA.CPP - Authenticated Key Exchange, k=6, Ate pairing, sextic twist! + BN.CPP - Program to generate BN k=12 curves + KSS8.CPP - Program to generate KSS k=8 curves + KSS18.CPP - Program to generate KSS k=18 curves + BLS12.CPP - Program to generate BLS k=12 curves + BLS24.CPP - Program to generate BLS k=24 curves + BESTPAIR.CPP - Program to generate nice pairing-friendly curves + AKE12BNE.CPP - Authenticated Key Exchange, k=12, BN curve - Experimental! + AKE12BNA.CPP - Authenticated Key Exchange, k=12, BN curve, Ate pairing, sextic twist! + AKE12BNR.CPP - Authenticated Key Exchange, k=12, BN curve, R-ate pairing, sextic twist! 1-2-6-12 tower + AKE12BNX.CPP - Authenticated Key Exchange, k=12, BN curve, R-ate pairing, sextic twist! 1-2-4-12 tower + AKE12BLSA.CPP - Authenticated Key Exchange, k=12, BLS curve, ate pairing, sextic twist! + AKE18KSSX.CPP - Authenticated Key Exchange, k=18, KSS curve, R-ate pairing, sextic twist! + AKE24BLSA.CPP - Authenticated Key Exchange, k=18, BLS curve, ate pairing, sextic twist! + AKE2CPT.CPP - Same as above, but k=2 Cocks-Pinch curve + AKE2SST.CPP - Same as above, but uses a supersingular curve + AKE4CPT.CPP - Same as above, but k=4 + AKEW4.CPP - Variation on the above + AKE8CPT.CPP - Same as above, but k=8 based + AKE8BWT.CPP - Variation on the above - uses Brezing-Weng curve + K2.ECS - Non-supersingular curve, k=2 + K2SS.ECS - Supersingular curve, k=2 + K4.ECS - Non-supersingular curve, k=4 + K4MNT.ECS - MNT k=4 curve + K8.ECS - Non-supersingular curve, k=8 + WENG.ECS - Non-supersingular curve, k=8 + DL.CPP - Duursma-Lee Char 2 pairings + DL2.CPP - Truncnated-loop eta_T char 2 pairings + ETAT271.c - C version of eta_T pairing + BANDW.CPP - Brezing & Weng curves + AKE2NSST.CPP - Faster k=2 key exchange program - Not Superingular Curves + AKE2CPW.CPP - Uses New Weil pairing, k=2 + AKE1KMT.CPP - Key Exchange program, for k=1 Koblitz-Menezes curve + MAKE_K1.CPP - Creates curves for the above + XK1.ECS - k=1 curve details + PAIRINGS.TXT - Details of pairing-based resources + PAIRING_1.H - High level type 1 pairings interface header + PAIRING_3.H - High level type 3 pairings interface header + AKE.CPP - Pairing-based Authentiated Key Exchange + BLS.CPP - Pairing-based Short Signature Scheme + DAA.CPP - Pairing-based Direct Anonymous Attestation + BMC.CPP - Pairing-based Signcryption scheme + BLMQ.CPP - Another pairing-based signcryption scheme + BB1.CPP - Boneh & Boyen BB1 IBE + FUZZY.CPP - Sahai & Waters Fuzzy IBE + PEKS.CPP - PKE with keyword search + HIBE.CPP - Hierarchical IBE (Lewko & Waters) + SK_1.CPP - Sakai-Kasahara IBE - type 1 pairing + SK_3.CPP - Sakai-Kasahara IBE - type 3 pairing + CPABE.CPP - Waters Attribute Based Cryptography + SOK.CPP - Sakai-Ohgishi-Kasahara key exchange (Type 1 pairing) + BGW.CPP - Boneh-Gentry-Waters Broadcast encryption + IPE.CPP - Inner Product Predicate Encryption + WANG.CPP - Key Exchange Protocol + CP_PAIR - AES-80 security from a Cocks-Pinch k=2 curve + MNT_PAIR.CPP - AES-80 security from an MNT k=6 curve + BN_PAIR.CPP - AES-128 security from a BN k=12 curve + KSS_PAIR.CPP - AES-192 security from a KSS k=18 curve + BLS_PAIR.CPP - AES-256 security from a BLS k=24 curve + SS2_PAIR.CPP - AES-80/128 security from a Supersingular k=4 curve over GF(2^m) + SSP_PAIR.CPP - AES-80/128 security from a Supersingular k=2 curve over GF(p) + + In the subdirectory INCLUDE + + MIRDEF.H16 - Standard hardware specific header file for 16-bit computer + MIRDEF.H32 - Header file for full 32-bit Computer + MIRDEF.H - Same as above + MIRDEF.H64 - Header file for full 64-bit Computer + MIRDEF.W64 - Header file for Microsoft 64-bit compiler + MIRDEF.HPC - Header file for pseudo-32 bit computer + MIRDEF.HAF - Header file for 16 bit use of 32 bit computer + MIRDEF.HIO - Integer-Only 32-bit header file + MIRDEF.HPP - Header file for full 64-bit Computer - C++ Library Build - see linux64_cpp + MIRDEF.MGW - Header file for 64-bit mingw build + MIRACL.H - Main MIRACL header + BIG.H - C++ header for 'big' numbers + FLASH.H - C++ header for 'flash' numbers + FLOATING.H - C++ header for 'float' numbers + ZZN.H - C++ header for 'big' numbers mod n + CRT.H - C++ header for chinese remainder thereom + ECN.H - C++ header for GF(p) Elliptic Curves + ECNZZN.H - ECn <-> ZZn functions + EC2.H - C++ header for GF(2^m) Elliptic Curves + GF2M.H - C++ header for GF(2^m) + BRICK.H - C++ header for Brickell's method + EBRICK.H - C++ header for Brickell's method (Elliptic Curve GF(p) version) + EBRICK2.H - C++ header for Brickell's method (Elliptic Curve GF(2^m) version) + + In the subdirectory LIB + + *DOIT.BAT - Batch files for constructing libraries and sample progs. + MINGW.BAT - Batch file to build library for 64-bit MINGW + MIRACL.MAK - John Kennedy's UNIX make file + LINUX - Linux bash script to build library - 32-bit + LINUX64 - Linux bash script to build library - 64-bit - C Library Build + LINUX64_CPP - Linux bash script to build library - 64-bit - C++ Library Build + + + To build the standard library on a standard OS, dump all of the MIRACL files + into a single directory, and move to that directory + + (1) If using Windows and the Microsoft compiler, open a command window, + ensure paths are set correctly by executing the microsoft-supplied + vcvars32.bat or vcvars64.bat, and then execute either ms32doit.bat + or ms64doit.bat, depending on your system being 32-bits or 64-bits + + (2) If using Linux, open a terminal window and simply execute either + "bash linux", or "bash linux64" for 64-bit systems + + Otherwise + + (1) Determine which of + mirdef.h64/mirdef.w64/mirdef.h32/mirdef.h16/mirdef.haf/mirdef.hpc etc + is suitable for you, and/or compile and run config.c to automatically + generate a suitable mirdef.h. + + (2) If for performance reasons a non-portable version is to be built, + select suitable assembly language routines from mrmuldv.any, or + write them yourself (send us a copy!). Even better - produce a + .mcs file for the processor and use either the KCM or Comba method. + + (3) Compile and link together the mr*.c components into an object library. + Also assemble and link in the assemble language component from + mrmuldv.any (if needed). + + In the subdirectory EXE some precompiled example programs + + FACT.EXE - Factorial program + ENCIPH.EXE - Enciphering program + DECIPH.EXE - Deciphering program + PUBLIC.KEY - Public key for use by enciphering program + PRIVATE.KEY - Private key for use by deciphering program + + In the sub-directory FREE some FREEWARE 32-bit IBM PC Command prompt + specific applications. CM.EXE is free as well, but omitted here for space + reasons. + + READ.TXT - Read this first + RATCALC.EXE - Rational Calculator + FACTOR.EXE - General purpose Factoring Program (80386+ only) + For maximum speed this is compiled as a true 32-bit + and runs in a 32-bit DOS Window + + These files (ONLY!!) are FREEWARE, and may be freely copied + and distributed, unmodified. Copyright remains with CertiVox. + diff --git a/miracl/smartmip.txt b/miracl/smartmip.txt new file mode 100644 index 0000000..0d67657 --- /dev/null +++ b/miracl/smartmip.txt @@ -0,0 +1,65 @@ + +The SmartMips is an example of the new generation of 32-bit smart cards. +Rather than support specialised crypographic co-processors, these smart +cards deploy enhanced instruction sets with instructions specially tailored +to the requirements of multi-precision arithmetic over GF(p) and GF(2^m). +This is a viable approach due to the increased speed and power of these +devices. (Smart cards are NOT low powered devices. Power is taken from +the card reader, and is thus not particularly limited) + +These smart cards also support impressive amounts of ROM, Flash memory, +EEPROM and RAM. Nonetheless the environment is heavily constrained compared +to a desktop workstation, or even a PDA or hand-held mobile device. + +One major constraint is a limited amount of RAM - typically just 16K bytes. +In this context it does not make sense to divide this limited resource between +static memory, a heap and a stack. Therefore a MIRACL build which requires +only a stack is appropriate. Many big number libraries support elaborate +mechanisms so that big numbers can grow without limit. In contrast MIRACL +has always supported fixed size big numbers, and this is particularly +appropriate in this context. By fixing big number sizes at compile time, +memory for big numbers can be allocated very quickly from the stack, with +minimal overhead. To do this define + +#define MR_STATIC X + +in mirdef.h, where X is the fixed size of the big numbers in 32-bit words. + +A file smartmip.mcs is supplied so that optimal assembly language can be +generated for big number modular multiplication, using the MIRACL macro +mechansism (see makemcs.txt and kcmcomba.txt). This also supports very fast +GF(2^m) polynomial multiplication, using a special instruction. By setting + +#define MR_COMBA2 X + +in mirdef.h, and running the mex utility, very fast code will be generated to +the file mrcomba2.c, which can be integrated into the MIRACL library. Here X +is again the fixed size of the big numbers in 32-bit words (rounded up). + +An example mirdef.h configuration header for implementing a fast elliptic +curve cryptosystem over GF(2^283) might look like this... + + +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype long long +#define mr_unsign64 unsigned long long +#define MR_STATIC 9 +#define MR_NOASM +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MR_NO_STANDARD_IO +#define MR_NO_FILE_IO +#define MR_COMBA2 9 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_SHORT_OF_MEMORY diff --git a/miracl/source/amd64.mcs b/miracl/source/amd64.mcs new file mode 100644 index 0000000..d6024c7 --- /dev/null +++ b/miracl/source/amd64.mcs @@ -0,0 +1,583 @@ +; MCS file for Gnu GCC AMD64 compiler +; +; Sorry about all the %'s! Each % must be input here as %% + +; Hybrid x2 step +; +; "Triple" register is now rcx|r11|r10|r9|r8 +; registers bh and bl are employed as "carry catchers" +; +;MACRO H2_MUL_START +; ASM ( +; "movq %%0,%%%%r15\n" +; "movq %%1,%%%%rsi\n" +; "movq %%2,%%%%rdi\n" +; "xorq %%%%rcx,%%%%rcx\n" +; "xorq %%%%r8,%%%%r8\n" +; "xorq %%%%r9,%%%%r9\n" +; "xorq %%%%r10,%%%%r10\n" +; "xorq %%%%r11,%%%%r11\n" +; "xorq %%%%rbx,%%%%rbx\n" +;ENDM +;MACRO H2_STEP +; "movq 8*%d(%%%%r15),%%%%r12\n" +; "movq 8*(%d+1)(%%%%r15),%%%%r13\n" +; "movq 8*%d(%%%%rsi),%%%%r14\n" +; "movq %%%%r14,%%%%rax\n" +; "mulq %%%%r12\n" +; "addq %%%%rax,%%%%r8\n" +; "adcq %%%%rdx,%%%%r9\n" +; "adc %%%%ch,%%%%bl\n" +; "movq %%%%r14,%%%%rax\n" +; "mulq %%%%r13\n" +; "addq %%%%rax,%%%%r9\n" +; "adcq %%%%rdx,%%%%r10\n" +; "adc %%%%ch,%%%%bh\n" +; "movq 8*(%d+1)(%%%%rsi),%%%%r14\n" +; "movq %%%%r14,%%%%rax\n" +; "mulq %%%%r12\n" +; "addq %%%%rax,%%%%r9\n" +; "adcq %%%%rdx,%%%%r10\n" +; "adc %%%%ch,%%%%bh\n" +; "movq %%%%r14,%%%%rax\n" +; "mulq %%%%r13\n" +; "addq %%%%rax,%%%%r10\n" +; "adcq %%%%rdx,%%%%r11\n" +; "adc %%%%ch,%%%%cl\n" +;ENDM +;MACRO H2_MFIN +; "movq %%%%r8,8*%d(%%%%rdi)\n" +; "movq %%%%r9,8*%d(%%%%rdi)\n" +; "movzbq %%%%bl,%%%%rax\n" +; "addq %%%%rax,%%%%r10\n" +; "mov %%%%bh,%%%%al\n" +; "movzbq %%%%al,%%%%rax\n" +; "adcq %%%%rax,%%%%r11\n" +; "adc %%%%ch,%%%%cl\n" +; "movq %%%%r10,%%%%r8\n" +; "movq %%%%r11,%%%%r9\n" +; "xorq %%%%rbx,%%%%rbx\n" +; "mov %%%%cl,%%%%bl\n" +; "xorq %%%%rcx,%%%%rcx\n" +; "xorq %%%%r10,%%%%r10\n" +; "xorq %%%%r11,%%%%r11\n" +;ENDM +;MACRO H2_MUL_END +; "movq %%%%r8,8*%d(%%%%rdi)\n" +; "movq %%%%r9,8*%d(%%%%rdi)\n" +; : +; :"m"(a),"m"(b),"m"(c) +; :"rax","rdi","rsi","rbx","rcx","rdx","r8","r9","r10","r11","r12","r13","r14","r15","memory" +; ); +;ENDM + +;MACRO H2_SQR_START +; ASM ( +; "movq %%0,%%%%rsi\n" +; "movq %%1,%%%%rdi\n" +; "xorq %%%%rcx,%%%%rcx\n" +; "xorq %%%%r8,%%%%r8\n" +; "xorq %%%%r9,%%%%r9\n" +; "xorq %%%%r10,%%%%r10\n" +; "xorq %%%%r11,%%%%r11\n" +; "xorq %%%%rbx,%%%%rbx\n" +;ENDM +;MACRO H2_DSTEP +; "movq 8*%d(%%%%rsi),%%%%r12\n" +; "movq 8*(%d+1)(%%%%rsi),%%%%r13\n" +; "movq 8*%d(%%%%rsi),%%%%r14\n" +; "movq %%%%r14,%%%%rax\n" +; "mulq %%%%r12\n" +; "addq %%%%rax,%%%%r8\n" +; "adcq %%%%rdx,%%%%r9\n" +; "adc %%%%ch,%%%%bl\n" +; "addq %%%%rax,%%%%r8\n" +; "adcq %%%%rdx,%%%%r9\n" +; "adc %%%%ch,%%%%bl\n" +; "movq %%%%r14,%%%%rax\n" +; "mulq %%%%r13\n" +; "addq %%%%rax,%%%%r9\n" +; "adcq %%%%rdx,%%%%r10\n" +; "adc %%%%ch,%%%%bh\n" +; "addq %%%%rax,%%%%r9\n" +; "adcq %%%%rdx,%%%%r10\n" +; "adc %%%%ch,%%%%bh\n" +; "movq 8*(%d+1)(%%%%rsi),%%%%r14\n" +; "movq %%%%r14,%%%%rax\n" +; "mulq %%%%r12\n" +; "addq %%%%rax,%%%%r9\n" +; "adcq %%%%rdx,%%%%r10\n" +; "adc %%%%ch,%%%%bh\n" +; "addq %%%%rax,%%%%r9\n" +; "adcq %%%%rdx,%%%%r10\n" +; "adc %%%%ch,%%%%bh\n" +; "movq %%%%r14,%%%%rax\n" +; "mulq %%%%r13\n" +; "addq %%%%rax,%%%%r10\n" +; "adcq %%%%rdx,%%%%r11\n" +; "adc %%%%ch,%%%%cl\n" +; "addq %%%%rax,%%%%r10\n" +; "adcq %%%%rdx,%%%%r11\n" +; "adc %%%%ch,%%%%cl\n" +;ENDM +;MACRO H2_SELF +; "movq 8*%d(%%%%rsi),%%%%r12\n" +; "movq 8*(%d+1)(%%%%rsi),%%%%r13\n" +; "movq %%%%r12,%%%%rax\n" +; "mulq %%%%rax\n" +; "addq %%%%rax,%%%%r8\n" +; "adcq %%%%rdx,%%%%r9\n" +; "adc %%%%ch,%%%%bl\n" +; "movq %%%%r13,%%%%rax\n" +; "mulq %%%%r12\n" +; "addq %%%%rax,%%%%r9\n" +; "adcq %%%%rdx,%%%%r10\n" +; "adc %%%%ch,%%%%bh\n" +; "addq %%%%rax,%%%%r9\n" +; "adcq %%%%rdx,%%%%r10\n" +; "adc %%%%ch,%%%%bh\n" +; "movq %%%%r13,%%%%rax\n" +; "mulq %%%%rax\n" +; "addq %%%%rax,%%%%r10\n" +; "adcq %%%%rdx,%%%%r11\n" +; "adc %%%%ch,%%%%cl\n" +;ENDM +;MACRO H2_SFIN +; "movq %%%%r8,8*%d(%%%%rdi)\n" +; "movq %%%%r9,8*%d(%%%%rdi)\n" +; "movzbq %%%%bl,%%%%rax\n" +; "addq %%%%rax,%%%%r10\n" +; "mov %%%%bh,%%%%al\n" +; "movzbq %%%%al,%%%%rax\n" +; "adcq %%%%rax,%%%%r11\n" +; "adc %%%%ch,%%%%cl\n" +; "movq %%%%r10,%%%%r8\n" +; "movq %%%%r11,%%%%r9\n" +; "xorq %%%%rbx,%%%%rbx\n" +; "mov %%%%cl,%%%%bl\n" +; "xorq %%%%rcx,%%%%rcx\n" +; "xorq %%%%r10,%%%%r10\n" +; "xorq %%%%r11,%%%%r11\n" +;ENDM +;MACRO H2_SQR_END +; "movq %%%%r8,8*%d(%%%%rdi)\n" +; "movq %%%%r9,8*%d(%%%%rdi)\n" +; : +; :"m"(a),"m"(c) +; :"rax","rdi","rsi","rbx","rcx","rdx","r8","r9","r10","r11","r12","r13","r14","memory" +; ); +;ENDM + + +MACRO PMUL_START + ASM ( + "movq %%0,%%%%rbx\n" + "movq %%1,%%%%rsi\n" + "movq %%2,%%%%rdi\n" + "xorq %%%%rcx,%%%%rcx\n" + "xorq %%%%r9,%%%%r9\n" + "movq %%3,%%%%r8\n" +ENDM + +MACRO PMUL + "movq %%%%r8,%%%%rax\n" + "mulq 8*%d(%%%%rbx)\n" + "addq %%%%rcx,%%%%rax\n" + "adcq %%%%r9,%%%%rdx\n" + "movq %%%%rdx,%%%%rcx\n" + "movq %%%%r9,8*%d(%%%%rsi)\n" + "movq %%%%rax,8*%d(%%%%rdi)\n" +ENDM + +MACRO PMUL_END + "movq %%%%r8,%%%%rax\n" + "mulq %%%%rcx\n" + "movq %%%%rax,(%%%%rsi)\n" + "movq %%%%rdx,8(%%%%rsi)\n" + : + :"m"(a),"m"(b),"m"(c),"m"(sn) + :"rax","rdi","rsi","rbx","rcx","rdx","r8","r9","memory" + ); + +ENDM + +; Triple register is cl|r9|r8 +; MUL_START. Initialise registers. Make rbx and rsi point to multipliers a +; and b. rdi points at result c. +; Initialise Triple register to 0 +; See makemcs.txt for more information about this file +; +MACRO MUL_START + ASM ( + "movq %%0,%%%%rbx\n" + "movq %%1,%%%%rsi\n" + "movq %%2,%%%%rdi\n" + "xorq %%%%rcx,%%%%rcx\n" + "xorq %%%%r9,%%%%r9\n" + "xorq %%%%r8,%%%%r8\n" +ENDM +; +; STEP macro. Calculates a double-register partial product +; and adds it to the triple register total +; Parameters 1 & 2: Indices i and j for partial product multipliers a[i] +; and b[j] +MACRO STEP + "movq 8*%d(%%%%rbx),%%%%rax\n" + "mulq 8*%d(%%%%rsi)\n" + "addq %%%%rax,%%%%r8\n" + "adcq %%%%rdx,%%%%r9\n" + "adc %%%%ch,%%%%cl\n" +ENDM +; +; LAST +; +MACRO LAST + "movq 8*%d(%%%%rbx),%%%%rax\n" + "mulq 8*%d(%%%%rsi)\n" + "addq %%%%rax,%%%%r8\n" +ENDM +; +; MFIN macro. Finish column calculation. Store Sum for this column +; and get Carry for next +; Parameter 1: Index k for Column Sum c[k] +MACRO MFIN + "movq %%%%r8,8*%d(%%%%rdi)\n" + "movq %%%%r9,%%%%r8\n" + "movq %%%%rcx,%%%%r9\n" + "xor %%%%cl,%%%%cl\n" +ENDM +; +; MUL_END +; Parameter 1: Index for final carry c[.] +MACRO MUL_END + "movq %%%%r8,8*%d(%%%%rdi)\n" + : + :"m"(a),"m"(b),"m"(c) + :"rax","rdi","rsi","rbx","rcx","rdx","r8","r9","memory" + ); +ENDM +; +; SQR_START +; +MACRO SQR_START + ASM ( + "movq %%0,%%%%rbx\n" + "movq %%1,%%%%rsi\n" + "xorq %%%%rcx,%%%%rcx\n" + "xorq %%%%r9,%%%%r9\n" + "xorq %%%%r8,%%%%r8\n" +ENDM +; +; DSTEP macro. Calculates a double-register partial product +; and add it twice to a triple register total +; Parameters 1 & 2 : Indices of partial product multipliers +MACRO DSTEP + "movq 8*%d(%%%%rbx),%%%%rax\n" + "mulq 8*%d(%%%%rbx)\n" + "addq %%%%rax,%%%%r8\n" + "adcq %%%%rdx,%%%%r9\n" + "adc %%%%ch,%%%%cl\n" + "addq %%%%rax,%%%%r8\n" + "adcq %%%%rdx,%%%%r9\n" + "adc %%%%ch,%%%%cl\n" +ENDM +; +; SELF macro. Calculate the double-register square and +; add it to a triple register total +; Parameter 1 : Index of diagonal element +MACRO SELF + "movq 8*%d(%%%%rbx),%%%%rax\n" + "mulq %%%%rax\n" + "addq %%%%rax,%%%%r8\n" + "adcq %%%%rdx,%%%%r9\n" + "adc %%%%ch,%%%%cl\n" +ENDM +; +; SFIN macro. Finish column calculation for squaring. Store Sum +; and get Carry for next column. +; Parameter 1: Index of Column Sum +MACRO SFIN + "movq %%%%r8,8*%d(%%%%rsi)\n" + "movq %%%%r9,%%%%r8\n" + "movq %%%%rcx,%%%%r9\n" + "xor %%%%cl,%%%%cl\n" +ENDM +; +; SQR_END +; Parameter 1: Index for final carry +MACRO SQR_END + "movq %%%%r8,8*%d(%%%%rsi)\n" + : + :"m"(a),"m"(c) + :"rax","rdi","rsi","rbx","rcx","rdx","r8","r9","memory" + ); +ENDM +; +; REDC_START +; +MACRO REDC_START + ASM ( + "movq %%0,%%%%rbx\n" + "movq %%1,%%%%rsi\n" + "movq %%2,%%%%rdi\n" + "xorq %%%%r9,%%%%r9\n" + "xorq %%%%rcx,%%%%rcx\n" + "movq (%%%%rbx),%%%%r8\n" + "movq (%%%%rsi),%%%%r10\n" +ENDM +; +; RFINU macro +; +MACRO RFINU + "movq %%%%r8,%%%%rax\n" + "mulq %%%%rdi\n" + "movq %%%%rax,8*%d(%%%%rbx)\n" + "mulq %%%%r10\n" + "addq %%%%rax,%%%%r8\n" + "adcq %%%%rdx,%%%%r9\n" + "adc %%%%ch,%%%%cl\n" + "movq %%%%r9,%%%%r8\n" + "movq %%%%rcx,%%%%r9\n" + "xorq %%%%rcx,%%%%rcx\n" + "addq 8*(%d+1)(%%%%rbx),%%%%r8\n" + "adcq %%%%rcx,%%%%r9\n" +ENDM +; +; RFIND macro +; +MACRO RFIND + "movq %%%%r8,8*%d(%%%%rbx)\n" + "movq %%%%r9,%%%%r8\n" + "movq %%%%rcx,%%%%r9\n" + "xorq %%%%rcx,%%%%rcx\n" + "addq 8*(%d+1)(%%%%rbx),%%%%r8\n" + "adcq %%%%rcx,%%%%r9\n" +ENDM +; +; REDC_END +; +MACRO REDC_END + "movq %%%%r8,8*%d(%%%%rbx)\n" + "movq %%%%r9,8*(%d+1)(%%%%rbx)\n" + : + :"m"(a),"m"(b),"m"(ndash) + :"rax","rdi","rsi","rbx","rcx","rdx","r8","r9","r10","memory" + ); +ENDM +; +; ADD_START macro - initialise for add. Do first one +; +MACRO ADD_START + ASM ( + "movq %%0,%%%%rsi\n" + "movq %%1,%%%%rbx\n" + "movq %%3,%%%%rdi\n" + "movq (%%%%rsi),%%%%rax\n" + "addq (%%%%rbx),%%%%rax\n" + "movq %%%%rax,(%%%%rdi)\n" +ENDM +; +; ADD macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO ADD + "movq 8*%d(%%%%rsi),%%%%rax\n" + "adcq 8*%d(%%%%rbx),%%%%rax\n" + "movq %%%%rax,8*%d(%%%%rdi)\n" +ENDM +; +; ADD_END macro. Catch Carry +; +MACRO ADD_END + "movq $0,%%%%rax\n" + "adcq %%%%rax,%%%%rax\n" + "movq %%%%rax,%%2\n" + : + :"m"(a),"m"(b),"m"(carry),"m"(c) + :"rax","rdi","rsi","rbx","memory" + ); +ENDM +; +; INC_START macro +; +MACRO INC_START + ASM ( + "movq %%0,%%%%rdi\n" + "movq %%1,%%%%rbx\n" + "movq (%%%%rbx),%%%%rax\n" + "addq %%%%rax,(%%%%rdi)\n" +ENDM +; +; INC macro. Increment number in memory. Don't forget carry +; +MACRO INC + "movq 8*%d(%%%%rbx),%%%%rax\n" + "adcq %%%%rax,8*%d(%%%%rdi)\n" +ENDM +; +; INC_END macro. Catch Carry +; +MACRO INC_END + "movq $0,%%%%rax\n" + "adcq %%%%rax,%%%%rax\n" + "movq %%%%rax,%%2\n" + : + :"m"(a),"m"(b),"m"(carry) + :"rax","rdi","rbx","memory" + ); +ENDM +; +; SUB_START macro. Do first one. +; +MACRO SUB_START + ASM ( + "movq %%0,%%%%rsi\n" + "movq %%1,%%%%rbx\n" + "movq %%3,%%%%rdi\n" + "movq (%%%%rsi),%%%%rax\n" + "subq (%%%%rbx),%%%%rax\n" + "movq %%%%rax,(%%%%rdi)\n" +ENDM +; +; SUB macro. Subtract two numbers in memory and store result in memory. +; +MACRO SUB + "movq 8*%d(%%%%rsi),%%%%rax\n" + "sbbq 8*%d(%%%%rbx),%%%%rax\n" + "movq %%%%rax,8*%d(%%%%rdi)\n" +ENDM +; +; SUB_END macro. Catch Carry +; +MACRO SUB_END + "movq $0,%%%%rax\n" + "adcq %%%%rax,%%%%rax\n" + "movq %%%%rax,%%2\n" + : + :"m"(a),"m"(b),"m"(carry),"m"(c) + :"rax","rdi","rsi","rbx","memory" + ); +ENDM +; +; DEC_START macro. Do first one. +; +MACRO DEC_START + ASM ( + "movq %%0,%%%%rdi\n" + "movq %%1,%%%%rbx\n" + "movq (%%%%rbx),%%%%rax\n" + "subq %%%%rax,(%%%%rdi)\n" +ENDM +; +; DEC macro. Decrement from number in memory. Don't forget borrow. +; +MACRO DEC + "movq 8*%d(%%%%rbx),%%%%rax\n" + "sbbq %%%%rax,8*%d(%%%%rdi)\n" +ENDM +; +; DEC_END macro +; +MACRO DEC_END + "movq $0,%%%%rax\n" + "adcq %%%%rax,%%%%rax\n" + "movq %%%%rax,%%2\n" + : + :"m"(a),"m"(b),"m"(carry) + :"rax","rdi","rbx","memory" + ); +ENDM +; +; KADD_START macro +; +MACRO KADD_START + ASM ( + "movq %%0,%%%%rsi\n" + "movq %%1,%%%%rbx\n" + "movq %%3,%%%%rdi\n" + "movl %%4,%%%%ecx\n" + "xorq %%%%rax,%%%%rax\n" + "k%d:\n" +ENDM +; +; KASL macro +; +MACRO KASL + "decl %%%%ecx\n" + "je k%d\n" + "leaq 8*%d(%%%%rsi),%%%%rsi\n" + "leaq 8*%d(%%%%rbx),%%%%rbx\n" + "leaq 8*%d(%%%%rdi),%%%%rdi\n" + "jmp k%d\n" + "k%d:\n" +ENDM +; +; KADD_END macro +; +MACRO KADD_END + "movq $0,%%%%rax\n" + "adcq %%%%rax,%%%%rax\n" + "movq %%%%rax,%%2\n" + : + :"m"(a),"m"(b),"m"(carry),"m"(c),"m"(n) + :"rax","rdi","rsi","rbx","ecx","memory" + ); +ENDM +; +; KINC_START macro. Zero carry flag. +; +MACRO KINC_START + ASM ( + "movq %%0,%%%%rdi\n" + "movq %%1,%%%%rbx\n" + "movl %%3,%%%%ecx\n" + "xorq %%%%rax,%%%%rax\n" + "k%d:\n" +ENDM +; +; KIDL macro +; +MACRO KIDL + "decl %%%%ecx\n" + "je k%d\n" + "leaq 8*%d(%%%%rbx),%%%%rbx\n" + "leaq 8*%d(%%%%rdi),%%%%rdi\n" + "jmp k%d\n" + "k%d:\n" +ENDM +; +; KINC_END macro +; +MACRO KINC_END + "movq $0,%%%%rax\n" + "adcq %%%%rax,%%%%rax\n" + "movq %%%%rax,%%2\n" + : + :"m"(a),"m"(b),"m"(carry),"m"(n) + :"rax","rdi","rbx","ecx","memory" + ); +ENDM +; +; KDEC_START macro +; +MACRO KDEC_START + ASM ( + "movq %%0,%%%%rdi\n" + "movq %%1,%%%%rbx\n" + "movl %%3,%%%%ecx\n" + "xorq %%%%rax,%%%%rax\n" + "k%d:\n" +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + "movq $0,%%%%rax\n" + "adcq %%%%rax,%%%%rax\n" + "movq %%%%rax,%%2\n" + : + :"m"(a),"m"(b),"m"(carry),"m"(n) + :"rax","rdi","rbx","ecx","memory" + ); +ENDM + diff --git a/miracl/source/arm.mcs b/miracl/source/arm.mcs new file mode 100644 index 0000000..2b0ad1e --- /dev/null +++ b/miracl/source/arm.mcs @@ -0,0 +1,553 @@ +; +; ARM Macros file +; +; Triple register is R4|R3|R2 +; MUL_START. Initialise registers. Make R5 and R6 point to multipliers a +; and b. R7 points at result c. +; Initialise Triple register to 0 +; See makemcs.txt for more information about this file +; +; + +MACRO PMUL_START + __asm { + MOV r5,a + MOV r6,b + MOV r7,c + MOV r4,sn + MOV r3,#0 + MOV r2,#0 +ENDM + +MACRO PMUL + LDR r0,[r5,#(4*%d)] + UMULL r8,r9,r0,r4 + ADDS r8,r8,r3 + ADC r3,r9,r2 + STR r2,[r6,#(4*%d)] + STR r8,[r7,#(4*%d)] +ENDM + +MACRO PMUL_END + UMULL r8,r9,r3,r4 + STR r8,[r6] + STR r9,[r6,#4] + } +ENDM + +MACRO H2_MUL_START + __asm { + MOV r5,a + MOV r6,b + MOV r7,c + MOV r4,#0 + MOV r3,#0 + MOV r2,#0 + MOV r10,#0 + MOV r11,#0 +ENDM + +MACRO H2_STEP + LDR r8,[r5,#(4*%d)] + LDR r9,[r5,#(4*%d+4)] + LDR r12,[r6,#(4*%d)] + UMULL r0,r1,r8,r12 + ADDS r2,r2,r0 + ADCS r3,r3,r1 + ADC r11,r11,#0 + UMULL r0,r1,r9,r12 + ADDS r3,r3,r0 + ADCS r4,r4,r1 + ADDCS r11,r11,0x100 + LDR r12,[r6,#(4*%d+4)] + UMULL r0,r1,r8,r12 + ADDS r3,r3,r0 + ADCS r4,r4,r1 + ADDCS r11,r11,0x100 + UMULL r0,r1,r9,r12 + ADDS r4,r4,r0 + ADCS r10,r10,r1 + ADDCS r11,r11,0x10000 +ENDM + +MACRO H2_LAST + LDR r8,[r5,#(4*%d)] + LDR r9,[r5,#(4*%d+4)] + LDR r12,[r6,#(4*%d)] + UMULL r0,r1,r8,r12 + ADDS r2,r2,r0 + ADCS r3,r3,r1 + UMULL r0,r1,r9,r12 + ADD r3,r3,r0 + LDR r12,[r6,#(4*%d+4)] + UMULL r0,r1,r8,r12 + ADD r3,r3,r0 +ENDM + +MACRO H2_MFIN + STR r2,[r7,#(4*%d)] + STR r3,[r7,#(4*%d)] + AND r0,r11,0xFF + ADDS r2,r4,r0 + AND r0,r11,0xFF00 + ADCS r3,r10,r0,LSR#8 + ADDCS r11,r11,0x10000 + MOV r4,r11,LSR#16 + MOV r10,#0 + MOV r11,#0 +ENDM + +MACRO H2_MUL_END + STR r2,[r7,#(4*%d)] + STR r3,[r7,#(4*%d)] + } +ENDM + +MACRO MUL_START + __asm { + MOV r5,a + MOV r6,b + MOV r7,c + MOV r4,#0 + MOV r3,#0 + MOV r2,#0 +ENDM +; +; STEP macro. Calculates a double-register partial product +; and adds it to the triple register total +; Parameters 1 & 2: Indices i and j for partial product multipliers a[i] +; and b[j] +; STEP 1 even +MACRO STEP + LDR r0,[r5,#(4*%d)] + LDR r1,[r6,#(4*%d)] + UMULL r8,r9,r0,r1 + ADDS r2,r2,r8 + ADCS r3,r3,r9 + ADC r4,r4,#0 +ENDM +; +; MFIN macro. Finish column calculation. Store Sum for this column +; and get Carry for next +; Parameter 1: Index k for Column Sum c[k] +MACRO MFIN + STR r2,[r7,#(4*%d)] + MOV r2,r3 + MOV r3,r4 + MOV r4,#0 +ENDM +; +; LAST +; +MACRO LAST + LDR r0,[r5,#(4*%d)] + LDR r1,[r6,#(4*%d)] + MLA r2,r0,r1,r2 +ENDM +; +; MUL_END +; Parameter 1: Index for final carry c[.] +MACRO MUL_END + STR r2,[r7,#(4*%d)] + } +ENDM + +MACRO H2_SQR_START + __asm { + MOV r5,a + MOV r7,c + MOV r4,#0 + MOV r3,#0 + MOV r2,#0 + MOV r10,#0 + MOV r11,#0 +ENDM + +MACRO H2_DSTEP + LDR r8,[r5,#(4*%d)] + LDR r9,[r5,#(4*%d+4)] + LDR r12,[r5,#(4*%d)] + UMULL r0,r1,r8,r12 + ADDS r2,r2,r0 + ADCS r3,r3,r1 + ADC r11,r11,#0 + ADDS r2,r2,r0 + ADCS r3,r3,r1 + ADC r11,r11,#0 + UMULL r0,r1,r9,r12 + ADDS r3,r3,r0 + ADCS r4,r4,r1 + ADDCS r11,r11,0x100 + ADDS r3,r3,r0 + ADCS r4,r4,r1 + ADDCS r11,r11,0x100 + LDR r12,[r5,#(4*%d+4)] + UMULL r0,r1,r8,r12 + ADDS r3,r3,r0 + ADCS r4,r4,r1 + ADDCS r11,r11,0x100 + ADDS r3,r3,r0 + ADCS r4,r4,r1 + ADDCS r11,r11,0x100 + UMULL r0,r1,r9,r12 + ADDS r4,r4,r0 + ADCS r10,r10,r1 + ADDCS r11,r11,0x10000 + ADDS r4,r4,r0 + ADCS r10,r10,r1 + ADDCS r11,r11,0x10000 +ENDM + +MACRO H2_SELF + LDR r8,[r5,#(4*%d)] + LDR r9,[r5,#(4*%d+4)] + UMULL r0,r1,r8,r8 + ADDS r2,r2,r0 + ADCS r3,r3,r1 + ADC r11,r11,#0 + UMULL r0,r1,r8,r9 + ADDS r3,r3,r0 + ADCS r4,r4,r1 + ADDCS r11,r11,0x100 + ADDS r3,r3,r0 + ADCS r4,r4,r1 + ADDCS r11,r11,0x100 + UMULL r0,r1,r9,r9 + ADDS r4,r4,r0 + ADCS r10,r10,r1 + ADDCS r11,r11,0x10000 +ENDM + +MACRO H2_SFIN + STR r2,[r7,#(4*%d)] + STR r3,[r7,#(4*%d)] + AND r0,r11,0xFF + ADDS r2,r4,r0 + AND r0,r11,0xFF00 + ADCS r3,r10,r0,LSR#8 + ADDCS r11,r11,0x10000 + MOV r4,r11,LSR#16 + MOV r10,#0 + MOV r11,#0 +ENDM + +MACRO H2_SQR_END + STR r2,[r7,#(4*%d)] + STR r3,[r7,#(4*%d)] + } +ENDM + +; +; SQR_START +; +MACRO SQR_START + __asm { + MOV r5,a + MOV r7,c + MOV r4,#0 + MOV r3,#0 + MOV r2,#0 +ENDM +; +; DSTEP macro. Calculates a double-register partial product +; and add it twice to a triple register total +; Parameters 1 & 2 : Indices of partial product multipliers +MACRO DSTEP + LDR r0,[r5,#(4*%d)] + LDR r1,[r5,#(4*%d)] + UMULL r8,r9,r0,r1 + ADDS r2,r2,r8 + ADCS r3,r3,r9 + ADC r4,r4,#0 + ADDS r2,r2,r8 + ADCS r3,r3,r9 + ADC r4,r4,#0 +ENDM + +; +; SELF macro. Calculate the double-register square and +; add it to a triple register total +; Parameter 1 : Index of diagonal element +MACRO SELF + LDR r0,[r5,#(4*%d)] + UMULL r8,r9,r0,r0 + ADDS r2,r2,r8 + ADCS r3,r3,r9 + ADC r4,r4,#0 +ENDM +; +; SFIN macro. Finish column calculation for squaring. Store Sum +; and get Carry for next column. +; Parameter 1: Index of Column Sum +MACRO SFIN + STR r2,[r7,#(4*%d)] + MOV r2,r3 + MOV r3,r4 + MOV r4,#0 +ENDM +; +; SQR_END +; Parameter 1: Index for final carry +MACRO SQR_END + STR r2,[r7,#(4*%d)] + } +ENDM +; +; REDC_START macro +; +MACRO REDC_START + __asm { + MOV r5,a + MOV r6,b + MOV r7,ndash + MOV r4,#0 + MOV r3,#0 + LDR r2,[r5] +ENDM +; +; RFINU macro +; +MACRO RFINU + MUL r1,r7,r2 + STR r1,[r5,#(4*%d)] + LDR r0,[r6] + UMULL r8,r9,r0,r1 + ADDS r0,r2,r8 + ADCS r2,r3,r9 + ADC r3,r4,#0 + LDR r0,[r5,#(4*(%d+1))] + ADDS r2,r2,r0 + ADC r3,r3,#0 + MOV r4,#0 +ENDM +; +; RFIND macro +; +MACRO RFIND + STR r2,[r5,#(4*%d)] + LDR r0,[r5,#(4*(%d+1))] + ADDS r2,r3,r0 + ADC r3,r4,#0 + MOV r4,#0 +ENDM +; +; REDC_END +; +MACRO REDC_END + STR r2,[r5,#(4*%d)] + STR r3,[r5,#(4*(%d+1))] + } +ENDM +; +; ADD_START macro - initialise for add/subtract, do first one +; +MACRO ADD_START + __asm { + MOV r6,a + MOV r7,b + MOV r8,c + LDR r0,[r6] + LDR r1,[r7] + ADDS r0,r0,r1 + STR r0,[r8] +ENDM +; +; ADD macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO ADD + LDR r0,[r6,#(4*%d)] + LDR r1,[r7,#(4*%d)] + ADCS r0,r0,r1 + STR r0,[r8,#(4*%d)] +ENDM +; +; ADD_END macro. Catch carry +; +MACRO ADD_END + MOV r0,#0 + MOVCS r0,#1 + MOV carry,r0 + } +ENDM +; +; INC_START macro. Do first one +; +MACRO INC_START + __asm { + MOV r6,a + MOV r7,b + LDR r0,[r6] + LDR r1,[r7] + ADDS r0,r0,r1 + STR r0,[r6] +ENDM +; +; INC macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO INC + LDR r0,[r6,#(4*%d)] + LDR r1,[r7,#(4*%d)] + ADCS r0,r0,r1 + STR r0,[r6,#(4*%d)] +ENDM +; +; INC_END macro. Catch carry +; +MACRO INC_END + MOV r0,#0 + MOVCS r0,#1 + MOV carry,r0 + } +ENDM +; +; SUB_START macro +; +MACRO SUB_START +__asm { + MOV r6,a + MOV r7,b + MOV r8,c + LDR r0,[r6] + LDR r1,[r7] + SUBS r0,r0,r1 + STR r0,[r8] +ENDM +; +; SUB macro. Subtract two numbers in memory and store result in memory. +; +MACRO SUB + LDR r0,[r6,#(4*%d)] + LDR r1,[r7,#(4*%d)] + SBCS r0,r0,r1 + STR r0,[r8,#(4*%d)] +ENDM +; +; SUB_END macro. Catch carry +; +MACRO SUB_END + MOV r0,#0 + MOVCC r0,#1 + MOV carry,r0 + } +ENDM +; +; DEC_START macro +; +MACRO DEC_START +__asm { + MOV r6,a + MOV r7,b + LDR r0,[r6] + LDR r1,[r7] + SUBS r0,r0,r1 + STR r0,[r6] +ENDM +; +; DEC macro. Subtract two numbers in memory and store result in memory. +; +MACRO DEC + LDR r0,[r6,#(4*%d)] + LDR r1,[r7,#(4*%d)] + SBCS r0,r0,r1 + STR r0,[r6,#(4*%d)] +ENDM +; +; DEC_END macro. Catch carry +; +MACRO DEC_END + MOV r0,#0 + MOVCC r0,#1 + MOV carry,r0 + } +ENDM +; +; KADD_START macro. Zero Carry flag +; +MACRO KADD_START + __asm { + MOV r6,a + MOV r7,b + MOV r8,c + MOV r9,n + MOV r0,#0 + ADDS r0,r0,r0 + k%d: +ENDM +; +; KASL macro. Important that carry flag is undisturbed! +; +MACRO KASL + SUB r9,r9,#1 + TEQ r9,#0 + BEQ k%d + ADD r6,r6,#(4*%d) + ADD r7,r7,#(4*%d) + ADD r8,r8,#(4*%d) + B k%d + k%d: +ENDM +; +; KADD_END macro +; +MACRO KADD_END + MOV r0,#0 + MOVCS r0,#1 + MOV carry,r0 + } +ENDM +; +; KINC_START macro. Set carry to Zero +; +MACRO KINC_START + __asm { + MOV r6,a + MOV r7,b + MOV r9,n + MOV r0,#0 + ADDS r0,r0,r0 + k%d: +ENDM +; +; KIDL macro. Important that carry flag is undisturbed! +; +MACRO KIDL + SUB r9,r9,#1 + TEQ r9,#0 + BEQ k%d + ADD r6,r6,#(4*%d) + ADD r7,r7,#(4*%d) + B k%d + k%d: +ENDM +; +; KINC_END macro +; +MACRO KINC_END + MOV r0,#0 + MOVCS r0,#1 + MOV carry,r0 + } +ENDM +; +; KDEC_START macro. Set carry +; +MACRO KDEC_START + __asm { + MOV r6,a + MOV r7,b + MOV r9,n + SUBS r0,r0,r0 + k%d: +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + MOV r0,#0 + MOVCC r0,#1 + MOV carry,r0 + } +ENDM + diff --git a/miracl/source/avr.mcs b/miracl/source/avr.mcs new file mode 100644 index 0000000..917246d --- /dev/null +++ b/miracl/source/avr.mcs @@ -0,0 +1,537 @@ +; Comba/KCM Macros for Atmel AVR +; +; Triple register is r8|r7|r6 +; +; X = r26|r27 +; Y = r28|r29 +; Z = r30|r31 +; +; Must remember to clear r1 - compiler expects it! +; +; *** Must use -fno-inline for mrkcm.c module +; +; See makemcs.txt for more information about this file +; +; + +MACRO PMUL_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%0\n" + "MOV r6,%%3\n" + "CLR r8\n" + "CLR r7\n" +ENDM + +MACRO PMUL + "LDD r0,Y+%d\n" + "MUL r0,r6\n" + "ADD r0,r8\n" + "ADC r1,r7\n" + "MOV r8,r1\n" + "STD %%a1+%d,r7\n" + "ST %%a2+,r0 ;%d \n" +ENDM + +MACRO PMUL_END + "MUL r6,r8\n" + "ST %%a1,r0\n" + "STD %%a1+1,r1\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + : + :"w"(a),"z"(b),"x"(c),"r"(sn) + :"r6","r7","r8","memory" + ); +ENDM + +MACRO MUL_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%0\n" + "CLR r8\n" + "CLR r7\n" + "CLR r6\n" + "CLR r5\n" +ENDM +; +; STEP macros +; +MACRO STEP + "LDD r0,Y+%d\n" + "LDD r1,%%a1+%d\n" + "MUL r1,r0\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r8,r5\n" +ENDM +; +; MFIN macro +; +MACRO MFIN + "ST %%a2+,r6 ;%d \n" + "MOV r6,r7\n" + "MOV r7,r8\n" + "CLR r8\n" +ENDM +; +; LAST +; +MACRO LAST + "LDD r0,Y+%d\n" + "LDD r1,%%a1+%d\n" + "MUL r1,r0\n" + "ADD r6,r0\n" +ENDM +; +; MULE +; + +MACRO MUL_END + "ST %%a2,r6 ;%d \n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + : + :"w"(a),"z"(b),"x"(c) + :"r5","r6","r7","r8","memory" + ); +ENDM +; +; SQR_START +; +MACRO SQR_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "CLR r8\n" + "CLR r7\n" + "CLR r6\n" + "CLR r5\n" +ENDM +; +; DSTEP +; +MACRO DSTEP + "LDD r0,%%a0+%d\n" + "LDD r1,%%a0+%d\n" + "MUL r1,r0\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r8,r5\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r8,r5\n" +ENDM +; +; SELF +; +MACRO SELF + "LDD r0,%%a0+%d\n" + "MUL r0,r0\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r8,r5\n" +ENDM +; +; SFIN +; +MACRO SFIN + "ST %%a1+,r6 ;%d \n" + "MOV r6,r7\n" + "MOV r7,r8\n" + "CLR r8\n" +ENDM +; +; SQR_END +; +MACRO SQR_END + "ST %%a1,r6 ;%d \n" + "CLR r1\n" + "POP r27\n" + "POP r26\n" + : + :"z"(a),"x"(c) + :"r5","r6","r7","r8","memory" + ); +ENDM +; +; RFINU macro +; +MACRO REDC_START + ASM ( + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%0\n" + "CLR r8\n" + "CLR r7\n" + "LD r6,Y\n" + "CLR r5\n" +ENDM +; +; RFINU macro +; +MACRO RFINU + "MUL r6,%%2\n" + "STD Y+%d,r0\n" + "LD r1,%%a1\n" + "MUL r1,r0\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r8,r5\n" + "MOV r6,r7\n" + "MOV r7,r8\n" + "CLR r8\n" + "LDD r0,Y+%d+1\n" + "ADD r6,r0\n" + "ADC r7,r5\n" + "CLR r8\n" +ENDM +; +; RFIND macro +; +MACRO RFIND + "STD Y+%d,r6\n" + "MOV r6,r7\n" + "MOV r7,r8\n" + "CLR r8\n" + "LDD r0,Y+%d+1\n" + "ADD r6,r0\n" + "ADC r7,r5\n" + "CLR r8\n" +ENDM +; +; REDC_END macro +; +MACRO REDC_END + "STD Y+%d,r6\n" + "STD Y+%d+1,r7\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + : + :"w"(a),"z"(b),"r"(ndash) + :"r5","r6","r7","r8","memory" + ); +ENDM +; +; ADD_START macro +; +MACRO ADD_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%1\n" + "LD r0,Y\n" + "LD r1,%%a2\n" + "ADD r1,r0\n" + "ST %%a3+,r1\n" +ENDM +; +; ADD macro - c[.]=a[.]+b[.] +; +MACRO ADD + "LDD r0,Y+%d\n" + "LDD r1,%%a2+%d\n" + "ADC r1,r0\n" + "ST %%a3+,r1 ;%d\n" +ENDM +; +; ADD_END macro. +; +MACRO ADD_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + :"=r"(carry) + :"w"(a),"z"(b),"x"(c) + :"memory" + ); +ENDM +; +; DOUBLE_START macro +; +MACRO DOUBLE_START + ASM ( + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%1\n" + "LD r0,Y\n" + "ADD r0,r0\n" + "ST Y,r0\n" +ENDM +; +; DOUBLE macro +; +MACRO DOUBLE + "LDD r0,Y+%d\n" + "ADC r0,r0\n" + "STD Y+%d,r0\n" +ENDM +; +; DOUBLE_END +; +MACRO DOUBLE_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "POP r29\n" + "POP r28\n" + :"=r"(carry) + :"w"(a) + :"memory" + ); +ENDM +; +; INC_START macro. Do first one. +; +MACRO INC_START + ASM ( + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%1\n" + "LD r0,Y\n" + "LD r1,%%a2\n" + "ADD r1,r0\n" + "ST Y,r1\n" +ENDM +; +; INC macro a[.]+=b[.] +; +MACRO INC + "LDD r0,Y+%d\n" + "LDD r1,%%a2+%d\n" + "ADC r1,r0\n" + "STD Y+%d,r1\n" +ENDM +MACRO INC_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + :"=r"(carry) + :"w"(a),"z"(b) + :"memory" + ); +ENDM +; +; SUB macro - c[.]=a[.]-b[.] +; +MACRO SUB_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%1\n" + "LD r0,Y\n" + "LD r1,%%a2\n" + "SUB r0,r1\n" + "ST %%a3+,r0\n" +ENDM +; +; SUB macro - c[.]=a[.]-b[.] +; +MACRO SUB + "LDD r0,Y+%d\n" + "LDD r1,%%a2+%d\n" + "SBC r0,r1\n" + "ST %%a3+,r0 ;%d\n" +ENDM +MACRO SUB_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + :"=r"(carry) + :"w"(a),"z"(b),"x"(c) + :"memory" + ); +ENDM +; +; DEC_START macro +; +MACRO DEC_START + ASM ( + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%1\n" + "LD r0,Y\n" + "LD r1,%%a2\n" + "SUB r0,r1\n" + "ST Y,r0\n" +ENDM +; +; DEC macro a[.]-=b[.] +; +MACRO DEC + "LDD r0,Y+%d\n" + "LDD r1,%%a2+%d\n" + "SBC r0,r1\n" + "STD Y+%d,r0\n" +ENDM +; +; DEC_END macro +; +MACRO DEC_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + :"=r"(carry) + :"w"(a),"z"(b) + :"memory" + ); +ENDM +; +; KADD_START macro. Zero Carry +; +MACRO KADD_START + ASM( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "PUSH r30\n" + "PUSH r31\n" + "MOVW r28,%%1\n" + "MOV r5,%%4\n" + "CLC\n" + "k%d:\n" +ENDM +; +; KASL macro - Important that carry flag is undisturbed +; +MACRO KASL + "DEC r5\n" + "BREQ k%d\n" + "CLR r0\n" + "ADC r0,r0\n" + "ADIW r28,%d\n" + "ADIW r30,%d ;%d \n" + "ROR r0\n" + "RJMP k%d\n" + "k%d:\n" +ENDM +; +; KADD_END macro +; +MACRO KADD_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r31\n" + "POP r30\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + :"=r"(carry) + :"w"(a),"z"(b),"x"(c),"r"(n) + :"r5","memory" + ); +ENDM +; +; KINC_START macro +; +MACRO KINC_START + ASM( + "PUSH r28\n" + "PUSH r29\n" + "PUSH r30\n" + "PUSH r31\n" + "MOVW r28,%%1\n" + "MOV r5,%%3\n" + "CLC\n" + "k%d:\n" +ENDM +; +; KIDL macro - Important that carry flag is undisturbed +; +MACRO KIDL + "DEC r5\n" + "BREQ k%d\n" + "CLR r0\n" + "ADC r0,r0\n" + "ADIW r28,%d\n" + "ADIW r30,%d\n" + "ROR r0\n" + "RJMP k%d\n" + "k%d:\n" +ENDM +; +; KINC_END macro +; +MACRO KINC_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r31\n" + "POP r30\n" + "POP r29\n" + "POP r28\n" + :"=r"(carry) + :"w"(a),"z"(b),"r"(n) + :"r5","memory" + ); +ENDM +; +; KDEC_START macro. Zero carry +; +MACRO KDEC_START + ASM( + "PUSH r28\n" + "PUSH r29\n" + "PUSH r30\n" + "PUSH r31\n" + "MOVW r28,%%1\n" + "MOV r5,%%3\n" + "CLC\n" + "k%d:\n" +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r31\n" + "POP r30\n" + "POP r29\n" + "POP r28\n" + :"=r"(carry) + :"w"(a),"z"(b),"r"(n) + :"r5","memory" + ); +ENDM + diff --git a/miracl/source/avr2.mcs b/miracl/source/avr2.mcs new file mode 100644 index 0000000..e3655e0 --- /dev/null +++ b/miracl/source/avr2.mcs @@ -0,0 +1,699 @@ +; Comba/KCM Macros for Atmel AVR +; +; Triple register is r8|r7|r6 +; +; Must remember to clear r1 - compiler expects it! +; +; *** Must use -fno-inline for mrkcm.c module +; +; See makemcs.txt for more information about this file +; +; Hybrid x2 step +; +; "Triple" register is now r12|r9|r8|r7|r6 +; registers r10 and r11 are employed as "carry catchers" +; + +MACRO PMUL_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%0\n" + "MOV r6,%%3\n" + "CLR r8\n" + "CLR r7\n" +ENDM + +MACRO PMUL + "LDD r0,Y+%d\n" + "MUL r0,r6\n" + "ADD r0,r8\n" + "ADC r1,r7\n" + "MOV r8,r1\n" + "STD %%a1+%d,r7\n" + "ST %%a2+,r0 ;%d \n" +ENDM + +MACRO PMUL_END + "MUL r6,r8\n" + "ST %%a1,r0\n" + "STD %%a1+1,r1\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + : + :"w"(a),"z"(b),"x"(c),"r"(sn) + :"r6","r7","r8","memory" + ); +ENDM + +MACRO H2_MUL_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%0\n" + "CLR r24\n" + "CLR r25\n" + "CLR r12\n" + "MOVW r6,r24\n" + "MOVW r8,r24\n" + "MOVW r10,r24\n" +ENDM +MACRO H2_STEP + "LDD r2,Y+%d\n" + "LDD r3,Y+%d+1\n" + "LDD r4,%%a1+%d\n" + "MUL r2,r4\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r10,r25\n" + "MUL r3,r4\n" + "ADD r7,r0\n" + "ADC r8,r1\n" + "ADC r11,r25\n" + "LDD r4,%%a1+%d+1\n" + "MUL r2,r4\n" + "ADD r7,r0\n" + "ADC r8,r1\n" + "ADC r11,r25\n" + "MUL r3,r4\n" + "ADD r8,r0\n" + "ADC r9,r1\n" + "ADC r12,r25\n" +ENDM +MACRO H2_LAST + "LDD r2,Y+%d\n" + "LDD r3,Y+%d+1\n" + "LDD r4,%%a1+%d\n" + "MUL r2,r4\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "MUL r3,r4\n" + "ADD r7,r0\n" + "LDD r4,%%a1+%d+1\n" + "MUL r2,r4\n" + "ADD r7,r0\n" +ENDM +MACRO H2_MFIN + "ST %%a2+,r6 ;%d \n" + "ST %%a2+,r7 ;%d \n" + "ADD r8,r10\n" + "ADC r9,r11\n" + "ADC r12,r25\n" + "MOVW r6,r8\n" + "MOV r8,r12\n" + "MOVW r10,r24\n" + "CLR r12\n" + "CLR r9\n" +ENDM +MACRO H2_MUL_END + "ST %%a2+,r6 ;%d \n" + "ST %%a2,r7 ;%d \n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + : + :"w"(a),"z"(b),"x"(c) + :"r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12","memory" + ); +ENDM +MACRO H2_SQR_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "CLR r24\n" + "CLR r25\n" + "CLR r12\n" + "MOVW r6,r24\n" + "MOVW r8,r24\n" + "MOVW r10,r24\n" +ENDM +MACRO H2_DSTEP + "LDD r2,%%a0+%d\n" + "LDD r3,%%a0+%d+1\n" + "LDD r4,%%a0+%d\n" + "MUL r2,r4\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r10,r25\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r10,r25\n" + "MUL r3,r4\n" + "ADD r7,r0\n" + "ADC r8,r1\n" + "ADC r11,r25\n" + "ADD r7,r0\n" + "ADC r8,r1\n" + "ADC r11,r25\n" + "LDD r4,%%a0+%d+1\n" + "MUL r2,r4\n" + "ADD r7,r0\n" + "ADC r8,r1\n" + "ADC r11,r25\n" + "ADD r7,r0\n" + "ADC r8,r1\n" + "ADC r11,r25\n" + "MUL r3,r4\n" + "ADD r8,r0\n" + "ADC r9,r1\n" + "ADC r12,r25\n" + "ADD r8,r0\n" + "ADC r9,r1\n" + "ADC r12,r25\n" +ENDM +MACRO H2_SELF + "LDD r2,%%a0+%d\n" + "LDD r3,%%a0+%d+1\n" + "MUL r2,r2\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r10,r25\n" + "MUL r2,r3\n" + "ADD r7,r0\n" + "ADC r8,r1\n" + "ADC r11,r25\n" + "ADD r7,r0\n" + "ADC r8,r1\n" + "ADC r11,r25\n" + "MUL r3,r3\n" + "ADD r8,r0\n" + "ADC r9,r1\n" + "ADC r12,r25\n" +ENDM +MACRO H2_SFIN + "ST %%a1+,r6 ;%d \n" + "ST %%a1+,r7 ;%d \n" + "ADD r8,r10\n" + "ADC r9,r11\n" + "ADC r12,r25\n" + "MOVW r6,r8\n" + "MOV r8,r12\n" + "MOVW r10,r24\n" + "CLR r12\n" + "CLR r9\n" +ENDM +MACRO H2_SQR_END + "ST %%a1+,r6 ;%d \n" + "ST %%a1,r7 ;%d \n" + "CLR r1\n" + "POP r27\n" + "POP r26\n" + : + :"z"(a),"x"(c) + :"r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12","memory" + ); +ENDM + +MACRO MUL_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%0\n" + "CLR r8\n" + "CLR r7\n" + "CLR r6\n" + "CLR r5\n" +ENDM +; +; STEP macros +; +MACRO STEP + "LDD r0,Y+%d\n" + "LDD r1,%%a1+%d\n" + "MUL r1,r0\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r8,r5\n" +ENDM +; +; MFIN macro +; +MACRO MFIN + "ST %%a2+,r6 ;%d \n" + "MOV r6,r7\n" + "MOV r7,r8\n" + "CLR r8\n" +ENDM +; +; LAST +; +MACRO LAST + "LDD r0,Y+%d\n" + "LDD r1,%%a1+%d\n" + "MUL r1,r0\n" + "ADD r6,r0\n" +ENDM +; +; MULE +; + +MACRO MUL_END + "ST %%a2,r6 ;%d \n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + : + :"w"(a),"z"(b),"x"(c) + :"r5","r6","r7","r8","memory" + ); +ENDM +; +; SQR_START +; +MACRO SQR_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "CLR r8\n" + "CLR r7\n" + "CLR r6\n" + "CLR r5\n" +ENDM +; +; DSTEP +; +MACRO DSTEP + "LDD r0,%%a0+%d\n" + "LDD r1,%%a0+%d\n" + "MUL r1,r0\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r8,r5\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r8,r5\n" +ENDM +; +; SELF +; +MACRO SELF + "LDD r0,%%a0+%d\n" + "MUL r0,r0\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r8,r5\n" +ENDM +; +; SFIN +; +MACRO SFIN + "ST %%a1+,r6 ;%d \n" + "MOV r6,r7\n" + "MOV r7,r8\n" + "CLR r8\n" +ENDM +; +; SQR_END +; +MACRO SQR_END + "ST %%a1,r6 ;%d \n" + "CLR r1\n" + "POP r27\n" + "POP r26\n" + : + :"z"(a),"x"(c) + :"r5","r6","r7","r8","memory" + ); +ENDM +; +; RFINU macro +; +MACRO REDC_START + ASM ( + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%0\n" + "CLR r8\n" + "CLR r7\n" + "LD r6,Y\n" + "CLR r5\n" +ENDM +; +; RFINU macro +; +MACRO RFINU + "MUL r6,%%2\n" + "STD Y+%d,r0\n" + "LD r1,%%a1\n" + "MUL r1,r0\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r8,r5\n" + "MOV r6,r7\n" + "MOV r7,r8\n" + "CLR r8\n" + "LDD r0,Y+%d+1\n" + "ADD r6,r0\n" + "ADC r7,r5\n" + "CLR r8\n" +ENDM +; +; RFIND macro +; +MACRO RFIND + "STD Y+%d,r6\n" + "MOV r6,r7\n" + "MOV r7,r8\n" + "CLR r8\n" + "LDD r0,Y+%d+1\n" + "ADD r6,r0\n" + "ADC r7,r5\n" + "CLR r8\n" +ENDM +; +; REDC_END macro +; +MACRO REDC_END + "STD Y+%d,r6\n" + "STD Y+%d+1,r7\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + : + :"w"(a),"z"(b),"r"(ndash) + :"r5","r6","r7","r8","memory" + ); +ENDM +; +; ADD_START macro +; +MACRO ADD_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%1\n" + "LD r0,Y\n" + "LD r1,%%a2\n" + "ADD r1,r0\n" + "ST %%a3+,r1\n" +ENDM +; +; ADD macro - c[.]=a[.]+b[.] +; +MACRO ADD + "LDD r0,Y+%d\n" + "LDD r1,%%a2+%d\n" + "ADC r1,r0\n" + "ST %%a3+,r1 ;%d\n" +ENDM +; +; ADD_END macro. +; +MACRO ADD_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + :"=r"(carry) + :"w"(a),"z"(b),"x"(c) + :"memory" + ); +ENDM +; +; DOUBLE_START macro +; +MACRO DOUBLE_START + ASM ( + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%1\n" + "LD r0,Y\n" + "ADD r0,r0\n" + "ST Y,r0\n" +ENDM +; +; DOUBLE macro +; +MACRO DOUBLE + "LDD r0,Y+%d\n" + "ADC r0,r0\n" + "STD Y+%d,r0\n" +ENDM +; +; DOUBLE_END +; +MACRO DOUBLE_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "POP r29\n" + "POP r28\n" + :"=r"(carry) + :"w"(a) + :"memory" + ); +ENDM +; +; INC_START macro. Do first one. +; +MACRO INC_START + ASM ( + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%1\n" + "LD r0,Y\n" + "LD r1,%%a2\n" + "ADD r1,r0\n" + "ST Y,r1\n" +ENDM +; +; INC macro a[.]+=b[.] +; +MACRO INC + "LDD r0,Y+%d\n" + "LDD r1,%%a2+%d\n" + "ADC r1,r0\n" + "STD Y+%d,r1\n" +ENDM +MACRO INC_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + :"=r"(carry) + :"w"(a),"z"(b) + :"memory" + ); +ENDM +; +; SUB macro - c[.]=a[.]-b[.] +; +MACRO SUB_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%1\n" + "LD r0,Y\n" + "LD r1,%%a2\n" + "SUB r0,r1\n" + "ST %%a3+,r0\n" +ENDM +; +; SUB macro - c[.]=a[.]-b[.] +; +MACRO SUB + "LDD r0,Y+%d\n" + "LDD r1,%%a2+%d\n" + "SBC r0,r1\n" + "ST %%a3+,r0 ;%d\n" +ENDM +MACRO SUB_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + :"=r"(carry) + :"w"(a),"z"(b),"x"(c) + :"memory" + ); +ENDM +; +; DEC_START macro +; +MACRO DEC_START + ASM ( + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%1\n" + "LD r0,Y\n" + "LD r1,%%a2\n" + "SUB r0,r1\n" + "ST Y,r0\n" +ENDM +; +; DEC macro a[.]-=b[.] +; +MACRO DEC + "LDD r0,Y+%d\n" + "LDD r1,%%a2+%d\n" + "SBC r0,r1\n" + "STD Y+%d,r0\n" +ENDM +; +; DEC_END macro +; +MACRO DEC_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + :"=r"(carry) + :"w"(a),"z"(b) + :"memory" + ); +ENDM +; +; KADD_START macro. Zero Carry +; +MACRO KADD_START + ASM( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "PUSH r30\n" + "PUSH r31\n" + "MOVW r28,%%1\n" + "MOV r5,%%4\n" + "CLC\n" + "k%d:\n" +ENDM +; +; KASL macro - Important that carry flag is undisturbed +; +MACRO KASL + "DEC r5\n" + "BREQ k%d\n" + "CLR r0\n" + "ADC r0,r0\n" + "ADIW r28,%d\n" + "ADIW r30,%d ;%d \n" + "ROR r0\n" + "RJMP k%d\n" + "k%d:\n" +ENDM +; +; KADD_END macro +; +MACRO KADD_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r31\n" + "POP r30\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + :"=r"(carry) + :"w"(a),"z"(b),"x"(c),"r"(n) + :"r5","memory" + ); +ENDM +; +; KINC_START macro +; +MACRO KINC_START + ASM( + "PUSH r28\n" + "PUSH r29\n" + "PUSH r30\n" + "PUSH r31\n" + "MOVW r28,%%1\n" + "MOV r5,%%3\n" + "CLC\n" + "k%d:\n" +ENDM +; +; KIDL macro - Important that carry flag is undisturbed +; +MACRO KIDL + "DEC r5\n" + "BREQ k%d\n" + "CLR r0\n" + "ADC r0,r0\n" + "ADIW r28,%d\n" + "ADIW r30,%d\n" + "ROR r0\n" + "RJMP k%d\n" + "k%d:\n" +ENDM +; +; KINC_END macro +; +MACRO KINC_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r31\n" + "POP r30\n" + "POP r29\n" + "POP r28\n" + :"=r"(carry) + :"w"(a),"z"(b),"r"(n) + :"r5","memory" + ); +ENDM +; +; KDEC_START macro. Zero carry +; +MACRO KDEC_START + ASM( + "PUSH r28\n" + "PUSH r29\n" + "PUSH r30\n" + "PUSH r31\n" + "MOVW r28,%%1\n" + "MOV r5,%%3\n" + "CLC\n" + "k%d:\n" +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r31\n" + "POP r30\n" + "POP r29\n" + "POP r28\n" + :"=r"(carry) + :"w"(a),"z"(b),"r"(n) + :"r5","memory" + ); +ENDM + diff --git a/miracl/source/avr4.mcs b/miracl/source/avr4.mcs new file mode 100644 index 0000000..6888d3b --- /dev/null +++ b/miracl/source/avr4.mcs @@ -0,0 +1,950 @@ +; Comba/KCM Macros for Atmel AVR +; +; Triple register is r8|r7|r6 +; +; Must remember to clear r1 - compiler expects it! +; +; *** Must use -fno-inline for mrkcm.c module +; +; See makemcs.txt for more information about this file +; +; Hybrid x4 step +; +; "Triple" register is now r22||r15|r14|r13|r12||r11|r10|r9|r8|| +; registers r16 to r21 are employed as "carry catchers" +; + +MACRO PMUL_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%0\n" + "MOV r6,%%3\n" + "CLR r8\n" + "CLR r7\n" +ENDM + +MACRO PMUL + "LDD r0,Y+%d\n" + "MUL r0,r6\n" + "ADD r0,r8\n" + "ADC r1,r7\n" + "MOV r8,r1\n" + "STD %%a1+%d,r7\n" + "ST %%a2+,r0 ;%d \n" +ENDM + +MACRO PMUL_END + "MUL r6,r8\n" + "ST %%a1,r0\n" + "STD %%a1+1,r1\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + : + :"w"(a),"z"(b),"x"(c),"r"(sn) + :"r6","r7","r8","memory" + ); +ENDM + +MACRO H4_MUL_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%0\n" + "CLR r2\n" + "CLR r3\n" + "CLR r7\n" + "CLR r22\n" + "MOVW r8,r2\n" + "MOVW r10,r2\n" + "MOVW r12,r2\n" + "MOVW r14,r2\n" + "MOVW r16,r2\n" + "MOVW r18,r2\n" + "MOVW r20,r2\n" +ENDM +MACRO H4_STEP + "LDD r2,Y+%d\n" + "LDD r3,Y+%d+1\n" + "LDD r4,Y+%d+2\n" + "LDD r5,Y+%d+3\n" + "LDD r6,%%a1+%d\n" + "MUL r6,r2\n" + "ADD r8,r0\n" + "ADC r9,r1\n" + "ADC r16,r7\n" + "MUL r6,r3\n" + "ADD r9,r0\n" + "ADC r10,r1\n" + "ADC r17,r7\n" + "MUL r6,r4\n" + "ADD r10,r0\n" + "ADC r11,r1\n" + "ADC r18,r7\n" + "MUL r6,r5\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r7\n" + "LDD r6,%%a1+%d+1\n" + "MUL r6,r2\n" + "ADD r9,r0\n" + "ADC r10,r1\n" + "ADC r17,r7\n" + "MUL r6,r3\n" + "ADD r10,r0\n" + "ADC r11,r1\n" + "ADC r18,r7\n" + "MUL r6,r4\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r7\n" + "MUL r6,r5\n" + "ADD r12,r0\n" + "ADC r13,r1\n" + "ADC r20,r7\n" + "LDD r6,%%a1+%d+2\n" + "MUL r6,r2\n" + "ADD r10,r0\n" + "ADC r11,r1\n" + "ADC r18,r7\n" + "MUL r6,r3\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r7\n" + "MUL r6,r4\n" + "ADD r12,r0\n" + "ADC r13,r1\n" + "ADC r20,r7\n" + "MUL r6,r5\n" + "ADD r13,r0\n" + "ADC r14,r1\n" + "ADC r21,r7\n" + "LDD r6,%%a1+%d+3\n" + "MUL r6,r2\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r7\n" + "MUL r6,r3\n" + "ADD r12,r0\n" + "ADC r13,r1\n" + "ADC r20,r7\n" + "MUL r6,r4\n" + "ADD r13,r0\n" + "ADC r14,r1\n" + "ADC r21,r7\n" + "MUL r6,r5\n" + "ADD r14,r0\n" + "ADC r15,r1\n" + "ADC r22,r7\n" +ENDM +MACRO H4_LAST + "LDD r2,Y+%d\n" + "LDD r3,Y+%d+1\n" + "LDD r4,Y+%d+2\n" + "LDD r5,Y+%d+3\n" + "LDD r6,%%a1+%d\n" + "MUL r6,r2\n" + "ADD r8,r0\n" + "ADC r9,r1\n" + "ADC r16,r7\n" + "MUL r6,r3\n" + "ADD r9,r0\n" + "ADC r10,r1\n" + "ADC r17,r7\n" + "MUL r6,r4\n" + "ADD r10,r0\n" + "ADC r11,r1\n" + "MUL r6,r5\n" + "ADD r11,r0\n" + "LDD r6,%%a1+%d+1\n" + "MUL r6,r2\n" + "ADD r9,r0\n" + "ADC r10,r1\n" + "ADC r17,r7\n" + "MUL r6,r3\n" + "ADD r10,r0\n" + "ADC r11,r1\n" + "MUL r6,r4\n" + "ADD r11,r0\n" + "LDD r6,%%a1+%d+2\n" + "MUL r6,r2\n" + "ADD r10,r0\n" + "ADC r11,r1\n" + "MUL r6,r3\n" + "ADD r11,r0\n" + "LDD r6,%%a1+%d+3\n" + "MUL r6,r2\n" + "ADD r11,r0\n" +ENDM +MACRO H4_MFIN + "ADD r10,r16\n" + "ADC r11,r17\n" + "ADC r12,r18\n" + "ADC r13,r19\n" + "ADC r14,r20\n" + "ADC r15,r21\n" + "ADC r22,r7\n" + "ST %%a2+,r8 ;%d \n" + "ST %%a2+,r9 ;%d \n" + "ST %%a2+,r10 ;%d \n" + "ST %%a2+,r11 ;%d \n" + "MOVW r8,r12\n" + "MOVW r10,r14\n" + "MOV r12,r22\n" + "CLR r13\n" + "CLR r2\n" + "CLR r3\n" + "MOVW r14,r2\n" + "MOVW r16,r2\n" + "MOVW r18,r2\n" + "MOVW r20,r2\n" + "CLR r22\n" +ENDM +MACRO H4_MUL_END + "ADD r10,r16\n" + "ADC r11,r17\n" + "ST %%a2+,r8 ;%d \n" + "ST %%a2+,r9 ;%d \n" + "ST %%a2+,r10 ;%d \n" + "ST %%a2,r11 ;%d \n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + : + :"w"(a),"z"(b),"x"(c) + :"r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12","r13","r14","r15","r16","r17","r18","r19","r20","r21","r22","memory" + ); +ENDM +MACRO H4_SQR_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "CLR r24\n" + "CLR r25\n" + "CLR r22\n" + "MOVW r8,r24\n" + "MOVW r10,r24\n" + "MOVW r12,r24\n" + "MOVW r14,r24\n" + "MOVW r16,r24\n" + "MOVW r18,r24\n" + "MOVW r20,r24\n" +ENDM +MACRO H4_DSTEP + "LDD r2,%%a0+%d\n" + "LDD r3,%%a0+%d+1\n" + "LDD r4,%%a0+%d+2\n" + "LDD r5,%%a0+%d+3\n" + "LDD r6,%%a0+%d\n" + "MUL r6,r2\n" + "ADD r8,r0\n" + "ADC r9,r1\n" + "ADC r16,r25\n" + "ADD r8,r0\n" + "ADC r9,r1\n" + "ADC r16,r25\n" + "MUL r6,r3\n" + "ADD r9,r0\n" + "ADC r10,r1\n" + "ADC r17,r25\n" + "ADD r9,r0\n" + "ADC r10,r1\n" + "ADC r17,r25\n" + "MUL r6,r4\n" + "ADD r10,r0\n" + "ADC r11,r1\n" + "ADC r18,r25\n" + "ADD r10,r0\n" + "ADC r11,r1\n" + "ADC r18,r25\n" + "MUL r6,r5\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r25\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r25\n" + "LDD r6,%%a0+%d+1\n" + "MUL r6,r2\n" + "ADD r9,r0\n" + "ADC r10,r1\n" + "ADC r17,r25\n" + "ADD r9,r0\n" + "ADC r10,r1\n" + "ADC r17,r25\n" + "MUL r6,r3\n" + "ADD r10,r0\n" + "ADC r11,r1\n" + "ADC r18,r25\n" + "ADD r10,r0\n" + "ADC r11,r1\n" + "ADC r18,r25\n" + "MUL r6,r4\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r25\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r25\n" + "MUL r6,r5\n" + "ADD r12,r0\n" + "ADC r13,r1\n" + "ADC r20,r25\n" + "ADD r12,r0\n" + "ADC r13,r1\n" + "ADC r20,r25\n" + "LDD r6,%%a0+%d+2\n" + "MUL r6,r2\n" + "ADD r10,r0\n" + "ADC r11,r1\n" + "ADC r18,r25\n" + "ADD r10,r0\n" + "ADC r11,r1\n" + "ADC r18,r25\n" + "MUL r6,r3\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r25\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r25\n" + "MUL r6,r4\n" + "ADD r12,r0\n" + "ADC r13,r1\n" + "ADC r20,r25\n" + "ADD r12,r0\n" + "ADC r13,r1\n" + "ADC r20,r25\n" + "MUL r6,r5\n" + "ADD r13,r0\n" + "ADC r14,r1\n" + "ADC r21,r25\n" + "ADD r13,r0\n" + "ADC r14,r1\n" + "ADC r21,r25\n" + "LDD r6,%%a0+%d+3\n" + "MUL r6,r2\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r25\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r25\n" + "MUL r6,r3\n" + "ADD r12,r0\n" + "ADC r13,r1\n" + "ADC r20,r25\n" + "ADD r12,r0\n" + "ADC r13,r1\n" + "ADC r20,r25\n" + "MUL r6,r4\n" + "ADD r13,r0\n" + "ADC r14,r1\n" + "ADC r21,r25\n" + "ADD r13,r0\n" + "ADC r14,r1\n" + "ADC r21,r25\n" + "MUL r6,r5\n" + "ADD r14,r0\n" + "ADC r15,r1\n" + "ADC r22,r25\n" + "ADD r14,r0\n" + "ADC r15,r1\n" + "ADC r22,r25\n" +ENDM +MACRO H4_SELF + "LDD r2,%%a0+%d\n" + "LDD r3,%%a0+%d+1\n" + "LDD r4,%%a0+%d+2\n" + "LDD r5,%%a0+%d+3\n" + "MUL r2,r2\n" + "ADD r8,r0\n" + "ADC r9,r1\n" + "ADC r16,r25\n" + "MUL r2,r3\n" + "ADD r9,r0\n" + "ADC r10,r1\n" + "ADC r17,r25\n" + "ADD r9,r0\n" + "ADC r10,r1\n" + "ADC r17,r25\n" + "MUL r2,r4\n" + "ADD r10,r0\n" + "ADC r11,r1\n" + "ADC r18,r25\n" + "ADD r10,r0\n" + "ADC r11,r1\n" + "ADC r18,r25\n" + "MUL r2,r5\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r25\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r25\n" + "MUL r3,r3\n" + "ADD r10,r0\n" + "ADC r11,r1\n" + "ADC r18,r25\n" + "MUL r3,r4\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r25\n" + "ADD r11,r0\n" + "ADC r12,r1\n" + "ADC r19,r25\n" + "MUL r3,r5\n" + "ADD r12,r0\n" + "ADC r13,r1\n" + "ADC r20,r25\n" + "ADD r12,r0\n" + "ADC r13,r1\n" + "ADC r20,r25\n" + "MUL r4,r4\n" + "ADD r12,r0\n" + "ADC r13,r1\n" + "ADC r20,r25\n" + "MUL r4,r5\n" + "ADD r13,r0\n" + "ADC r14,r1\n" + "ADC r21,r25\n" + "ADD r13,r0\n" + "ADC r14,r1\n" + "ADC r21,r25\n" + "MUL r5,r5\n" + "ADD r14,r0\n" + "ADC r15,r1\n" + "ADC r22,r25\n" +ENDM +MACRO H4_SFIN + "ADD r10,r16\n" + "ADC r11,r17\n" + "ADC r12,r18\n" + "ADC r13,r19\n" + "ADC r14,r20\n" + "ADC r15,r21\n" + "ADC r22,r25\n" + "ST %%a1+,r8 ;%d \n" + "ST %%a1+,r9 ;%d \n" + "ST %%a1+,r10 ;%d \n" + "ST %%a1+,r11 ;%d \n" + "MOVW r8,r12\n" + "MOVW r10,r14\n" + "MOV r12,r22\n" + "CLR r13\n" + "MOVW r14,r24\n" + "MOVW r16,r24\n" + "MOVW r18,r24\n" + "MOVW r20,r24\n" + "CLR r22\n" +ENDM +MACRO H4_SQR_END + "ADD r10,r16\n" + "ADC r11,r17\n" + "ST %%a1+,r8 ;%d \n" + "ST %%a1+,r9 ;%d \n" + "ST %%a1+,r10 ;%d \n" + "ST %%a1+,r11 ;%d \n" + "CLR r1\n" + "POP r27\n" + "POP r26\n" + : + :"z"(a),"x"(c) + :"r2","r3","r4","r5","r6","r8","r9","r10","r11","r12","r13","r14","r15","r16","r17","r18","r19","r20","r21","r22","r24","r25","memory" + ); +ENDM + +MACRO MUL_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%0\n" + "CLR r8\n" + "CLR r7\n" + "CLR r6\n" + "CLR r5\n" +ENDM +; +; STEP macros +; +MACRO STEP + "LDD r0,Y+%d\n" + "LDD r1,%%a1+%d\n" + "MUL r1,r0\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r8,r5\n" +ENDM +; +; MFIN macro +; +MACRO MFIN + "ST %%a2+,r6 ;%d \n" + "MOV r6,r7\n" + "MOV r7,r8\n" + "CLR r8\n" +ENDM +; +; LAST +; +MACRO LAST + "LDD r0,Y+%d\n" + "LDD r1,%%a1+%d\n" + "MUL r1,r0\n" + "ADD r6,r0\n" +ENDM +; +; MULE +; +MACRO MUL_END + "ST %%a2,r6 ;%d \n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + : + :"w"(a),"z"(b),"x"(c) + :"r5","r6","r7","r8","memory" + ); +ENDM +; +; SQR_START +; +MACRO SQR_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "CLR r8\n" + "CLR r7\n" + "CLR r6\n" + "CLR r5\n" +ENDM +; +; DSTEP +; +MACRO DSTEP + "LDD r0,%%a0+%d\n" + "LDD r1,%%a0+%d\n" + "MUL r1,r0\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r8,r5\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r8,r5\n" +ENDM +; +; SELF +; +MACRO SELF + "LDD r0,%%a0+%d\n" + "MUL r0,r0\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r8,r5\n" +ENDM +; +; SFIN +; +MACRO SFIN + "ST %%a1+,r6 ;%d \n" + "MOV r6,r7\n" + "MOV r7,r8\n" + "CLR r8\n" +ENDM +; +; SQR_END +; +MACRO SQR_END + "ST %%a1,r6 ;%d \n" + "CLR r1\n" + "POP r27\n" + "POP r26\n" + : + :"z"(a),"x"(c) + :"r5","r6","r7","r8","memory" + ); +ENDM +; +; REDC_START macro +; +MACRO REDC_START + ASM ( + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%0\n" + "CLR r8\n" + "CLR r7\n" + "LD r6,Y\n" + "CLR r5\n" +ENDM +; +; RFINU macro +; +MACRO RFINU + + "MUL r6,%%2\n" + "STD Y+%d,r0\n" + "LD r1,%%a1\n" + "MUL r1,r0\n" + "ADD r6,r0\n" + "ADC r7,r1\n" + "ADC r8,r5\n" + + "MOV r6,r7\n" + "MOV r7,r8\n" + "CLR r8\n" + "LDD r0,Y+%d+1\n" + "ADD r6,r0\n" + "ADC r7,r5\n" + "CLR r8\n" +ENDM +; +; RFIND macro +; +MACRO RFIND + "STD Y+%d,r6\n" + "MOV r6,r7\n" + "MOV r7,r8\n" + "CLR r8\n" + "LDD r0,Y+%d+1\n" + "ADD r6,r0\n" + "ADC r7,r5\n" + "CLR r8\n" +ENDM +; +; REDC_END macro +; +MACRO REDC_END + "STD Y+%d,r6\n" + "STD Y+%d+1,r7\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + : + :"w"(a),"z"(b),"r"(ndash) + :"r5","r6","r7","r8","memory" + ); +ENDM +; +; ADD_START macro +; +MACRO ADD_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%1\n" + "LD r0,Y\n" + "LD r1,%%a2\n" + "ADD r1,r0\n" + "ST %%a3+,r1\n" +ENDM +; +; ADD macro - c[.]=a[.]+b[.] +; +MACRO ADD + "LDD r0,Y+%d\n" + "LDD r1,%%a2+%d\n" + "ADC r1,r0\n" + "ST %%a3+,r1 ;%d\n" +ENDM +; +; ADD_END macro. +; +MACRO ADD_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + :"=r"(carry) + :"w"(a),"z"(b),"x"(c) + :"memory" + ); +ENDM +; +; DOUBLE_START macro +; +MACRO DOUBLE_START + ASM ( + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%1\n" + "LD r0,Y\n" + "ADD r0,r0\n" + "ST Y,r0\n" +ENDM +; +; DOUBLE macro +; +MACRO DOUBLE + "LDD r0,Y+%d\n" + "ADC r0,r0\n" + "STD Y+%d,r0\n" +ENDM +; +; DOUBLE_END +; +MACRO DOUBLE_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "POP r29\n" + "POP r28\n" + :"=r"(carry) + :"w"(a) + :"memory" + ); +ENDM +; +; INC_START macro. Do first one. +; +MACRO INC_START + ASM ( + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%1\n" + "LD r0,Y\n" + "LD r1,%%a2\n" + "ADD r1,r0\n" + "ST Y,r1\n" +ENDM +; +; INC macro a[.]+=b[.] +; +MACRO INC + "LDD r0,Y+%d\n" + "LDD r1,%%a2+%d\n" + "ADC r1,r0\n" + "STD Y+%d,r1\n" +ENDM +MACRO INC_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + :"=r"(carry) + :"w"(a),"z"(b) + :"memory" + ); +ENDM +; +; SUB macro - c[.]=a[.]-b[.] +; +MACRO SUB_START + ASM ( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%1\n" + "LD r0,Y\n" + "LD r1,%%a2\n" + "SUB r0,r1\n" + "ST %%a3+,r0\n" +ENDM +; +; SUB macro - c[.]=a[.]-b[.] +; +MACRO SUB + "LDD r0,Y+%d\n" + "LDD r1,%%a2+%d\n" + "SBC r0,r1\n" + "ST %%a3+,r0 ;%d\n" +ENDM +MACRO SUB_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + :"=r"(carry) + :"w"(a),"z"(b),"x"(c) + :"memory" + ); +ENDM +; +; DEC_START macro +; +MACRO DEC_START + ASM ( + "PUSH r28\n" + "PUSH r29\n" + "MOVW r28,%%1\n" + "LD r0,Y\n" + "LD r1,%%a2\n" + "SUB r0,r1\n" + "ST Y,r0\n" +ENDM +; +; DEC macro a[.]-=b[.] +; +MACRO DEC + "LDD r0,Y+%d\n" + "LDD r1,%%a2+%d\n" + "SBC r0,r1\n" + "STD Y+%d,r0\n" +ENDM +; +; DEC_END macro +; +MACRO DEC_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r29\n" + "POP r28\n" + :"=r"(carry) + :"w"(a),"z"(b) + :"memory" + ); +ENDM +; +; KADD_START macro. Zero Carry +; +MACRO KADD_START + ASM( + "PUSH r26\n" + "PUSH r27\n" + "PUSH r28\n" + "PUSH r29\n" + "PUSH r30\n" + "PUSH r31\n" + "MOVW r28,%%1\n" + "MOV r5,%%4\n" + "CLC\n" + "k%d:\n" +ENDM +; +; KASL macro - Important that carry flag is undisturbed +; +MACRO KASL + "DEC r5\n" + "BREQ k%d\n" + "CLR r0\n" + "ADC r0,r0\n" + "ADIW r28,%d\n" + "ADIW r30,%d ;%d \n" + "ROR r0\n" + "RJMP k%d\n" + "k%d:\n" +ENDM +; +; KADD_END macro +; +MACRO KADD_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r31\n" + "POP r30\n" + "POP r29\n" + "POP r28\n" + "POP r27\n" + "POP r26\n" + :"=r"(carry) + :"w"(a),"z"(b),"x"(c),"r"(n) + :"r5","memory" + ); +ENDM +; +; KINC_START macro +; +MACRO KINC_START + ASM( + "PUSH r28\n" + "PUSH r29\n" + "PUSH r30\n" + "PUSH r31\n" + "MOVW r28,%%1\n" + "MOV r5,%%3\n" + "CLC\n" + "k%d:\n" +ENDM +; +; KIDL macro - Important that carry flag is undisturbed +; +MACRO KIDL + "DEC r5\n" + "BREQ k%d\n" + "CLR r0\n" + "ADC r0,r0\n" + "ADIW r28,%d\n" + "ADIW r30,%d\n" + "ROR r0\n" + "RJMP k%d\n" + "k%d:\n" +ENDM +; +; KINC_END macro +; +MACRO KINC_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r31\n" + "POP r30\n" + "POP r29\n" + "POP r28\n" + :"=r"(carry) + :"w"(a),"z"(b),"r"(n) + :"r5","memory" + ); +ENDM +; +; KDEC_START macro. Zero carry +; +MACRO KDEC_START + ASM( + "PUSH r28\n" + "PUSH r29\n" + "PUSH r30\n" + "PUSH r31\n" + "MOVW r28,%%1\n" + "MOV r5,%%3\n" + "CLC\n" + "k%d:\n" +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + "CLR r0\n" + "ADC r0,r0\n" + "MOV %%0,r0\n" + "CLR r1\n" + "POP r31\n" + "POP r30\n" + "POP r29\n" + "POP r28\n" + :"=r"(carry) + :"w"(a),"z"(b),"r"(n) + :"r5","memory" + ); +ENDM + diff --git a/miracl/source/big.cpp b/miracl/source/big.cpp new file mode 100644 index 0000000..391c2ae --- /dev/null +++ b/miracl/source/big.cpp @@ -0,0 +1,452 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ functions big.cpp + * + * AUTHOR : N.Coghlan + * Modified by M.Scott + * + * PURPOSE : Implementation of class Big functions + */ + +#include "big.h" + +void Big::negate() const + { negify(fn,fn); } +big Big::getbig() const + { return fn;} +BOOL Big::iszero() const + { if (size(fn)==0) return TRUE; return FALSE;} +BOOL Big::isone() const + { if (size(fn)==1) return TRUE; return FALSE;} +int Big::len() const + { return numdig(fn); } + +Big operator-(const Big& b) +{Big nb; negify(b.fn,nb.fn); return nb;} +Big operator+(const Big& b,int i) +{Big abi; incr(b.fn, i, abi.fn); return abi;} +Big operator+(int i,const Big& b) +{Big aib; incr(b.fn, i, aib.fn); return aib;} +Big operator+(const Big& b1, const Big& b2) +{Big abb;add(b1.fn,b2.fn,abb.fn);return abb;} + +Big operator-(const Big& b, int i) +{Big mbi; decr(b.fn, i, mbi.fn); return mbi;} +Big operator-(int i, const Big& b) +{Big mib;decr(b.fn, i, mib.fn);negify(mib.fn,mib.fn);return mib;} +Big operator-(const Big& b1, const Big& b2) +{Big mbb; subtract(b1.fn,b2.fn,mbb.fn); return mbb;} + +Big operator*(const Big& b, int i) +{Big xbi; premult(b.fn, i, xbi.fn); return xbi;} +Big operator*(int i, const Big& b) +{Big xib; premult(b.fn, i, xib.fn); return xib;} +Big operator*(const Big& b1, const Big& b2) +{Big xbb; multiply(b1.fn,b2.fn,xbb.fn); return xbb;} + +#ifndef MR_STATIC +BOOL fmth(int n,const Big& b1,const Big& b2,Big& f) +{ +#ifdef MR_KCM + return kcm_top(n,b1.fn,b2.fn,f.fn); /* see mrkcm.tpl */ +#else + return fastmultop(n,b1.fn,b2.fn,f.fn); /* see mrfast.c */ +#endif +} +#endif + +Big operator/(const Big& b, int i) +{Big dbi; subdiv(b.fn, i, dbi.fn); return dbi;} +Big operator/(const Big& b1, const Big& b2) +{Big dbb; copy(b1.fn,dbb.fn); divide(dbb.fn,b2.fn,dbb.fn); return dbb;} + +int operator%(const Big& b, int i) +{Big mdbi; return(subdiv(b.fn,i, mdbi.fn));} +Big operator%(const Big& b1, const Big& b2) +{Big mdbb;copy(b1.fn,mdbb.fn);divide(mdbb.fn,b2.fn,b2.fn);return mdbb;} + +Big operator<<(const Big& b, int i) +{Big ms; sftbit(b.fn,i,ms.fn); return ms;} + +Big operator>>(const Big& b, int i) +{Big ms; sftbit(b.fn,-i,ms.fn); return ms;} + +#ifndef MR_FP +Big land(const Big& x,const Big& y) +{Big z; mr_and(x.fn,y.fn,z.fn); return z;} +Big lxor(const Big& x,const Big& y) +{Big z; mr_xor(x.fn,y.fn,z.fn); return z;} + +#endif + +Big from_binary(int len,char *ptr) +{Big z; bytes_to_big(len,ptr,z.fn); return z;} + +//int to_binary(const Big& b,int max,char *ptr,BOOL justify) +//{ return big_to_bytes(max,b.fn,ptr,justify);} + +Big modmult(const Big& b1,const Big& b2,const Big& m) +{Big z; mad(b1.fn,b2.fn,b2.fn,m.fn,m.fn,z.fn); return z;} +Big mad(const Big& b1,const Big& b2,const Big& b3,const Big& m,Big &r) +{Big q; mad(b1.fn,b2.fn,b3.fn,m.fn,q.fn,r.fn); return q;} + +Big norm(const Big& b) {Big z; normalise(b.fn,z.fn); return z;} +Big sqrt(const Big& b) {Big z; nroot(b.fn, 2, z.fn); return z;} +Big abs(const Big& b) {Big z; absol(b.fn,z.fn); return z;} +Big root(const Big &b,int n) {Big z; nroot(b.fn, n, z.fn); return z;} +Big gcd(const Big& b1, const Big& b2){Big z;egcd(b1.fn,b2.fn,z.fn);return z;} +Big pow(const Big& b,int n) +{Big z;int x; +if (mr_abs(x=size(b.fn))fn,z.fn); +// else lucas(b1.fn,b2.fn,b3.fn,z.fn,z.fn); +//return z;} + + +Big inverse(const Big& b1, const Big& b2) +{Big z; xgcd(b1.fn,b2.fn,z.fn,z.fn,z.fn);return z;} + +Big moddiv(const Big& b1,const Big& b2,const Big& m) +{Big z; xgcd(b2.fn,m.fn,z.fn,z.fn,z.fn); mad(b1.fn,z.fn,z.fn,m.fn,m.fn,z.fn); return z;} + +#ifndef MR_NO_RAND + +Big rand(const Big& b) {Big z; bigrand(b.fn,z.fn); return z;} +Big rand(int n,int b) {Big z; bigdig(n,b,z.fn); return z;} +Big randbits(int n) {Big z; bigbits(n,z.fn); return z;} + +Big strong_rand(csprng *rng,const Big& b) {Big z; strong_bigrand(rng,b.fn,z.fn); return z;} +Big strong_rand(csprng *rng,int n,int b) {Big z; strong_bigdig(rng,n,b,z.fn); return z;} + +#endif + +Big nextprime(const Big& b) {Big z; nxprime(b.fn,z.fn); return z;} +Big nextsafeprime(int type,int subset,const Big& b) {Big z; +nxsafeprime(type,subset,b.fn,z.fn); return z; } +Big trial_divide(const Big& b) {Big r; trial_division(b.fn,r.fn); return r;} +BOOL small_factors(const Big& b) +{if (trial_division(b.fn,b.fn)==0) return TRUE; return FALSE;} +BOOL perfect_power(const Big& b) +{int i; + miracl *mip=get_mip(); + if (size(b.fn)<4) return FALSE; + for (i=2;;i++) + { + if (nroot(b.fn,i,mip->w8)) return TRUE; + if (size(mip->w8)<=1) break; + } + return FALSE; +} + + +Big sqrt(const Big& x,const Big& p) {Big z; sqroot(x.fn,p.fn,z.fn); return z;} + +void modulo(const Big& n) {prepare_monty(n.fn);} +Big get_modulus() +{Big m; +miracl *mip=get_mip(); +copy(mip->modulus,m.fn); +return m;} + + +Big nres(const Big& b) {Big z; nres(b.fn,z.fn); return z;} +Big redc(const Big& b) {Big z; redc(b.fn,z.fn);return z;} + +/* + +Big nres_negate(const Big& b) +{ Big z; nres_negate(b.fn,z.fn); return z;} +Big nres_modmult(const Big& b1,const Big& b2) +{ Big z; nres_modmult(b1.fn,b2.fn,z.fn); return z;} +Big nres_premult(const Big& b1,int i) +{ Big z; nres_premult(b1.fn,i,z.fn); return z;} + +Big nres_modadd(const Big& b1,const Big& b2) +{ Big z; nres_modadd(b1.fn,b2.fn,z.fn); return z;} +Big nres_modsub(const Big& b1,const Big& b2) +{ Big z; nres_modsub(b1.fn,b2.fn,z.fn); return z;} +Big nres_moddiv(const Big& b1,const Big& b2) +{ Big z; nres_moddiv(b1.fn,b2.fn,z.fn); return z;} +Big nres_pow(const Big& b1,const Big& b2) +{ Big z; nres_powmod(b1.fn,b2.fn,z.fn); return z;} + + + + +Big nres_pow2(const Big& b1,const Big& b2,const Big& b3,const Big& b4) +{ Big z; nres_powmod2(b1.fn,b2.fn,b3.fn,b4.fn,z.fn); return z;} + + +Big nres_pown(int n,Big *a,Big *b) +{ + Big z; + int i; + big *x=(big *)mr_alloc(n,sizeof(big)); + big *y=(big *)mr_alloc(n,sizeof(big)); + for (i=0;ifn,z.fn); + else nres_lucas(b1.fn,b2.fn,z.fn,z.fn); + return z;} + +Big nres_sqrt(const Big& b) +{ Big z; nres_sqroot(b.fn,z.fn); return z;} +*/ + +Big shift(const Big&b,int n) +{ + Big r; + mr_shift(b.fn,n,r.fn); + return r; +} + +int length(const Big& b) +{ + return mr_lent(b.fn); +} + +/* Note that when inputting text as a number the CR is NOT * + * included in the text, unlike C I/O which does include CR. */ + +#ifndef MR_NO_STANDARD_IO +#ifndef MR_SIMPLE_IO + +istream& operator>>(istream& s, Big& x) +{ + miracl *mip=get_mip(); +#ifndef MR_SIMPLE_BASE + + if (mip->IOBASE>60) + { + s.sync(); + s.getline(mip->IOBUFF,mip->IOBSIZ); + } + else +#endif + s >> mip->IOBUFF; + if (s.eof() || s.bad()) + { + zero(x.fn); + return s; + } +#ifdef MR_SIMPLE_BASE + instr(x.fn,mip->IOBUFF); +#else + cinstr(x.fn,mip->IOBUFF); +#endif + return s; +} + +#endif +#endif + +// Note new parameter of window_size. Default to 5, but reduce to 4 (or even 3) to save RAM + +//int window(const Big& x,int i,int *nbs,int *nzs,int window_size) +//{ + /* returns sliding window value, max. of 5 bits, * + * starting at i-th bit of big x. nbs is number of bits * + * processed, nzs is the number of additional trailing * + * zeros detected. Returns valid bit pattern 1x..x1 with * + * no two adjacent 0's. So 10101 will return 21 with * + * nbs=5, nzs=0. 11001 will return 3, with nbs=2, nzs=2, * + * having stopped after the first 11.. */ + +// return mr_window(x.fn,i,nbs,nzs,window_size); +//} + +//int naf_window(const Big& x,const Big& x3,int i,int *nbs,int *nzs,int store) +//{ + /* returns sliding window value, max of 5 bits * + * starting at i-th bit of x. nbs is number of bits * + * processed. nzs is number of additional trailing * + * zeros detected. x and x3 (which is 3*x) are * + * combined to produce the NAF (non-adjacent form) * + * So if x=11011(27) and x3 is 1010001, the LSB is * + * ignored and the value 100T0T (32-4-1=27) processed, * + * where T is -1. Note x.P = (3x-x)/2.P. This value will * + * return +7, with nbs=4 and nzs=1, having stopped after * + * the first 4 bits. Note in an NAF non-zero elements * + * are never side by side, so 10T10T won't happen */ + + +// return mr_naf_window(x.fn,x3.fn,i,nbs,nzs,store); +//} + +#ifndef MR_NO_ECC_MULTIADD +void jsf(const Big& k0,const Big& k1,Big& u0p,Big& u0m,Big& u1p,Big& u1m) +{ + mr_jsf(k0.fn,k1.fn,u0p.fn,u0m.fn,u1p.fn,u1m.fn); +} +#endif + +#ifndef MR_NO_STANDARD_IO + +ostream& operator<<(ostream& s, const Big& x) +{ + miracl *mip=get_mip(); +#if defined(MR_SIMPLE_BASE) || defined(MR_SIMPLE_IO) + otstr(x.fn,mip->IOBUFF); +#else + cotstr(x.fn,mip->IOBUFF); +#endif + s << mip->IOBUFF; + return s; +} + +#ifdef MR_FLASH + +ostream& otfloat(ostream& s,const Big& m,int e) +{ + miracl *mip=get_mip(); + copy(m.fn,mip->w5); + + convert(1,mip->w6); + copy(mip->w6,mip->w9); + mr_shift(mip->w6,mr_lent(m.fn),mip->w6); + mround(mip->w5,mip->w6,mip->w8); + if (e>=-2 && e<=2) + { + if (e>0) + { + mr_shift(mip->w9,e,mip->w9); + fmul(mip->w8,mip->w9,mip->w8); + } + else + { + mr_shift(mip->w9,-e,mip->w9); + fdiv(mip->w8,mip->w9,mip->w8); + } +#if defined(MR_SIMPLE_BASE) || defined(MR_SIMPLE_IO) + otstr(mip->w8,mip->IOBUFF); +#else + cotstr(mip->w8,mip->IOBUFF); +#endif + s << mip->IOBUFF; + } + else + { +#if defined(MR_SIMPLE_BASE) || defined(MR_SIMPLE_IO) + otstr(mip->w8,mip->IOBUFF); +#else + cotstr(mip->w8,mip->IOBUFF); +#endif + s << mip->IOBUFF; + s << ".2^" << e*MIRACL; + } + + return s; +} + +#endif + +#endif + +char* operator<<(char *s,const Big& x) +{ + miracl *mip=get_mip(); + int i,n; +#if defined(MR_SIMPLE_BASE) || defined(MR_SIMPLE_IO) + n=otstr(x.fn,mip->IOBUFF); +#else + n=cotstr(x.fn,mip->IOBUFF); +#endif + if (s!=mip->IOBUFF) for (i=0;i<=n;i++) s[i]=mip->IOBUFF[i]; + return s; +} + +void ecurve(const Big& a,const Big& b,const Big& p,int t) +{ + ecurve_init(a.fn,b.fn,p.fn,t); +} + +BOOL ecurve2(int m,int a,int b,int c,const Big& a2,const Big& a6,BOOL check,int t) +{ return ecurve2_init(m,a,b,c,a2.fn,a6.fn,check,t);} + diff --git a/miracl/source/blackfin.mcs b/miracl/source/blackfin.mcs new file mode 100644 index 0000000..659c954 --- /dev/null +++ b/miracl/source/blackfin.mcs @@ -0,0 +1,358 @@ +; MCS file for VisualDSP++ compiler +; 16-bit MIRACL +; +; Sorry about all the %'s! Each % must be input here as %% +; Triple register is A0 +; MUL_START. +; Initialise Triple register to 0 +; See makemcs.txt for more information about this file +; +; It would be worth experimenting with generated code to see where parallel issue of instructions +; might be exploited +; +MACRO PMUL_START + asm ( + "R1=R1-R1;\n" + "R2=R2-R2;\n" +ENDM +MACRO PMUL + "R3=W[%%0+2*%d] (Z);\n" + "R3=%%3.L*R3.L (FU);\n" + "R3=R1+R3 (NS);\n" + "R1=R3>>16;\n" + "W[%%1+2*%d]=R2;\n" + "W[%%2+2*%d]=R3;\n" +ENDM +MACRO PMUL_END + "R3=%%3.L*R1.L (FU);\n" + "W[%%1]=R3;\n" + "R2=R3>>16;\n" + "W[%%1+2]=R2;\n" + : + :"a"(a),"a"(b),"a"(c),"d"(sn) + :"R1","R2","R3","A0","A1","memory" + ); +ENDM +MACRO MUL_START + asm ( + "A1=A0=0;\n" +ENDM +; +; STEP macro. Calculates a double-register partial product +; and adds it to the triple register total +; Parameters 1 & 2: Indices i and j for partial product multipliers a[i] +; and b[j] +MACRO STEP + "R3=W[%%0+2*%d] (Z);\n" + "R4=W[%%1+2*%d] (Z);\n" + "A0+=R3.L*R4.L (FU);\n" +ENDM +; +; LAST +; +MACRO LAST + "R3=W[%%0+2*%d] (Z);\n" + "R4=W[%%1+2*%d] (Z);\n" + "A0+=R3.L*R4.L (FU);\n" +ENDM +; +; MFIN macro. Finish column calculation. Store Sum for this column +; and get Carry for next +; Parameter 1: Index k for Column Sum c[k] +MACRO MFIN + "R4=A0.W;\n" + "W[%%2+2*%d]=R4;\n" + "A0=A0>>16;\n" +ENDM +; +; MUL_END +; Parameter 1: Index for final carry c[.] +MACRO MUL_END + "R4=A0.W;\n" + "W[%%2+2*%d]=R4;\n" + : + :"a"(a),"a"(b),"a"(c) + :"R3","R4","A0","A1","memory" + ); +ENDM +; +; SQR_START +; +MACRO SQR_START + asm ( + "A0=0;\n" +ENDM +; +; DSTEP +; +MACRO DSTEP + "R3=W[%%0+2*%d] (Z);\n" + "R4=W[%%0+2*%d] (Z);\n" + "A0+=R3.L*R4.L (FU);\n" + "A0+=R3.L*R4.L (FU);\n" +ENDM +; +; SELF +; +MACRO SELF + "R4=W[%%0+2*%d] (Z);\n" + "A0+=R4.L*R4.L (FU);\n" +ENDM +; +; SFIN +; +MACRO SFIN + "R4=A0.W;\n" + "W[%%1+2*%d]=R4;\n" + "A0=A0>>16;\n" +ENDM +; +; SQR_END +; +MACRO SQR_END + "R4=A0.W;\n" + "W[%%1+2*%d]=R4;\n" + : + :"a"(a),"a"(c) + :"R3","R4","A0","memory" + ); +ENDM +; +; REDC_START +; +MACRO REDC_START + asm ( + "A1=A0=0;\n" + "R4=W[%%0] (Z);\n" + "A0.L=R4.L;\n" +ENDM +; +; RFINU macro +; +MACRO RFINU + "R4=A0.W;\n" + "R3=R4.L*%%2.L (FU);\n" + "W[%%0+2*%d]=R3;\n" + "R4=W[%%1] (Z);\n" + "A0+=R3.L*R4.L (FU);\n" + "A0=A0>>16;\n" + "R3=W[%%0+2*%d+2] (Z);\n" + "A1.L=R3.L ;\n" + "A0+=A1 ;\n" +ENDM +; +; RFIND macro +; +MACRO RFIND + "R4=A0.W;\n" + "W[%%0+2*%d]=R4;\n" + "A0=A0>>16;\n" + "R3=W[%%0+2*%d+2] (Z);\n" + "A1.L=R3.L ;\n" + "A0+=A1 ;\n" +ENDM +; +; REDC_END macro +; +MACRO REDC_END + "R4=A0.W;\n" + "W[%%0+2*%d]=R4;\n" + "A0=A0>>16;\n" + "R4=A0.W;\n" + "W[%%0+2*%d+2]=R4;\n" + : + :"a"(a),"a"(b),"d"(ndash) + :"R3","R4","A0","A1","memory" + ); +ENDM +; +; ADD_START macro +; +MACRO ADD_START + asm ( + "R3=W[%%1] (Z);\n" + "R4=W[%%2] (Z);\n" + "R3=R4+R3;\n" + "W[%%3]=R3;\n" + "%%0=R3>>16;\n" +ENDM +; +; ADD macro - c[.]=a[.]+b[.] +; +MACRO ADD + "R3=W[%%1+2*%d] (Z);\n" + "R4=W[%%2+2*%d] (Z);\n" + "R3=R4+R3;\n" + "R3=%%0+R3;\n" + "W[%%3+2*%d]=R3;\n" + "%%0=R3>>16;\n" +ENDM +; +; ADD_END macro. +; +MACRO ADD_END + :"=d"(carry) + :"a"(a),"a"(b),"a"(c) + :"R3","R4","memory" + ); +ENDM +; +; INC_START macro. Do first one. +; +MACRO INC_START + asm ( + "R3=W[%%1] (Z);\n" + "R4=W[%%2] (Z);\n" + "R3=R4+R3;\n" + "W[%%1]=R3;\n" + "%%0=R3>>16;\n" +ENDM +; +; INC macro a[.]+=b[.] +; +MACRO INC + "R3=W[%%1+2*%d] (Z);\n" + "R4=W[%%2+2*%d] (Z);\n" + "R3=R4+R3;\n" + "R3=%%0+R3;\n" + "W[%%1+2*%d]=R3;\n" + "%%0=R3>>16;\n" +ENDM +MACRO INC_END + :"=d"(carry) + :"a"(a),"a"(b) + :"R3","R4","memory" + ); +ENDM +MACRO SUB_START + asm ( + "R3=W[%%1] (Z);\n" + "R4=W[%%2] (Z);\n" + "R3=R3-R4;\n" + "W[%%3]=R3;\n" + "%%0=R3>>>16;\n" +ENDM +; +; SUB macro - c[.]=a[.]-b[.] +; +MACRO SUB + "R3=W[%%1+2*%d] (Z);\n" + "R4=W[%%2+2*%d] (Z);\n" + "R3=R3-R4;\n" + "R3=%%0+R3;\n" + "W[%%3+2*%d]=R3;\n" + "%%0=R3>>>16;\n" +ENDM +MACRO SUB_END + "%%0=-%%0;\n" + :"=d"(carry) + :"a"(a),"a"(b),"a"(c) + :"R3","R4","memory" + ); +ENDM +; +; DEC_START macro +; +MACRO DEC_START + asm ( + "R3=W[%%1] (Z);\n" + "R4=W[%%2] (Z);\n" + "R3=R3-R4;\n" + "W[%%1]=R3;\n" + "%%0=R3>>>16;\n" +ENDM +; +; DEC macro a[.]-=b[.] +; +MACRO DEC + "R3=W[%%1+2*%d] (Z);\n" + "R4=W[%%2+2*%d] (Z);\n" + "R3=R3-R4;\n" + "R3=%%0+R3;\n" + "W[%%1+2*%d]=R3;\n" + "%%0=R3>>>16;\n" +ENDM +; +; DEC_END macro +; +MACRO DEC_END + "%%0=-%%0;\n" + :"=d"(carry) + :"a"(a),"a"(b) + :"R3","R4","memory" + ); +ENDM +; +; KADD_START macro +; +MACRO KADD_START + asm ( + "k%d:\n" +ENDM +; +; KASL macro +; +MACRO KASL + "%%4+= -1;\n" + "CC=%%4;\n" + "IF !CC JUMP k%d;\n" + "%%1+=2*%d;\n" + "%%2+=2*%d;\n" + "%%3+=2*%d;\n" + "JUMP k%d;\n" + "k%d:\n" +ENDM +; +; KADD_END macro +; +MACRO KADD_END + :"=d"(carry) + :"a"(a),"a"(b),"a"(c),"d"(n) + :"R3","R4","memory" + ); +ENDM +; +; KINC_START macro. Zero carry flag. +; +MACRO KINC_START + asm ( + "k%d:\n" +ENDM +; +; KIDL macro +; +MACRO KIDL + "%%3+= -1;\n" + "CC=%%3;\n" + "IF !CC JUMP k%d;\n" + "%%1+=2*%d;\n" + "%%2+=2*%d;\n" + "JUMP k%d;\n" + "k%d:\n" +ENDM +; +; KINC_END macro +; +MACRO KINC_END + :"=d"(carry) + :"a"(a),"a"(b),"d"(n) + :"R3","R4","memory" + ); +ENDM +; +; KDEC_START macro +; +MACRO KDEC_START + asm ( + "k%d:\n" +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + "%%0=-%%0;\n" + :"=d"(carry) + :"a"(a),"a"(b),"d"(n) + :"R3","R4","memory" + ); +ENDM diff --git a/miracl/source/bmark.c b/miracl/source/bmark.c new file mode 100644 index 0000000..5e19864 --- /dev/null +++ b/miracl/source/bmark.c @@ -0,0 +1,1125 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * Benchmarking program for PK implementations + * + */ + +#include +#include +#include +#include "miracl.h" + +/* define minimum duration of each timing, and min. number of iterations */ + +#define MIN_TIME 10.0 +#define MIN_ITERS 20 + +/* define fixed precomputation window size */ + +#define WINDOW 8 + +/* random "safe" primes - (p-1)/2 is also prime */ + +char p512[]="A89BmxRFLAnMTGV1EofBF3t9vxHwLw3upSiJQqGrSSJanNwAWm4qeIpR0QZos81Cb0T3GSB8Vvioo2ShdHeocZl"; +char p1024[]="33pn5XYfRZ6oa1SgeSZ0gLXbIHYKsAL2vf2hMPp4BShBUUwVqJSaZMHBtYRr2C8CtD2ql3cKco8tsbol9KiiW0kmgYdmX2OYuDirwVHBXU6iarsuWLsFI8f9IcXF5mQUhhIfNL1UgB9iOopI4DZJdaAkweMrr0L7H6DTcJCv4uOG8l"; +char p2048[]="9JhODtckdgHoisG3BF7icLO1W2kQN8uERdD45ta8ECK2pSl74xmjtptZhoFRXLCn8SHJtmwXTuf6aUbUUGsT6dE8GMWSkdg3qN4owcJE6wuCUiKKDOrsUEaFA6GCaSoHrHd6upEOTFJrSt5JZvvPUmZExbgTtVkZaM3EHVO5hhmaOglEXNmWbQlSZR57EPH4VS5nYPHsj3YEqtQjBxOg509VY3Efa3WCBXSILEksrBCdxBFeboPQ2ImO8gt52UX68ClTq4hUO7HltCJ8DEXT0QitGp5G39H3EGlBM7a1Pto1XRctShgDCJkKtedRvCTHJ81IaLUM2QRgVvY2oAUfU6DpqPl"; + + +/* 160-bit Elliptic Curve A= -3 (1,y) is of prime order r wrt prime p */ + +char b160[]="547961736808018748879088091015409822321903727720"; +char y160[]="1184021062507719516935416374276431034553065993786"; +char p160[]="1243254415344564576487568858887587143562341624873"; +char r160[]="1243254415344564576487570064860738948886682236669"; + + +/* 192-bit Elliptic Curve A= -3 (1,y) is of prime order r wrt prime p */ + +char b192[]="4061049254666112630970447728594959377821841236338949398359"; +char y192[]="939373580274738592696031201994651073677369517020051213856"; +char p192[]="4361274637164371634176431764172114141371368173651736587859"; +char r192[]="4361274637164371634176431764042976768701814568420333347189"; + +/* 224-bit Elliptic Curve A= -3 (1,y) is of prime order r wrt prime p */ + +char b224[]="17383927112623192126321700675122043803151281370446907580591543997888"; +char y224[]="6566202929975094781252846334642707436688198986599754639429350077046"; +char p224[]="26237462376427386428736423786423764364625346524653462546544347644653"; +char r224[]="26237462376427386428736423786423773752689811507809031319417547459991"; + +/* 256-bit Elliptic Curve A= -3 (1,y) is of prime order r wrt prime p */ + +char b256[]="25389140340672155341527372976612393184553582461816899055687141548002290977046"; +char y256[]="51289739734510562976895380525256763300476168821636300126346201758371757118206"; +char p256[]="115324781748134865946503563657643838352352623747656242345890742746828256867467"; +char r256[]="115324781748134865946503563657643838352221626521810006206950260876359658535911"; + +#ifndef MR_FP + +/* Elliptic Curve wrt GF(2^163). This is NIST standard Curve */ + +int A163=1; +char B163[]="20A601907B8C953CA1481EB10512F78744A3205FD"; +char x163[]="3F0EBA16286A2D57EA0991168D4994637E8343E36"; +char y163[]="D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"; +int m163=163; +int a163=7; +int b163=6; +int c163=3; +char r163[]="5846006549323611672814742442876390689256843201587"; +int cf163=2; + +/* Elliptic Curve wrt GF(2^163). NIST Koblitz Curve */ + +int KA163=1; +char KB163[]="1"; +char Kx163[]="396C30B475EF87A2B37CA911D272DE90E109CA80F"; +char Ky163[]="3947D0E4C8BB41DC3BABB142D2923A253D6E76391"; + +/* Elliptic Curve wrt GF(2^233). This is NIST standard Curve */ + +int A233=1; +char B233[]="66647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD"; +char x233[]="FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"; +char y233[]="1006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052"; +int m233=233; +int a233=74; +int b233=0; +int c233=0; +char r233[]="6901746346790563787434755862277025555839812737345013555379383634485463"; +int cf233=2; + +/* Elliptic Curve wrt GF(2^233). This is NIST Koblitz Curve */ + +int KA233=0; +char KB233[]="1"; +char Kx233[]="17232ba853a7e731af129f22ff4149563a419c26bf50a4c9d6eefad6126"; +char Ky233[]="1db537dece819b7f70f555a67c427a8cd9bf18aeb9b56e0c11056fae6a3"; + +/* Elliptic Curve wrt GF(2^283). This is NIST standard Curve */ + +int A283=1; +char B283[]="27B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5"; +char x283[]="5F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"; +char y283[]="3676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4"; +int m283=283; +int a283=12;/* 119; these are faster.. */ +int b283=7; /* 97; */ +int c283=5; /* 93; */ +char r283[]="7770675568902916283677847627294075626569625924376904889109196526770044277787378692871"; +int cf283=2; + +/* Elliptic Curve wrt GF(2^283). This is NIST Koblitz Curve */ + +int KA283=0; +char KB283[]="1"; +char Kx283[]="503213f78ca44883f1a3b8162f188e553cd265f23c1567a16876913b0c2ac2458492836"; +char Ky283[]="1ccda380f1c9e318d90f95d07e5426fe87e45c0e8184698e45962364e34116177dd2259"; + +/* Elliptic Curve wrt GF(2^571). This is NIST standard Curve */ + +int A571=1; +char B571[]="02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A"; +char x571[]="0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"; +char y571[]="037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B"; +int m571=571; +int a571=10; +int b571=5; +int c571=2; +int cf571=2; + +/* Elliptic Curve wrt GF(2^571). This is NIST Koblitz Curve */ + +int KA571=0; +char KB571[]="1"; +char Kx571[]="026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"; +char Ky571[]="0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3"; + +#endif + +void primemod(int bits,big p) +{ + do { + printf("%d bit prime.....\n",bits); + bigbits(bits,p); + nxprime(p,p); + } while (logb2(p)!=bits); +} + +double powers(int gb,int eb,big p) +{ + int iterations=0; + big g,e,w; + clock_t start; + double elapsed; + char *mem; + + mem=(char *)memalloc(3); + g=mirvar_mem(mem,0); + e=mirvar_mem(mem,1); + w=mirvar_mem(mem,2); + + bigbits(gb,g); + bigbits(eb,e); + start=clock(); + + do { + powmod(g,e,p,w); + iterations++; + elapsed=(clock()-start)/(double)CLOCKS_PER_SEC; + } while (elapsedIOBASE=60; + + time(&seed); + irand((long)seed); + + printf("MIRACL - %d bit version\n",MIRACL); +#ifdef MR_LITTLE_ENDIAN + printf("Little Endian processor\n"); +#endif +#ifdef MR_BIG_ENDIAN + printf("Big Endian processor\n"); +#endif +#ifdef MR_NOASM + printf("C-Only Version of MIRACL\n"); +#else + printf("Using some assembly language\n"); +#endif +#ifdef MR_STRIPPED_DOWN + printf("Stripped down version of MIRACL - no error messages\n"); +#endif +#ifdef MR_KCM + k=MR_KCM*MIRACL; + printf("Using KCM method \n"); + printf("Optimized for %d, %d, %d, %d...etc. bit moduli\n",k,k*2,k*4,k*8); +#endif +#ifdef MR_COMBA + k=MR_COMBA*MIRACL; + printf("Using COMBA method \n"); + printf("Optimized for %d bit moduli\n",k); +#endif +#ifdef MR_PENTIUM + printf("Floating-point co-processor arithmetic used for Pentium\n"); +#endif +#ifndef MR_KCM +#ifndef MR_COMBA +#ifndef MR_PENTIUM + printf("No special optimizations\n"); +#endif +#endif +#endif + printf("Precomputation uses fixed Window size = %d\n",WINDOW); + printf("So %d values are precomputed and stored\n",(1<IOBASE=10; + + printf("\n160 bit GF(p) Elliptic Curve....\n"); + k=160; + cinstr(p,p160); + cinstr(b,b160); + cinstr(y,y160); + + ecurve_init(a,b,p,MR_PROJECTIVE); + g=epoint_init(); + if (!epoint_set(x,y,0,g)) + { + printf("This is not a point on the curve!\n"); + exit(0); + } + + tr1=mults(k,g); + td=mult_double(k,g); + tp=mult_precomp(k,x,y,a,b,p); + + printf("\n"); + printf("%4d bit ECDH :-\n",k); + printf(" offline, no precomputation %8.2lf ms \n",tr1); + printf(" offline, w. precomputation %8.2lf ms \n",tp); + printf(" online %8.2lf ms \n",tr1); + printf("%4d bit ECDSA :-\n",k); + printf(" signature no precomputation %8.2lf ms \n",tr1); + printf(" signature w. precomputation %8.2lf ms \n",tp); + printf(" verification %8.2lf ms \n",td); + + printf("\n192 bit GF(p) Elliptic Curve....\n"); + k=192; + cinstr(p,p192); + cinstr(b,b192); + cinstr(y,y192); + + ecurve_init(a,b,p,MR_PROJECTIVE); + g=epoint_init(); + if (!epoint_set(x,y,0,g)) + { + printf("This is not a point on the curve!\n"); + exit(0); + } + + + tr1=mults(k,g); + td=mult_double(k,g); + tp=mult_precomp(k,x,y,a,b,p); + + printf("\n"); + printf("%4d bit ECDH :-\n",k); + printf(" offline, no precomputation %8.2lf ms \n",tr1); + printf(" offline, w. precomputation %8.2lf ms \n",tp); + printf(" online %8.2lf ms \n",tr1); + printf("%4d bit ECDSA :-\n",k); + printf(" signature no precomputation %8.2lf ms \n",tr1); + printf(" signature w. precomputation %8.2lf ms \n",tp); + printf(" verification %8.2lf ms \n",td); + + printf("\n224 bit GF(p) Elliptic Curve....\n"); + k=224; + cinstr(p,p224); + cinstr(b,b224); + cinstr(y,y224); + + ecurve_init(a,b,p,MR_PROJECTIVE); + g=epoint_init(); + if (!epoint_set(x,y,0,g)) + { + printf("This is not a point on the curve!\n"); + exit(0); + } + + tr1=mults(k,g); + td=mult_double(k,g); + tp=mult_precomp(k,x,y,a,b,p); + + printf("\n"); + printf("%4d bit ECDH :-\n",k); + printf(" offline, no precomputation %8.2lf ms \n",tr1); + printf(" offline, w. precomputation %8.2lf ms \n",tp); + printf(" online %8.2lf ms \n",tr1); + printf("%4d bit ECDSA :-\n",k); + printf(" signature no precomputation %8.2lf ms \n",tr1); + printf(" signature w. precomputation %8.2lf ms \n",tp); + printf(" verification %8.2lf ms \n",td); + + printf("\n256 bit GF(p) Elliptic Curve....\n"); + k=256; + cinstr(p,p256); + cinstr(b,b256); + cinstr(y,y256); + + ecurve_init(a,b,p,MR_PROJECTIVE); + g=epoint_init(); + if (!epoint_set(x,y,0,g)) + { + printf("This is not a point on the curve!\n"); + exit(0); + } + + tr1=mults(k,g); + td=mult_double(k,g); + tp=mult_precomp(k,x,y,a,b,p); + + printf("\n"); + printf("%4d bit ECDH :-\n",k); + printf(" offline, no precomputation %8.2lf ms \n",tr1); + printf(" offline, w. precomputation %8.2lf ms \n",tp); + printf(" online %8.2lf ms \n",tr1); + printf("%4d bit ECDSA :-\n",k); + printf(" signature no precomputation %8.2lf ms \n",tr1); + printf(" signature w. precomputation %8.2lf ms \n",tp); + printf(" verification %8.2lf ms \n",td); + +#ifndef MR_FP + + printf("\n163 bit GF(2^m) Elliptic Curve....\n"); + k=163; + mip->IOBASE=16; + cinstr(b,B163); + cinstr(x,x163); + cinstr(y,y163); + mip->IOBASE=10; + convert(A163,A2); + ecurve2_init(m163,a163,b163,c163,A2,b,FALSE,MR_PROJECTIVE); + g=epoint_init(); + if (!epoint2_set(x,y,0,g)) + { + printf("This is not a point on the curve!\n"); + exit(0); + } + + tr1=mults2(k,g); + td=mult2_double(k,g); + tp=mult2_precomp(k,x,y,A2,b,m163,a163,b163,c163); + + printf("\n"); + printf("%4d bit ECDH :-\n",k); + printf(" offline, no precomputation %8.2lf ms \n",tr1); + printf(" offline, w. precomputation %8.2lf ms \n",tp); + printf(" online %8.2lf ms \n",tr1); + printf("%4d bit ECDSA :-\n",k); + printf(" signature no precomputation %8.2lf ms \n",tr1); + printf(" signature w. precomputation %8.2lf ms \n",tp); + printf(" verification %8.2lf ms \n",td); + + printf("\n163 bit GF(2^m) Koblitz Elliptic Curve....\n"); + k=163; + mip->IOBASE=16; + cinstr(b,KB163); + cinstr(x,Kx163); + cinstr(y,Ky163); + mip->IOBASE=10; + convert(KA163,A2); + ecurve2_init(m163,a163,b163,c163,A2,b,FALSE,MR_PROJECTIVE); + g=epoint_init(); + if (!epoint2_set(x,y,0,g)) + { + printf("This is not a point on the curve!\n"); + exit(0); + } + + tr1=mults2(k,g); + td=mult2_double(k,g); + tp=mult2_precomp(k,x,y,A2,b,m163,a163,b163,c163); + + printf("\n"); + printf("%4d bit ECDH :-\n",k); + printf(" offline, no precomputation %8.2lf ms \n",tr1); + printf(" offline, w. precomputation %8.2lf ms \n",tp); + printf(" online %8.2lf ms \n",tr1); + printf("%4d bit ECDSA :-\n",k); + printf(" signature no precomputation %8.2lf ms \n",tr1); + printf(" signature w. precomputation %8.2lf ms \n",tp); + printf(" verification %8.2lf ms \n",td); + + printf("\n233 bit GF(2^m) Elliptic Curve....\n"); + k=233; + mip->IOBASE=16; + cinstr(b,B233); + cinstr(x,x233); + cinstr(y,y233); + mip->IOBASE=10; + convert(A233,A2); + ecurve2_init(m233,a233,b233,c233,A2,b,FALSE,MR_PROJECTIVE); + g=epoint_init(); + if (!epoint2_set(x,y,0,g)) + { + printf("This is not a point on the curve!\n"); + exit(0); + } + + tr1=mults2(k,g); + td=mult2_double(k,g); + tp=mult2_precomp(k,x,y,A2,b,m233,a233,b233,c233); + + printf("\n"); + printf("%4d bit ECDH :-\n",k); + printf(" offline, no precomputation %8.2lf ms \n",tr1); + printf(" offline, w. precomputation %8.2lf ms \n",tp); + printf(" online %8.2lf ms \n",tr1); + printf("%4d bit ECDSA :-\n",k); + printf(" signature no precomputation %8.2lf ms \n",tr1); + printf(" signature w. precomputation %8.2lf ms \n",tp); + printf(" verification %8.2lf ms \n",td); + + printf("\n233 bit GF(2^m) Koblitz Elliptic Curve....\n"); + k=233; + mip->IOBASE=16; + cinstr(b,KB233); + cinstr(x,Kx233); + cinstr(y,Ky233); + mip->IOBASE=10; + convert(KA233,A2); + ecurve2_init(m233,a233,b233,c233,A2,b,FALSE,MR_PROJECTIVE); + g=epoint_init(); + if (!epoint2_set(x,y,0,g)) + { + printf("This is not a point on the curve!\n"); + exit(0); + } + + tr1=mults2(k,g); + td=mult2_double(k,g); + tp=mult2_precomp(k,x,y,A2,b,m233,a233,b233,c233); + + printf("\n"); + printf("%4d bit ECDH :-\n",k); + printf(" offline, no precomputation %8.2lf ms \n",tr1); + printf(" offline, w. precomputation %8.2lf ms \n",tp); + printf(" online %8.2lf ms \n",tr1); + printf("%4d bit ECDSA :-\n",k); + printf(" signature no precomputation %8.2lf ms \n",tr1); + printf(" signature w. precomputation %8.2lf ms \n",tp); + printf(" verification %8.2lf ms \n",td); + + + printf("\n283 bit GF(2^m) Elliptic Curve....\n"); + k=283; + mip->IOBASE=16; + cinstr(b,B283); + cinstr(x,x283); + cinstr(y,y283); + mip->IOBASE=10; + + convert(A283,A2); + ecurve2_init(m283,a283,b283,c283,A2,b,FALSE,MR_PROJECTIVE); + g=epoint_init(); + if (!epoint2_set(x,y,0,g)) + { + printf("This is not a point on the curve!\n"); + exit(0); + } + + tr1=mults2(k,g); + td=mult2_double(k,g); + tp=mult2_precomp(k,x,y,A2,b,m283,a283,b283,c283); + + printf("\n"); + printf("%4d bit ECDH :-\n",k); + printf(" offline, no precomputation %8.2lf ms \n",tr1); + printf(" offline, w. precomputation %8.2lf ms \n",tp); + printf(" online %8.2lf ms \n",tr1); + printf("%4d bit ECDSA :-\n",k); + printf(" signature no precomputation %8.2lf ms \n",tr1); + printf(" signature w. precomputation %8.2lf ms \n",tp); + printf(" verification %8.2lf ms \n",td); + + printf("\n283 bit GF(2^m) Koblitz Elliptic Curve....\n"); + k=283; + mip->IOBASE=16; + cinstr(b,KB283); + cinstr(x,Kx283); + cinstr(y,Ky283); + mip->IOBASE=10; + + convert(KA283,A2); + ecurve2_init(m283,a283,b283,c283,A2,b,FALSE,MR_PROJECTIVE); + g=epoint_init(); + if (!epoint2_set(x,y,0,g)) + { + printf("This is not a point on the curve!\n"); + exit(0); + } + + tr1=mults2(k,g); + td=mult2_double(k,g); + tp=mult2_precomp(k,x,y,A2,b,m283,a283,b283,c283); + + printf("\n"); + printf("%4d bit ECDH :-\n",k); + printf(" offline, no precomputation %8.2lf ms \n",tr1); + printf(" offline, w. precomputation %8.2lf ms \n",tp); + printf(" online %8.2lf ms \n",tr1); + printf("%4d bit ECDSA :-\n",k); + printf(" signature no precomputation %8.2lf ms \n",tr1); + printf(" signature w. precomputation %8.2lf ms \n",tp); + printf(" verification %8.2lf ms \n",td); + + printf("\n571 bit GF(2^m) Elliptic Curve....\n"); + k=571; + mip->IOBASE=16; + cinstr(b,B571); + cinstr(x,x571); + cinstr(y,y571); + mip->IOBASE=10; + + convert(A571,A2); + ecurve2_init(m571,a571,b571,c571,A2,b,FALSE,MR_PROJECTIVE); + g=epoint_init(); + if (!epoint2_set(x,y,0,g)) + { + printf("This is not a point on the curve!\n"); + exit(0); + } + + tr1=mults2(k,g); + td=mult2_double(k,g); + tp=mult2_precomp(k,x,y,A2,b,m571,a571,b571,c571); + + printf("\n"); + printf("%4d bit ECDH :-\n",k); + printf(" offline, no precomputation %8.2lf ms \n",tr1); + printf(" offline, w. precomputation %8.2lf ms \n",tp); + printf(" online %8.2lf ms \n",tr1); + printf("%4d bit ECDSA :-\n",k); + printf(" signature no precomputation %8.2lf ms \n",tr1); + printf(" signature w. precomputation %8.2lf ms \n",tp); + printf(" verification %8.2lf ms \n",td); + + printf("\n571 bit GF(2^m) Koblitz Elliptic Curve....\n"); + k=571; + mip->IOBASE=16; + cinstr(b,KB571); + cinstr(x,Kx571); + cinstr(y,Ky571); + mip->IOBASE=10; + + convert(KA571,A2); + ecurve2_init(m571,a571,b571,c571,A2,b,FALSE,MR_PROJECTIVE); + g=epoint_init(); + if (!epoint2_set(x,y,0,g)) + { + printf("This is not a point on the curve!\n"); + exit(0); + } + + tr1=mults2(k,g); + td=mult2_double(k,g); + tp=mult2_precomp(k,x,y,A2,b,m571,a571,b571,c571); + + printf("\n"); + printf("%4d bit ECDH :-\n",k); + printf(" offline, no precomputation %8.2lf ms \n",tr1); + printf(" offline, w. precomputation %8.2lf ms \n",tp); + printf(" online %8.2lf ms \n",tr1); + printf("%4d bit ECDSA :-\n",k); + printf(" signature no precomputation %8.2lf ms \n",tr1); + printf(" signature w. precomputation %8.2lf ms \n",tp); + printf(" verification %8.2lf ms \n",td); + +#endif + return 0; +} + diff --git a/miracl/source/bp160.ecs b/miracl/source/bp160.ecs new file mode 100644 index 0000000..dcb739d --- /dev/null +++ b/miracl/source/bp160.ecs @@ -0,0 +1,7 @@ +160 +E95E4A5F737059DC60DFC7AD95B3D8139515620F +340E7BE2A280EB74E2BE61BADA745D97E8F7C300 +1E589A8595423412134FAA2DBDEC95C8D8675E58 +E95E4A5F737059DC60DF5991D45029409E60FC09 +BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC3 +1667CB477A1A8EC338F94741669C976316DA6321 diff --git a/miracl/source/bpt160.ecs b/miracl/source/bpt160.ecs new file mode 100644 index 0000000..5cf9c07 --- /dev/null +++ b/miracl/source/bpt160.ecs @@ -0,0 +1,7 @@ +160 +E95E4A5F737059DC60DFC7AD95B3D8139515620F +-3 +7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380 +E95E4A5F737059DC60DF5991D45029409E60FC09 +B199B13B9B34EFC1397E64BAEB05ACC265FF2378 +ADD6718B7C7C1961F0991B842443772152C9E0AD diff --git a/miracl/source/brent.c b/miracl/source/brent.c new file mode 100644 index 0000000..af41b09 --- /dev/null +++ b/miracl/source/brent.c @@ -0,0 +1,98 @@ +/* + * Program to factor big numbers using Brent-Pollard method. + * See "An Improved Monte Carlo Factorization Algorithm" + * by Richard Brent in BIT Vol. 20 1980 pp 176-184 + * + */ + +#include +#ifdef MR_STATIC +#include +#endif + +#include "miracl.h" + +#define mr_min(a,b) ((a) < (b)? (a) : (b)) + +int main() +{ /* factoring program using Brents method */ + long k,r,i,m,iter; + big x,y,z,n,q,ys,c3; +#ifndef MR_STATIC + miracl *mip=mirsys(16,0); /* if allocating from the heap, specify size of bigs here */ + char *mem=(char *)memalloc(7); /* allocate and clear memory from the heap for 7 bigs */ +#else + miracl *mip=mirsys(MR_STATIC,0); /* If allocating from the stack, size of bigs is pre-defined */ + char mem[MR_BIG_RESERVE(7)]; /* reserve space on the stack for 7 bigs ... */ + memset(mem,0,MR_BIG_RESERVE(7)); /* ... and clear this memory */ +#endif + + x=mirvar_mem(mem,0); /* 7 bigs have index from 0-6 */ + y=mirvar_mem(mem,1); + ys=mirvar_mem(mem,2); + z=mirvar_mem(mem,3); + n=mirvar_mem(mem,4); + q=mirvar_mem(mem,5); + c3=mirvar_mem(mem,6); + convert(3,c3); + + printf("input number to be factored\n"); + cinnum(n,stdin); + if (isprime(n)) + { + printf("this number is prime!\n"); + return 0; + } + m=10L; + r=1L; + iter=0L; + do + { + printf("iterations=%5ld",iter); + convert(1,q); + do + { + copy(y,x); + for (i=1L;i<=r;i++) + mad(y,y,c3,n,n,y); + k=0; + do + { + iter++; + if (iter%10==0) printf("\b\b\b\b\b%5ld",iter); + fflush(stdout); + copy(y,ys); + for (i=1L;i<=mr_min(m,r-k);i++) + { + mad(y,y,c3,n,n,y); + subtract(y,x,z); + mad(z,q,q,n,n,q); + } + egcd(q,n,z); + k+=m; + } while (k +#include +#include "zzn.h" + +using namespace std; + +#define mr_min(a,b) ((a) < (b)? (a) : (b)) + +#ifndef MR_NOFULLWIDTH +Miracl precision(50,0); +#else +Miracl precision(50,MAXBASE); +#endif + +int main() +{ /* factoring program using Brents method */ + long k,r,i,m,iter; + Big n,z; + ZZn x,y,q,ys; + + cout << "input number to be factored\n"; + cin >> n; + if (prime(n)) + { + cout << "this number is prime!\n"; + return 0; + } + m=10L; + r=1L; + iter=0L; + z=0; + do + { + modulo(n); /* ZZn arithmetic done mod n */ + y=z; /* convert back to ZZn (n has changed!) */ + /* note:- a change of modulus is tricky for + for n-residue representation used in Montgomery + arithmetic */ + cout << "iterations=" << setw(5) << iter; + q=1; + do + { + x=y; + for (i=1L;i<=r;i++) y=(y*y+3); + k=0; + do + { + iter++; + if (iter%10==0) cout << "\b\b\b\b\b" << setw(5) << iter << flush; + ys=y; + for (i=1L;i<=mr_min(m,r-k);i++) + { + y=(y*y+3); + q=((y-x)*q); + } + z=gcd(q,n); + k+=m; + } while (k +#include "miracl.h" + +#define mr_min(a,b) ((a) < (b)? (a) : (b)) + +int main() +{ /* factoring program using Brents method */ + long k,r,i,m,iter; + big x,y,z,n,q,ys,c3; + miracl instance; /* create miracl workspace on the stack */ +#ifndef MR_STATIC + miracl *mip=mirsys(&instance,16,0); /* initialise miracl workspace and define size of bigs here */ + char *mem=memalloc(mip,7); /* allocate space from the heap for 7 bigs */; +#else + miracl *mip=mirsys(&instance,MR_STATIC,0); /* size of bigs is fixed */ + char mem[MR_BIG_RESERVE(7)]; /* reserve space on the stack for 7 bigs */ + memset(mem,0,MR_BIG_RESERVE(7)); /* clear this memory */ +#endif + + x=mirvar_mem(mip,mem,0); /* initialise the 7 bigs */ + y=mirvar_mem(mip,mem,1); + ys=mirvar_mem(mip,mem,2); + z=mirvar_mem(mip,mem,3); + n=mirvar_mem(mip,mem,4); + q=mirvar_mem(mip,mem,5); + c3=mirvar_mem(mip,mem,6); + convert(mip,3,c3); + + printf("input number to be factored\n"); + cinnum(mip,n,stdin); + if (isprime(mip,n)) + { + printf("this number is prime!\n"); + return 0; + } + m=10L; + r=1L; + iter=0L; + do + { + printf("iterations=%5ld",iter); + convert(mip,1,q); + do + { + copy(y,x); + for (i=1L;i<=r;i++) + mad(mip,y,y,c3,n,n,y); + k=0; + do + { + iter++; + if (iter%10==0) printf("\b\b\b\b\b%5ld",iter); + fflush(stdout); + copy(y,ys); + for (i=1L;i<=mr_min(m,r-k);i++) + { + mad(mip,y,y,c3,n,n,y); + subtract(mip,y,x,z); + mad(mip,z,q,q,n,n,q); + } + egcd(mip,q,n,z); + k+=m; + } while (k +#include "miracl.h" + +int main() +{ + FILE *fp; + big e,n,g,a; + brick binst; + int window,nb,bits; + miracl *mip=mirsys(100,0); + n=mirvar(0); + e=mirvar(0); + a=mirvar(0); + g=mirvar(0); + fp=fopen("common.dss","rt"); + fscanf(fp,"%d\n",&bits); + mip->IOBASE=16; + cinnum(n,fp); + cinnum(g,fp); + cinnum(g,fp); + mip->IOBASE=10; + + printf("modulus is %d bits in length\n",logb2(n)); + printf("Enter size of exponent in bits = "); + scanf("%d",&nb); + getchar(); + printf("Enter window size in bits (1-10)= "); + scanf("%d",&window); + getchar(); + + if (!brick_init(&binst,g,n,window,nb)) + { + printf("Failed to initialize\n"); + return 0; + } + + printf("%d big numbers have been precomputed and stored\n",(1< +#include +#include "brick.h" /* include MIRACL system */ + +using namespace std; + +Miracl precision=100; + +int main() +{ + ifstream common("common.dss"); + Big a,e,n,g; + int w,nb,bits; + miracl *mip=&precision; + common >> bits; + mip->IOBASE=16; + common >> n >> g >> g; + mip->IOBASE=10; + + w=8; // window size + + cout << "Enter size of exponent in bits = "; + cin >> nb; + + Brick b(g,n,w,nb); + + e=rand(nb,2); /* random exponent */ + + cout << "naive method" << endl; + a=pow(g,e,n); + cout << a << endl; + + cout << "Comb method" << endl; + + a=b.pow(e); + + cout << a << endl; + return 0; +} + diff --git a/miracl/source/brute.c b/miracl/source/brute.c new file mode 100644 index 0000000..a21c05d --- /dev/null +++ b/miracl/source/brute.c @@ -0,0 +1,77 @@ +/* + * Program to factor numbers using brute force. + */ + +#include +#include +#include "miracl.h" +#define LIMIT 15000 + +int main() +{ /* find factors by brute force division */ + int n,p; + +#ifdef MR_NOFULLWIDTH + miracl *mip=mirsys(50,MAXBASE); +#else + miracl *mip=mirsys(50,0); +#endif + + char stack_mem[mr_big_reserve(2,50)]; // 2 bigs, 4 bytes per big... + big x,y; + + memset(stack_mem,0,mr_big_reserve(2,50)); + x=mirvar_mem(stack_mem,0); + y=mirvar_mem(stack_mem,1); + +/* This is an example of allocating bigs x and y from the stack rather than + from the heap. The "50" should be the same as that used in the prior call + to mirsys(.), and MUST be a constant. There is never a need to explicitly + delete bigs allocated from the stack, via a call to mirkill(). Therefore + do not use for sensitive data as these bigs are not erased, unless you + do it yourself via a call to zero(.) + + Allocation from the stack is not particularly recommended, but could be + faster if bigs are not too big, and are required as temporary variables + in an often called subroutine. Allocating from the stack also avoids the + possibility of memory leaks. + + NOTE: A big allocated from the stack has a random initial value + +*/ + gprime(LIMIT); + printf("input number to be factored\n"); + cinnum(x,stdin); + if (isprime(x)) + { + printf("this number is prime!\n"); + return 0; + } + n=0; + p=mip->PRIMES[0]; + printf("factors are \n"); + forever + { /* try division by each prime in turn */ + if (subdiv(x,p,y)==0) + { /* factor found */ + copy(y,x); + printf("prime factor "); + printf("%d\n",p); + if (size(x)==1) return 0; + continue; + } + if (size(y)<=p) + { /* must be prime */ + printf("prime factor "); + cotnum(x,stdout); + return 0; + } + p=mip->PRIMES[++n]; + if (p==0) break; + } + if (isprime(x)) printf("prime factor "); + else printf("composite factor "); + cotnum(x,stdout); + return 0; +} + diff --git a/miracl/source/brute.cpp b/miracl/source/brute.cpp new file mode 100644 index 0000000..1acaadb --- /dev/null +++ b/miracl/source/brute.cpp @@ -0,0 +1,52 @@ +/* + * Program to factor numbers using brute force. + * + * Requires: big.cpp + */ + +#include +#include "big.h" + +using namespace std; + +#define LIMIT 10000 + +#ifndef MR_NOFULLWIDTH +Miracl precision=50; +#else +Miracl precision(50,MAXBASE); +#endif + +int main() +{ + int n,p; + Big x; + miracl *mr=&precision; + gprime(LIMIT); /* generate all primes < LIMIT */ + cout << "input number to be factored\n"; + cin >> x; + n=0; + p=mr->PRIMES[0]; + cout << "factors are "; + forever + { /* try division by each prime */ + if (x%p==0) + { /* factor found */ + x/=p; + cout << "\nprime factor " << p << flush; + if (x==1) return 0; + continue; + } + if ((x/p)<=p) + { /* must be prime */ + cout << "\nprime factor " << x << "\n"; + return 0; + } + p=mr->PRIMES[++n]; + if (p==0) break; + } + if (prime(x)) cout << "\nprime factor " << x << "\n"; + else cout << "\ncomposite factor " << x << "\n"; + return 0; +} + diff --git a/miracl/source/c.mcs b/miracl/source/c.mcs new file mode 100644 index 0000000..a137bf0 --- /dev/null +++ b/miracl/source/c.mcs @@ -0,0 +1,335 @@ +; Comba/KCM Macros for C +; +; ** if mr_qltype is defined in mirdef.h use c2.mcs ** +; +; Scheduled Version +; +; Note that: +; mr_small is a word length unsigned type +; mr_large is a double word length unsigned type +; +; Triple register is extra|sum +; The test "extra+=(sum>MIRACL); + b[%d]=0; + c[%d]=(mr_small)u; +ENDM + +MACRO PMUL_END + u=(mr_large)carry*sn; + b[0]=(mr_small)u; + b[1]=(mr_small)(u>>MIRACL); +ENDM + +MACRO MUL_START + extra=0; + sum=0; +ENDM +; +; STEP macros +; +MACRO STEP + pp1=(mr_large)a[%d]*b[%d]; + sum+=pp1; + extra+=(sum>MIRACL)|((mr_large)extra<>MIRACL)|((mr_large)extra<>MIRACL)|((mr_large)extra<>MIRACL)|((mr_large)extra<>MIRACL); +ENDM +; +; ADD_START macro +; +MACRO ADD_START + u=(mr_large)a[0]+b[0]; + c[0]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +; +; ADD macro - c[.]=a[.]+b[.] +; +MACRO ADD + u=(mr_large)carry+a[%d]+b[%d]; + c[%d]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +; +; ADD_END macro. +; +MACRO ADD_END +ENDM +; +; DOUBLE_START macro +; +MACRO DOUBLE_START + u=(mr_large)a[0]+a[0]; + a[0]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +; +; DOUBLE macro +; +MACRO DOUBLE + u=(mr_large)a[%d]; + u+=u; u+=carry; + a[%d]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +; +; DOUBLE_END +; +MACRO DOUBLE_END +ENDM +; +; INC_START macro. Do first one. +; +MACRO INC_START + u=(mr_large)a[0]+b[0]; + a[0]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +; +; INC macro a[.]+=b[.] +; +MACRO INC + u=(mr_large)carry+a[%d]+b[%d]; + a[%d]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +MACRO INC_END +ENDM +MACRO SUB_START + u=(mr_large)a[0]-b[0]; + c[0]=(mr_small)u; + carry=0-(mr_small)(u>>MIRACL); +ENDM +; +; SUB macro - c[.]=a[.]-b[.] +; +MACRO SUB + u=(mr_large)a[%d]-b[%d]-carry; + c[%d]=(mr_small)u; + carry=0-(mr_small)(u>>MIRACL); +ENDM +MACRO SUB_END +ENDM +; +; DEC_START macro +; +MACRO DEC_START + u=(mr_large)a[0]-b[0]; + a[0]=(mr_small)u; + carry=0-(mr_small)(u>>MIRACL); +ENDM +; +; DEC macro a[.]-=b[.] +; +MACRO DEC + u=(mr_large)a[%d]-b[%d]-carry; + a[%d]=(mr_small)u; + carry=0-(mr_small)(u>>MIRACL); +ENDM +; +; DEC_END macro +; +MACRO DEC_END +ENDM +; +; KADD_START macro. Zero Carry +; +MACRO KADD_START + carry=0; + k%d: +ENDM +; +; KASL macro +; +MACRO KASL + n--; + if (n==0) goto k%d; + a+=%d; + b+=%d; + c+=%d; + goto k%d; + k%d: +ENDM +; +; KADD_END macro +; +MACRO KADD_END +ENDM +; +; KINC_START macro +; +MACRO KINC_START + carry=0; + k%d: +ENDM +; +; KIDL macro +; +MACRO KIDL + n--; + if (n==0) goto k%d; + a+=%d; + b+=%d; + goto k%d; + k%d: +ENDM +; +; KINC_END macro +; +MACRO KINC_END +ENDM +; +; KDEC_START macro. Zero carry +; +MACRO KDEC_START + carry=0; + k%d: +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END +ENDM + diff --git a/miracl/source/c1.mcs b/miracl/source/c1.mcs new file mode 100644 index 0000000..1d85f25 --- /dev/null +++ b/miracl/source/c1.mcs @@ -0,0 +1,348 @@ +; Comba/KCM Macros for C - alternate version with minimal branches +; +; ** if mr_qltype is defined in mirdef.h use c2.mcs ** +; +; Scheduled version +; +; Note that: +; mr_small is a word length unsigned type +; mr_large is a double word length unsigned type +; +; Triple register is extra|s1|s0 +; +; See makemcs.txt for more information about this file +; +MACRO PMUL_START + carry=0; +ENDM + +MACRO PMUL + u=(mr_large)a[%d]*sn+carry; + carry=(mr_small)(u>>MIRACL); + b[%d]=0; + c[%d]=(mr_small)u; +ENDM + +MACRO PMUL_END + u=(mr_large)carry*sn; + b[0]=(mr_small)u; + b[1]=(mr_small)(u>>MIRACL); +ENDM + +MACRO MUL_START + extra=s1=s0=0; +ENDM +; +; STEP macro +; +MACRO STEP + pp1=(mr_large)a[%d]*b[%d]; + sum=pp1+s0; + s0=(mr_small)sum; + sum=(mr_large)s1+(sum>>MIRACL); + s1=(mr_small)sum; + extra+=(mr_small)(sum>>MIRACL); +ENDM +MACRO STEP1M + pp1=(mr_large)a[%d]*b[%d]; +ENDM +MACRO STEP1A + sum=pp1+s0; + s0=(mr_small)sum; + sum=(mr_large)s1+(sum>>MIRACL); + s1=(mr_small)sum; + extra+=(mr_small)(sum>>MIRACL); +ENDM +MACRO STEP2M + pp2=(mr_large)a[%d]*b[%d]; +ENDM +MACRO STEP2A + sum=pp2+s0; + s0=(mr_small)sum; + sum=(mr_large)s1+(sum>>MIRACL); + s1=(mr_small)sum; + extra+=(mr_small)(sum>>MIRACL); +ENDM +; +; MFIN macro +; +MACRO MFIN + c[%d]=s0; + s0=s1; + s1=extra; + extra=0; +ENDM +; +; LAST +; +MACRO LAST + pp1=(mr_large)a[%d]*b[%d]+s0; + s0=(mr_small)pp1; +ENDM +; +; MULE +; +MACRO MUL_END + c[%d]=s0; +ENDM +; +; SQR_START +; +MACRO SQR_START + extra=s1=s0=0; +ENDM +; +; DSTEP +; +MACRO DSTEP + pp1=(mr_large)a[%d]*a[%d]; + sum=(mr_large)s0+(mr_small)pp1+(mr_small)pp1; + s0=(mr_small)sum; + sum=(mr_large)s1+(pp1>>MIRACL)+(pp1>>MIRACL)+(sum>>MIRACL); + s1=(mr_small)sum; + extra+=(mr_small)(sum>>MIRACL); +ENDM +MACRO DSTEP1M + pp1=(mr_large)a[%d]*a[%d]; +ENDM +MACRO DSTEP1A + sum=(mr_large)s0+(mr_small)pp1+(mr_small)pp1; + s0=(mr_small)sum; + sum=(mr_large)s1+(pp1>>MIRACL)+(pp1>>MIRACL)+(sum>>MIRACL); + s1=(mr_small)sum; + extra+=(mr_small)(sum>>MIRACL); +ENDM +MACRO DSTEP2M + pp2=(mr_large)a[%d]*a[%d]; +ENDM +MACRO DSTEP2A + sum=(mr_large)s0+(mr_small)pp2+(mr_small)pp2; + s0=(mr_small)sum; + sum=(mr_large)s1+(pp2>>MIRACL)+(pp2>>MIRACL)+(sum>>MIRACL); + s1=(mr_small)sum; + extra+=(mr_small)(sum>>MIRACL); +ENDM +; +; SELF +; +MACRO SELF + pp1=(mr_large)a[%d]*a[%d]+s0; + s0=(mr_small)pp1; + pp1=(mr_large)s1+(pp1>>MIRACL); + s1=(mr_small)pp1; + extra+=(mr_small)(pp1>>MIRACL); +ENDM +; +; SFIN +; +MACRO SFIN + c[%d]=s0; + s0=s1; + s1=extra; + extra=0; +ENDM +; +; SQR_END +; +MACRO SQR_END + c[%d]=s0; +ENDM +; +; REDC_START +; +MACRO REDC_START + extra=s1=0; + s0=a[0]; +ENDM +; +; RFINU macro +; +MACRO RFINU + sp=s0*ndash; + a[%d]=sp; + pp1=(mr_large)sp*b[0]+s0; + s0=(mr_small)pp1; + pp1=(mr_large)s1+(pp1>>MIRACL); + s0=(mr_small)pp1; + s1=extra+(mr_small)(pp1>>MIRACL); + extra=0; + pp1=(mr_large)a[%d+1]+s0; + s0=(mr_small)pp1; + s1+=(mr_small)(pp1>>MIRACL); +ENDM +; +; RFIND macro +; +MACRO RFIND + a[%d]=s0; + s0=s1; + s1=extra; + extra=0; + pp1=(mr_large)a[%d+1]+s0; + s0=(mr_small)pp1; + s1+=(mr_small)(pp1>>MIRACL); +ENDM +; +; REDC_END macro +; +MACRO REDC_END + a[%d]=s0; + a[%d+1]=s1; +ENDM +; +; ADD_START macro +; +MACRO ADD_START + u=(mr_large)a[0]+b[0]; + c[0]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +; +; ADD macro - c[.]=a[.]+b[.] +; +MACRO ADD + u=(mr_large)carry+a[%d]+b[%d]; + c[%d]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +; +; ADD_END macro. +; +MACRO ADD_END +ENDM +; +; DOUBLE_START macro +; +MACRO DOUBLE_START + u=(mr_large)a[0]+a[0]; + a[0]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +; +; DOUBLE macro +; +MACRO DOUBLE + u=(mr_large)a[%d]; + u+=u; u+=carry; + a[%d]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +; +; DOUBLE_END +; +MACRO DOUBLE_END +ENDM +; +; INC_START macro. Do first one. +; +MACRO INC_START + u=(mr_large)a[0]+b[0]; + a[0]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +; +; INC macro a[.]+=b[.] +; +MACRO INC + u=(mr_large)carry+a[%d]+b[%d]; + a[%d]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +MACRO INC_END +ENDM +MACRO SUB_START + u=(mr_large)a[0]-b[0]; + c[0]=(mr_small)u; + carry=0-(mr_small)(u>>MIRACL); +ENDM +; +; SUB macro - c[.]=a[.]-b[.] +; +MACRO SUB + u=(mr_large)a[%d]-b[%d]-carry; + c[%d]=(mr_small)u; + carry=0-(mr_small)(u>>MIRACL); +ENDM +MACRO SUB_END +ENDM +; +; DEC_START macro +; +MACRO DEC_START + u=(mr_large)a[0]-b[0]; + a[0]=(mr_small)u; + carry=0-(mr_small)(u>>MIRACL); +ENDM +; +; DEC macro a[.]-=b[.] +; +MACRO DEC + u=(mr_large)a[%d]-b[%d]-carry; + a[%d]=(mr_small)u; + carry=0-(mr_small)(u>>MIRACL); +ENDM +; +; DEC_END macro +; +MACRO DEC_END +ENDM +; +; KADD_START macro. Zero Carry +; +MACRO KADD_START + carry=0; + k%d: +ENDM +; +; KASL macro +; +MACRO KASL + n--; + if (n==0) goto k%d; + a+=%d; + b+=%d; + c+=%d; + goto k%d; + k%d: +ENDM +; +; KADD_END macro +; +MACRO KADD_END +ENDM +; +; KINC_START macro +; +MACRO KINC_START + carry=0; + k%d: +ENDM +; +; KIDL macro +; +MACRO KIDL + n--; + if (n==0) goto k%d; + a+=%d; + b+=%d; + goto k%d; + k%d: +ENDM +; +; KINC_END macro +; +MACRO KINC_END +ENDM +; +; KDEC_START macro. Zero carry +; +MACRO KDEC_START + carry=0; + k%d: +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END +ENDM + diff --git a/miracl/source/c2.mcs b/miracl/source/c2.mcs new file mode 100644 index 0000000..1011b13 --- /dev/null +++ b/miracl/source/c2.mcs @@ -0,0 +1,260 @@ +; Comba/KCM Macros for C +; ** ONLY use this version if mr_qltype is defined in mirdef.h ** +; +; Note that: +; mr_small is a word length unsigned type +; mr_large is a double word length unsigned type +; mr_vlarge is a quad word length unsigned type +; +; Triple register is sum +; See makemcs.txt for more information about this file +; +MACRO PMUL_START + carry=0; +ENDM + +MACRO PMUL + u=(mr_large)a[%d]*sn+carry; + carry=(mr_small)(u>>MIRACL); + b[%d]=0; + c[%d]=(mr_small)u; +ENDM + +MACRO PMUL_END + u=(mr_large)carry*sn; + b[0]=(mr_small)u; + b[1]=(mr_small)(u>>MIRACL); +ENDM + +MACRO MUL_START + sum=0; +ENDM +; +; STEP macros +; +MACRO STEP + pp1=(mr_large)a[%d]*b[%d]; + sum+=(mr_vlarge)pp1; +ENDM +; +; MFIN macro +; +MACRO MFIN + c[%d]=(mr_small)sum; + sum=(sum>>MIRACL); +ENDM +; +; LAST +; +MACRO LAST + pp1=(mr_large)a[%d]*b[%d]; + sum+=(mr_vlarge)pp1; +ENDM +; +; MULE +; +MACRO MUL_END + c[%d]=(mr_small)sum; +ENDM +; +; SQR_START +; +MACRO SQR_START + sum=0; +ENDM +; +; DSTEP +; +MACRO DSTEP + pp1=(mr_large)a[%d]*a[%d]; + sum+=(mr_vlarge)pp1; + sum+=(mr_vlarge)pp1; +ENDM +; +; SELF +; +MACRO SELF + pp1=(mr_large)a[%d]; + pp1*=pp1; + sum+=(mr_vlarge)pp1; +ENDM +; +; SFIN +; +MACRO SFIN + c[%d]=(mr_small)sum; + sum=sum>>MIRACL; +ENDM +; +; SQR_END +; +MACRO SQR_END + c[%d]=(mr_small)sum; +ENDM +; +; REDC_START +; +MACRO REDC_START + sum=a[0]; +ENDM +; +; RFINU macro +; +MACRO RFINU + sp=(mr_small)sum*ndash; + a[%d]=sp; + pp1=(mr_large)sp*b[0]; + sum+=(mr_vlarge)pp1; + sum=(sum>>MIRACL); + sum+=(mr_vlarge)a[%d+1]; +ENDM +; +; RFIND macro +; +MACRO RFIND + a[%d]=(mr_small)sum; + sum=(sum>>MIRACL); + sum+=(mr_vlarge)a[%d+1]; +ENDM +; +; REDC_END macro +; +MACRO REDC_END + a[%d]=(mr_small)sum; + a[%d+1]=(sum>>MIRACL); +ENDM +; +; ADD_START macro +; +MACRO ADD_START + u=(mr_large)a[0]+b[0]; + c[0]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +; +; ADD macro - c[.]=a[.]+b[.] +; +MACRO ADD + u=(mr_large)carry+a[%d]+b[%d]; + c[%d]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +; +; ADD_END macro. +; +MACRO ADD_END +ENDM +; +; INC_START macro. Do first one. +; +MACRO INC_START + u=(mr_large)a[0]+b[0]; + a[0]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +; +; INC macro a[.]+=b[.] +; +MACRO INC + u=(mr_large)carry+a[%d]+b[%d]; + a[%d]=(mr_small)u; + carry=(mr_small)(u>>MIRACL); +ENDM +MACRO INC_END +ENDM +MACRO SUB_START + u=(mr_large)a[0]-b[0]; + c[0]=(mr_small)u; + carry=0-(mr_small)(u>>MIRACL); +ENDM +; +; SUB macro - c[.]=a[.]-b[.] +; +MACRO SUB + u=(mr_large)a[%d]-b[%d]-carry; + c[%d]=(mr_small)u; + carry=0-(mr_small)(u>>MIRACL); +ENDM +MACRO SUB_END +ENDM +; +; DEC_START macro +; +MACRO DEC_START + u=(mr_large)a[0]-b[0]; + a[0]=(mr_small)u; + carry=0-(mr_small)(u>>MIRACL); +ENDM +; +; DEC macro a[.]-=b[.] +; +MACRO DEC + u=(mr_large)a[%d]-b[%d]-carry; + a[%d]=(mr_small)u; + carry=0-(mr_small)(u>>MIRACL); +ENDM +; +; DEC_END macro +; +MACRO DEC_END +ENDM +; +; KADD_START macro. Zero Carry +; +MACRO KADD_START + carry=0; + k%d: +ENDM +; +; KASL macro +; +MACRO KASL + n--; + if (n==0) goto k%d; + a+=%d; + b+=%d; + c+=%d; + goto k%d; + k%d: +ENDM +; +; KADD_END macro +; +MACRO KADD_END +ENDM +; +; KINC_START macro +; +MACRO KINC_START + carry=0; + k%d: +ENDM +; +; KIDL macro +; +MACRO KIDL + n--; + if (n==0) goto k%d; + a+=%d; + b+=%d; + goto k%d; + k%d: +ENDM +; +; KINC_END macro +; +MACRO KINC_END +ENDM +; +; KDEC_START macro. Zero carry +; +MACRO KDEC_START + carry=0; + k%d: +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END +ENDM + diff --git a/miracl/source/cardano.cpp b/miracl/source/cardano.cpp new file mode 100644 index 0000000..064818c --- /dev/null +++ b/miracl/source/cardano.cpp @@ -0,0 +1,177 @@ +/* Solving cubic x^3+AX+B using Cardano's formula */ +/* cl /O2 /GX cardona.cpp zzn2.cpp zzn.cpp big.cpp miracl.lib */ + +#include +#include +#include "zzn2.h" + +using namespace std; + +Miracl precision(50,0); + +// +// Shanks method modified to find cube roots +// + +ZZn2 shanks(ZZn2 n) +{ + int i,s; + Big q,p=get_modulus(); + ZZn2 t,W,R,V; + BOOL inv; + + if (pow(n,(p*p-1)/3)!=1) + { + // cout << "Not a cubic residue" << endl; + return (ZZn2)0; + } + + W=randn2(); + while (pow(W,(p*p-1)/3)==1) W=randn2(); + + s=0; + q=p*p-1; + while (q%3==0) + { + q/=3; + s++; + } + + if ((q+1)%3==0) + { + R=pow(n,(q+1)/3); + inv=FALSE; + } + else + { + R=pow(n,(q-1)/3); + inv=TRUE; + } + + V=pow(W,q); + + forever + { + if (!inv) t=(R*R*R)/n; + else t=(R*R*R)*n; + + for (i=0;;i++ ) + { + if (t==1) break; + t=t*t*t; + } + if (i==0) + { + if (!inv) return R; + else return (ZZn2)1/R; + } + R=R*pow(V,pow((Big)3,s-i-1)); + } + +} + +int main(int argc, char *argv[]) +{ + int i,j,lt,gt; + Big p; + ZZn x,A,B,D; + ZZn2 r,r3,r1,r2,CD,cu; + time_t seed; + + time(&seed); + irand((long)seed); + +// +// Generate a random prime, (not 1 mod 8) +// + + cout << "Generate a random prime and a random cubic, and try to solve it!" << endl; + cout << "Solutions might be Complex" << endl << endl; + + + p=rand(80,2); + while (p%8==1 || !prime(p)) p+=1; + + cout << "p= " << p << endl; + cout << "p%24= " << p%24 << endl; + modulo(p); + +// Find a cube root of unity + + do + { + cu=pow((ZZn2)randn2(),(p*p-1)/3); + } while(cu==1); +// cout << "cube root of unity= " << cu << endl; + + A=(ZZn)rand(p); + B=(ZZn)rand(p); + +// Generate random parameters + + cout << "Finding a root of x^3+AX+B mod p, where" << endl; + cout << "A= " << A << endl; + cout << "B= " << B << endl; + +// Cardona's formula + + D=(B*B)/4 + (A*A*A)/27; + + CD=sqrt((ZZn2)D); // Solution may be "complex" + + r1=(ZZn2)-B/2+CD; r2=(ZZn2)-B/2-CD; + + r1=shanks(r1); // cube roots + r2=shanks(r2); + + if (r1==0 || r2==0) + { + cout << "No roots exist" << endl; + return 0; + } + +// search for "right" r2 + + if (r1*r2!=-A/3) + r2*=cu; + + if (r1*r2!=-A/3) + r2*=cu; + + r=r1+r2; + + cout << "root 1= " << r << endl; + if (r*r*r+A*r+B!=0) cout << "Check failed" << endl; + +// try next value for r1 + + r1*=cu; + + if (r1*r2!=-A/3) + r2*=cu; + + if (r1*r2!=-A/3) + r2*=cu; + + + r=r1+r2; + + cout << "root 2= " << r << endl; + if (r*r*r+A*r+B!=0) cout << "Check failed" << endl; + + r1*=cu; + + if (r1*r2!=-A/3) + r2*=cu; + + if (r1*r2!=-A/3) + r2*=cu; + + r=r1+r2; + + cout << "root 3= " << r << endl; + if (r*r*r+A*r+B!=0) cout << "Check failed" << endl; + + return 0; + +} diff --git a/miracl/source/clmul.mcs b/miracl/source/clmul.mcs new file mode 100644 index 0000000..a39ae99 --- /dev/null +++ b/miracl/source/clmul.mcs @@ -0,0 +1,18 @@ +; +; Binary Macros to exploit the Intel PCLMULQDQ instruction +; for use by Microsoft Visual C++ compiler. +; +MACRO MULB_START +sum=_mm_setzero_si128(); +ENDM +MACRO STEPB +m1=_mm_loadl_epi64((__m128i *)&a[%d]); +m2=_mm_loadl_epi64((__m128i *)&b[%d]); +sum=_mm_xor_si128(sum,_mm_clmulepi64_si128( m1, m2, 0)); +ENDM +MACRO MBFIN +c[%d]=((mr_unsign64 *)&sum)[0]; +sum=_mm_srli_si128(sum,8); +ENDM +MACRO MULB_END +ENDM diff --git a/miracl/source/common.dss b/miracl/source/common.dss new file mode 100644 index 0000000..6964135 --- /dev/null +++ b/miracl/source/common.dss @@ -0,0 +1,4 @@ +1024 +C38E5055E7CD056A5D4B8BDD21B4A957F23E5FC7918CA52DA55952B33B22B3CB772275C64EB4092BA97A4576369D542763D8B45B4F2DA56CBC81DB0509D1C96CFC732207D056E41A46554515C224D4AB9F66547399A0C58DB3BE88B351339527867D4F566A01CFB7A076A2139CB2026FF70C765FB78954BD325690FCA2679F73 +E6DD5BAD72FC2877148E834C495112030D4B771B +560561A8479C66F1E5DC768BA38676F114CE612A378E39E9D0E8ADF21F29697E262BBBB8BD31A98978A44AC919A6BF9197D6817D05A1CEFD57A2024F8738FD7F46B72DDCF1BF90EF0F6AAF72A2C00AA8AACFC0CAFE4A422E198EEAB4F505D41A15FC7D76846540EE59FB4956245F4F0B4D60C3DBA66278396FFC69783F83AD10 diff --git a/miracl/source/common.ecs b/miracl/source/common.ecs new file mode 100644 index 0000000..7096b71 --- /dev/null +++ b/miracl/source/common.ecs @@ -0,0 +1,7 @@ +192 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF +-3 +64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1 +FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831 +188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012 +07192B95FFC8DA78631011ED6B24CDD573F977A11E794811 diff --git a/miracl/source/common2.ecs b/miracl/source/common2.ecs new file mode 100644 index 0000000..050ddb5 --- /dev/null +++ b/miracl/source/common2.ecs @@ -0,0 +1,9 @@ +163 +1 +20A601907B8C953CA1481EB10512F78744A3205FD +40000000000000000000292FE77E70C12A4234C33 +3F0EBA16286A2D57EA0991168D4994637E8343E36 +D51FBC6C71A0094FA2CDD545B11C5C0C797324F1 +7 +6 +3 diff --git a/miracl/source/crdecode.cpp b/miracl/source/crdecode.cpp new file mode 100644 index 0000000..349a514 --- /dev/null +++ b/miracl/source/crdecode.cpp @@ -0,0 +1,140 @@ +/* + * Cramer-Shoup public Key system - Hybrid Implementation + * + * This program decrypts the contents of the file xxx.crs to the screen + * usng the AES key recovered from xxx.key using the Cramer-Shoup + * private key from private.crs + * + * Requires: big.cpp + */ + +#include +#include +#include "big.h" +#include + +using namespace std; + +Miracl precision(300,256); + +void strip(char *name) +{ /* strip extension off filename */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +void hash(sha *s,Big x) +{ /* hash in a big number */ + int ch; + while (x!=0) + { + ch=x%256; x/=256; + shs_process(s,ch); + } +} + +int main() +{ + int i,bits; + static char ifname[100]; + ifstream common("common.crs"); // construct file I/O streams + ifstream private_key("private.crs"); + ifstream key_file,ciphertext,ct; + Big p,q,g1,g2,x1,x2,y1,y2,z,u1,u2,e,v,m,e1,e2,alpha; + char ch,H[20],iv[16],block[16]; + miracl *mip=&precision; + sha sh; + aes a; + +// get common data + mip->IOBASE=16; + common >> bits; + common >> q >> p >> g1 >> g2; + +// get private key + private_key >> x1 >> x2 >> y1 >> y2 >> z; + +// figure out where input is coming from + + cout << "file to be decoded = "; + cin >> ifname; + + strip(ifname); // open key file + strcat(ifname,".key"); + key_file.open(ifname,ios::in); + if (!key_file) + { + cout << "Key file " << ifname << " not found\n"; + return 0; + } + + strip(ifname); // open ciphertext + strcat(ifname,".crs"); + ciphertext.open(ifname,ios::binary|ios::in); + if (!ciphertext) + { + cout << "Unable to open file " << ifname << "\n"; + return 0; + } + + mip->IOBASE=16; + key_file >> u1 >> u2 >> v; + + shs_init(&sh); + hash(&sh,u1); + hash(&sh,u2); + +// first pass - scan in ciphertext, and calculate alpha=H(u1,u2,ciphertext) + cout << "Checking ciphertext validity\n" ; + forever + { + ciphertext.get(ch); + if (ciphertext.eof()) break; + shs_process(&sh,ch); + } + + ciphertext.close(); + shs_hash(&sh,H); + mip->INPLEN=20; + mip->IOBASE=256; + alpha=(char *)H; // alpha=H(u1,u2,ciphertext); + + e1=(x1+y1*alpha)%q; + e2=(x2+y2*alpha)%q; + +// check validity of ciphertext + + if (v!=pow(u1,e1,u2,e2,p)) + { + cout << "*** Cipher text is rejected ***" << endl; + return 0; + } + + shs_init(&sh); + hash(&sh,pow(u1,z,p)); + shs_hash(&sh,H); // H=hash(u1^z mod p) = AES Key + + for (i=0;i<16;i++) iv[i]=i; // Set CFB IV + aes_init(&a,MR_PCFB1,16,H,iv); // Set 128 bit AES Key + +// decrypt file on second pass + + ct.open(ifname,ios::binary|ios::in); + cout << "decoding message\n"; + forever + { // decrypt input .. + ct.get(ch); + if (ct.eof()) break; + aes_decrypt(&a,&ch); + cout << ch; + } + aes_end(&a); + ct.close(); + return 0; +} + diff --git a/miracl/source/crencode.cpp b/miracl/source/crencode.cpp new file mode 100644 index 0000000..0c4d55f --- /dev/null +++ b/miracl/source/crencode.cpp @@ -0,0 +1,135 @@ +/* + * Cramer-Shoup Public Key Encryption - Hybrid Implementation + * + * This program encrypts a file fred.xxx to fred.crs. The AES encryption + * key is encrypted under the public key in the file fred.key + * + * The public key comes from from public.crs + * + * Requires: big.cpp + * + */ + +#include +#include +#include +#include "big.h" + +using namespace std; + +Miracl precision(300,256); + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +void hash(sha *s,Big x) +{ /* hash in a big number one byte at a time */ + int ch; + while (x!=0) + { + ch=x%256; x/=256; + shs_process(s,ch); + } +} + +int main() +{ + int i,bits; + ifstream common("common.crs"); // construct file I/O streams + ifstream plaintext,public_key("public.crs"); + ofstream key_file,ciphertext; + Big p,q,g1,g2,h,m,r,u1,u2,e,v,ex,c,d,alpha; + static char ifname[100],ofname[100]; + char ch,H[20],iv[16],block[16]; + sha sh; + aes a; + long seed; + miracl *mip=&precision; + +// randomise + cout << "Enter 9 digit random number seed = "; + cin >> seed; + irand(seed); + mip->IOBASE=16; + +// get common data + common >> bits; + common >> q >> p >> g1 >> g2; + +// get public key of receiver + public_key >> c >> d >> h; + + r=rand(q); + + shs_init(&sh); + hash(&sh,pow(h,r,p)); + shs_hash(&sh,H); // AES Key = Hash(h^r mod p) + for (i=0;i<16;i++) iv[i]=i; // Set CFB IV + aes_init(&a,MR_PCFB1,16,H,iv); // Set 128 bit AES Key + +// figure out where input is coming from + + cout << "file to be encoded = " ; + cin >> ifname; + + /* set up output files */ + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".crs"); + plaintext.open(ifname,ios::in); + if (!plaintext) + { + cout << "Unable to open file " << ifname << "\n"; + return 0; + } + cout << "encoding message\n"; + + ciphertext.open(ofname,ios::binary|ios::out); + + u1=pow(g1,r,p); + u2=pow(g2,r,p); + + shs_init(&sh); + hash(&sh,u1); + hash(&sh,u2); + +// now encrypt the plaintext +// and hash in the ciphertext. + + forever + { // encrypt input .. + plaintext.get(ch); + if (plaintext.eof()) break; + aes_encrypt(&a,&ch); + shs_process(&sh,ch); + ciphertext << ch; + } + + aes_end(&a); + + shs_hash(&sh,H); + mip->INPLEN=20; + mip->IOBASE=256; + alpha=(char *)H; // alpha=Hash(u1,u2,ciphertext) + + ex=(r*alpha)%q; + v=pow(c,r,d,ex,p); // multi-exponentiation + + strip(ofname); + strcat(ofname,".key"); + mip->IOBASE=16; + key_file.open(ofname); + key_file << u1 << endl; + key_file << u2 << endl; + key_file << v << endl; + return 0; +} + diff --git a/miracl/source/crgen.cpp b/miracl/source/crgen.cpp new file mode 100644 index 0000000..8b7e741 --- /dev/null +++ b/miracl/source/crgen.cpp @@ -0,0 +1,58 @@ +/* + * Cramer-Shoup Public Key System + * + * This program generates one set of public and private keys in files + * public.crs and private.crs respectively + * + * Requires: big.cpp + */ + +#include +#include +#include "big.h" + +using namespace std; + +Miracl precision=100; + +int main() +{ + ifstream common("common.crs"); // construct file I/O streams + ofstream public_key("public.crs"); + ofstream private_key("private.crs"); + Big p,q,h,g1,g2,x1,x2,y1,y2,z,c,d; + int bits; + long seed; + cout << "Enter 9 digit random number seed = "; + cin >> seed; + irand(seed); + get_mip()->IOBASE=16; + +// get common data + common >> bits; + common >> q >> p >> g1 >> g2; + +// generate public/private keys + x1=rand(q); + x2=rand(q); + y1=rand(q); + y2=rand(q); + z=rand(q); + + c=pow(g1,x1,g2,x2,p); // c=g1^x1.g2^x2 mod p + d=pow(g1,y1,g2,y2,p); + h=pow(g1,z,p); + + private_key << x1 << endl; + private_key << x2 << endl; + private_key << y1 << endl; + private_key << y2 << endl; + private_key << z << endl; + + public_key << c << endl; + public_key << d << endl; + public_key << h << endl; + + return 0; +} + diff --git a/miracl/source/crsetup.cpp b/miracl/source/crsetup.cpp new file mode 100644 index 0000000..b401491 --- /dev/null +++ b/miracl/source/crsetup.cpp @@ -0,0 +1,76 @@ +/* + * Cramer-Shoup Public Key Cryptography + * + * This program generates the common values q, p, g1 and g2 to a file + * common.crs + * + * Requires: big.cpp + */ + +#include +#include +#include "big.h" + +using namespace std; + +#define PBITS 1024 +#define QBITS 160 + +Miracl precision=100; + +int main() +{ + ofstream common("common.crs"); // construct file I/O streams + Big p,q,h,t,s,r,n,g; + long seed; + cout << "Enter 9 digit random number seed = "; + cin >> seed; + irand(seed); + + get_mip()->IOBASE=16; + +/* generate q */ + forever + { + n=rand(QBITS-2,2); /* QBIT-2 bit number, base 2 */ + q=2*n+1; + while (!prime(q)) q+=2; + if (bits(q)>=QBITS) continue; + break; + } + cout << "q= " << q << endl; + common << PBITS << endl; + common << q << endl; + +/* generate p */ + t=(pow((Big)2,PBITS)-1)/(2*q); + s=(pow((Big)2,PBITS-1)-1)/(2*q); + forever + { + n=rand(t); + if (nbase_mask; + sum>>=mr_mip->lg2b; +ENDM +; +; LAST +; +MACRO LAST + sum+=(mr_large)a[%d]*b[%d]; +ENDM +; +; MULE +; +MACRO MUL_END + c[%d]=(mr_small)sum&mr_mip->base_mask; +ENDM +; +; SQR_START +; +MACRO SQR_START + sum=0; +ENDM +; +; DSTEP +; +MACRO DSTEP + pp1=(mr_large)a[%d]*a[%d]; + sum+=pp1; + sum+=pp1; +ENDM +; +; SELF +; +MACRO SELF + pp1=(mr_large)a[%d]; + pp1*=pp1; + sum+=pp1; +ENDM +; +; SFIN +; +MACRO SFIN + c[%d]=(mr_small)sum&mr_mip->base_mask; + sum>>=mr_mip->lg2b; +ENDM +; +; SQR_END +; +MACRO SQR_END + c[%d]=(mr_small)sum&mr_mip->base_mask; +ENDM +; +; REDC_START +; +MACRO REDC_START + sum=a[0]; +ENDM +; +; RFINU macro +; +MACRO RFINU + sp=(mr_small)sum*ndash; + sp&=mr_mip->base_mask; + a[%d]=sp; + + sum+=(mr_large)sp*b[0]; + + sum>>=mr_mip->lg2b; + + sum+=(mr_large)a[%d+1]; +ENDM +; +; RFIND macro +; +MACRO RFIND + a[%d]=(mr_small)sum&mr_mip->base_mask; + sum>>=mr_mip->lg2b; + sum+=(mr_large)a[%d+1]; +ENDM +; +; REDC_END macro +; +MACRO REDC_END + a[%d]=(mr_small)sum&mr_mip->base_mask; + a[%d+1]=(mr_small)(sum>>mr_mip->lg2b); +ENDM +; +; ADD_START macro +; +MACRO ADD_START + + c[0]=a[0]+b[0]; + carry=(c[0]>>mr_mip->lg2b); + c[0]&=mr_mip->base_mask; +ENDM +; +; ADD macro - c[.]=a[.]+b[.] +; +MACRO ADD + su=a[%d]+b[%d]+carry; + c[%d]=su&mr_mip->base_mask; + carry=(su>>mr_mip->lg2b); +ENDM +; +; ADD_END macro. +; +MACRO ADD_END +ENDM +; +; DOUBLE_START macro +; +MACRO DOUBLE_START + a[0]+=a[0]; + carry=(a[0]>>mr_mip->lg2b); + a[0]&=mr_mip->base_mask; +ENDM +; +; DOUBLE macro +; +MACRO DOUBLE + su=a[%d]; + su+=su; + su+=carry; + a[%d]=su&mr_mip->base_mask; + carry=(su>>mr_mip->lg2b); +ENDM +; +; DOUBLE_END +; +MACRO DOUBLE_END +ENDM +; +; INC_START macro. Do first one. +; +MACRO INC_START + a[0]+=b[0]; + carry=(a[0]>>mr_mip->lg2b); + a[0]&=mr_mip->base_mask; +ENDM +; +; INC macro a[.]+=b[.] +; +MACRO INC + su=a[%d]+b[%d]+carry; + a[%d]=su&mr_mip->base_mask; + carry=(su>>mr_mip->lg2b); +ENDM +MACRO INC_END +ENDM +MACRO SUB_START + c[0]=a[0]-b[0]; + carry=(c[0]>>mr_mip->lg2b)&1; + c[0]&=mr_mip->base_mask; +ENDM +; +; SUB macro - c[.]=a[.]-b[.] +; +MACRO SUB + su=a[%d]-b[%d]-carry; + c[%d]=su&mr_mip->base_mask; + carry=(su>>mr_mip->lg2b)&1; +ENDM +MACRO SUB_END +ENDM +; +; DEC_START macro +; +MACRO DEC_START + a[0]-=b[0]; + carry=(a[0]>>mr_mip->lg2b)&1; + a[0]&=mr_mip->base_mask; + +ENDM +; +; DEC macro a[.]-=b[.] +; +MACRO DEC + su=a[%d]-b[%d]-carry; + a[%d]=su&mr_mip->base_mask; + carry=(su>>mr_mip->lg2b)&1; +ENDM +; +; DEC_END macro +; +MACRO DEC_END +ENDM +; +; KADD_START macro. Zero Carry +; +MACRO KADD_START + carry=0; + k%d: +ENDM +; +; KASL macro +; +MACRO KASL + n--; + if (n==0) goto k%d; + a+=%d; + b+=%d; + c+=%d; + goto k%d; + k%d: +ENDM +; +; KADD_END macro +; +MACRO KADD_END +ENDM +; +; KINC_START macro +; +MACRO KINC_START + carry=0; + k%d: +ENDM +; +; KIDL macro +; +MACRO KIDL + n--; + if (n==0) goto k%d; + a+=%d; + b+=%d; + goto k%d; + k%d: +ENDM +; +; KINC_END macro +; +MACRO KINC_END +ENDM +; +; KDEC_START macro. Zero carry +; +MACRO KDEC_START + carry=0; + k%d: +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END +ENDM + diff --git a/miracl/source/curve/cm.cpp b/miracl/source/curve/cm.cpp new file mode 100644 index 0000000..7b95168 --- /dev/null +++ b/miracl/source/curve/cm.cpp @@ -0,0 +1,1362 @@ +/* + * cm.cpp - Finding an elliptic curve and point of nearly prime order + * See IEEE 1363 Annex A for documentation! + * + * !!! New much improved version - March 2002 + * !!! Now tested for D up to 10^7 + * + * !!! New faster version - uses Floats instead of Flashs - November 2003 + * !!! Now 100 times faster! + * !!! Now tested for D up to and beyond 10^9 + * + * !!! New invariants - gamma2, w3, w5, w7 and w13. Thanks to Marcel Martin. + * + * Sometimes its better to use the -IEEE flag, as this can often be faster + * than the Gamma2 invariant, as although it requires a bigger "class number", + * it needs less precision. + * + * Uses functions from the MIRACL multiprecision library, specifically + * classes:- + * Float - Big floating point + * Complex - Big Complex float + * Big - Big integer + * ZZn - Big integers mod an integer + * FPoly - Big Float polynomial + * Poly - Big ZZn polynomial + * + * Written by Mike Scott, Dublin, Ireland. March 1998 - March 2004 + * + */ + +#include +#include +#include +#include +#include "ecn.h" +#include "complex.h" +#include "flpoly.h" +#include "poly.h" + +using namespace std; + +miracl *mip; + +FPoly T[25]; // Reduced class Polynomial. +static char *s; +BOOL fout,suppress,three; + +// F(z) Function A.13.3 + +Complex Fz(Complex z) +{ + Complex t; + int sign=1; + Complex osum,sum=(Float)1; + + if (z.iszero()) return sum; + + Complex zi=z; + Complex zj=z*z; + Complex r=z; + Complex z3=zj*z; + + forever + { // do 2 terms at a time.... + t=zi+zj; + osum=sum; + if (sign) sum-=t; + else sum+=t; + + if (sum==osum) break; + + r*=z3; + zi*=r; zj*=r; zj*=z; + + sign=1-sign; + } + + return sum; +} + +// Fj(A,B,C) function A.13.3 + +Complex F(int j,Big A,Big B,Big C,Big D,int N) +{ + Complex t,theta24,theta,theta2,theta3,theta6; + Float sd; + + if (j>=3) + { // Gamma 2 and Morain's invariants + sd=-sqrt((Float)D); + t=Complex(sd*fpi(),(fpi()*(Float)B)); + t/=((Float)A); + theta=exp(t); + if (j==3) + { + theta3=theta; + theta3*=theta3; + theta3*=theta; + theta6=theta3; + theta6*=theta6; + t=theta*pow((Fz(theta6)/Fz(theta3)),8); + return (256*t*t*t+1)/t; + } + if (j==4) + { + return (pow(Fz(theta)/Fz(pow(theta,N)),24/(N-1))/theta); + } + return 0; + } + + sd=-sqrt((Float)D); + t=Complex(sd*fpi(),(fpi()*(Float)B)); + + t/=(Float)(24*A); + theta24=exp(t); // theta^(1/24) + theta=pow(theta24,24); // theta + + if (j!=2) + t=recip(theta24); // -24th root + else + t=theta24*theta24; // 12th root + + theta2=theta; + theta2*=theta2; + + if (j==0) return (t*Fz(-theta)/Fz(theta2)); + if (j==1) return (t*Fz(theta)/Fz(theta2)); + if (j==2) return (sqrt((Float)2)*t*Fz(theta2*theta2)/Fz(theta2)); + return 0; +} + +int geti(Big D) +{ + Big d=D%8; + if (d==1 || d==2 || d==6 || d==7) return 3; + if (d==3) + { + if (D%3==0) return 2; + else return 0; + } + if (d==5) return 6; + return 0; +} + +int getk(Big D) +{ + Big d=D%8; + if (d==1 || d==2 || d==6) return 2; + if (d==3 || d==7) return 1; + if (d==5) return 4; + return 0; +} + +int getN(Big D) +{ + if (D%13==0) return 13; + if (D%7==0) return 7; + if (D%5==0) return 5; + if (D%3==0) return 3; + return 2; +} + +// A.13.3 + +void class_poly(Complex& lam,Float *Fi2,Big A,Big B,Big C,Big D,BOOL conj,BOOL P1363) +{ + Big ac,l,t; + int i,j,k,g,e,m,n,dm8; + Complex cinv; + + if (P1363) + { + g=1; + if (D%3==0) g=3; + + ac=A*C; + if (ac%2==1) + { + j=0; + l=A-C+A*A*C; + } + if (C%2==0) j=1; + if (A%2==0) j=2; + + if (A%2==0) + { + t=(C*C-1)/8; + if (t%2==0) m=1; + else m=-1; + } + else + { + t=(A*A-1)/8; + if (t%2==0) m=1; + else m=-1; + } + + dm8=D%8; + i=geti(D); + k=getk(D); + switch (dm8) + { + case 1: + case 2: n=m; + if (C%2==0) l=A+2*C-A*C*C; + if (A%2==0) l=A-C-A*C*C; + break; + case 3: if (ac%2==1) n=1; + else n=-m; + if (C%2==0) l=A+2*C-A*C*C; + if (A%2==0) l=A-C+5*A*C*C; + break; + case 5: n=1; + if (C%2==0) l=A-C+A*A*C; + if (A%2==0) l=A-C-A*C*C; + break; + case 6: n=m; + if (C%2==0) l=A+2*C-A*C*C; + if (A%2==0) l=A-C-A*C*C; + break; + case 7: if (ac%2==0) n=1; + else n=m; + if (C%2==0) l=A+2*C-A*C*C; + if (A%2==0) l=A-C-A*C*C; + break; + + default: break; + } + e=(k*B*l)%48; + if (e<0) e+=48; + cinv=pow(lam,e); + cinv*=(n*Fi2[i]); + cinv=pow(cinv*pow(F(j,A,B,C,D,0),k),g); + } + else + { + int N=getN(D); +// adjust A and B + + if (N==2) + { + j=3; + if (A%3!=0) + { + if (B%3!=0) + { + if ((B+A+A)%3!=0) B+=(4*A); + else B+=(A+A); + } + } + else + { + if (B%3!=0) + { + if (C%3!=0) + { + if ((C+B)%3!=0) B+=(4*A); + else B+=(A+A); + } + } + } + A*=3; + } + else + { + j=4; + if ((A%N)==0) + { + A=C; + B=-B; + } + while (B%N!=0) B+=(A+A); + A*=N; + } + cinv=F(j,A,B,C,D,N); + } + + + // multiply polynomial by new term(s) + + FPoly F; + if (conj) + { // conjugate pair + // t^2-2a+(a^2+b^2) , where cinv=a+ib + F.addterm((Float)1,2); + F.addterm(-2*real(cinv),1); + F.addterm(real(cinv)*real(cinv)+imaginary(cinv)*imaginary(cinv),0); + } + else + { // t-cinv + F.addterm((Float)1,1); + F.addterm(-real(cinv),0); + +// store as a linear polynomial, or combine 2 to make a quadratic + if (T[0].iszero()) + { + T[0]=F; + return; + } + else + { + F=T[0]*F; // got a quadratic + T[0].clear(); + } + } + +// accumulate Polynomial as 2^m degree components +// This allows the use of karatsuba via the "special" function +// This is the time critical bit.... + + for (i=1;;i++) + { + if (T[i].iszero()) + { + T[i]=F; // store this 2^i degree polynomial + break; + } + else + { + F=special(T[i],F); // e.g. if i=1 two quadratics make a quartic.. + T[i].clear(); + } + } +} + +// A.13.2 +// Set P1363 to False to calculate class number a la Cohen + +int groups(Complex& lam,Float *Fi2,unsigned long D,BOOL doit,BOOL P1363) +{ + unsigned long s,t,A,C,B,TB,lim; + int cn=0; + s=mr_lsqrt(D/3,1); + for (B=0;B<=s;B+=1) + { +// cout << "B= " << B << " s= " << s << endl; + t=D+B*B; + if (!P1363) + { + if (t%4!=0) continue; + else t/=4; + } +// cout << "t= " << t << endl; + lim=mr_lsqrt(t,1); +// cout << "lim= " << lim << endl; + if (P1363) A=2*B; + else A=B; + if (A==0) A+=1; + for(;;) + { + while (t%A!=0) + { + A+=1; + if (A>lim) break; + } + + if (A>lim) break; + C=t/A; + + TB=B; + if (P1363) TB*=2; + if (lgcd(lgcd(A,TB),C)==1) + { // output more class group members + BOOL conj; + if (TB>0 && C>A && A>TB) + { + conj=TRUE; + cn+=2; + if (doit) + { + if (!suppress) cout << ".." << flush; + } + } + else + { + conj=FALSE; + cn+=1; + if (doit) + { + if (!suppress) cout << "." << flush; + } + } + if (doit) class_poly(lam,Fi2,(Big)A,(Big)B,(Big)C,(Big)D,conj,P1363); + } + A+=1; + } + } + return cn; // class number +} + +// check congruence conditions A14.2.1 + +BOOL isaD(unsigned long d,int pm8,Big k) +{ + unsigned int dm8; + unsigned long i; + BOOL sqr; + dm8=d%8; + if (k==1 && dm8!=3) return FALSE; + if ((k==2 || k==3) && dm8==7) return FALSE; + if (pm8==3 && (dm8==1 || dm8==4 || dm8==5 || dm8==6)) return FALSE; + if (pm8==5 && dm8%2==0) return FALSE; + if (pm8==7 && (dm8==1 || dm8==2 || dm8==4 || dm8==5)) return FALSE; + sqr=FALSE; + for (i=2;;i++) + { + if (d%(i*i)==0) + { + sqr=TRUE; + break; + } + if (i*i>d) break; + } + if (sqr) return FALSE; + return TRUE; +} + +// Testing for CM discriminants A.14.2.2 + +Big floor(Big N,Big D) +{ + Big R; + if (N==0) return 0; + if (N>0 && D>0) return N/D; + if (N<0 && D<0) return (-N)/(-D); + R=N/D; + if (N%D!=0) R-=1; + return R; +} + +BOOL isacm(Big p,unsigned long D,Big &W,Big &V) +{ + Big B2,A,B,C,t,X,Y,ld,delta; + B=sqrt(p-(Big)D,p); + A=p; + C=(B*B+(Big)D)/p; + X=1; + Y=0; + ld=0; + + while (1) + { + if (C>=A) + { + B2=2*B; + if (B2<0) B2=-B2; + if (A>=B2) break; + } + delta=floor(2*B+C,2*C); + +// are we stuck in hopeless loop? This can't happen now - thanks Marcel + + if (delta==0 && ld==0) return FALSE; + ld=delta; + t=X; + X=(delta*X+Y); + Y=-t; + + t=C; + + C=(A+C*delta*delta-2*B*delta); + B=(t*delta-B); + A=t; + } + if (D==11 && A==3) + { + t=X; + X=Y; + Y=-t; + B=-B; + t=C; + C=A; + A=t; + } + if (D==1 || D==3) + { + W=2*X; + V=2*Y; + return TRUE; + } + else V=0; + + if (A==1) + { + W=2*X; + return TRUE; + } + + if (A==4) + { + W=4*X+B*Y; + return TRUE; + } + + return FALSE; +} + + +// Constructing a Curve (and Point if order is prime) +// A.14.4 + +BOOL get_curve(Complex& lam,Float *Fi2,ofstream& ofile,Big r,Big other_r,Big ord,unsigned long D,Big p,Big W,int m,BOOL always) +{ + Poly polly; + Big A0,B0,k; + BOOL unstable; + char c; + int i,j,terms,class_number; + BOOL P1363,pord=prime(ord); + + P1363=TRUE; + if (!always && D>3 && D%8==3) P1363=FALSE; + + k=r; + while (k%ord==0) k/=ord; + + if (!suppress) + { + if (D>1000 && D%3==0) cout << "D= " << D << " (Divisible by 3 - might need extra precision)" << endl; + else cout << "D= " << D << endl; + if (P1363) cout << "IEEE-1363 invariant" << endl; + else + { + switch (getN(D)) + { + case 2: cout << "Gamma2 invariant" << endl; + break; + case 3: cout << "w3 invariant" << endl; + break; + case 5: cout << "w5 invariant" << endl; + break; + case 7: cout << "w7 invariant" << endl; + break; + case 13: cout << "w13 invariant" << endl; + break; + } + } + cout << "D mod 24 = " << D%24 << endl; + if (prime(ord)) cout << "K= " << k << endl; + } + + class_number=groups(lam,Fi2,D,FALSE,P1363); + + cout << "class number= " << class_number << endl; + + cout << "Group order= " << ord << endl; + cout << "do you want to proceed with this one (Y/N)? " ; + cin >> c; + if (c=='N' || c=='n') + { + if (!suppress) cout << "finding a curve..." << endl; + return FALSE; + } + + modulo(p); + +// A.14.4.1 + + if (D==1) + { + A0=1; B0=0; + } + if (D==3) + { + A0=0; B0=1; + } + + if (D!=1 && D!=3) + { + FPoly Acc; + + for (i=0;i<25;i++) T[i].clear(); + if (!suppress) cout << "constructing polynomial"; + groups(lam,Fi2,D,TRUE,P1363); + +// Construct Polynomial from its 2^m degree components.. + + for (i=24;i>=0;i--) + { + if (!T[i].iszero()) + { + Acc=T[i]; // find the first component.. + T[i].clear(); + break; + } + } + if (i>0) + { + for (j=i-1;j>0;j--) + { + if (!T[j].iszero()) + { + Acc=special(Acc,T[j]); // special karatsuba function + T[j].clear(); // multiply into accumulator + } + } + if (!T[0].iszero()) + { // check for a left-over linear poly + Acc=Acc*T[0]; + T[0].clear(); + } + } + for (i=0;i<25;i++) T[i].clear(); + + terms=degree(Acc); + Float f,rem; + Big whole; + int nbits,maxbits=0; + + unstable=FALSE; + for (i=terms;i>=0;i--) + { + f=Acc.coeff(i); + if (f>0) + f+=makefloat(1,10000); + else f-=makefloat(1,10000); + whole=f.trunc(&rem); + nbits=bits(whole); + if (nbits>maxbits) maxbits=nbits; + polly.addterm((ZZn)whole,i); + if (fabs(rem)>makefloat(1,100)) + { + unstable=TRUE; + break; + } + } + Acc.clear(); + if (!suppress) cout << endl; + if (unstable) + { + if (!suppress) cout << "Curve abandoned - numerical instability!" << endl; + if (!suppress) cout << "Curve abandoned - double MIRACL precision and try again!" << endl; + if (!suppress) cout << "finding a curve..." << endl; + return FALSE; + } + if (!suppress) + { + cout << polly << endl; + cout << "Maximum precision required in bits= " << maxbits << endl; + } + } + +// save space with smaller miracl + + mirexit(); + mip=mirsys(128,0); + modulo(p); + + ECn pt,G; + Big a,b,x,y; + Big w,eps; + int at; + Poly g,spolly=polly; // smaller polly + polly.clear(); + forever + { + if (D!=1 && D!=3) + { + if (!suppress) cout << "Factoring polynomial of degree " << degree(spolly) << " ....." << endl; + + if (P1363) + { + if (W%2==0) + { + ZZn V; + g=factor(spolly,1); + V=-g.coeff(0); + V=pow(V,24/(lgcd(D,3)*getk(D))); + V*=pow((ZZn)2,(4*geti(D))/getk(D)); + if (D%2!=0) V=-V; + A0=(Big)((ZZn)(-3)*(V+64)*(V+16)); + B0=(Big)((ZZn)2*(V+64)*(V+64)*(V-8)); + } + else + { + Poly V,w,w1,w2,w3,a,b; + + g=factor(spolly,3); + if (D%3!=0) + w.addterm(-1,24); + else + w.addterm(-256,8); + V=w%g; + w.clear(); + w1=V; w2=V; w3=V; + w1.addterm(64,0); + w2.addterm(256,0); + w3.addterm(-512,0); + a=w1*w2; + a.multerm(-3,0); + a=a%g; + b=w1*w1*w3; + b.multerm(2,0); + b=b%g; + + a=((a*a)*a)%g; + b=(b*b)%g; + for (int d=degree(g)-1;d>=0;d--) + { + ZZn t,c=a.coeff(d); + if (c!=(ZZn)0) + { + t=b.coeff(d); + A0=(Big)(c*t); + B0=(Big)(c*t*t); + if (d==1) break; + } + } + } + } + else + { + ZZn X,J,X2,K; + + g=factor(spolly,1); + X=-g.coeff(0); + X2=X*X; + switch (getN(D)) + { + case 2: J=X2*X; + break; + case 3: J=(pow((X+3),3)*(X+27))/X; + break; + case 5: J=pow((X2+10*X+5),3)/X; + break; + case 7: J=(pow((X2+5*X+1),3)*(X2+13*X+49))/X; + break; + case 13: J=(pow((X2*X2+7*X2*X+20*X2+19*X+1),3)*(X2+5*X+13))/X; + default: break; + } + K=J/(J-1728); + A0=-3*K; + B0=2*K; + } + + } + +// A.14.4.2 +// but try -3 first, followed by small positive values for A + + a=A0; + b=B0; + at=-3; + if (D==3) at=1; + forever + { + if (D==1) + { + if (at<100) + eps=(ZZn)at/(ZZn)A0; + else eps=rand(p); + a=modmult(A0,eps,p); + } + if (D==3) + { + if (at<100) + eps=(ZZn)at/(ZZn)B0; + else eps=rand(p); + b=modmult(B0,eps,p); + } + if (D!=1 && D!=3) + { + if (at<100) + { // transform a to be simple if possible + w=(ZZn)at/ZZn(A0); + if (jacobi(w,p)!=1) + { + if (at==-3) at=1; + else at++; + continue; + } + eps=sqrt(w,p); + } else eps=rand(p); + a=modmult(A0,pow(eps,2,p),p); + b=modmult(B0,pow(eps,3,p),p); + } + ecurve(a,b,p,MR_PROJECTIVE); + for (int xc=1;;xc++) + { + if (!pt.set((Big)xc)) continue; + pt*=k; + if (pt.iszero()) continue; + break; + } + G=pt; // check its not the other one... + + if (r!=ord || !(other_r*G).iszero()) + { + pt*=ord; + if (pt.iszero()) break; + } + + if (at==-3) at=1; + else at++; + } + if (a==(p-3)) a=-3; + + if (D!=1 && D!=3 && three && a!=-3) continue; + +// check MOV condition +// A.12.1 + + BOOL MOV=TRUE; + + w=1; + for (i=1;i<100;i++) + { + w=modmult(w,p,ord); + if (w==1) + { + MOV=FALSE; + if (!suppress) + { + if (i==1 || pord) cout << "\n*** Failed MOV condition - k = " << i << endl; + else cout << "\n*** Failed MOV condition - k <= " << i << endl; + } + break; + } + } + + if (!suppress) + { + if (MOV) cout << "MOV condition OK" << endl; + if (pord) cout << "\nCurve and Point Found" << endl; + else cout << "\nCurve Found" << endl; + } + + cout << "A= " << a << endl; + cout << "B= " << b << endl; + G.get(x,y); + cout << "P= " << p << endl; + cout << "R= " << ord; + if (pord) + { + cout << " a " << bits(ord) << " bit prime" << endl; + cout << "X= " << x << endl; + cout << "Y= " << y << endl; + } + else cout << " NOT prime" << endl; + cout << endl; + + if (D!=1 && D!=3 ) + { + cout << "Try for different random factorisation (Y/N)? "; + cin >> c; + if (c=='Y' || c=='y') continue; + } + break; + } + if (pord) cout << "\nCurve and Point OK (Y/N)? " ; + else cout << "\nCurve OK (Y/N)? " ; + cin >> c; + if (c=='N' || c=='n') + { + if (!suppress) cout << "finding a curve..." << endl; + mirexit(); + int precision=(1<RPOINT=ON; + + + return FALSE; + } + if (fout) + { + ofile << bits(p) << endl; + mip->IOBASE=16; + ofile << p << endl; + ofile << a << endl; + ofile << b << endl; + ofile << ord << endl; + if (pord) + { + ofile << x << endl; + ofile << y << endl; + } + mip->IOBASE=10; + } + exit(0); + return TRUE; +} + +// Code to parse formula +// This code isn't mine, but its public domain +// Shamefully I forget the source +// +// NOTE: It may be necessary on some platforms to change the operators * and # + +#if defined(unix) +#define TIMES '.' +#define RAISE '^' +#else +#define TIMES '*' +#define RAISE '#' +#endif + +void eval_power (Big& oldn,Big& n,char op) +{ + if (op) n=pow(oldn,toint(n)); // power(oldn,size(n),n,n); +} + +void eval_product (Big& oldn,Big& n,char op) +{ + switch (op) + { + case TIMES: + n*=oldn; + break; + case '/': + n=oldn/n; + break; + case '%': + n=oldn%n; + } +} + +void eval_sum (Big& oldn,Big& n,char op) +{ + switch (op) + { + case '+': + n+=oldn; + break; + case '-': + n=oldn-n; + } +} + +void eval (Big& t) +{ + Big oldn[3]; + Big n; + int i; + char oldop[3]; + char op; + char minus; + for (i=0;i<3;i++) + { + oldop[i]=0; + } +LOOP: + while (*s==' ') + s++; + if (*s=='-') /* Unary minus */ + { + s++; + minus=1; + } + else + minus=0; + while (*s==' ') + s++; + if (*s=='(' || *s=='[' || *s=='{') /* Number is subexpression */ + { + s++; + eval(t); + n=t; + } + else /* Number is decimal value */ + { + for (i=0;s[i]>='0' && s[i]<='9';i++) + ; + if (!i) /* No digits found */ + { + cout << "Error - invalid number" << endl; + exit (20); + } + op=s[i]; + s[i]=0; + n=atoi(s); + s+=i; + *s=op; + } + if (minus) n=-n; + do + op=*s++; + while (op==' '); + if (op==0 || op==')' || op==']' || op=='}') + { + eval_power (oldn[2],n,oldop[2]); + eval_product (oldn[1],n,oldop[1]); + eval_sum (oldn[0],n,oldop[0]); + t=n; + return; + } + else + { + if (op==RAISE) + { + eval_power (oldn[2],n,oldop[2]); + oldn[2]=n; + oldop[2]=RAISE; + } + else + { + if (op==TIMES || op=='/' || op=='%') + { + eval_power (oldn[2],n,oldop[2]); + oldop[2]=0; + eval_product (oldn[1],n,oldop[1]); + oldn[1]=n; + oldop[1]=op; + } + else + { + if (op=='+' || op=='-') + { + eval_power (oldn[2],n,oldop[2]); + oldop[2]=0; + eval_product (oldn[1],n,oldop[1]); + oldop[1]=0; + eval_sum (oldn[0],n,oldop[0]); + oldn[0]=n; + oldop[0]=op; + } + else /* Error - invalid operator */ + { + cout << "Error - invalid operator" << endl; + exit (20); + } + } + } + } + goto LOOP; +} + +int main(int argc,char **argv) +{ + BOOL good,dir,always; + int i,ip,m,precision; + unsigned long SD,D; + ofstream ofile; + + mip=mirsys(128,0); + Big p,k,t; + + argv++; argc--; + + irand(0L); + if (argc<1) + { + cout << "Incorrect Usage" << endl; + cout << "Program tries to find Elliptic Curve mod a prime P and point of prime order" << endl; + cout << "that is a point (X,Y) on the curve y^2=x^3+Ax+B of order R" << endl; + cout << "where R is large and prime > |P/K|. (K defaults to 256)" << endl; + cout << "cm " << endl; + cout << "OR" << endl; + cout << "cm -f " << endl; +#if defined(unix) + cout << "e.g. cm -f 2^192-2^64-1" << endl; +#else + cout << "e.g. cm -f 2#192-2#64-1" << endl; +#endif + cout << "To suppress commentary, use flag -s. To insist on A= -3, use flag -t" << endl; + cout << "(the commentary will make some sense to readers of IEEE 1363 Annex)" << endl; + cout << "To search downwards for a prime, use flag -d" << endl; + cout << "To output to a file, use flag -o " << endl; + cout << "To set maximum co-factor size K, use e.g. flag -K8" << endl; + cout << "To set infinite co-factor size K, use flag -K0" << endl; + cout << "(In this case the reported R is the number of points on the curve)" << endl; + cout << "To start searching from a particular D value, use e.g. flag -D10000" << endl; + cout << "To set MIRACL precision to 2^n words, use e.g. flag -Pn (default -P5)" << endl; + cout << "If program fails, try again with n=n+1" << endl; + cout << "To insist on IEEE-1363 invariants, use flag -IEEE" << endl; +#if defined(unix) + cout << "e.g. cm -f 2^224-2^96+1 -K12 -D4000000 -P9 -o common.ecs" << endl; +#else + cout << "e.g. cm -f 2#224-2#96+1 -K12 -D4000000 -P9 -o common.ecs" << endl; +#endif + cout << "Freeware from Certivox, Dublin, Ireland" << endl; + cout << "Full C++ source code and MIRACL multiprecision library available" << endl; + cout << "Email to mscott@indigo.ie for details" << endl; + return 0; + } + + gprime(1000); + m=5; + ip=0; + k=256; + SD=1; + suppress=FALSE; + fout=FALSE; + dir=FALSE; + three=FALSE; + always=FALSE; + p=0; + while (ip2048) + { + cout << "Prime is too big - sorry" << endl; + return 0; + } + + + Big W,V,K,r1,r2,ord,rmin; + + if (k==0) rmin=1; + else rmin=(p-2*sqrt(p))/k; + if (rmin==0) + { + cout << "Bad k co-factor value" << endl; + return 0; + } + + W=sqrt(p)+1; + K=(W*W)/rmin; + + if (!suppress) cout << "P mod 8 = " << p%8 << endl; + if (!suppress) cout << "P is " << bits(p) << " bits long" << endl; + if (!suppress) cout << "precomputations..." << endl; + + mirexit(); + + if (m<4) m=4; + + precision=(1<PRIMES[i]; + if (D==sp || sp*sp>D) break; + if (D%sp==0 && jacobi(p,(Big)sp)==-1) + { + good=FALSE; + break; + } + } + if (!good) continue; + if (!isacm(p,D,W,V)) continue; + + r1=p+1+W; + r2=p+1-W; + + if (k==0) ord=r1; + else + { + ord=trial_divide(r1); + if (!prime(ord) && r1%k==0) ord=r1/k; + } + if (ord==1) ord=r1; + + if (ord>=rmin && (k==0 || prime(ord))) + get_curve(lam,Fi2,ofile,r1,r2,ord,D,p,W,m,always); + + if (k==0) ord=r2; + else + { + ord=trial_divide(r2); + if (!prime(ord) && r2%k==0) ord=r2/k; + } + if (ord==1) ord=r2; + + if (ord>=rmin && (k==0 || prime(ord))) + get_curve(lam,Fi2,ofile,r2,r1,ord,D,p,W,m,always); + + if (D==1) + { + r1=p+1+V; + r2=p+1-V; + if (k==0) ord=r1; + else + { + ord=trial_divide(r1); + if (!prime(ord) && r1%k==0) ord=r1/k; + } + if (ord==1) ord=r1; + if (ord>=rmin && (k==0 || prime(ord))) + get_curve(lam,Fi2,ofile,r1,r2,ord,D,p,W,m,always); + + if (k==0) ord=r2; + else + { + ord=trial_divide(r2); + if (!prime(ord) && r2%k==0) ord=r2/k; + } + if (ord==1) ord=r2; + if (ord>=rmin && (k==0 || prime(ord))) + get_curve(lam,Fi2,ofile,r2,r1,ord,D,p,W,m,always); + + } + if (D==3) + { + r1=p+1+(W+3*V)/2; + r2=p+1-(W+3*V)/2; + if (k==0) ord=r1; + else + { + ord=trial_divide(r1); + if (!prime(ord) && r1%k==0) ord=r1/k; + } + if (ord==1) ord=r1; + if (ord>=rmin && (k==0 || prime(ord))) + get_curve(lam,Fi2,ofile,r1,r2,ord,D,p,W,m,always); + + if (k==0) ord=r2; + else + { + ord=trial_divide(r2); + if (!prime(ord) && r2%k==0) ord=r2/k; + } + if (ord==1) ord=r2; + if (ord>=rmin && (k==0 || prime(ord))) + get_curve(lam,Fi2,ofile,r2,r1,ord,D,p,W,m,always); + + r1=p+1+(W-3*V)/2; + r2=p+1-(W-3*V)/2; + if (k==0) ord=r1; + else + { + ord=trial_divide(r1); + if (!prime(ord) && r1%k==0) ord=r1/k; + } + if (ord==1) ord=r1; + if (ord>=rmin && (k==0 || prime(ord))) + get_curve(lam,Fi2,ofile,r1,r2,ord,D,p,W,m,always); + + if (k==0) ord=r2; + else + { + ord=trial_divide(r2); + if (!prime(ord) && r2%k==0) ord=r2/k; + } + if (ord==1) ord=r2; + if (ord>=rmin && (k==0 || prime(ord))) + get_curve(lam,Fi2,ofile,r2,r1,ord,D,p,W,m,always); + } + } + cout << "No satisfactory curve found" << endl; + return 0; +} + + diff --git a/miracl/source/curve/cm.txt b/miracl/source/curve/cm.txt new file mode 100644 index 0000000..35c7444 --- /dev/null +++ b/miracl/source/curve/cm.txt @@ -0,0 +1,131 @@ + +NOTE: as of version 4.81 the CM program has been much improved. It is now up +to 100 times faster than the original. See comments in cm.cpp + +A precompiled Windows executable is available from +ftp://ftp.compapp.dcu.ie/pub/crypto/cm.exe + +To build the CM application, you must compile and link the modules +together, and with the MIRACL library. + +So for Borland C++ + +bcc32 cm.cpp poly.cpp flpoly.cpp complex.cpp floating.cpp big.cpp zzn.cpp +ecn.cpp miracl.lib + +On UNIX using g++, something like + +g++ -I. -c poly.cpp +g++ -I. -c flpoly.cpp +g++ -I. -c complex.cpp +g++ -I. -c floating.cpp + +g++ -I. cm.cpp poly.o flpoly.o complex.o floating.o big.o zzn.o ecn.o +miracl.a /usr/lib/libm.a -o cm + +should work + + +For best performance, use a KCM build of MIRACL, with MR_KCM defined in +mirdef.h to be a power of 2, for example 8. + + +For example on a PC use this mirdef.h file + +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype __int64 +#define mr_unsign64 unsigned __int64 +#define MR_FLASH 52 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_KCM 16 +#define MR_BITSINCHAR 8 + + +and compile and run the mex utility + +mex 16 ms86 mrkcm + +This creates mrkcm.c + + +IMPORTANT! + +If you have a Pentium 4 processor (which has SSE2 extensions), use + +mex 16 sse2 mrkcm + +to create mrkcm.c This will be much faster. + + +Remember to include the module mrkcm.obj in the library - using MS C +execute + + +cl /c /O2 /W3 mrcore.c +cl /c /O2 /W3 mrarth0.c +cl /c /O2 /W3 mrarth1.c +cl /c /O2 /W3 mrarth2.c +cl /c /O2 /W3 mralloc.c +cl /c /O2 /W3 mrsmall.c +cl /c /O2 /W3 mrio1.c +cl /c /O2 /W3 mrio2.c +cl /c /O2 /W3 mrgcd.c +cl /c /O2 /W3 mrjack.c +cl /c /O2 /W3 mrxgcd.c +cl /c /O2 /W3 mrarth3.c +cl /c /O2 /W3 mrrand.c +cl /c /O2 /W3 mrprime.c +cl /c /O2 /W3 mrcrt.c +cl /c /O2 /W3 mrscrt.c +cl /c /O2 /W3 mrmonty.c +cl /c /O2 /W3 mrpower.c +cl /c /O2 /W3 mrsroot.c +cl /c /O2 /W3 mrbits.c +cl /c /O2 /W3 mrcurve.c +cl /c /O2 /W3 mrfast.c +cl /c /O2 /W3 mrlucas.c +cl /c /O2 /W3 mrshs.c +cl /c /O2 /W3 mrshs256.c +cl /c /O2 /W3 mrshs512.c +cl /c /O2 /W3 mraes.c +cl /c /O2 /W3 mrgcm.c +cl /c /O2 /W3 mrstrong.c +cl /c /O2 /W3 mrbrick.c +cl /c /O2 /W3 mrebrick.c +cl /c /O2 /W3 mrec2m.c +cl /c /O2 /W3 mrgf2m.c +cl /c /O2 /W3 mrflash.c +cl /c /O2 /W3 mrfrnd.c +cl /c /O2 /W3 mrdouble.c +cl /c /O2 /W3 mrround.c +cl /c /O2 /W3 mrbuild.c +cl /c /O2 /W3 mrflsh1.c +cl /c /O2 /W3 mrpi.c +cl /c /O2 /W3 mrflsh2.c +cl /c /O2 /W3 mrflsh3.c +cl /c /O2 /W3 mrflsh4.c +cl /c /O2 /W3 mrkcm.c +cl /c /O2 /W3 mrmuldv.c + +del miracl.lib + +lib /OUT:miracl.lib mrflsh4.obj mrflsh3.obj mrflsh2.obj mrpi.obj mrflsh1.obj +lib /OUT:miracl.lib miracl.lib mrdouble.obj mrflash.obj mrfrnd.obj mrround.obj mrbuild.obj +lib /OUT:miracl.lib miracl.lib mrio2.obj mrio1.obj mrrand.obj mrprime.obj mrcrt.obj mrscrt.obj mrbits.obj mrfast.obj +lib /OUT:miracl.lib miracl.lib mrjack.obj mrxgcd.obj mrgcd.obj mrarth3.obj mrarth2.obj mrpower.obj mrsroot.obj +lib /OUT:miracl.lib miracl.lib mrmonty.obj mralloc.obj mrarth1.obj mrarth0.obj mrsmall.obj mrcore.obj mrmuldv.obj +lib /OUT:miracl.lib miracl.lib mrcurve.obj mrshs.obj mraes.obj mrlucas.obj mrstrong.obj mrbrick.obj mrgcm.obj +lib /OUT:miracl.lib miracl.lib mrshs256.obj mrshs512.obj mrebrick.obj mrgf2m.obj mrec2m.obj mrkcm.obj +del mr*.obj + +cl /O2 /GX cm.cpp poly.cpp flpoly.cpp complex.cpp floating.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + diff --git a/miracl/source/curve/complex.cpp b/miracl/source/curve/complex.cpp new file mode 100644 index 0000000..5527361 --- /dev/null +++ b/miracl/source/curve/complex.cpp @@ -0,0 +1,160 @@ +#include "complex.h" + +#include +using namespace std; + +BOOL Complex::iszero() const +{ if (x.iszero() && y.iszero()) return TRUE; return FALSE; } + +Complex& Complex::operator=(const Complex& a) +{x=a.x; y=a.y; return *this;} + +Complex& Complex::operator+=(const Complex& a) +{x+=a.x; y+=a.y; return *this;} + +Complex& Complex::operator-=(const Complex& a) +{x-=a.x; y-=a.y; return *this;} + +Complex& Complex::operator*=(const Complex& a) +{ // using karatsuba.... + Float t,t1,t2; + + if (this==&a) + { // squaring - a bit faster + +// x=(x+y)(x-y), y=2xy + + t=x; t+=y; t1=x; t1-=y; t*=t1; + y*=x; + y*=2; + x=t; + return *this; + } + +// x=x*a.x-y*a.y, y=(x+y)*(a.x+a.y) - x*a.x - y*a.y; + + t=x; t*=a.x; + t2=y; t2*=a.y; + t1=a.x; t1+=a.y; + y+=x; y*=t1; y-=t; y-=t2; + t-=t2; x=t; + + return *this; +} + +Complex& Complex::operator/=(const Complex& a) +{Float t,d=reciprocal(a.x*a.x+a.y*a.y); + t=(x*a.x+y*a.y)*d; y=(y*a.x-x*a.y)*d; x=t; return *this;} + +Complex& Complex::operator/=(const Float& f) +{ + Float t=reciprocal(f); + x*=t; + y*=t; + return *this; +} + +Float real(const Complex &a) {Float f; f=a.x; return f;} +Float imaginary(const Complex &a) {Float f; f=a.y; return f;} + +Complex recip(const Complex &a) +{ + Complex c=a; + Float d=reciprocal(c.x*c.x+c.y*c.y); + c.x*=d; + c.y*=d; + c.y.negate(); + return c; +} + +Complex operator-(const Complex& a) +{Complex c=a; c.x.negate(); c.y.negate(); return c;} + +BOOL operator==(const Complex& a,const Complex& b) +{ if (a.x==b.x && a.y==b.y) return TRUE; else return FALSE;} + +BOOL operator!=(const Complex& a,const Complex& b) +{ if (a.x!=b.x || a.y!=b.y) return TRUE; else return FALSE;} + +Complex operator+(const Complex &a,const Complex &b) +{Complex c=a; c+=b; return c;} + +Complex operator-(const Complex &a,const Complex &b) +{Complex c=a; c-=b; return c;} + +Complex operator*(const Complex &a,const Complex &b) +{Complex c=a; c*=b; return c;} + +Complex operator/(const Complex &a,const Complex &b) +{Complex c=a; c/=b; return c; } + +Complex exp(const Complex& a) +{ + + Complex c; + Float t,d,e=a.y; + + d=exp(a.x); + t=cos(e); + c.x=d*t; + t=sqrt(1-t*t); + if (norm(2,e)==MINUS) t.negate(); + c.y=d*t; + + return c; +} + +Complex pow(const Complex& a,int b) +{ + Complex w=1; + Complex c=a; + + if (b==0) return w; + if (b==1) return c; + forever + { + if (b%2!=0) w*=c; + b/=2; + if (b==0) break; + c*=c; + } + return w; +} + +ostream& operator<<(ostream& s,const Complex& a) +{ + s << "(" << a.x << "," << a.y << ")"; + return s; +} + +// Note - this function is flawed...it only returns the POSITIVE root +Complex sqrt(Complex &c) +{ + if(c.y != 0 || c.x < 0) { + Float r = sqrt(c.x*c.x + c.y*c.y); + Float b = sqrt((r-c.x)/2); + Float a = c.y/(2*b); + c.x = a; + c.y = b; + } else { + Float r = sqrt(c.x); + c.x = r; + } + return c; +} + +// Get the absolute value of the complex number squared +// |z|^2 = x^2 + y^2 +Float norm2(const Complex &a) +{ + Float f; + f = (a.x * a.x) + (a.y * a.y); + return f; +} + +Float norm(const Complex &a) +{ + Float f; + f = (a.x * a.x) + (a.y * a.y); + return sqrt(f); +} diff --git a/miracl/source/curve/complex.h b/miracl/source/curve/complex.h new file mode 100644 index 0000000..3830507 --- /dev/null +++ b/miracl/source/curve/complex.h @@ -0,0 +1,54 @@ +/* + * Quick and dirty complex data type using float arithmetic + * Should be extended + */ + + +#ifndef COMFLOAT_H +#define COMFLOAT_H + +#include "floating.h" + +class Complex +{ + Float x,y; +public: + Complex() {x=(Float)0; y=(Float)0; } + Complex(int a) {x=(Float)a; y=(Float)0; } + Complex(const Float& a) {x=a; y=(Float)0; } + Complex(const Float& a,const Float& b) {x=a;y=b;} + Complex(const Complex& a) {x=a.x;y=a.y;} + + Complex& operator=(const Complex &); + Complex& operator+=(const Complex &); + Complex& operator-=(const Complex &); + Complex& operator*=(const Complex &); + Complex& operator/=(const Complex &); + Complex& operator/=(const Float &); + + BOOL iszero() const; + + friend Float real(const Complex &); + friend Float imaginary(const Complex &); + friend Float norm2(const Complex &); + friend Float norm(const Complex &); + friend Complex recip(const Complex &); + + friend Complex operator-(const Complex&); + + friend BOOL operator==(const Complex&,const Complex&); + friend BOOL operator!=(const Complex&,const Complex&); + + friend Complex operator+(const Complex &, const Complex &); + friend Complex operator-(const Complex &, const Complex &); + friend Complex operator*(const Complex &, const Complex &); + friend Complex operator/(const Complex &, const Complex &); + friend Complex exp(const Complex &); + friend Complex pow(const Complex &,int); + friend Complex sqrt(Complex &); + friend ostream& operator<<(ostream&,const Complex&); + ~Complex() {} +}; + +#endif + diff --git a/miracl/source/curve/flpoly.cpp b/miracl/source/curve/flpoly.cpp new file mode 100644 index 0000000..94a277f --- /dev/null +++ b/miracl/source/curve/flpoly.cpp @@ -0,0 +1,468 @@ +/* + * C++ class to implement a polynomial type and to allow + * arithmetic on polynomials whose elements are float numbers + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.6 + */ + +#include "flpoly.h" + +#include +using namespace std; + +FPoly::FPoly(const FPoly& p) +{ + fterm *ptr=p.start; + fterm *pos=NULL; + start=NULL; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->n,pos); + ptr=ptr->next; + } +} + +FPoly::~FPoly() +{ + fterm *nx; + while (start!=NULL) + { + nx=start->next; + delete start; + start=nx; + } +} + +BOOL FPoly::iszero() const +{ + if (start==NULL) return TRUE; + else return FALSE; +} + +FPoly& FPoly::operator*=(const Float& x) +{ + fterm *ptr=start; + while (ptr!=NULL) + { + ptr->an*=x; + ptr=ptr->next; + } + return *this; +} + +FPoly operator*(const FPoly& x,const Float& y) +{ + FPoly z=x; + z*=y; + return z; +} + +Float FPoly::coeff(int power) const +{ + fterm *ptr=start; + while (ptr!=NULL) + { + if (ptr->n==power) return ptr->an; + ptr=ptr->next; + } + return (Float)0; +} + +FPoly& FPoly::divxn(FPoly& a,int n) +{ + fterm *lptr=NULL; + fterm *ptr=start; + + while(ptr!=NULL) + { + if (ptr->nnext=NULL; + break; + } + else + { + ptr->n-=n; + } + lptr=ptr; + ptr=ptr->next; + } + return *this; +} + +FPoly& FPoly::mulxn(int n) +{ + fterm *ptr=start; + while (ptr!=NULL) + { + ptr->n+=n; + ptr=ptr->next; + } + return *this; +} + +// fast Karatsuba multiplication of polynomials with n terms, where n=2^m + +FPoly twobytwo(const FPoly& a,const FPoly& b) +{ // a and b both have 2 terms (a1.x+a0)*(b1.x+b0) + FPoly R; + + Float a0,b0,a1,b1,ax; + fterm *ptr,*pos=NULL; + + ptr=a.start; + while (ptr!=NULL) + { + if (ptr->n==1) a1=ptr->an; + if (ptr->n==0) a0=ptr->an; + ptr=ptr->next; + } + + ptr=b.start; + while (ptr!=NULL) + { + if (ptr->n==1) b1=ptr->an; + if (ptr->n==0) b0=ptr->an; + ptr=ptr->next; + } + + ax=a0; ax*=b0; + + a0+=a1; b0+=b1; a0*=b0; + a0-=ax; + + a1*=b1; + a0-=a1; + + pos=R.addterm(a1,2,pos); + pos=R.addterm(a0,1,pos); + pos=R.addterm(ax,0,pos); + + return R; +} + +FPoly pow2bypow2(const FPoly &a,const FPoly &b,int deg) +{ // a and b are both have 2^n terms + + if (deg==2) return twobytwo(a,b); + + FPoly higha,lowa,highb,lowb,highr,lowr,midr; + int half=deg/2; + + higha=a; // chop into low and high halves + higha.divxn(lowa,half); + + highb=b; + highb.divxn(lowb,half); + + lowr =pow2bypow2(lowa,lowb,half); // Karatsuba recursion + highr=pow2bypow2(higha,highb,half); + + higha+=lowa; + highb+=lowb; + + midr =pow2bypow2(higha,highb,half); + midr-=lowr; + midr-=highr; + + midr.mulxn(half); + highr.mulxn(2*half); + + lowr+=midr; + lowr+=highr; + + return lowr; +} + +FPoly powsof2(const FPoly& a,int n,const FPoly& b,int m) +{ // a has n terms, b has m terms with n >= m amd m|n and m=2^i + + if (n==m) return pow2bypow2(a,b,n); + FPoly r,q,w,t; + int i,c=0; + + q=a; + for (i=0;inext; + delete ptr; + + ptr=y.start; // remove x^m term + y.start=ptr->next; + delete ptr; + + if (n>=m) w=powsof2(x,n,y,m); + else w=powsof2(y,m,x,n); + + x.mulxn(m); + w+=x; + y.mulxn(n); + w+=y; + + w.addterm((Float)1,m+n); + return w; +} + +FPoly operator*(const FPoly& a,const FPoly& b) +{ + FPoly prod; + fterm *iptr,*pos; + fterm *ptr; + miracl *mip=get_mip(); + + if (&a==&b) + { // squaring + pos=NULL; + ptr=b.start; + while (ptr!=NULL) + { // diagonal terms + pos=prod.addterm(ptr->an*ptr->an,ptr->n+ptr->n,pos); + ptr=ptr->next; + } + ptr=b.start; + while (ptr!=NULL) + { // above the diagonal + iptr=ptr->next; + pos=NULL; + while (iptr!=NULL) + { + pos=prod.addterm(2*ptr->an*iptr->an,ptr->n+iptr->n,pos); + iptr=iptr->next; + } + ptr=ptr->next; + } + } + else + { + ptr=b.start; + + mip->same=TRUE; // multiplying by a constant + while (ptr!=NULL) + { + pos=NULL; + iptr=a.start; + mip->first_one=FALSE; + // first multiplication by this constant needed + while (iptr!=NULL) + { + pos=prod.addterm(iptr->an*ptr->an,iptr->n+ptr->n,pos); + iptr=iptr->next; + } + ptr=ptr->next; + } + mip->same=FALSE; + } + return prod; +} + +int degree(const FPoly& p) +{ + return p.start->n; +} + +void FPoly::clear() +{ + fterm *ptr; + while (start!=NULL) + { + ptr=start->next; + delete start; + start=ptr; + } + +} + +FPoly &FPoly::operator=(const FPoly& p) +{ + fterm *ptr,*pos=NULL; + clear(); + ptr=p.start; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->n,pos); + ptr=ptr->next; + } + return *this; + +} + +FPoly& FPoly::operator+=(const FPoly& p) +{ + fterm *ptr,*pos=NULL; + ptr=p.start; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->n,pos); + ptr=ptr->next; + } + return *this; +} + +FPoly operator+(const FPoly &a,const FPoly &b) +{ + FPoly r=a; + r+=b; + return r; +} + +FPoly& FPoly::operator-=(const FPoly& p) +{ + fterm *ptr,*pos=NULL; + ptr=p.start; + while (ptr!=NULL) + { + pos=addterm(-(ptr->an),ptr->n,pos); + ptr=ptr->next; + } + return *this; +} + +FPoly operator-(const FPoly &a,const FPoly &b) +{ + FPoly r=a; + r-=b; + return r; +} + +void FPoly::multerm(Float a,int power) +{ + fterm *ptr=start; + while (ptr!=NULL) + { + ptr->an*=a; + ptr->n+=power; + ptr=ptr->next; + } +} + +fterm* FPoly::addterm(Float a,int power,fterm *pos) +{ + fterm* newone; + fterm* ptr; + fterm *t,*iptr; + ptr=start; + iptr=NULL; + if (a.iszero()) return pos; + +// quick scan through to detect if term exists already +// and to find insertion point + + if (pos!=NULL) ptr=pos; + while (ptr!=NULL) + { + if (ptr->n==power) + { + ptr->an+=a; + if (ptr->an.iszero()) + { // delete term + if (ptr==start) + { // delete first one + start=ptr->next; + delete ptr; + return start; + } + iptr=ptr; + ptr=start; + while (ptr->next!=iptr)ptr=ptr->next; + ptr->next=iptr->next; + delete iptr; + return ptr; + } + return ptr; + } + if (ptr->n>power) iptr=ptr; + else break; + ptr=ptr->next; + } + newone=new fterm; + newone->next=NULL; + newone->an=a; + newone->n=power; + pos=newone; + if (start==NULL) + { + start=newone; + return pos; + } + +// insert at the start + + if (iptr==NULL) + { + t=start; + start=newone; + newone->next=t; + return pos; + } + +// insert new term + + t=iptr->next; + iptr->next=newone; + newone->next=t; + return pos; +} + +ostream& operator<<(ostream& s,const FPoly& p) +{ + int first=1; + Float a; + fterm *ptr=p.start; + if (ptr==NULL) + { + s << "0"; + return s; + } + while (ptr!=NULL) + { + + a=ptr->an; + if (a>0) + { + if (!first) s << " + "; + } + else s << " - "; + + if (a<0) a=(-a); + if (ptr->n==0) + s << a; + else + { + if (a!=(Float)1) s << a << "*x"; + else s << "x"; + if (ptr->n!=1) s << "^" << ptr->n; + } + first=0; + ptr=ptr->next; + } + return s; +} + diff --git a/miracl/source/curve/flpoly.h b/miracl/source/curve/flpoly.h new file mode 100644 index 0000000..774bd74 --- /dev/null +++ b/miracl/source/curve/flpoly.h @@ -0,0 +1,62 @@ +/* + * C++ class to implement a polynomial type and to allow + * arithmetic on polynomials whose elements are float numbers + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.6 + */ + +#ifndef FPOLY_H +#define FPOLY_H + +#include "floating.h" + +class fterm +{ +public: + Float an; + int n; + fterm *next; +}; + +class FPoly +{ + fterm *start; +public: + FPoly() {start=NULL;} + FPoly(const FPoly&); + void clear(); + fterm* addterm(Float,int,fterm *pos=NULL); + void multerm(Float,int); + Float coeff(int) const; + BOOL iszero() const; + + FPoly& operator=(const FPoly&); + FPoly& operator+=(const FPoly&); + FPoly& operator-=(const FPoly&); + FPoly& operator*=(const Float&); + FPoly& divxn(FPoly&,int); + FPoly& mulxn(int); + + friend int degree(const FPoly&); + friend FPoly twobytwo(const FPoly&,const FPoly&); + friend FPoly pow2bypow2(const FPoly&,const FPoly&,int); + friend FPoly powsof2(const FPoly&,int,const FPoly&,int); + friend FPoly special(const FPoly&,const FPoly&); + + friend FPoly operator+(const FPoly&,const FPoly&); + friend FPoly operator-(const FPoly&,const FPoly&); + + friend FPoly operator*(const FPoly&,const FPoly&); + friend FPoly operator*(const FPoly&,const Float&); + + friend ostream& operator<<(ostream&,const FPoly&); + ~FPoly(); +}; + + +#endif + diff --git a/miracl/source/curve/glv.cpp b/miracl/source/curve/glv.cpp new file mode 100644 index 0000000..41bd211 --- /dev/null +++ b/miracl/source/curve/glv.cpp @@ -0,0 +1,129 @@ +// Apply the GLV algorithm to decompose k (for use by GLS elliptic curves) +// See "Faster Point Multiplication on Elliptic Curves with efficient Endomorphisms", +// by Gallant, Lambert and Vanstone". +// cl /O2 /GX glv.cpp big.cpp miracl.lib +// August 2008 + +#include +#include "big.h" + +using namespace std; + +Miracl precision(50,0); + +char *group="3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE09C5F010948D9D930E79156D8BA3CAF5"; + +int main() +{ + int i,mkb,tmkb; + miracl *mip=&precision; + mip->IOBASE=16; + Big r=group; + Big lambda,p; + Big u,v,u1,u2,u3,v1,v2,v3,t1,t2,t3,q,s,rm,tm,rm1,tm1,rm2,tm2,V1[2],V2[2],det,k,b1,b2,t,V[2],U[2],e; + +// offline calculations + + cout << "r= " << r << endl; + lambda=sqrt(r-1,r); // endomorphism corresponds to sqrt(-1) mod r + cout << "lambda= " << lambda << endl; + + p=pow((Big)2,127)-1; + t="3204F5AE088C39A7"; + + cout << "p^2+1-2*p+t*t= " << p*p+1-2*p+t*t << endl; + + cout << "t+(p-1)*lambda mod r = " << (t+(p-1)*lambda)%r << endl; + cout << "(p-1) - lambda*t mod r = " << ((p-1)-lambda*t)%r << endl; + + u1=1; u2=0; u3=r; + v1=0; v2=1; v3=lambda; + s=sqrt(r); + + cout << "s= " << s << endl; + cout << "2^127-2= " << pow((Big)2,127)-2 << endl; + while (u3>s) + { + q=u3/v3; + t1=u1-q*v1; t2=u2-q*v2; t3=u3-q*v3; + u1=v1, u2=v2; u3=v3; + v1=t1; v2=t2; v3=t3; + } + cout << "u3= " << u3 << endl; + cout << "u2= " << u2 << endl; + cout << "u1= " << u1 << endl; + rm=u3; tm=-u2; + q=u3/v3; + t1=u1-q*v1; t2=u2-q*v2; t3=u3-q*v3; + u1=v1, u2=v2; u3=v3; + v1=t1; v2=t2; v3=t3; + rm1=u3; tm1=-u2; + q=u3/v3; + t1=u1-q*v1; t2=u2-q*v2; t3=u3-q*v3; + u1=v1, u2=v2; u3=v3; + v1=t1; v2=t2; v3=t3; + rm2=u3; tm2=-u2; + V1[0]=rm1; V1[1]=tm1; + + cout << "(V1[0]+V1[1]*lambda)%r= " << (V1[0]+V1[1]*lambda)%r << endl; + + if (rm*rm+tm*tm < rm2*rm2+tm2*tm2) + { + V2[0]=rm; V2[1]=tm; + } + else + { + V2[0]=rm2; V2[1]=tm2; + } + + cout << "(V2[0]+V2[1]*lambda)%r= " << (V2[0]+V2[1]*lambda)%r << endl; + + + cout << "v1[0]= " << V1[0] << endl; + cout << "v1[1]= " << V1[1] << endl; + cout << "v2[0]= " << V2[0] << endl; + cout << "v2[1]= " << V2[1] << endl; + + det=V1[0]*V2[1]-V2[0]*V1[1]; + det=-det; + cout << "det= " << det << endl; + +// online calculation - input V1, V2, determinant, and multiplier k which will be decomposed into k0 and k1 + tmkb=0; + for (i=0;i<10;i++) + { + k=randbits(254); + + t=-(V2[1]*k); + b1=t/det; + if (t%det>(det/2)) b1+=1; // don't bother with "rounding to nearest" + + t=-(-V1[1]*k); + b2=t/det; + if (t%det>(det/2)) b2+=1; + + cout << "b1= " << b1 << endl; + cout << "b2= " << b2 << endl; + + V[0]=b1*V1[0]+b2*V2[0]; + V[1]=b1*V1[1]+b2*V2[1]; + + U[0]=k-V[0]; + U[1]=-V[1]; + + cout << "k0= " << (U[0]) << " bits= " << bits(U[0]) << endl; + cout << "k1= " << (U[1]) << " bits= " << bits(U[1]) << endl; + e=(U[0]+U[1]*lambda)%r; + if (e<0) e+=r; + cout << "k= " << k << endl; + cout << "(k0+k1*lam)%r= " << e << endl; + if (k!=e) break; + if (bits(U[0])>126 || bits(U[1])>126) break; + mkb=bits(U[0]); + if (bits(U[1])>mkb) mkb=bits(U[1]); + tmkb+=mkb; + // if (U[0]<0 || U[1]<0) break; + } + cout << "tmkb= " << tmkb << endl; + return 0; +} diff --git a/miracl/source/curve/modpol.cpp b/miracl/source/curve/modpol.cpp new file mode 100644 index 0000000..7af526e --- /dev/null +++ b/miracl/source/curve/modpol.cpp @@ -0,0 +1,668 @@ +// +// Program to generate Modular Polynomials mod p, as required for fast +// implementations of the Schoof-Elkies-Atkins algorithm +// for counting points on an elliptic curve Y^2=X^3 + A.X + B mod p +// +// Implemented entirely from the description provided in: +// 1. "Distributed Computation of the number of points on an elliptic curve +// over a finite prime field", Buchmann, Mueller, & Shoup, SFB 124-TP D5 +// Report 03/95, April 1995, Universitat des Saarlandes, and +// 2. "Counting the number of points on elliptic curves over finite fields +// of characteristic greater than three", Lehmann, Maurer, Mueller & Shoup, +// Proc. 1st Algorithmic Number Theory Symposium (ANTS), pp 60-70, 1994 +// +// Both papers are available on the Web from Volker Mueller's home page +// www.informatik.th-darmstadt.de/TI/Mitarbeiter/vmueller.html +// +// Also strongly recommended is the book +// +// 3. "Elliptic Curves in Cryptography" +// by Blake, Seroussi and Smart, London Mathematical Society Lecture Note +// Series 265, Cambridge University Press. ISBN 0 521 65374 6 +// +// The programs's output for each prime in the range is a bivariate polynomial +// in X and Y, which can optionally be stored to disk. Some informative output +// is generated just to convince you that it is still working, and to give an +// idea of progress. +// +// This program is a composite of the "mueller" and "process" applications. +// It generates the modular polynomials, pre-reduced wrt to a specified prime +// modulus. This may be the only feasible way to do it on a small computer +// system, for which the "mueller" application is too resource intensive. +// +// Although less memory intensive than "mueller", problems may still arise. +// See mueller.cpp for a description of the -s2, -s3 and -s6 flags +// +// .pol file format +// ,,<1st coef>,<1st power of X>,<1st power of Y>,<2nd coef>... +// Each polynomial ends wih zero powers of X and Y. +// +// For example +// modpol -d -f 2#512 0 500 -o test512.pol +// +// If appending to a file with the -a flag, make sure and use the same +// prime modulus as used to create the file originally - no check is made +// +// generates the test512.pol file directly, given the range 0 to 500 and +// using the first prime modulus it can find less than 2^512. This file can +// then be used directly with the "sea" application +// + +#include +#include +#include +#include +#include "ps_zzn.h" // power series class + +using namespace std; + +extern int psN; // power series are modulo x^psN + +BOOL fout; +BOOL append; +Miracl precision=20; + +ofstream mueller; + +// Code to parse formula in command line +// This code isn't mine, but its public domain +// Shamefully I forget the source +// +// NOTE: It may be necessary on some platforms to change the operators * and # +// + +#if defined(unix) +#define TIMES '.' +#define RAISE '^' +#else +#define TIMES '*' +#define RAISE '#' +#endif + +Big tt; +static char *ss; + +void eval_power (Big& oldn,Big& n,char op) +{ + if (op) n=pow(oldn,toint(n)); // power(oldn,size(n),n,n); +} + +void eval_product (Big& oldn,Big& n,char op) +{ + switch (op) + { + case TIMES: + n*=oldn; + break; + case '/': + n=oldn/n; + break; + case '%': + n=oldn%n; + } +} + +void eval_sum (Big& oldn,Big& n,char op) +{ + switch (op) + { + case '+': + n+=oldn; + break; + case '-': + n=oldn-n; + } +} + +void eval (void) +{ + Big oldn[3]; + Big n; + int i; + char oldop[3]; + char op; + char minus; + for (i=0;i<3;i++) + { + oldop[i]=0; + } +LOOP: + while (*ss==' ') + ss++; + if (*ss=='-') /* Unary minus */ + { + ss++; + minus=1; + } + else + minus=0; + while (*ss==' ') + ss++; + if (*ss=='(' || *ss=='[' || *ss=='{') /* Number is subexpression */ + { + ss++; + eval (); + n=tt; + } + else /* Number is decimal value */ + { + for (i=0;ss[i]>='0' && ss[i]<='9';i++) + ; + if (!i) /* No digits found */ + { + cout << "Error - invalid number" << endl; + exit (20); + } + op=ss[i]; + ss[i]=0; + n=atoi(ss); + ss+=i; + *ss=op; + } + if (minus) n=-n; + do + op=*ss++; + while (op==' '); + if (op==0 || op==')' || op==']' || op=='}') + { + eval_power (oldn[2],n,oldop[2]); + eval_product (oldn[1],n,oldop[1]); + eval_sum (oldn[0],n,oldop[0]); + tt=n; + return; + } + else + { + if (op==RAISE) + { + eval_power (oldn[2],n,oldop[2]); + oldn[2]=n; + oldop[2]=RAISE; + } + else + { + if (op==TIMES || op=='/' || op=='%') + { + eval_power (oldn[2],n,oldop[2]); + oldop[2]=0; + eval_product (oldn[1],n,oldop[1]); + oldn[1]=n; + oldop[1]=op; + } + else + { + if (op=='+' || op=='-') + { + eval_power (oldn[2],n,oldop[2]); + oldop[2]=0; + eval_product (oldn[1],n,oldop[1]); + oldop[1]=0; + eval_sum (oldn[0],n,oldop[0]); + oldn[0]=n; + oldop[0]=op; + } + else /* Error - invalid operator */ + { + cout << "Error - invalid operator" << endl; + exit (20); + } + } + } + } + goto LOOP; +} + +// +// When summing the Zk^n 0<=k " << endl; + cout << "OR" << endl; + cout << "modpol " << endl; + cout << "where the numbers define a range. The program will find the" << endl; + cout << "Modular Polynomials for primes in this range wrt the specified modulus" << endl; + cout << "To input P in Hex, precede with -h" << endl; + cout << "To search downwards for a prime, use flag -d" << endl; + cout << "NOTE: Program is both memory and time intensive" << endl; + cout << "To skip \"difficult\" primes, use -s2, -s3 or -s6" << endl; + cout << "where -s2 skips most and -s6 skips least" << endl; + cout << "To output polynomials to a file use flag -o " << endl; +#if defined(unix) + cout << "e.g. modpol -f 2^192-2^64-1 0 150 -o p192.pol" << endl; +#else + cout << "e.g. modpol -f 2#192-2#64-1 0 150 -o p192.pol" << endl; +#endif + cout << "Alternatively to append to a file use flag -a " << endl; + cout << "See source code file for details" << endl; + cout << "\nFreeware from Certivox, Dublin, Ireland" << endl; + cout << "Full C++ source code and MIRACL multiprecision library available" << endl; + cout << "email mscott@indigo.ie" << endl; + + return 0; + } + if (argc<3) + { + cout << "Error in command line" << endl; + return 0; + } + ip=0; + skip=12; + fout=FALSE; + dir=gotP=gothi=gotlo=FALSE; + append=FALSE; + Base=10; + while (ipIOBASE=Base; + p=argv[ip++]; + mip->IOBASE=10; + gotP=TRUE; + continue; + } + if (!gotlo) + { + lo=atoi(argv[ip++]); + gotlo=TRUE; + continue; + } + if (!gothi) + { + hi=atoi(argv[ip++]); + gothi=TRUE; + continue; + } + cout << "Error in command line" << endl; + return 0; + } + if (!gothi || !gotlo) + { + cout << "Error in command line" << endl; + return 0; + } + if (lo>hi || hi>1000) + { + cout << "Invalid range specified" << endl; + return 0; + } + + gprime(1000); // get all primes < 1000 + for (i=0;;i++) + { + sp=mip->PRIMES[i]; + primes[i]=sp; + if (sp==0) break; + } + + if (!prime(p)) + { + int incr=0; + cout << "That number is not prime!" << endl; + if (dir) + { + cout << "Looking for next lower prime" << endl; + p-=1; incr++; + while (!prime(p)) { p-=1; incr++; } + cout << "Prime P = P-" << incr << endl; + } + else + { + cout << "Looking for next higher prime" << endl; + p+=1; incr++; + while (!prime(p)) { p+=1; incr++; } + cout << "Prime P = P+" << incr << endl; + } + cout << "Prime P = " << p << endl; + } + cout << "P mod 24 = " << p%24 << endl; + cout << "P is " << bits(p) << " bits long" << endl; + + if (fout && !append) mueller << p << endl; + + modulo(p); // Set prime modulus for ZZn type + + for (j=0,i=1;;i++) // lets go + { + sp=primes[i]; + if (sp==0) break; + if (sphi) break; + for (s=1;;s++) + if (s*(sp-1)%12==0) break; + if (s>=skip) continue; + j++; + cout << endl; + cout << "prime " << j << " = " << sp << " (s=" << s << ")" << endl; + mueller_pol(sp,s); + } + cout << endl; + if (j==0) cout << "No primes processed in the specified range" << endl; + if (j==1) cout << "One prime processed in the specified range" << endl; + if (j>1) cout << j << " primes processed in the specified range" << endl; + return 0; +} + diff --git a/miracl/source/curve/mueller.cpp b/miracl/source/curve/mueller.cpp new file mode 100644 index 0000000..a7ea117 --- /dev/null +++ b/miracl/source/curve/mueller.cpp @@ -0,0 +1,495 @@ +// +// Program to generate Modular Polynomials, as required for fast +// implementations of the Schoof-Elkies-Atkins algorithm +// for counting points on an elliptic curve Y^2=X^3 + A.X + B mod p +// +// Implemented entirely from the description provided in: +// 1. "Distributed Computation of the number of points on an elliptic curve +// over a finite prime field", Buchmann, Mueller, & Shoup, SFB 124-TP D5 +// Report 03/95, April 1995, Universitat des Saarlandes, and +// 2. "Counting the number of points on elliptic curves over finite fields +// of characteristic greater than three", Lehmann, Maurer, Mueller & Shoup, +// Proc. 1st Algorithmic Number Theory Symposium (ANTS), pp 60-70, 1994 +// +// Both papers are available on the Web from Volker Mueller's home page +// www.informatik.th-darmstadt.de/TI/Mitarbeiter/vmueller.html +// +// Also strongly recommended is the book +// +// 3. "Elliptic Curves in Cryptography" +// by Blake, Seroussi and Smart, London Mathematical Society Lecture Note +// Series 265, Cambridge University Press. ISBN 0 521 65374 6 +// +// The programs's output for each prime in the range is a bivariate polynomial +// in X and Y, which can optionally be stored to disk. Some informative output +// is generated just to convince you that it is still working, and to give an +// idea of progress. +// +// .raw file format +// ,<1st coef>,<1st power of X>,<1st power of Y>,<2nd coef>... +// Each polynomial ends wih zero powers of X and Y. +// +// NOTE: This program is very hard on memory. In places "obvious" speed +// optimizations have not been applied, if they are memory intensive. But in +// any case 64Mb is really a minimal requirement to generate enough +// polynomials for serious work. +// +// The time/memory requirements for a particular prime L depend on the value +// s, defined as the smallest integer such that s.(L-1) is divisible by 12. +// The value of s can be 1, 2, 3 or 6. The bigger s, the worse the time/memory +// requirements, and the bigger the coefficients in the polynomial. +// The flags -s2, -s3, and -s6 cause the primes in the specified +// range to be skipped if, for example, s>=3. +// +// Four things can go wrong. An "Out of Space message means that you have run +// out of virtual memory. The "control panel" on your operating system should +// enable you to fix this. A "Number too big" error means that the value +// specified in the first parameter of the call to mirsys() has proven to be +// too small. This also means that you have pushed the program beyond the +// limits for which we have tested it (well done!). If your hard disk +// "trashes" continually, and processing slows to a crawl, you have run out of +// physical memory. Buy more memory for your computer, or a new computer. +// Another problem may be I/O buffer overflow. Use set_io_buffer_size() to +// specify a larger I/O buffer +// +// With 96 Mb of RAM, what works for me (so far, running over a long weekend) +// is +// +// mueller 0 180 -o mueller.raw +// mueller 180 300 -s6 -a mueller.raw +// +// and it should be possible to continue, for example, like +// +// mueller 300 400 -s3 -a mueller.raw +// mueller 400 500 -s2 -a mueller.raw +// +// This creates a file mueller.raw containing modular polynomials +// for 69 primes +// +// Of course different ranges can be covered simultaneously on multiple +// computers, if you have them. +// +// Alternatively, if these problems should prove insurmountable - see the +// "modpol" application +// +// This program would be a lot faster if the coefficients were calculated mod +// many 32-bit primes, and then combined via the CRT. +// +// + +#include +#include +#include +#include +#include "ps_big.h" // power series class + +using namespace std; + +extern int psN; // power series are modulo x^psN + +BOOL fout; +ofstream mueller; + +// +// When summing the Zk^n 0<=k=0) k+=L; + } + + for (;k0 && (!first || !brackets)) cout << "+"; + first=FALSE; + if (cf==1) cout << "Y"; + if (cf==-1) cout << "-Y"; + if (abs(cf)!=1) cout << cf << "*Y"; + if (j!=1) cout << "^" << j; + } + cf=z.coeff(0); + if (fout) mueller << cf << "\n" << L+1-i << "\n" << 0 << endl; + + if (cf>0) cout << "+"; + if (brackets) cout << cf << ")*X"; + else + { + if (i==L+1) + { + cout << cf; + continue; + } + if (cf==1) cout << "X"; + if (cf==-1) cout << "-X"; + if (abs(cf)!=1) cout << cf << "*X"; + } + + if (i!=L) cout << "^" << L+1-i ; + // all other coefficients should now be zero + if (z.coeff(L)!=0) + { // check next coefficient is zero + cout << "\n\n Sanity Check Failed " << endl; + exit(0); + } + } + for (i=0;i<=L+1;i++) c[i].clear(); // reclaim space + for (i=0;i<=v;i++) jlt[i].clear(); + cout << endl; + + fft_reset(); +} + +int main(int argc,char **argv) +{ + miracl *mip; + int i,j,s,lo,hi,p,ip,skip; + int primes[200]; + BOOL gothi,gotlo; + argv++; argc--; + + if (argc<1) + { + cout << "Incorrect usage" << endl; + cout << "Program generates Modular Polynomials, for use by fast Schoof-Elkies-Atkins" << endl; + cout << "program for counting points on an elliptic curve" << endl; + cout << "mueller " << endl; + cout << "where the numbers define a range. The program will attempt to" << endl; + cout << "find the Modular Polynomials for all primes in this range" << endl; + cout << "To output polynomials to a file use flag -o " << endl; + cout << "e.g. mueller 0 10 -o mueller.raw" << endl; + cout << "Alternatively to append to a file use flag -a " << endl; + cout << "NOTE: Program is both memory and time intensive" << endl; + cout << "To skip \"difficult\" primes, use -s2, -s3 or -s6" << endl; + cout << "where -s2 skips most and -s6 skips least" << endl; + cout << "See source code file for details" << endl; + cout << "Files generated from different ranges may be combined in an" << endl; + cout << "obvious way using a standard text editor" << endl; + cout << "\nFreeware from Certivox, Dublin, Ireland" << endl; + cout << "Full C++ source code and MIRACL multiprecision library available" << endl; + cout << "email mscott@indigo.ie" << endl; + + return 0; + } + if (argc<2) + { + cout << "Error in command line" << endl; + return 0; + } + ip=0; + skip=12; + fout=FALSE; + gothi=gotlo=FALSE; + while (iphi || hi>1000) + { + cout << "Invalid range specified" << endl; + return 0; + } + + mip=mirsys(20,0); + + gprime(1000); // get all primes < 1000 + for (i=0;;i++) + { + p=mip->PRIMES[i]; + primes[i]=p; + if (p==0) break; + } + mirexit(); + + for (j=0,i=1;;i++) // lets go + { + p=primes[i]; + if (p==0) break; + if (phi) break; + for (s=1;;s++) + if (s*(p-1)%12==0) break; + if (s>=skip) continue; + + // p*s/6 seems to be a fortuitous upper bound (?) + // on the size of integer coefficients generated. + // This MAY need to be increased if "number + // too big" errors accur. + + mirsys(1+(p*s)/6,0); + set_io_buffer_size(4096); + j++; + cout << "prime " << j << " = " << p << " (s=" << s << ")" << endl; + cout << 32*(1+(p*s)/6) << " bits reserved for each coefficient" << endl; + mueller_pol(p,s); + mirexit(); + } + cout << endl; + if (j==0) cout << "No primes processed in the specified range" << endl; + if (j==1) cout << "One prime processed in the specified range" << endl; + if (j>1) cout << j << " primes processed in the specified range" << endl; + return 0; +} + diff --git a/miracl/source/curve/pairing/ake.cpp b/miracl/source/curve/pairing/ake.cpp new file mode 100644 index 0000000..9320bac --- /dev/null +++ b/miracl/source/curve/pairing/ake.cpp @@ -0,0 +1,131 @@ +/* + Scott's AKE Client/Server testbed + + Compile with modules as specified below + + For MR_PAIRING_CP curve + cl /O2 /GX ake.cpp cp_pair.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_MNT curve + cl /O2 /GX ake.cpp mnt_pair.cpp zzn6a.cpp ecn3.cpp zzn3.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_BN curve + cl /O2 /GX ake.cpp bn_pair.cpp zzn12a.cpp ecn2.cpp zzn4.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_KSS curve + cl /O2 /GX ake.cpp kss_pair.cpp zzn18.cpp zzn6.cpp ecn3.cpp zzn3.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_BLS curve + cl /O2 /GX ake.cpp bls_pair.cpp zzn24.cpp zzn8.cpp zzn4.cpp zzn2.cpp ecn4.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + See http://eprint.iacr.org/2002/164 + +*/ + +#include +#include + +//********* choose just one of these pairs ********** +//#define MR_PAIRING_CP // AES-80 security +//#define AES_SECURITY 80 + +//#define MR_PAIRING_MNT // AES-80 security +//#define AES_SECURITY 80 + +//#define MR_PAIRING_BN // AES-128 or AES-192 security +//#define AES_SECURITY 128 +//#define AES_SECURITY 192 + +//#define MR_PAIRING_KSS // AES-192 security +//#define AES_SECURITY 192 + +#define MR_PAIRING_BLS // AES-256 security +#define AES_SECURITY 256 +//********************************************* + +#include "pairing_3.h" + +int main() +{ + PFC pfc(AES_SECURITY); // initialise pairing-friendly curve + + time_t seed; + G1 Alice,Bob,sA,sB; + G2 B6,Server,sS; + GT res,sp,ap,bp; + Big ss,s,a,b; + + time(&seed); + irand((long)seed); + + pfc.random(ss); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + pfc.hash_and_map(Server,(char *)"Server"); + + cout << "Mapping Alice & Bob ID's to points" << endl; + pfc.hash_and_map(Alice,(char *)"Alice"); + pfc.hash_and_map(Bob,(char *)"Robert"); + + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=pfc.mult(Server,ss); + sA=pfc.mult(Alice,ss); + sB=pfc.mult(Bob,ss); + + cout << "Alice and Server Key Exchange" << endl; + + + pfc.random(a); // Alice's random number + pfc.random(s); // Server's random number + + res=pfc.pairing(Server,sA); + + if (!pfc.member(res)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + ap=pfc.power(res,a); + + res=pfc.pairing(sS,Alice); + + if (!pfc.member(res)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + sp=pfc.power(res,s); + + cout << "Alice Key= " << pfc.hash_to_aes_key(pfc.power(sp,a)) << endl; + cout << "Server Key= " << pfc.hash_to_aes_key(pfc.power(ap,s)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + pfc.random(b); // Bob's random number + pfc.random(s); // Server's random number + + res=pfc.pairing(Server,sB); + if (!pfc.member(res)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=pfc.power(res,b); + + res=pfc.pairing(sS,Bob); + if (!pfc.member(res)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + sp=pfc.power(res,s); + + cout << "Bob's Key= " << pfc.hash_to_aes_key(pfc.power(sp,b)) << endl; + cout << "Server Key= " << pfc.hash_to_aes_key(pfc.power(bp,s)) << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/ake.txt b/miracl/source/curve/pairing/ake.txt new file mode 100644 index 0000000..8028a10 --- /dev/null +++ b/miracl/source/curve/pairing/ake.txt @@ -0,0 +1,64 @@ + +The files AKEnGNt.CPP implement variations of the ake protocol described in +http://eprint.iacr.org/2002/164/, where n is the embedding degree, GN +is the curve generation method (SS for supersingular, CP for Cocks-Pinch, +MNT for MNT curves, BW for Brezing and Weng, FST for Freeman-Scott-Teske, KM +for Koblitz-Menezes), and t is the pairing type (t=A for Ate, T for tate, +E for eta and R for r-ate pairings). + +This authenticated key exchange algorithm is used as a test-bed for testing +fast implementations of pairings. + +AKE2CPT.CPP contains an implementation that uses a non-supersingular curve with +a 160-bit group order whose security depends on the difficulty of a 1024-bit +discrete logarithm problem. The prime modulus is 512 bits. The "security +multiplier" is 2. The curve parameters are in the file k2.ecs + +AKE2SST.CPP implements the same protocol, but this time using a supersingular +curve. + +AKE6MNTT.CPP contains an implementation that uses a non-supersingular curve +with a 160-bit group order whose security depends on the difficulty of a 960-bit +discrete logarithm problem. The prime modulus is 160 bits. The "security +multiplier" is 6. The curve parameters are in the file mnt.ecs + +AKE4CPT.CPP contains an implementation that uses a non-supersingular curve with +a 192-bit group order whose security depends on the difficulty of a 2048-bit +discrete logarithm problem. The prime modulus is 512 bits. The "security +multiplier" is 4. The curve parameters are in the file k4.ecs + +AKE8CPT.CPP contains an implementation that uses a non-supersingular curve with +a 224-bit group order whose security depends on the difficulty of a 4096-bit +discrete logarithm problem. The prime modulus is 512 bits. The "security +multiplier" is 8. The curve parameters are in the file k8.ecs + +The implementations AKE2CPT.CPP, AKE4CPT.CPP and AKE8CPT.CPP use a "twisted" +curve, and compress the output of the pairing. See +http://eprint.iacr.org/2004/032/ + +AKE4CPT.CPP and AKE8CPT.CPP uses a "tower extension field" as a simple way of +moving from k=2 to k=4 and k=8. See ZZn4.CPP/ZZn8.CPP + +By using a series of such extensions, higher and higher security levels can +be reached. This is thought to be a nice way of scaling security for pairing- +based protocols. These implementations all depend on the same fast 512-bit +modular multiplier. + +AKE4FSTA contains an implementation that uses a non-supersingular curve with a +165-bit group order whose security depends on the difficulty of a 1024-bit +discrete logarithm problem. The prime modulus is 255 bits. The "security +multiplier" is 4. The curve parameters are in the file kw4.ecs. Note that the +group order is of a low hamming weight. + +AKE8BWT.CPP contains an implementation that uses a non-supersingular curve with a +192-bit group order whose security depends on the difficulty of a 2048-bit +discrete logarithm problem. The prime modulus is 256 bits. The "security +multiplier" is 8. The curve parameters are in the file weng.ecs. This curve +was constructed using a method due to Brezing & Weng. See +http://eprint.iacr.org/2003/143/ + +The files k2.ecs, k4.ecs and k8.ecs are created by the utility folklore.cpp +The file mnt.ecs is created by the mnt.cpp utility. + +See pairings.txt for more details. + diff --git a/miracl/source/curve/pairing/ake12blsa.cpp b/miracl/source/curve/pairing/ake12blsa.cpp new file mode 100644 index 0000000..1e3c7af --- /dev/null +++ b/miracl/source/curve/pairing/ake12blsa.cpp @@ -0,0 +1,635 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=6 ake12blsa.cpp zzn12a.cpp zzn4.cpp ecn2.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + using COMBA build + + Barreto-Lynn-Scott Curve - Ate pairing + + The curve generated is generated from a 64-bit x parameter + This version implements that Ate pairing + + This is implemented on the Barreto-Lynn-Scott k=12, rho=1.5 pairing friendly curve + + NOTE: Irreducible polynomial is of the form x^6+sqrt(-2) + + See bls12.cpp for a program to generate suitable curves + + Modified to prevent sub-group confinement attack +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn2.h" +#include "zzn12a.h" + +using namespace std; + +Miracl precision(6,0); +/* +extern "C" +{ + int fpc=0; + int fpa=0; + int fpx=0; +} +*/ + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// Using SHA-256 as basic hash algorithm + +#define HASH_LEN 32 + +// +// Ate Pairing Code +// + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + X.set((Big)0,(Big)1); // = (sqrt(-2)^(p-1)/2 + break; + case 3: // = (1+sqrt(-1))^(p-1)/2 + X.set((Big)1,(Big)1); + break; + case 7: + X.set((Big)2,(Big)1); // = (2+sqrt(-1))^(p-1)/2 + default: break; + } + X=pow(X,(p-1)/6); +} + +ZZn12 Frobenius(ZZn12 P, ZZn2 &X, int k) +{ + ZZn12 Q=P; + for (int i=0; iX; + y=(A.get_point())->Y; + y=-y; + x*=Beta; + copy(getbig(x),(A.get_point())->X); + copy(getbig(y),(A.get_point())->Y); +} + +// +// This calculates p.A quickly using Frobenius +// 1. Extract A(x,y) from twisted curve to point on curve over full extension, as X=i^2.x and Y=i^3.y +// where i=NR^(1/k) +// 2. Using Frobenius calculate (X^p,Y^p) +// 3. map back to twisted curve +// Here we simplify things by doing whole calculation on the twisted curve +// +// +// Note we have to be careful as in detail it depends on w where p=w mod k +// Its simplest if w=1, which in this case it is. +// + +ECn2 psi(ECn2 &A,ZZn2 &F,int n) +{ + int i; +// Fast multiplication of A by q (for Trace-Zero group members only) + ZZn2 x,y,z,w,r; + ECn2 P=A; + +#ifdef PROJECTIVE + P.get(x,y,z); +#else + P.get(x,y); +#endif + + w=F*F; + r=F; + for (i=0;i return (Qy-y)-slope.(Qx-x) +// + +ZZn12 line(ECn2& A,ECn2& C,ECn2&B,ZZn2& slope,ZZn2& extra,BOOL Doubling,ZZn& Qx,ZZn& Qy) +{ + ZZn12 w; + ZZn4 nn,dd; + ZZn2 X,Y; + +#ifdef AFFINE + A.get(X,Y); + + nn.set((ZZn2)-Qy,Y-slope*X); + dd.set(slope*Qx); + + w.set(nn,dd); + +#endif +#ifdef PROJECTIVE + ZZn2 Z3; + + C.getZ(Z3); + +// Thanks to A. Menezes for pointing out this optimization... + if (Doubling) + { + ZZn2 Z,ZZ; + A.get(X,Y,Z); + ZZ=Z; ZZ*=ZZ; + nn.set((Z3*ZZ)*Qy,slope*X-extra); + dd.set(-(ZZ*slope)*Qx); + } + else + { + ZZn2 X2,Y2; + B.get(X2,Y2); + nn.set(Z3*Qy,slope*X2-Y2*Z3); + dd.set(-slope*Qx); + } + w.set(nn,dd); +#endif + + return w; +} + + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn12 g(ECn2& A,ECn2& B,ZZn& Qx,ZZn& Qy) +{ + ZZn2 lam,extra; + ZZn12 r; + ECn2 P=A; + BOOL Doubling; + +// Evaluate line from A + Doubling=A.add(B,lam,extra); + + if (A.iszero()) return (ZZn12)1; + r=line(P,A,B,lam,extra,Doubling,Qx,Qy); + + return r; +} + +void SoftExpo(ZZn12 &f3, ZZn2 &X){ + ZZn12 t0; + int i; + + t0=f3; f3.conj(); f3/=t0; + f3.mark_as_regular(); + t0=f3; f3.powq(X); f3.powq(X); f3*=t0; + f3.mark_as_unitary(); +} + +ZZn12 HardExpo(ZZn12 &f3x0, ZZn2 &X, Big &x){ +//vector=[ 1, 2, 3 ] + ZZn12 r; + ZZn12 xA; + ZZn12 xB; + ZZn12 t0; + ZZn12 t1; + ZZn12 f3x1; + ZZn12 f3x2; + ZZn12 f3x3; + ZZn12 f3x4; + ZZn12 f3x5; + + f3x1=pow(f3x0,x); + f3x2=pow(f3x1,x); + f3x3=pow(f3x2,x); + f3x4=pow(f3x3,x); + f3x5=pow(f3x4,x); + + xA=f3x2*inverse(f3x4)*Frobenius(f3x1,X,1)*Frobenius(inverse(f3x3),X,1)*Frobenius(inverse(f3x2),X,2)*Frobenius(inverse(f3x1),X,3); + xB=f3x0; + t0=xA*xB; + xA=inverse(f3x1)*f3x5*Frobenius(inverse(f3x0),X,1)*Frobenius(f3x4,X,1)*Frobenius(f3x1,X,2)*Frobenius(f3x3,X,2)*Frobenius(f3x0,X,3)*Frobenius(f3x2,X,3); + xB=f3x0; + t1=xA*xB; + t0=t0*t0; + t0=t0*t1; + +r=t0; +return r; + +} + +// +// Ate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order q. +// Note that P is a point on the sextic twist of the curve over Fp^2, Q(x,y) is a point on the +// curve over the base field Fp +// + +BOOL fast_pairing(ECn2& P,ZZn& Qx,ZZn& Qy,Big &x,ZZn2 &X,ZZn12& res) +{ + ECn2 A; + int i,nb; + Big n; + ZZn12 w,r; + + n=x; // t-1 + A=P; // remember A + + nb=bits(n); + r=1; +//fpc=fpa=fpx=0; + for (i=nb-2;i>=0;i--) + { + r*=r; + r*=g(A,A,Qx,Qy); + + if (bit(n,i)) + r*=g(A,P,Qx,Qy); + } + + + if (r.iszero()) return FALSE; + + SoftExpo(r,X); + res=HardExpo(r,X,x); + + return TRUE; +} + +// +// ecap(.) function +// + +BOOL ecap(ECn2& P,ECn& Q,Big& x,ZZn2 &X,ZZn12& r) +{ + BOOL Ok; + Big xx,yy; + ZZn Qx,Qy; + + Q.get(xx,yy); Qx=xx; Qy=yy; + P.norm(); + + Ok=fast_pairing(P,Qx,Qy,x,X,r); + + if (Ok) return TRUE; + return FALSE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha256 sh; + + shs256_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs256_process(&sh,string[i]); + } + shs256_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn12 x) +{ // Compress and hash an Fp12 to a big number + sha256 sh; + ZZn4 u; + ZZn2 h,l; + Big a,hash,p,xx[4]; + char s[HASH_LEN]; + int i,j,m; + + shs256_init(&sh); + x.get(u); // compress to single ZZn4 + u.get(l,h); + xx[0]=real(l); xx[1]=imaginary(l); xx[2]=real(h); xx[3]=imaginary(h); + + for (i=0;i<4;i++) + { + a=xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&sh,m); + a/=256; + } + } + shs256_hash(&sh,s); + hash=from_binary(HASH_LEN,s); + return hash; +} + +// Hash and map a Server Identity to a curve point E_(Fp2) + +ECn2 hash_and_map2(char *ID) +{ + int i; + ECn2 S,SS; + ZZn2 X; + + Big x0=H1(ID); + + forever + { + x0+=1; + X.set((ZZn)1,(ZZn)x0); + if (!S.set(X)) continue; + break; + } + + return S; +} + +// Hash and map a Client Identity to a curve point E_(Fp) of order q + +ECn hash_and_map(char *ID,Big cf) +{ + ECn Q; + Big x0=H1(ID); + + while (!Q.set(x0,x0)) x0+=1; + Q*=cf; + + return Q; +} + +// Use GLV endomorphism idea for multiplication in G1. + +ECn G1_mult(ECn &P,Big &e,Big &x,ZZn &Beta) +{ +// return e*P; + int i; + ECn Q; + Big x2,u[2]; + x2=x*x; + u[0]=e%x2; u[1]=e/x2; + + Q=P; + endomorph(Q,Beta); + + Q=mul(u[0],P,u[1],Q); + + return Q; +} + +//.. for multiplication in G2 + +ECn2 G2_mult(ECn2 &P,Big e,Big &x,ZZn2 &X) +{ +// return e*P; + int i; + ECn2 Q[4]; + Big u[4]; + + for (i=0;i<4;i++) {u[i]=e%x; e/=x;} + + Q[0]=P; + for (i=1;i<4;i++) + Q[i]=psi(Q[i-1],X,1); + +// simple multi-addition + + return mul(4,Q,u); +} + +//.. and for exponentiation in GT + +ZZn12 GT_pow(ZZn12 &res,Big e,Big &x,ZZn2 &X) +{ +// return pow(res,e); + int i,j; + ZZn12 Y[4]; + Big u[4]; + + for (i=0;i<4;i++) {u[i]=e%x; e/=x;} + + Y[0]=res; + for (i=1;i<4;i++) + {Y[i]=Y[i-1]; Y[i].powq(X);} + +// simple multi-exponentiation + return pow(4,Y,u); +} + +ECn2 HashG2(ECn2 &Qx0, Big &x, ZZn2 &X){ +//vector=[ 1, 2, 4 ] + ECn2 r; + ECn2 xA; + ECn2 xB; + ECn2 xC; + ECn2 t0; + ECn2 Qx0_; + ECn2 Qx1; + ECn2 Qx1_; + ECn2 Qx2; + ECn2 Qx2_; + ECn2 Qx3; + ECn2 Qx3_; + + Qx0_=-(Qx0); + Qx1=x*Qx0; + Qx1_=-(Qx1); + Qx2=x*Qx1; + Qx2_=-(Qx2); + Qx3=x*Qx2; + Qx3_=-(Qx3); + + xA=Qx0; + xB=Qx0; + t0=xA+xB; + xB=psi(Qx1,X,2); + + t0=t0+xB; + t0+=t0; + xB=Qx1_; + xC=Qx2_; + + xB+=xC; + xC=Qx3; + xB+=xC; + xC=psi(Qx0,X,1); + xB+=xC; + xC=psi(Qx1_,X,1); + xB+=xC; + xC=psi(Qx2_,X,1); + xB+=xC; + xC=psi(Qx3,X,1); + xB+=xC; + xC=psi(Qx0_,X,2); + xB+=xC; + xC=psi(Qx2_,X,2); + xB+=xC; + xB.norm(); + t0=t0+xB; + +r=t0; +r.norm(); +return r; + +} + +int main() +{ + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn2 Server,sS; + ZZn12 sp,ap,bp,res; + ZZn2 X; + Big a,b,s,ss,p,q,x,y,B,cf,t,cof; + ZZn Beta; + int i,bits,A; + time_t seed; + + mip->IOBASE=16; + x= (char *)"C000000000040405"; // found by BLS12.CPP + + p=(pow(x,6)-2*pow(x,5)+2*pow(x,3)+x+1)/3; + t=x+1; + q=pow(x,4)-x*x+1; + cof=(p+1-t)/q; + + // cf=9*((x-1)*(x-1)*(p+t)/3 + 1); + + modulo(p); + set_frobenius_constant(X); + + cout << "Initialised... " << endl; + + time(&seed); + irand((long)seed); + +#ifdef AFFINE + ecurve((Big)0,(Big)1,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve((Big)0,(Big)1,p,MR_PROJECTIVE); +#endif + + Beta=pow((ZZn)2,(p-1)/3); + Beta*=Beta; // right cube root of unity + + mip->IOBASE=16; + mip->TWIST=MR_SEXTIC_D; // map Server to point on twisted curve E(Fp2) + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + Server=hash_and_map2((char *)"Server"); + Server=HashG2(Server,x,X); + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice",cof); + Bob= hash_and_map((char *)"Robert",cof); + + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=G2_mult(Server,ss,x,X); + sA=G1_mult(Alice,ss,x,Beta); + sB=G1_mult(Bob,ss,x,Beta); + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + // for (i=0;i<1000;i++) + + if (!ecap(Server,sA,x,X,res)) cout << "Trouble" << endl; + if (pow(res,q)!=(ZZn12)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + ap=GT_pow(res,a,x,X); + + if (!ecap(sS,Alice,x,X,res)) cout << "Trouble" << endl; + if (pow(res,q)!=(ZZn12)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=GT_pow(res,s,x,X); + + cout << "Alice Key= " << H2(GT_pow(sp,a,x,X)) << endl; + cout << "Server Key= " << H2(GT_pow(ap,s,x,X)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!ecap(Server,sB,x,X,res)) cout << "Trouble" << endl; + if (pow(res,q)!=(ZZn12)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=GT_pow(res,b,x,X); + + if (!ecap(sS,Bob,x,X,res)) cout << "Trouble" << endl; + if (pow(res,q)!=(ZZn12)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=GT_pow(res,s,x,X); + + cout << "Bob's Key= " << H2(GT_pow(sp,b,x,X)) << endl; + cout << "Server Key= " << H2(GT_pow(bp,s,x,X)) << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/ake12bna.cpp b/miracl/source/curve/pairing/ake12bna.cpp new file mode 100644 index 0000000..9b80b2f --- /dev/null +++ b/miracl/source/curve/pairing/ake12bna.cpp @@ -0,0 +1,494 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=8 ake12bna.cpp zzn12.cpp zzn6a.cpp ecn2.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + using COMBA build + + Barreto-Naehrig Curve - Ate pairing + + The curve generated is generated from a 64-bit x parameter + This version implements the Ate pairing + + See "Pairing-Friendly Elliptic Curves of Prime Order", by Paulo S. L. M. Barreto and Michael Naehrig, + Cryptology ePrint Archive: Report 2005/133 + + NOTE: Irreducible polynomial is of the form x^6+(1+sqrt(-2)) + + See bn.cpp for a program to generate suitable BN curves + + Modified to prevent sub-group confinement attack +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn2.h" +#include "zzn12.h" + + +// cofactor - number of points on curve=CF.q + +using namespace std; + +#ifdef MR_COUNT_OPS +extern "C" +{ + int fpc=0; + int fpa=0; + int fpx=0; +} +#endif + +Miracl precision(8,0); + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// Using SHA-256 as basic hash algorithm + +#define HASH_LEN 32 + +// +// Ate Pairing Code +// + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + X.set((Big)0,(Big)1); // = (sqrt(-2)^(p-1)/2 + break; + case 3: // = (1+sqrt(-1))^(p-1)/2 + X.set((Big)1,(Big)1); + break; + case 7: + X.set((Big)2,(Big)1); // = (2+sqrt(-1))^(p-1)/2 + default: break; + } + X=pow(X,(p-1)/6); +} + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn12 line(ECn2& A,ECn2& C,ZZn2& slope,ZZn& Qx,ZZn& Qy) +{ + ZZn12 w; + ZZn6 nn,dd; + ZZn2 X,Y; + +#ifdef AFFINE + A.get(X,Y); + + dd.set(slope*Qx,Y-slope*X); + nn.set((ZZn2)-Qy); + w.set(nn,dd); + +#endif +#ifdef PROJECTIVE + ZZn2 Z,Z2,ZZ,ZZZ; + + A.get(X,Y,Z); + C.getZ(Z2); + + ZZ=Z*Z; + ZZZ=ZZ*Z; + + dd.set((ZZZ*slope)*Qx,Z2*Y-Z*X*slope); + nn.set((ZZn2)-(ZZZ*Z2)*Qy); + w.set(nn,dd); + +#endif + + return w; +} + +// +// fast multiplication by p-1+t +// We know F^2-tF+p = 0 +// So p.S=t.F(S)-F^2(S), where F is Frobenius Endomorphism +// So (p-1+t).S = t(F(S)+S)-F^2(S)-S +// This is just multiplication by t, which is half size of (p-1+t) +// + +void cofactor(ECn2& S,ZZn2 &F,Big& t) +{ + ZZn2 x,y,w,z; + ECn2 K,T; + + K=S; + z=F; + w=F*F; + S.get(x,y); + x=w*conj(x); + y=z*w*conj(y); + S.set(x,y); + x=w*conj(x); + y=z*w*conj(y); + T.set(x,y); + + S+=K; + S*=t; + + S-=T; + S-=K; + S.norm(); + +} + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn12 g(ECn2& A,ECn2& B,ZZn& Qx,ZZn& Qy) +{ + ZZn2 lam; + ZZn12 r; + ECn2 P=A; + // int fpcb=fpc; + +// Evaluate line from A + A.add(B,lam); +//cout << "point addition/doubling= " << fpc-fpcb << endl; + if (A.iszero()) return (ZZn12)1; +//fpcb=fpc; + r=line(P,A,lam,Qx,Qy); +//cout << "line calculation= " << fpc-fpcb << endl; +//cout << "r= " << r << endl; + return r; +} + +// +// Ate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order q. +// Note that P is a point on the sextic twist of the curve over Fp^2, Q(x,y) is a point on the +// curve over the base field Fp +// + +BOOL fast_pairing(ECn2& P,ZZn& Qx,ZZn& Qy,Big &x,ZZn2 &X,ZZn6& res) +{ + ECn2 A; + int i,nb; + Big n; + ZZn12 w,r,a,b,c,rp; + + n=6*x*x; // t-1 + A=P; // remember A + + nb=bits(n); + r=1; +#ifdef MR_COUNT_OPS +fpc=fpa=fpx=0; +#endif + for (i=nb-2;i>=0;i--) + { + r*=r; + r*=g(A,A,Qx,Qy); + + if (bit(n,i)) + r*=g(A,P,Qx,Qy); + } +#ifdef MR_COUNT_OPS +cout << "Miller fpc= " << fpc << endl; +cout << "Miller fpa= " << fpa << endl; +cout << "Miller fpx= " << fpx << endl; +fpa=fpc=fpx=0; +#endif + if (r.iszero()) return FALSE; + + w=r; + + r.conj(); + r/=w; // r^(p^6-1) + + r.mark_as_unitary(); + + w=r; + r.powq(X); r.powq(X); + r*=w; // r^[(p^6-1)*(p^2+1)] + +// New idea.. + +//1. Calculate a=r^(6x-5) +//2. Calculate b=a^p using Frobenius +//3. Calculate c=ab +//4. Calculate r^p, r^{p^2} and r^{p^3} using Frobenius +//5. Calculate final exponentiation as +// r^{p^3}.[c.(r^p)^2.r^{p^2}]^(6x^2+1).c.(r^p.r)^9.a.r^4 +// +// Does not require multi-exponentiation, but total exponent length is the same. +// Also does not need precomputation (x is sparse). +// + + if (x>0) a=pow(r,6*x-5); + else a=inverse(pow(r,5-6*x)); // inverses are "free" for unitary values + + b=a; b.powq(X); + b*=a; + rp=r; rp.powq(X); + a*=b; + w=r; w*=w; w*=w; + a*=w; + c=rp*r; w=c; w*=w; w*=w; w*=w; w*=c; + a*=w; w=(rp*rp); + + rp.powq(X); + w*=(b*rp); + + c=pow(w,x); + r=w*pow(c,6*x); // r=pow(w,6*x*x+1); // time consuming bit... + + rp.powq(X); a*=rp; + r*=a; +#ifdef MR_COUNT_OPS +cout << "FE fpc= " << fpc << endl; +cout << "FE fpa= " << fpa << endl; +cout << "FE fpx= " << fpx << endl; +fpa=fpc=fpx=0; +#endif + res= real(r); // compress to half size... + + return TRUE; +} + +// +// ecap(.) function +// + +BOOL ecap(ECn2& P,ECn& Q,Big& x,ZZn2 &X,ZZn6& r) +{ + BOOL Ok; + Big xx,yy; + ZZn Qx,Qy; + + P.norm(); + Q.get(xx,yy); Qx=xx; Qy=yy; + + Ok=fast_pairing(P,Qx,Qy,x,X,r); + + if (Ok) return TRUE; + return FALSE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha256 sh; + + shs256_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs256_process(&sh,string[i]); + } + shs256_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn6 x) +{ // Hash an Fp6 to a big number + sha256 sh; + ZZn2 u,v,w; + ZZn h,l; + Big a,hash,p,xx[6]; + char s[HASH_LEN]; + int i,j,m; + + shs256_init(&sh); + x.get(u,v,w); + u.get(l,h); + xx[0]=l; xx[1]=h; + v.get(l,h); + xx[2]=l; xx[3]=h; + w.get(l,h); + xx[4]=l; xx[5]=h; + + for (i=0;i<6;i++) + { + a=xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&sh,m); + a/=256; + } + } + shs256_hash(&sh,s); + hash=from_binary(HASH_LEN,s); + return hash; +} + +// Hash and map a Server Identity to a curve point E_(Fp2) + +ECn2 hash_and_map2(char *ID) +{ + int i; + ECn2 S; + ZZn2 X; + + Big x0=H1(ID); + + forever + { + x0+=1; + X.set((ZZn)0,(ZZn)x0); +//cout << "X= " << X << endl; + if (!S.set(X)) continue; + break; + } + +// cout << "S= " << S << endl; + return S; +} + +// Hash and map a Client Identity to a curve point E_(Fp) of order q + +ECn hash_and_map(char *ID) +{ + ECn Q; + Big x0=H1(ID); + + while (!Q.set(x0,x0)) x0+=1; + + return Q; +} + +int main() +{ + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn2 Server,sS; + ZZn6 sp,ap,bp,res; + ZZn2 X; + Big a,b,s,ss,p,q,x,y,B,cf,t; + int i,bits,A; + time_t seed; + + mip->IOBASE=16; + x= (char *)"600000000000219B"; // found by BN.CPP + + p=36*pow(x,4)-36*pow(x,3)+24*x*x-6*x+1; + t=6*x*x+1; + q=p+1-t; + cf=p-1+t; + modulo(p); + set_frobenius_constant(X); + + cout << "Initialised... " << endl; + + time(&seed); + irand((long)seed); + +#ifdef AFFINE + ecurve((Big)0,(Big)3,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve((Big)0,(Big)3,p,MR_PROJECTIVE); +#endif + + mip->IOBASE=16; + mip->TWIST=MR_SEXTIC_D; // map Server to point on twisted curve E(Fp2) + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + Server=hash_and_map2((char *)"Server"); + cofactor(Server,X,t); // fast multiplication by cf + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice"); + Bob= hash_and_map((char *)"Robert"); + + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=ss*Server; + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + // for (i=0;i<1000;i++) + + if (!ecap(Server,sA,x,X,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + ap=powl(res,a); + + if (!ecap(sS,Alice,x,X,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powl(res,s); + + cout << "Alice Key= " << H2(powl(sp,a)) << endl; + cout << "Server Key= " << H2(powl(ap,s)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!ecap(Server,sB,x,X,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powl(res,b); + + if (!ecap(sS,Bob,x,X,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powl(res,s); + + cout << "Bob's Key= " << H2(powl(sp,b)) << endl; + cout << "Server Key= " << H2(powl(bp,s)) << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/ake12bne.cpp b/miracl/source/curve/pairing/ake12bne.cpp new file mode 100644 index 0000000..c2a3b40 --- /dev/null +++ b/miracl/source/curve/pairing/ake12bne.cpp @@ -0,0 +1,498 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=8 ake12bne.cpp zzn12.cpp zzn6a.cpp ecn2.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + using COMBA build + + Barreto-Naehrig curve - Eta pairing + + The curve generated is generated from a 64-bit x parameter + + See "Pairing-Friendly Elliptic Curves of Prime Order", by Paulo S. L. M. Barreto and Michael Naehrig, + Cryptology ePrint Archive: Report 2005/133 + + NOTE: Irreducible polynomial is of the form x^6+(1+sqrt(-2)) + + See bn.cpp for a program to generate suitable BN curves + + Modified to prevent sub-group confinement attack + + Nov. 2007. Now implements Eta or Tate pairing (Eta is faster) + See "A Note on the Ate Pairing", by Chang-An Zhao, Fangguo Zhang and Jiwu Huang + http://eprint.iacr.org/2007/247.pdf, and + "On compressible pairings and their computation", by Naehrig & Barreto + http://eprint.iacr.org/2007/429 + + Select which pairing below. +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn2.h" +#include "zzn12.h" + +// cofactor - number of points on curve=CF.q + +using namespace std; + +Miracl precision(8,0); + +// Using SHA-256 as basic hash algorithm + +#ifdef MR_COUNT_OPS +extern "C" +{ + int fpc,fpa,fpx,fpm2,fpi2; +} +#endif + + +#define HASH_LEN 32 + +//#define TATE +#define ETA + + +// +// Define one or the other of these +// +// Which is faster depends on the I/M ratio - See imratio.c +// Roughly if I/M ratio > 16 use PROJECTIVE, otherwise use AFFINE +// + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; +#ifndef MR_AFFINE_ONLY + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +#endif +} + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + X.set((Big)0,(Big)1); // = (sqrt(-2)^(p-1)/2 + break; + case 3: // = (1+sqrt(-1))^(p-1)/2 + X.set((Big)1,(Big)1); + break; + case 7: + X.set((Big)2,(Big)1); // = (2+sqrt(-1))^(p-1)/2 + default: break; + } + X=pow(X,(p-1)/6); +} + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn12 line(ECn& A,ECn& C,ZZn& slope,ZZn2& Qx,ZZn2& Qy) +{ + ZZn12 w; + ZZn6 nn,dd; + ZZn x,y,z,t; + +#ifdef AFFINE + dd.set1(Qy); + extract(A,x,y); + nn.set(slope*x-y,-slope*Qx); + w.set(nn,dd); +#endif +#ifdef PROJECTIVE + extract(A,x,y,z); + x*=z; t=z; z*=z; z*=t; + x*=slope; t=slope*z; + nn.set1(Qx*t); + nn-=x; t=z; + extract(C,x,x,z); + nn+=(z*y); t*=z; + dd.set1(-t*Qy); + w.set(nn,dd); +#endif + return w; +} + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn12 g(ECn& A,ECn& B,ZZn2& Qx,ZZn2& Qy) +{ + int type; + ZZn6 u; + big ptr; + ZZn12 r; + ZZn lam; + ECn P=A; + +// Evaluate line from A + type=A.add(B,&ptr); + if (!type) return (ZZn12)1; + lam=ptr; + if (A.iszero()) return (ZZn12)1; + r=line(P,A,lam,Qx,Qy); +//cout << "r= " << r << endl; + return r; +} + +// +// Eta or Tate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order m.q. +// Note that P is a point on the curve over Fp, Q(x,y) a point on the +// sextic twist curve over the extension field Fp^2 +// + +BOOL fast_pairing(ECn& P,ZZn2& Qx,ZZn2& Qy,Big &x,ZZn2 &X,ZZn6& res) +{ + ECn A; + int i,nb; + Big n,p,q,t,rho; + ZZn12 w,r,a,b,c,rp; +#ifdef MR_COUNT_OPS +fpc=fpa=fpx=0; +#endif + p=36*pow(x,4)-36*pow(x,3)+24*x*x-6*x+1; + t=6*x*x+1; + q=p+1-t; + + A=P; // remember A +#ifdef TATE + n=q-1; // Tate Pairing +#endif +#ifdef ETA + n = ((t-1)*(t-1))%q - 1; // Eta pairing +#endif + nb=bits(n); + r=1; + + for (i=nb-2;i>=0;i--) + { + r*=r; + r*=g(A,A,Qx,Qy); + + if (bit(n,i)) + r*=g(A,P,Qx,Qy); + } +#ifdef MR_COUNT_OPS +printf("After tate fpc= %d fpa= %d fpx= %d\n",fpc,fpa,fpx); +fpa=fpc=fpx=0; +#endif +#ifdef TATE + if (A != -P || r.iszero()) return FALSE; +#endif + w=r; + + r.conj(); + r/=w; // r^(p^6-1) + + r.mark_as_unitary(); + + w=r; + r.powq(X); r.powq(X); + + r*=w; // r^[(p^6-1)*(p^2+1)] + +// New idea.. + +//1. Calculate a=r^(6x-5) +//2. Calculate b=a^p using Frobenius +//3. Calculate c=ab +//4. Calculate r^p, r^{p^2} and r^{p^3} using Frobenius +//5. Calculate final exponentiation as +// r^{p^3}.[c.(r^p)^2.r^{p^2}]^{6x^2+1).c.(r^p.r)^9.a.r^4 + +// +// Does not require multi-exponentiation, but total exponent length is the same. +// Also does not need precomputation (x is sparse) + + if (x>0) a=pow(r,6*x-5); + else a=inverse(pow(r,5-6*x)); // inverses are "free" for unitary values + + b=a; b.powq(X); + b*=a; + rp=r; rp.powq(X); + a*=b; + w=r; w*=w; w*=w; + a*=w; + c=rp*r; w=c; w*=w; w*=w; w*=w; w*=c; + a*=w; w=(rp*rp); + + rp.powq(X); + w*=(b*rp); + + c=pow(w,x); + r=w*pow(c,6*x); // r=pow(w,6*x*x+1); // time consuming bit... + + + rp.powq(X); a*=rp; + r*=a; +#ifdef MR_COUNT_OPS +printf("After final exp fpc= %d fpa= %d fpx= %d\n",fpc,fpa,fpx); +#endif + res= real(r); + return TRUE; +} + +// +// ecap(.) function +// + +BOOL ecap(ECn& P,ECn2& Q,Big& x,ZZn2 &X,ZZn6& r) +{ + BOOL Ok; + ECn PP=P; + ZZn2 Qx,Qy; + + normalise(PP); + Q.get(Qx,Qy); + + Ok=fast_pairing(PP,Qx,Qy,x,X,r); + + if (Ok) return TRUE; + return FALSE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha256 sh; + + shs256_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs256_process(&sh,string[i]); + } + shs256_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn6 x) +{ // Hash an Fp6 to a big number + sha256 sh; + ZZn2 u,v,w; + ZZn h,l; + Big a,hash,p,xx[6]; + char s[HASH_LEN]; + int i,j,m; + + shs256_init(&sh); + x.get(u,v,w); + u.get(l,h); + xx[0]=l; xx[1]=h; + v.get(l,h); + xx[2]=l; xx[3]=h; + w.get(l,h); + xx[4]=l; xx[5]=h; + + for (i=0;i<6;i++) + { + a=xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&sh,m); + a/=256; + } + } + shs256_hash(&sh,s); + hash=from_binary(HASH_LEN,s); + return hash; +} + +// Hash and map a Server Identity to a curve point E_(Fp2) + +ECn2 hash_and_map2(char *ID) +{ + int i; + ECn2 S; + ZZn2 X; + + Big x0=H1(ID); + + forever + { + x0+=1; + X.set((ZZn)0,(ZZn)x0); +//cout << "X= " << X << endl; + if (!S.set(X)) continue; + + break; + } + +// cout << "S= " << S << endl; + return S; +} + +// Hash and map a Client Identity to a curve point E_(Fp) of order q + +ECn hash_and_map(char *ID) +{ + ECn Q; + Big x0=H1(ID); + + while (!Q.set(x0,x0)) x0+=1; + + return Q; +} + +int main() +{ + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn2 B6,Server,sS; + ZZn6 sp,ap,bp,res; + ZZn2 X; + Big a,b,s,ss,p,q,x,y,B,cf,t; + int i,bits,A; + time_t seed; + + mip->IOBASE=16; + x= (char *)"600000000000219B"; // found by BN.CPP + + p=36*pow(x,4)-36*pow(x,3)+24*x*x-6*x+1; + t=6*x*x+1; + q=p+1-t; + cf=p-1+t; + modulo(p); + set_frobenius_constant(X); + + cout << "Initialised... " << endl; + + time(&seed); + irand((long)seed); + +#ifdef AFFINE + ecurve((Big)0,(Big)3,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve((Big)0,(Big)3,p,MR_PROJECTIVE); +#endif + + mip->IOBASE=16; + mip->TWIST=MR_SEXTIC_D; // map Server to point on twisted curve E(Fp2) + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + Server=hash_and_map2((char *)"Server"); + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice"); + Bob= hash_and_map((char *)"Robert"); + + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=ss*Server; + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + +// for (i=0;i<10000;i++) + + if (!ecap(sA,Server,x,X,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + ap=powl(res,a); + + if (!ecap(Alice,sS,x,X,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powl(res,s); + + cout << "Alice Key= " << H2(powl(sp,a)) << endl; + cout << "Server Key= " << H2(powl(ap,s)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!ecap(sB,Server,x,X,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powl(res,b); + + if (!ecap(Bob,sS,x,X,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powl(res,s); + + cout << "Bob's Key= " << H2(powl(sp,b)) << endl; + cout << "Server Key= " << H2(powl(bp,s)) << endl; + + + return 0; +} + diff --git a/miracl/source/curve/pairing/ake12bnr.cpp b/miracl/source/curve/pairing/ake12bnr.cpp new file mode 100644 index 0000000..5b08fa3 --- /dev/null +++ b/miracl/source/curve/pairing/ake12bnr.cpp @@ -0,0 +1,713 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=8 ake12bnr.cpp zzn12.cpp zzn6a.cpp ecn2.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + using COMBA build + + Using g++, compile as + + g++ -O2 -DZZNS=4 ake12bnr.cpp zzn12.cpp zzn6a.cpp ecn2.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.a -o ake12bnr + + Barreto-Naehrig curve - R-ate pairing + + The curve generated is generated from a 64-bit x parameter + + See "Efficient and Generalized pairing Computation on Abelian Varieties", by E. Lee, H-S Lee and C-M Park + Cryptology ePrint Archive: Report 2008/040 + + NOTE: Irreducible polynomial is of the form x^6+(2+sqrt(-1)) + + See bn.cpp for a program to generate suitable BN curves + + Modified to prevent sub-group confinement attack + + This is implemented using a 2-3-2 tower +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn2.h" +#include "zzn12.h" + +// cofactor - number of points on curve=CF.q + +using namespace std; + +#ifdef MR_COUNT_OPS +extern "C" +{ + int fpc=0; + int fpa=0; + int fpx=0; + int fpm2=0; + int fpi2=0; +} +#endif + +Miracl precision(8,0); + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// Using SHA-256 as basic hash algorithm + +#define HASH_LEN 32 + +// +// R-ate Pairing Code +// + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + X.set((Big)0,(Big)1); // = (sqrt(-2)^(p-1)/2 + break; + case 3: // = (1+sqrt(-1))^(p-1)/2 + X.set((Big)1,(Big)1); + break; + case 7: + X.set((Big)2,(Big)1); // = (2+sqrt(-1))^(p-1)/2 + default: break; + } + X=pow(X,(p-1)/6); +} + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn12 line(ECn2& A,ECn2& C,ECn2&B,ZZn2& slope,ZZn2& extra,BOOL Doubling,ZZn& Qx,ZZn& Qy) +{ + ZZn12 w; + ZZn6 nn,dd; + ZZn2 X,Y; + +#ifdef AFFINE + A.get(X,Y); + + dd.set(slope*Qx,Y-slope*X); + nn.set((ZZn2)-Qy); + w.set(nn,dd); + +#endif +#ifdef PROJECTIVE + ZZn2 Z3; + + C.getZ(Z3); + +// Thanks to A. Menezes for pointing out this optimization... + if (Doubling) + { + ZZn2 Z,ZZ; + A.get(X,Y,Z); + ZZ=Z; ZZ*=ZZ; + dd.set(-(ZZ*slope)*Qx,slope*X-extra); + nn.set((Z3*ZZ)*Qy); + } + else + { + ZZn2 X2,Y2; + B.get(X2,Y2); + dd.set(-slope*Qx,slope*X2-Y2*Z3); + nn.set(Z3*Qy); + } + w.set(nn,dd); +#endif +//cout << "w= " << w << endl; + return w; +} + +// +// fast multiplication by p-1+t +// We know F^2-tF+p = 0 +// So p.S=t.F(S)-F^2(S), where F is Frobenius Endomorphism +// So (p-1+t).S = t(F(S)+S)-F^2(S)-S +// This is just multiplication by t, which is half size of (p-1+t) +// + +void cofactor(ECn2& S,ZZn2 &F,Big& t) +{ + ZZn2 x,y,w,z; + ZZn6 h,l,W; + ECn2 K,T; + + K=S; + z=F; + w=F*F; + S.get(x,y); + x=w*conj(x); + y=z*w*conj(y); + S.set(x,y); + x=w*conj(x); + y=z*w*conj(y); + T.set(x,y); + + S+=K; + S*=t; + + S-=T; + S-=K; + S.norm(); + + +// First "untwist" the point A to (X,Y) where X,Y in F_p^{12} + +/* + K=S; + ZZn12 X,Y,X2,Y2; + S.get(x,y); + + h.clear(); + l.set1(x); + X.set(l,h); + + l.clear(); + h.set1(y); + Y.set(l,h); + + +// Apply the Frobenius.. + X.powq(F); + Y.powq(F); + + X2=X; X2.powq(F); + Y2=Y; Y2.powq(F); + +// Now "twist" it back to S + + X.get(l,h); + l.get1(x); + + Y.get(l,h); + h.get1(y); + S.set(x,y); + +// untwist unto T + + X2.get(l,h); + l.get1(x); + + Y2.get(l,h); + h.get1(y); + + T.set(x,y); + + S+=K; + S*=t; + S-=T; + S-=K; +*/ +} + +void q_power_frobenius(ECn2 &A,ZZn2 &F) +{ +// Fast multiplication of A by q (for Trace-Zero group members only) + ZZn2 x,y,z,w,r; + +// Faster method + +#ifdef AFFINE + A.get(x,y); +#else + A.get(x,y,z); +#endif + + w=F*F; + r=F; + + x=w*conj(x); + y=r*w*conj(y); + +#ifdef AFFINE + A.set(x,y); +#else + z=conj(z); + A.set(x,y,z); +#endif + + +/* + +// First "untwist" the point A to (X,Y) where X,Y in F_p^{12} + A.get(x,y); + h.clear(); + l.set1(x); + X.set(l,h); + + l.clear(); + h.set1(y); + Y.set(l,h); + +// Apply the Frobenius.. + + X.powq(F); + Y.powq(F); + +// Now "twist" it back to A + + X.get(l,h); + l.get1(x); + + Y.get(l,h); + h.get1(y); + + A.set(x,y); + +*/ +} + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn12 g(ECn2& A,ECn2& B,ZZn& Qx,ZZn& Qy) +{ + ZZn2 lam,extra; + ZZn12 r; + ECn2 P=A; + BOOL Doubling; + +// Evaluate line from A + Doubling=A.add(B,lam,extra); + + if (A.iszero()) return (ZZn12)1; + r=line(P,A,B,lam,extra,Doubling,Qx,Qy); + + return r; +} + +// +// R-ate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order q. +// Note that P is a point on the sextic twist of the curve over Fp^2, Q(x,y) is a point on the +// curve over the base field Fp +// + +BOOL fast_pairing(ECn2& P,ZZn& Qx,ZZn& Qy,Big &x,ZZn2 &X,ZZn6& res) +{ + ECn2 A,KA; + ZZn2 AX,AY; + int i,nb; + Big n; + ZZn12 r,w; + ZZn12 t0,t1; + ZZn12 x0,x1,x2,x3,x4,x5; + +#ifdef MR_COUNT_OPS +fpc=fpa=fpx=0; +#endif + + if (x>0) n=6*x+2; + else n=-3-6*x; + + A=P; + nb=bits(n); + r=1; + +// Short Miller loop + + + for (i=nb-2;i>=0;i--) + { + r*=r; + r*=g(A,A,Qx,Qy); + if (bit(n,i)) + r*=g(A,P,Qx,Qy); + } + +// a small amount of extra work.. + t0=r; + KA=A; + if (x>0) + { + r*=g(A,P,Qx,Qy); + r.powq(X); + r*=t0; + } + else + { + r.powq(X); + r*=t0; + r*=g(KA,P,Qx,Qy); + } + + q_power_frobenius(A,X); // A*=(t-1) + + KA.norm(); + r*=g(A,KA,Qx,Qy); + +#ifdef MR_COUNT_OPS +cout << "Miller fpc= " << fpc << endl; +cout << "Miller fpa= " << fpa << endl; +fpa=fpc=fpx=0; +#endif + if (r.iszero()) return FALSE; + +// The final exponentiation + + t0=r; + + r.conj(); + r/=t0; // r^(p^6-1) + + r.mark_as_unitary(); // from now on all inverses are just conjugates !! + + t0=r; + + r.powq(X); + + r.powq(X); + r*=t0; // r^[(p^6-1)*(p^2+1)] + +// Newer new idea... +// See "On the final exponentiation for calculating pairings on ordinary elliptic curves" +// Michael Scott and Naomi Benger and Manuel Charlemagne and Luis J. Dominguez Perez and Ezekiel J. Kachisa + + t1=pow(r,-x); // x is sparse.. + + t0=r; t0.powq(X); + x0=t0; x0.powq(X); + + x0*=(r*t0); + x0.powq(X); + + x1=inverse(r); // just a conjugation! + + x3=t1; x3.powq(X); + x4=t1; + + t1=pow(t1,-x); + + x2=t1; x2.powq(X); + x4/=x2; + + x2.powq(X); + + x5=inverse(t1); + + t0=pow(t1,-x); + t1=t0; t1.powq(X); t0*=t1; + + t0*=t0; + t0*=x4; + t0*=x5; + t1=x3*x5; + t1*=t0; + t0*=x2; + t1*=t1; + t1*=t0; + t1*=t1; + t0=t1*x1; + t1*=x0; + t0*=t0; + t0*=t1; + +#ifdef MR_COUNT_OPS +cout << "FE fpc= " << fpc << endl; +cout << "FE fpa= " << fpa << endl; +cout << "FE fpx= " << fpx << endl; +fpa=fpc=fpx=0; +#endif + + res= real(t0); // compress to half size... + + return TRUE; + +/* + +// New idea.. + +//1. Calculate a=1/r^(6x+5) +//2. Calculate b=a^p using Frobenius +//3. Calculate c=ab +//4. Calculate r^p, r^{p^2} and r^{p^3} using Frobenius +//5. Calculate final exponentiation as +// r^{p^3}.[c.(r^p)^2.r^{p^2}]^{6x^2+1).c.(r^p.r)^9.a.r^4 +// +// Does not require multi-exponentiation, but total exponent length is the same. +// Also does not need precomputation (x is sparse). +// + + if (x<0) + a=pow(r,-5-6*x); + else + a=inverse(pow(r,5+6*x)); // inverses are "free" for unitary values + + b=a; b.powq(X); + b*=a; + rp=r; rp.powq(X); + a*=b; + w=r; w*=w; w*=w; + a*=w; + c=rp*r; w=c; w*=w; w*=w; w*=w; w*=c; + a*=w; w=(rp*rp); + + rp.powq(X); + w*=(b*rp); + + c=pow(w,x); + r=w*pow(c,6*x); // r=pow(w,6*x*x+1); // time consuming bit... + + rp.powq(X); a*=rp; + r*=a; + +#ifdef MR_COUNT_OPS +cout << "FE fpc= " << fpc << endl; +cout << "FE fpa= " << fpa << endl; +cout << "FE fpx= " << fpx << endl; +fpa=fpc=fpx=0; +#endif + res= real(r); // compress to half size... + + return TRUE; + +*/ +} + +// +// ecap(.) function +// + +BOOL ecap(ECn2& P,ECn& Q,Big& x,ZZn2 &X,ZZn6& r) +{ + BOOL Ok; + Big xx,yy; + ZZn Qx,Qy; + + P.norm(); + Q.get(xx,yy); Qx=xx; Qy=yy; + + Ok=fast_pairing(P,Qx,Qy,x,X,r); + + if (Ok) return TRUE; + return FALSE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha256 sh; + + shs256_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs256_process(&sh,string[i]); + } + shs256_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn6 x) +{ // Hash an Fp6 to a big number + sha256 sh; + ZZn2 u,v,w; + ZZn h,l; + Big a,hash,p,xx[6]; + char s[HASH_LEN]; + int i,j,m; + + shs256_init(&sh); + x.get(u,v,w); + u.get(l,h); + xx[0]=l; xx[1]=h; + v.get(l,h); + xx[2]=l; xx[3]=h; + w.get(l,h); + xx[4]=l; xx[5]=h; + + for (i=0;i<6;i++) + { + a=xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&sh,m); + a/=256; + } + } + shs256_hash(&sh,s); + hash=from_binary(HASH_LEN,s); + return hash; +} + +// Hash and map a Server Identity to a curve point E_(Fp2) + +ECn2 hash_and_map2(char *ID) +{ + int i; + ECn2 S; + ZZn2 X; + + Big x0=H1(ID); + + forever + { + x0+=1; + X.set((ZZn)0,(ZZn)x0); +//cout << "X= " << X << endl; + if (!S.set(X)) continue; + break; + } + +// cout << "S= " << S << endl; + return S; +} + +// Hash and map a Client Identity to a curve point E_(Fp) of order q + +ECn hash_and_map(char *ID) +{ + ECn Q; + Big x0=H1(ID); + + while (!Q.set(x0,x0)) x0+=1; + + return Q; +} + +int main() +{ + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn2 Server,sS; + ZZn6 sp,ap,bp,res; + ZZn2 X; + // ZZn12 Y; + Big a,b,s,ss,p,q,x,y,cf,t; + int i,bits,A,B; + time_t seed; + + mip->IOBASE=16; +// x= (char *)"-600000000000219B"; // found by BN.CPP B=3 +// B=3; + x=(char *)"-4080000000000001"; // Nogami et al.'s curve B=22 + B=22; + p=36*pow(x,4)+36*pow(x,3)+24*x*x+6*x+1; + t=6*x*x+1; + q=p+1-t; + cf=p-1+t; + modulo(p); + + set_frobenius_constant(X); + + cout << "Initialised... " << endl; +// cout << "sqrt(-3)= " << sqrt((ZZn)-3,p) << endl; + cout << "p= " << p << endl; + + time(&seed); + irand((long)seed); + +#ifdef AFFINE + ecurve((Big)0,(Big)B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve((Big)0,(Big)B,p,MR_PROJECTIVE); +#endif + + mip->IOBASE=16; + mip->TWIST=MR_SEXTIC_D; // map Server to point on twisted curve E(Fp2) + + ss=rand(q); // TA's super-secret + + Server=hash_and_map2((char *)"Server"); + + cofactor(Server,X,t); // fast multiplication by cf + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice"); + Bob= hash_and_map((char *)"Robert"); + + sS=ss*Server; +//for (i=0;i<10000;i++) + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + +//for (i=0;i<10000;i++) + + if (!ecap(Server,sA,x,X,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + ap=powl(res,a); + + if (!ecap(sS,Alice,x,X,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powl(res,s); + + cout << "Alice Key= " << H2(powl(sp,a)) << endl; + cout << "Server Key= " << H2(powl(ap,s)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!ecap(Server,sB,x,X,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powl(res,b); + + if (!ecap(sS,Bob,x,X,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powl(res,s); + + cout << "Bob's Key= " << H2(powl(sp,b)) << endl; + cout << "Server Key= " << H2(powl(bp,s)) << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/ake12bnx.cpp b/miracl/source/curve/pairing/ake12bnx.cpp new file mode 100644 index 0000000..8d3d7dd --- /dev/null +++ b/miracl/source/curve/pairing/ake12bnx.cpp @@ -0,0 +1,776 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + On 64-bit processors compile as + cl /O2 /GX /DZZNS=4 ake12bnx.cpp zzn12a.cpp zzn4.cpp ecn2.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + using COMBA build + + Using g++, compile as + + g++ -O2 -DZZNS=4 ake12bnx.cpp zzn12a.cpp zzn4.cpp ecn2.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.a -o ake12bnx + + Barreto-Naehrig curve - R-ate pairing, and 1-2-4-12 Towering plus most known optimizations. + + The curve generated is generated from a 64-bit x parameter + + See "Efficient and Generalized pairing Computation on Abelian Varieties", by E. Lee, H-S Lee and C-M Park + Cryptology ePrint Archive: Report 2008/040 + + Irreducible poly is X^3+n, where n=sqrt(w+sqrt(m)), m= {-1,-2} and w= {0,1,2} + if p=5 mod 8, n=sqrt(-2) + if p=3 mod 8, n=1+sqrt(-1) + if p=7 mod 8, p=2,3 mod 5, n=2+sqrt(-1) + + See bn.cpp for a program to generate suitable BN curves + + Modified to prevent sub-group confinement attack. + + Modified 9/11/2011 to support M-type twists + + This is implemented using a 1-2-4-12 tower +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn2.h" +#include "zzn12a.h" + +using namespace std; + +#ifdef MR_COUNT_OPS +extern "C" +{ + int fpc=0; + int fpa=0; + int fpx=0; + int fpm2=0; + int fpi2=0; + int fpmq=0; + int fpsq=0; + int fpaq=0; +} +#endif + +#if MIRACL==64 +Miracl precision(4,0); +#else +Miracl precision(8,0); +#endif + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// Using SHA-256 as basic hash algorithm + +#define HASH_LEN 32 + +// +// R-ate Pairing Code +// + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + X.set((Big)0,(Big)1); // = (sqrt(-2)^(p-1)/2 + break; + case 3: // = (1+sqrt(-1))^(p-1)/2 + X.set((Big)1,(Big)1); + break; + case 7: + X.set((Big)2,(Big)1); // = (2+sqrt(-1))^(p-1)/2 + default: break; + } + X=pow(X,(p-1)/6); +} + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn12 line(ECn2& A,ECn2& C,ECn2& B,ZZn2& slope,ZZn2& extra,BOOL Doubling,ZZn& Qx,ZZn& Qy) +{ + ZZn12 w; + ZZn4 nn,dd,cc; + ZZn2 X,Y; + +#ifdef AFFINE + A.get(X,Y); + + if (get_mip()->TWIST==MR_SEXTIC_M) + { + nn.set(txx((ZZn2)-Qy),Y-slope*X); + cc.seth(slope*Qx); + } + if (get_mip()->TWIST==MR_SEXTIC_D) + { + nn.set((ZZn2)-Qy,Y-slope*X); + dd.set(slope*Qx); + } + w.set(nn,dd,cc); + +#endif +#ifdef PROJECTIVE + ZZn2 Z3; + + C.getZ(Z3); + +// Thanks to A. Menezes for pointing out this optimization... + if (Doubling) + { + ZZn2 Z,ZZ; + A.get(X,Y,Z); + ZZ=Z; ZZ*=ZZ; + if (get_mip()->TWIST==MR_SEXTIC_M) + { // "multiplied across" by i to simplify + nn.set((Z3*ZZ)*txx((ZZn2)Qy),slope*X-extra); + cc.seth(-(ZZ*slope)*Qx); + } + if (get_mip()->TWIST==MR_SEXTIC_D) + { + nn.set((Z3*ZZ)*Qy,slope*X-extra); + dd.set(-(ZZ*slope)*Qx); + } + } + else + { + ZZn2 X2,Y2; + B.get(X2,Y2); + if (get_mip()->TWIST==MR_SEXTIC_M) + { + nn.set(Z3*txx((ZZn2)Qy),slope*X2-Y2*Z3); + cc.seth(-slope*Qx); + } + if (get_mip()->TWIST==MR_SEXTIC_D) + { + nn.set(Z3*Qy,slope*X2-Y2*Z3); + dd.set(-slope*Qx); + } + } + w.set(nn,dd,cc); +#endif + + return w; +} + +void endomorph(ECn &A,ZZn &Beta) +{ // apply endomorphism (x,y) = (Beta*x,y) where Beta is cube root of unity + ZZn x; + x=(A.get_point())->X; + x*=Beta; + copy(getbig(x),(A.get_point())->X); +} + +void q_power_frobenius(ECn2 &A,ZZn2 &F) +{ +// Fast multiplication of A by q (for Trace-Zero group members only) + ZZn2 x,y,z,w,r; + +#ifdef AFFINE + A.get(x,y); +#else + A.get(x,y,z); +#endif + + w=F*F; + r=F; + + if (get_mip()->TWIST==MR_SEXTIC_M) r=inverse(F); // could be precalculated + if (get_mip()->TWIST==MR_SEXTIC_D) r=F; + + w=r*r; + x=w*conj(x); + y=r*w*conj(y); + +#ifdef AFFINE + A.set(x,y); +#else + z.conj(); + A.set(x,y,z); + +#endif +} + +// +// Faster Hashing to G2 - Fuentes-Castaneda, Knapp and Rodriguez-Henriquez +// + +void cofactor(ECn2& S,ZZn2 &F,Big& x) +{ + ECn2 T,K; + T=S; + T*=x; + T.norm(); + K=(T+T)+T; + K.norm(); + q_power_frobenius(K,F); + q_power_frobenius(S,F); q_power_frobenius(S,F); q_power_frobenius(S,F); + S+=T; S+=K; + q_power_frobenius(T,F); q_power_frobenius(T,F); + S+=T; + S.norm(); +} + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn12 g(ECn2& A,ECn2& B,ZZn& Qx,ZZn& Qy) +{ + ZZn2 lam,extra; + ZZn12 r; + ECn2 P=A; + BOOL Doubling; + +// Evaluate line from A + Doubling=A.add(B,lam,extra); + + if (A.iszero()) return (ZZn12)1; + r=line(P,A,B,lam,extra,Doubling,Qx,Qy); + + return r; +} + +// +// R-ate Pairing G2 x G1 -> GT +// +// P is a point of order q in G1. Q(x,y) is a point of order q in G2. +// Note that P is a point on the sextic twist of the curve over Fp^2, Q(x,y) is a point on the +// curve over the base field Fp +// + +BOOL fast_pairing(ECn2& P,ZZn& Qx,ZZn& Qy,Big &x,ZZn2 &X,ZZn12& res) +{ + ECn2 A,KA; + ZZn2 AX,AY; + int i,nb; + Big n; + ZZn12 r; + ZZn12 t0,t1; + ZZn12 x0,x1,x2,x3,x4,x5; + +#ifdef MR_COUNT_OPS +fpc=fpa=fpx=fpmq=fpsq=fpaq=0; +#endif + + if (x<0) n=-(6*x+2); + else n=6*x+2; + A=P; + nb=bits(n); + r=1; +// Short Miller loop + r.mark_as_miller(); + + for (i=nb-2;i>=0;i--) + { + r*=r; + r*=g(A,A,Qx,Qy); + if (bit(n,i)) + r*=g(A,P,Qx,Qy); + } +// Combining ideas due to Longa, Aranha et al. and Naehrig + KA=P; + q_power_frobenius(KA,X); + if (x<0) {A=-A; r.conj();} + r*=g(A,KA,Qx,Qy); + q_power_frobenius(KA,X); KA=-KA; + r*=g(A,KA,Qx,Qy); + +#ifdef MR_COUNT_OPS +cout << "Miller fpc= " << fpc << endl; +cout << "Miller fpa= " << fpa << endl; +cout << "Miller fpx= " << fpx << endl; +cout << "Miller fpmq= " << fpmq << endl; +cout << "Miller fpsq= " << fpsq << endl; +cout << "Miller fpaq= " << fpaq << endl; + +fpa=fpc=fpx=fpmq=fpsq=fpaq=0; +#endif + if (r.iszero()) return FALSE; + +// The final exponentiation + + t0=r; + + r.conj(); + + r/=t0; // r^(p^6-1) + r.mark_as_regular(); // no longer "miller" + + t0=r; + r.powq(X); r.powq(X); + r*=t0; // r^[(p^6-1)*(p^2+1)] + + r.mark_as_unitary(); // from now on all inverses are just conjugates !! (and squarings are faster) + + res=r; +// Newer new idea... +// See "On the final exponentiation for calculating pairings on ordinary elliptic curves" +// Michael Scott and Naomi Benger and Manuel Charlemagne and Luis J. Dominguez Perez and Ezekiel J. Kachisa + + + t0=res; t0.powq(X); + x0=t0; x0.powq(X); + + x0*=(res*t0); + x0.powq(X); + + x1=inverse(res); // just a conjugation! + + x4=pow(res,-x); // x is sparse.. + x3=x4; x3.powq(X); + + x2=pow(x4,-x); + x5=inverse(x2); + t0=pow(x2,-x); + + x2.powq(X); + x4/=x2; + + x2.powq(X); + + res=t0; res.powq(X); t0*=res; + + t0*=t0; + t0*=x4; + t0*=x5; + res=x3*x5; + res*=t0; + t0*=x2; + res*=res; + res*=t0; + res*=res; + t0=res*x1; + res*=x0; + t0*=t0; + t0*=res; + +#ifdef MR_COUNT_OPS +cout << "FE fpc= " << fpc << endl; +cout << "FE fpa= " << fpa << endl; +cout << "FE fpx= " << fpx << endl; +cout << "FE fpmq= " << fpmq << endl; +cout << "FE fpsq= " << fpsq << endl; +cout << "FE fpaq= " << fpaq << endl; +fpa=fpc=fpx=fpmq=fpsq=fpaq=0; +#endif + + res= t0; + return TRUE; +} + +// +// ecap(.) function +// + +BOOL ecap(ECn2& P,ECn& Q,Big& x,ZZn2 &X,ZZn12& r) +{ + BOOL Ok; + Big xx,yy; + ZZn Qx,Qy; + + P.norm(); + Q.get(xx,yy); Qx=xx; Qy=yy; + + Ok=fast_pairing(P,Qx,Qy,x,X,r); + + if (Ok) return TRUE; + return FALSE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha256 sh; + + shs256_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs256_process(&sh,string[i]); + } + shs256_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn12 x) +{ // Compress and hash an Fp12 to a big number + sha256 sh; + ZZn4 u; + ZZn2 h,l; + Big a,hash,p,xx[4]; + char s[HASH_LEN]; + int i,j,m; + + shs256_init(&sh); + x.get(u); // compress to single ZZn4 + u.get(l,h); + xx[0]=real(l); xx[1]=imaginary(l); xx[2]=real(h); xx[3]=imaginary(h); + + for (i=0;i<4;i++) + { + a=xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&sh,m); + a/=256; + } + } + shs256_hash(&sh,s); + hash=from_binary(HASH_LEN,s); + return hash; +} + +// Hash and map a Server Identity to a curve point E_(Fp2) + +ECn2 hash_and_map2(char *ID) +{ + int i; + ECn2 S; + ZZn2 X; + Big x0=H1(ID); + + forever + { + x0+=1; + X.set((ZZn)1,(ZZn)x0); + if (!S.set(X)) continue; + break; + } + return S; +} + +// Hash and map a Client Identity to a curve point E_(Fp) of order q + +ECn hash_and_map(char *ID) +{ + ECn Q; + Big x0=H1(ID); + + while (!Q.set(x0,x0)) x0+=1; + + return Q; +} + +// test if a ZZn12 element is of order q +// test r^q = r^p+1-t =1, so test r^p=r^(t-1) + +BOOL member(ZZn12 r,Big &x,ZZn2 &X) +{ + ZZn12 w=r; + w.powq(X); + r=pow(r,x); r=pow(r,x); r=pow(r,(Big)6); // t-1=6x^2 + if (w==r) return TRUE; + return FALSE; +} + +// Use Galbraith & Scott Homomorphism idea ... + +void galscott(Big &e,Big &r,Big WB[4],Big B[4][4],Big u[4]) +{ + int i,j; + Big v[4],w; + + for (i=0;i<4;i++) + { + v[i]=mad(WB[i],e,(Big)0,r,w); + u[i]=0; + } + + u[0]=e; + for (i=0;i<4;i++) + for (j=0;j<4;j++) + u[i]-=v[j]*B[j][i]; + return; +} + +// GLV method + +void glv(Big &e,Big &r,Big W[2],Big B[2][2],Big u[2]) +{ + int i,j; + Big v[2],w; + for (i=0;i<2;i++) + { + v[i]=mad(W[i],e,(Big)0,r,w); + u[i]=0; + } + u[0]=e; + for (i=0;i<2;i++) + for (j=0;j<2;j++) + u[i]-=v[j]*B[j][i]; + return; +} + +// Use GLV endomorphism idea for multiplication in G1 + + +ECn G1_mult(ECn &P,Big &e,ZZn &Beta,Big &r,Big W[2],Big B[2][2]) +{ +// return e*P; + int i; + ECn Q; + Big u[2]; + glv(e,r,W,B,u); + + Q=P; + endomorph(Q,Beta); + + Q=mul(u[0],P,u[1],Q); + + return Q; +} + +//.. for multiplication in G2 + +ECn2 G2_mult(ECn2 &P,Big &e,ZZn2 &X,Big &r,Big WB[4],Big B[4][4]) +{ +// return e*P; + int i; + ECn2 Q[4]; + Big u[4]; + galscott(e,r,WB,B,u); + + Q[0]=P; + for (i=1;i<4;i++) + { + Q[i]=Q[i-1]; + q_power_frobenius(Q[i],X); + } + +// deal with -ve multipliers + for (i=0;i<4;i++) + { + if (u[i]<0) + {u[i]=-u[i];Q[i]=-Q[i];} + } + +// simple multi-addition + return mul4(Q,u); +} + +//.. and for exponentiation in GT + +ZZn12 GT_pow(ZZn12 &res,Big &e,ZZn2 &X,Big &r,Big WB[4],Big B[4][4]) +{ +// return pow(res,e); + int i,j; + ZZn12 Y[4]; + Big u[4]; + + galscott(e,r,WB,B,u); + + Y[0]=res; + for (i=1;i<4;i++) + {Y[i]=Y[i-1]; Y[i].powq(X);} + +// deal with -ve exponents + for (i=0;i<4;i++) + { + if (u[i]<0) + {u[i]=-u[i];Y[i].conj();} + } + +// simple multi-exponentiation + return pow(4,Y,u); +} + +int main() +{ + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn2 Server,sS; + ZZn12 sp,ap,bp,res; + ZZn2 X; + Big a,b,s,ss,p,q,x,y,cf,t,BB[4][4],WB[4],SB[2][2],W[2]; + int i,A,B; + time_t seed; + + mip->IOBASE=16; + +// Set Curve. Note D-Type Curves are recommended. Use BN.CPP program to generate curves. + +// Curve 1. +// x= (char *)"6000000000160007"; // found by BN.CPP +// B=23; +// mip->TWIST=MR_SEXTIC_D; + +// Curve 2. + x= (char *)"-4080000000000001"; + B=2; + mip->TWIST=MR_SEXTIC_D; + +// Curve 3. +// x= (char *)"408000000000967A"; +// B=2; +// mip->TWIST=MR_SEXTIC_D; + +// Curve 4. +// x= (char *)"4080000000002C77"; +// B=3; +// mip->TWIST=MR_SEXTIC_M; // map Server to point on twisted curve E(Fp2) + +// See ftp://ftp.computing.dcu.ie/pub/resources/crypto/twists.pdf +// D and M-type twists require a different "untwisting" operation - see paper above + + p=36*pow(x,4)+36*pow(x,3)+24*x*x+6*x+1; + t=6*x*x+1; + q=p+1-t; + cf=p-1+t; + modulo(p); + +// Big Lambda=-(36*pow(x,3)+18*x*x+6*x+2); // cube root of unity mod q + ZZn Beta=-(18*pow(x,3)+18*x*x+9*x+2); // cube root of unity mod p + + set_frobenius_constant(X); + +// Use standard Gallant-Lambert-Vanstone endomorphism method for G1 + + W[0]=6*x*x+4*x+1; // This is first column of inverse of SB (without division by determinant) + W[1]=-(2*x+1); + + SB[0][0]=6*x*x+2*x; + SB[0][1]=-(2*x+1); + SB[1][0]=-(2*x+1); + SB[1][1]=-(6*x*x+4*x+1); + +// Use Galbraith & Scott Homomorphism idea for G2 & GT ... (http://eprint.iacr.org/2008/117.pdf Example 5) + + WB[0]=2*x*x+3*x+1; // This is first column of inverse of BB (without division by determinant) + WB[1]=12*x*x*x+8*x*x+x; + WB[2]=6*x*x*x+4*x*x+x; + WB[3]=-2*x*x-x; + + BB[0][0]=x+1; BB[0][1]=x; BB[0][2]=x; BB[0][3]=-2*x; + BB[1][0]=2*x+1; BB[1][1]=-x; BB[1][2]=-(x+1); BB[1][3]=-x; + BB[2][0]=2*x; BB[2][1]=2*x+1; BB[2][2]=2*x+1; BB[2][3]=2*x+1; + BB[3][0]=x-1; BB[3][1]=4*x+2; BB[3][2]=-(2*x-1); BB[3][3]=x-1; + + cout << "Initialised... " << endl; + + time(&seed); + irand((long)seed); + +#ifdef AFFINE + ecurve((Big)0,(Big)B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve((Big)0,(Big)B,p,MR_PROJECTIVE); +#endif + + mip->IOBASE=16; + ss=rand(q); // TA's super-secret + + Server=hash_and_map2((char *)"Server"); + cofactor(Server,X,x); // fast multiplication by cf + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice"); + Bob= hash_and_map((char *)"Robert"); + + + sS=G2_mult(Server,ss,X,q,WB,BB); // Use Galbraith-Scott Homomorphism to multiply in G2 + sA=G1_mult(Alice,ss,Beta,q,W,SB); // Use GLV method to multiply in G1 + sB=G1_mult(Bob,ss,Beta,q,W,SB); + + + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + +//for (i=0;i<10000;i++) // for timing + if (!ecap(Server,sA,x,X,res)) cout << "Trouble" << endl; + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + +#ifdef MR_COUNT_OPS +fpc=fpa=fpx=fpmq=fpsq=fpaq=0; +#endif + ap=GT_pow(res,a,X,q,WB,BB); // Use Galbraith-Scott Homomorphism > 2 times faster! + +#ifdef MR_COUNT_OPS +cout << "EXP fpc= " << fpc << endl; +cout << "EXP fpa= " << fpa << endl; +cout << "EXP fpx= " << fpx << endl; +cout << "EXP fpmq= " << fpmq << endl; +cout << "EXP fpsq= " << fpsq << endl; +cout << "EXP fpaq= " << fpaq << endl; +fpa=fpc=fpx=fpmq=fpsq=fpaq=0; +#endif + + if (!ecap(sS,Alice,x,X,res)) cout << "Trouble" << endl; + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=GT_pow(res,s,X,q,WB,BB); + + cout << "Alice Key= " << H2(GT_pow(sp,a,X,q,WB,BB)) << endl; + cout << "Server Key= " << H2(GT_pow(ap,s,X,q,WB,BB)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!ecap(Server,sB,x,X,res)) cout << "Trouble" << endl; + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=GT_pow(res,b,X,q,WB,BB); + + if (!ecap(sS,Bob,x,X,res)) cout << "Trouble" << endl; + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=GT_pow(res,s,X,q,WB,BB); + + cout << "Bob's Key= " << H2(GT_pow(sp,b,X,q,WB,BB)) << endl; + cout << "Server Key= " << H2(GT_pow(bp,s,X,q,WB,BB)) << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/ake18kssx.cpp b/miracl/source/curve/pairing/ake18kssx.cpp new file mode 100644 index 0000000..bb8b6f2 --- /dev/null +++ b/miracl/source/curve/pairing/ake18kssx.cpp @@ -0,0 +1,796 @@ +/* + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=8 ake18kssx.cpp zzn18.cpp zzn6.cpp ecn3.cpp zzn3.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + KSS k=18 Curve - R-ate pairing + + The KSS curve generated is generated from a 64-bit x parameter + This version implements the R-ate pairing + + NOTE: Irreducible polynomial is of the form x^18+2 + + See kss18.cpp for a program to generate suitable kss18 curves + + Modified to prevent sub-group confinement attack +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn3.h" +#include "zzn18.h" + +using namespace std; + +#ifdef MR_COUNT_OPS +extern "C" +{ + int fpc=0; + int fpa=0; + int fpx=0; + int fpm2=0; + int fpi2=0; +} +#endif + +#if MIRACL==64 +Miracl precision(8,0); +#else +Miracl precision(16,0); +#endif + +// Non-Residue. Irreducible Poly is binomial x^18-NR + +#define NR -2 + +// Using SHA-256 as basic hash algorithm + +#define HASH_LEN 32 + +// +// Ate Pairing Code +// + +// Note - this representation depends on p-1=12 mod 18 + +void set_frobenius_constant(ZZn &X) +{ // Note X=NR^[(p-13)/18]; + Big p=get_modulus(); + X=pow((ZZn)NR,(p-13)/18); +} + +void endomorph(ECn &A,ZZn &Beta) +{ // apply endomorphism (x,y) = (Beta*x,y) where Beta is cube root of unity + ZZn x; + x=(A.get_point())->X; + x*=Beta; + copy(getbig(x),(A.get_point())->X); +} + +// +// This calculates p.A quickly using Frobenius +// 1. Extract A(x,y) from twisted curve to point on curve over full extension, as X=i^2.x and Y=i^3.y +// where i=NR^(1/k) +// 2. Using Frobenius calculate (X^p,Y^p) +// 3. map back to twisted curve +// Here we simplify things by doing whole calculation on the twisted curve +// +// Note we have to be careful as in detail it depends on w where p=w mod k +// In this case w=13 +// + +ECn3 psi(ECn3 &A,ZZn &W,int n) +{ + int i; + ECn3 R; + ZZn3 X,Y; + ZZn FF; +// Fast multiplication of A by q^n + A.get(X,Y); + + FF=NR*W*W; + for (i=0;isru; + } + R.set(X,Y); + return R; +} + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn18 line(ECn3& A,ECn3& C,ZZn3& slope,ZZn& Qx,ZZn& Qy) +{ + ZZn18 w; + ZZn6 nn,dd; + ZZn3 X,Y; + + A.get(X,Y); + + nn.set(Qy,Y-slope*X); + dd.set(slope*Qx); + w.set(nn,dd); + + return w; +} + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn18 g(ECn3& A,ECn3& B,ZZn& Qx,ZZn& Qy) +{ + ZZn3 lam; + ZZn18 r; + ECn3 P=A; + +// Evaluate line from A + A.add(B,lam,NULL,NULL); + if (A.iszero()) return (ZZn18)1; + r=line(P,A,lam,Qx,Qy); + + return r; +} + +ZZn18 Frobenius(const ZZn18& W,ZZn& X,int n) +{ + int i; + ZZn18 V=W; + for (i=0;i=0;i--) + { + r*=r; + r*=g(A,A,Qx,Qy); + if (bit(d,i)) + r*=g(A,P,Qx,Qy); + } + rd=r; + dA=A; + + r*=r; + r*=g(A,A,Qx,Qy); + + m2A=A; + + rd*=r; + rd*=g(A,dA,Qx,Qy); + + r*=Frobenius(rd,X,6); + + A=psi(A,X,6); + r*=g(A,m2A,Qx,Qy); +#ifdef MR_COUNT_OPS +cout << "Miller fpc= " << fpc << endl; +cout << "Miller fpa= " << fpa << endl; +cout << "Miller fpx= " << fpx << endl; +fpa=fpc=fpx=0; +#endif + +// final exponentiation + rd=r; + r.conj(); + r/=rd; // r^(p^9-1) + r.mark_as_regular(); // no longer "miller" + rd=r; + r.powq(X); r.powq(X); r.powq(X); r*=rd; //r^(p^3+1) + + r.mark_as_unitary(); + r=HardExpo(r,X,x); + +#ifdef MR_COUNT_OPS +cout << "FE fpc= " << fpc << endl; +cout << "FE fpa= " << fpa << endl; +cout << "FE fpx= " << fpx << endl; +fpa=fpc=fpx=0; +#endif + + return TRUE; +} + +// +// ecap(.) function +// + +BOOL ecap(ECn3& P,ECn& Q,Big& x,ZZn &X,ZZn18& r) +{ + BOOL Ok; + Big xx,yy; + ZZn Qx,Qy; + + Q.get(xx,yy); Qx=xx; Qy=yy; + + Ok=fast_pairing(P,Qx,Qy,x,X,r); + + if (Ok) return TRUE; + return FALSE; +} + +// +// Hash functions +// + +Big H2(ZZn18 x) +{ // Compress and hash an Fp18 to a big number + sha256 sh; + ZZn6 u; + ZZn3 h,l; + Big a,hash,p; + ZZn xx[6]; + char s[HASH_LEN]; + int i,j,m; + + shs256_init(&sh); + x.get(u); // compress to single ZZn6 + u.get(l,h); + l.get(xx[0],xx[1],xx[2]); + h.get(xx[3],xx[4],xx[5]); + + for (i=0;i<6;i++) + { + a=(Big)xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&sh,m); + a/=256; + } + } + shs256_hash(&sh,s); + hash=from_binary(HASH_LEN,s); + return hash; +} + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha256 sh; + + shs256_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs256_process(&sh,string[i]); + } + shs256_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +// Hash and map a Server Identity to a curve point E_(Fp3) + +ECn3 hash_and_map3(char *ID) +{ + int i; + ECn3 S; + ZZn3 X; + + Big x0=H1(ID); + forever + { + x0+=1; + X.set((ZZn)0,(ZZn)x0,(ZZn)0); + if (!S.set(X)) continue; + break; + } + + return S; +} + +// Hash and Map a Client Identity to a curve point E_(Fp) of order q + +ECn hash_and_map(char *ID,Big cf) +{ + ECn Q; + Big x0=H1(ID); + while (!Q.set(x0,x0)) x0+=1; + Q*=cf; + return Q; +} + +// Faster Hashing to G2 - Fuentes-Castaneda, Knapp and Rodriguez-Henriquez + +ECn3 HashG2(ECn3& Qx0,Big &x,ZZn&F) +{ + ECn3 Qx0_; + ECn3 Qx1; + ECn3 Qx1_; + ECn3 Qx2; + ECn3 Qx2_; + ECn3 Qx3; + ECn3 t1; + ECn3 t2; + ECn3 t3; + ECn3 t4; + ECn3 t5; + ECn3 t6; + + Qx0_=-Qx0; + Qx1=x*Qx0; + Qx1_=-Qx1; + Qx2=x*Qx1; + Qx2_=-Qx2; + Qx3=x*Qx2; + + t1=Qx0; + t2=psi(Qx1_,F,2); + t3=Qx1+psi(Qx1,F,5); + t4=psi(Qx1,F,3)+psi(Qx2,F,1)+psi(Qx2_,F,2); + t5=psi(Qx0_,F,4); + t6=psi(Qx0,F,1)+psi(Qx0,F,3)+psi(Qx2_,F,4)+psi(Qx2,F,5)+psi(Qx3,F,1); + + t2+=t1; // Olivos addition sequence + t1+=t1; + t1+=t3; + t1+=t2; + t4+=t2; + t5+=t1; + t4+=t1; + t5+=t4; + t4+=t6; + t5+=t5; + t5+=t4; + + return t5; +} + +// Use Galbraith & Scott Homomorphism idea ... + +void galscott(Big &e,Big &r,Big WB[6],Big B[6][6],Big u[6]) +{ + int i,j; + Big v[6],w; + + for (i=0;i<6;i++) + { + v[i]=mad(WB[i],e,(Big)0,r,w); + u[i]=0; + } + + u[0]=e; + for (i=0;i<6;i++) + { + for (j=0;j<6;j++) + u[i]-=v[j]*B[j][i]; + } + return; +} + +// GLV method + +void glv(Big &e,Big &r,Big W[2],Big B[2][2],Big u[2]) +{ + int i,j; + Big v[2],w; + for (i=0;i<2;i++) + { + v[i]=mad(W[i],e,(Big)0,r,w); + u[i]=0; + } + u[0]=e; + for (i=0;i<2;i++) + for (j=0;j<2;j++) + u[i]-=v[j]*B[j][i]; + return; +} + +// Use GLV endomorphism idea for multiplication in G1 + +ECn G1_mult(ECn &P,Big &e,ZZn &Beta,Big &r,Big W[2],Big B[2][2]) +{ +// return e*P; + int i; + ECn Q; + Big u[2]; + + glv(e,r,W,B,u); + + Q=P; + endomorph(Q,Beta); + + Q=mul(u[0],P,u[1],Q); + + return Q; +} + +//.. for multiplication in G2 + +ECn3 G2_mult(ECn3 &P,Big &e,ZZn &X,Big &r,Big WB[6],Big B[6][6]) +{ +// return e*P; + int i; + ECn3 Q[6]; + Big u[6]; + galscott(e,r,WB,B,u); + + Q[0]=P; + for (i=1;i<6;i++) + Q[i]=psi(Q[i-1],X,1); + +// deal with -ve multipliers + for (i=0;i<6;i++) + { + if (u[i]<0) + {u[i]=-u[i];Q[i]=-Q[i];} + } + +// simple multi-addition + + return mul(6,Q,u); +} + +//.. and for exponentiation in GT + +ZZn18 GT_pow(ZZn18 &res,Big &e,ZZn &X,Big &r,Big WB[6],Big B[6][6]) +{ +// return pow(res,e); + int i,j; + ZZn18 Y[6]; + Big u[6]; + + galscott(e,r,WB,B,u); + + Y[0]=res; + for (i=1;i<6;i++) + {Y[i]=Y[i-1]; Y[i].powq(X);} + +// deal with -ve exponents + for (i=0;i<6;i++) + { + if (u[i]<0) + {u[i]=-u[i];Y[i].conj();} + } + +// simple multi-exponentiation + return pow(6,Y,u); +} + +int main() +{ + miracl* mip=&precision; + ZZn X; + ZZn3 XX,YY; + ECn Alice,Bob,sA,sB; + ECn3 Server,sS; + ZZn18 sp,ap,bp,res,XXX,YYY; + Big a,b,s,ss,p,q,x,y,B,cf,t,n,sru,BB[6][6],WB[6],SB[2][2],W[2]; + int i,A; + time_t seed; + + mip->IOBASE=16; + + x= (char *)"15000000007004210"; // found by KSS18.CPP - Hamming weight of 9 + t=(pow(x,4) + 16*x + 7)/7; + q=(pow(x,6) + 37*pow(x,3) + 343)/343; + + cf=(49*x*x+245*x+343)/3; + n=cf*q; + p=cf*q+t-1; + +// cout << "p= " << p << endl; +// cout << "bits(p)= " << bits(p) << endl; +// cout << "bits(q)= " << bits(q) << endl; + +// p=(pow(x,8) + 5*pow(x,7) + 7*pow(x,6) + 37*pow(x,5) + 188*pow(x,4) + 259*pow(x,3) + 343*pow(x,2) + 1763*x + 2401)/21; + + time(&seed); + irand((long)seed); + + ecurve((Big)0,(Big)2,p,MR_AFFINE); + +// Big Lambda=pow(x,3)+18; // cube root of unity mod q +// Desperately avoiding overflow... - cube root of unity mod p + Big BBeta=(/*2*pow(x,8)+*/3*pow(x,7)-7*pow(x,6)+46*pow(x,5)+68*pow(x,4)-308*pow(x,3)+189*x*x+145*x-3192)/56; + BBeta+=x*(pow(x,7)/28); + BBeta/=3; + + sru=p-BBeta; // sixth root of unity = -Beta + set_zzn3(NR,sru); + ZZn Beta=BBeta; + +// Use standard Gallant-Lambert-Vanstone endomorphism method for G1 + + W[0]=(x*x*x)/343; // This is first column of inverse of SB (without division by determinant) + W[1]=(18*x*x*x+343)/343; + + SB[0][0]=(x*x*x)/343; + SB[0][1]=-(18*x*x*x+343)/343; + SB[1][0]=(19*x*x*x+343)/343; + SB[1][1]=(x*x*x)/343; + +// Use Galbraith & Scott Homomorphism idea for G2 & GT ... (http://eprint.iacr.org/2008/117.pdf) + + WB[0]=5*pow(x,3)/49+2; // This is first column of inverse of BB (without division by determinant) + WB[1]=-(x*x)/49; + WB[2]=pow(x,4)/49+3*x/7; + WB[3]=-(17*pow(x,3)/343+1); + WB[4]=-(pow(x,5)/343+2*(x*x)/49); + WB[5]=5*pow(x,4)/343+2*x/7; + + BB[0][0]=1; BB[0][1]=0; BB[0][2]=5*x/7; BB[0][3]=1; BB[0][4]=0; BB[0][5]=-x/7; + BB[1][0]=-5*x/7; BB[1][1]=-2; BB[1][2]=0; BB[1][3]=x/7; BB[1][4]=1; BB[1][5]=0; + BB[2][0]=0; BB[2][1]=2*x/7; BB[2][2]=1; BB[2][3]=0; BB[2][4]=x/7; BB[2][5]=0; + BB[3][0]=1; BB[3][1]=0; BB[3][2]=x; BB[3][3]=2; BB[3][4]=0; BB[3][5]=0; + BB[4][0]=-x; BB[4][1]=-3; BB[4][2]=0; BB[4][3]=0; BB[4][4]=1; BB[4][5]=0; + BB[5][0]=0; BB[5][1]=-x; BB[5][2]=-3; BB[5][3]=0; BB[5][4]=0; BB[5][5]=1; + + cout << "Initialised... " << endl; + + mip->IOBASE=16; + + mip->TWIST=MR_SEXTIC_D; // map Server to point on twisted curve E(Fp3) + // See ftp://ftp.computing.dcu.ie/pub/resources/crypto/twists.pdf + // NOTE: This program only supports D-type twists + // An M-type twist requires a different "untwisting" operation - see paper above + + set_frobenius_constant(X); + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice",cf); + Bob= hash_and_map((char *)"Robert",cf); + cout << "Mapping Server ID to point" << endl; + Server=hash_and_map3((char *)"Server"); + Server=HashG2(Server,x,X); // fast multiplication by co-factor + + ss=rand(q); // TA's super-secret + + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=G2_mult(Server,ss,X,q,WB,BB); + sA=G1_mult(Alice,ss,Beta,q,W,SB); + sB=G1_mult(Bob,ss,Beta,q,W,SB); + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + // for (i=0;i<1000;i++) + if (!ecap(Server,sA,x,X,res)) cout << "Trouble" << endl; + if (pow(res,q)!=(ZZn18)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + ap=GT_pow(res,a,X,q,WB,BB); + + if (!ecap(sS,Alice,x,X,res)) cout << "Trouble" << endl; + if (pow(res,q)!=(ZZn18)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + sp=GT_pow(res,s,X,q,WB,BB); + + cout << "Alice Key= " << H2(GT_pow(sp,a,X,q,WB,BB)) << endl; + cout << "Server Key= " << H2(GT_pow(ap,s,X,q,WB,BB)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!ecap(Server,sB,x,X,res)) cout << "Trouble" << endl; + if (pow(res,q)!=(ZZn18)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + bp=GT_pow(res,b,X,q,WB,BB); + + if (!ecap(sS,Bob,x,X,res)) cout << "Trouble" << endl; + if (pow(res,q)!=(ZZn18)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + sp=GT_pow(res,s,X,q,WB,BB); + + cout << "Bob's Key= " << H2(GT_pow(sp,b,X,q,WB,BB)) << endl; + cout << "Server Key= " << H2(GT_pow(bp,s,X,q,WB,BB)) << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/ake1kmt.cpp b/miracl/source/curve/pairing/ake1kmt.cpp new file mode 100644 index 0000000..117383a --- /dev/null +++ b/miracl/source/curve/pairing/ake1kmt.cpp @@ -0,0 +1,563 @@ +/* + + Scott's AKE Client/Server testbed + + See http://www.compapp.dcu.ie/research/CA_Working_Papers/wp02.html#0202 + + Compile as + cl /O2 /GX ake1kmt.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + Requires file xk1.ecs which contains details of non-supersingular + elliptic curve, with security multiplier k=1. The prime p is 1024 bits + + xk1.ecs is generated by make_k1.cpp +*/ + +#include +#include +#include "ecn.h" +#include "zzn.h" +#include + +using namespace std; + +#ifdef MR_COUNT_OPS +extern "C" +{ + int fpc=0; + int fpa=0; + int fpx=0; +} +#endif + +//#define ENDO + +Miracl precision(32,0); + +// Using SHA-512 as basic hash algorithm + +#define HASH_LEN 64 + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=(ZZn)1; + else z=t; +} + +void insert(ECn& A,ZZn& x,ZZn& y,ZZn &z) +{ + copy(x.getzzn(),(A.get_point())->X); + copy(y.getzzn(),(A.get_point())->Y); + copy(z.getzzn(),(A.get_point())->Z); + A.get_point()->marker=MR_EPOINT_GENERAL; +} + +// +// Add A=A+B (or A=A+A) +// Calculate numerators and denominators +// Line from A to destination B. Let A=(x,y) +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// Also evaluate vertical line through destination +// + +void g(ECn& A,ECn& B,ZZn& Qx,ZZn& Qy,ZZn& bQx,ZZn& num,ZZn& denom,ZZn& num2,ZZn& denom2,BOOL last) +{ + ZZn lam,x,y,z,x2,y2,z2,t1,t2,t3; + ZZn zz,zzz; + +// Evaluate line from A - lam is line slope + + extract(A,x,y,z); + zz=z*z; zzz=zz*z; + + if (&A==&B) + { // double + t1=x*x; lam=t1+t1+t1; t2=y*y; + t3=x*t2; t3+=t3; t3+=t3; + x2=lam*lam-(t3+t3); + z2=z*y; z2+=z2; + t1=t2+t2; t2=t1*t1; t2+=t2; + t3-=x2; y2=lam*t3-t2; + } + else + { // add + ZZn xs,ys; + extract(B,xs,ys); + + t1=zz*xs; + lam=zzz*ys; t1-=x; lam-=y; + z2=z*t1; t3=t1*t1; t2=t3*t1; + t3*=x; t1=t3+t3; x2=lam*lam-t1-t2; t2*=y; + t3-=x2; y2=lam*t3-t2; + } + + t1=z2*z2; + lam*=z; lam*=z2; + t2=zzz*Qy; + + num=t1*(t2-y)-lam*(zz*Qx-x); + denom=zzz*(t1*Qx-x2); + if (!last) + { + num2=t1*(t2+y)+lam*(zz*bQx-x); + denom2=zzz*(t1*bQx-x2); + } + else + { + num2=-zz*bQx+x; + denom2=zz; + } + + insert(A,x2,y2,z2); + return; +} + + +void g(ECn& A,ECn& B,ZZn& Qx,ZZn& Qy,ZZn& num,ZZn& denom,BOOL last) +{ + ZZn lam,x,y,z,x2,y2,z2,t1,t2,t3; + ZZn zz,zzz; + +// Evaluate line from A - lam is line slope + + extract(A,x,y,z); + zz=z*z; zzz=zz*z; + + if (&A==&B) + { // double + t1=x*x; lam=t1+t1+t1; t2=y*y; + t3=x*t2; t3+=t3; t3+=t3; + x2=lam*lam-(t3+t3); + z2=z*y; z2+=z2; + t1=t2+t2; t2=t1*t1; t2+=t2; + t3-=x2; y2=lam*t3-t2; + } + else + { // add + ZZn xs,ys; + extract(B,xs,ys); + + t1=zz*xs; + lam=zzz*ys; t1-=x; lam-=y; + z2=z*t1; t3=t1*t1; t2=t3*t1; + t3*=x; t1=t3+t3; x2=lam*lam-t1-t2; t2*=y; + t3-=x2; y2=lam*t3-t2; + } + + t1=z2*z2; + lam*=z; lam*=z2; + t2=zzz*Qy; + + if (!last) + { + num=t1*(t2-y)-lam*(zz*Qx-x); + denom=zzz*(t1*Qx-x2); + } + else + { + num=-zz*Qx+x; + denom=zz; + } + + insert(A,x2,y2,z2); + return; +} + + +// +// Tate Pairing - Note no denominator elimination possible +// +// P is a point of order q. Q(x,y) is a point of order m.q. +// Note that P and Q are points on the curve over Fp +// + +BOOL fast_tate_pairing(ECn& P,ZZn& Qx,ZZn& Qy,ZZn& bQx,Big& q,Big& cofactor,ZZn& res) +{ + int i,j,nb; + ECn A,W; + ZZn ha,had,hab,ha2,had2; + ZZn n,d,n2,d2; + + ha=had=ha2=had2=1; + +#ifdef MR_COUNT_OPS +fpc=fpa=fpx=0; +#endif + + normalise(P); + + A=P; +#ifndef ENDO +// Here I am not using the endomorphism... + nb=bits(q); + for (i=nb-2;i>=1;i--) + { + ha*=ha; + had*=had; + g(A,A,Qx,Qy,n,d,FALSE); + ha*=n; + had*=d; + if (bit(q,i)==1) + { + g(A,P,Qx,Qy,n,d,FALSE); + ha*=n; + had*=d; + } + } + ha*=ha; + had*=had; + g(A,A,Qx,Qy,n,d,FALSE); + ha*=n; + had*=d; + + g(A,P,Qx,Qy,n,d,TRUE); + ha*=n; + had*=d; + + ha/=had; + +#else + + // lambda=pow((Big)2,80)+pow((Big)2,16); + // Use endomorphism for half length loop.. + + for (i=0;i<64;i++) + { + ha*=ha; ha2*=ha2; + had*=had; had2*=had2; + g(A,A,Qx,Qy,bQx,n,d,n2,d2,FALSE); + + ha*=n; ha2*=n2; + had*=d; had2*=d2; + } + + g(A,P,Qx,Qy,bQx,n,d,n2,d2,FALSE); + + ha*=n; ha2*=n2; + had*=d; had2*=d2; + + for (i=0;i<16;i++) + { + ha*=ha; ha2*=ha2; + had*=had; had2*=had2; + g(A,A,Qx,Qy,bQx,n,d,n2,d2,FALSE); + + ha*=n; ha2*=n2; + had*=d; had2*=d2; + } + + g(A,P,Qx,Qy,bQx,n,d,n2,d2,TRUE); + ha*=n; had*=d; + ha2*=n2; had2*=d2; + + ha/=had; + ha2/=had2; + + hab=ha; + for (i=0;i<64;i++) ha*=ha; + ha*=hab; + for (i=0;i<16;i++) ha*=ha; + ha*=ha2; + +#endif + res=ha; + res=res*res*res; // wipes out multiples of zeta + res=pow(res,cofactor); // since p=1 mod 4, -1 gets wiped out as well + res=pow(res,cofactor); + res=pow(res,q); + +#ifdef MR_COUNT_OPS +cout << "Tate fpc= " << fpc << endl; +cout << "Tate fpa= " << fpa << endl; +cout << "Tate fpx= " << fpx << endl; +fpa=fpc=fpx=0; +#endif + + if (res==(ZZn)1) return FALSE; + return TRUE; +} + +// +// Pairing ecap(.) function +// + +BOOL ecap(ECn& P,ECn& Q,Big& order,ZZn& zeta,Big& cofactor,ZZn& res) +{ + BOOL Ok; + Big Qx,Qy; + ZZn bQx; + + Q.get(Qx,Qy); + bQx=zeta*zeta*(ZZn)Qx; + Ok=fast_tate_pairing(P,(ZZn)Qx,(ZZn)Qy,bQx,order,cofactor,res); + + if (Ok) return TRUE; + return FALSE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha512 sh; + + shs512_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs512_process(&sh,string[i]); + } + shs512_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn x) +{ // Hash an Fp to a big number + sha sh; + Big a,b,h,p; + char s[20]; + int i,j,m; + + shs_init(&sh); + a=x; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + shs_hash(&sh,s); + h=from_binary(20,s); + return h; +} + +// Hash and map an Identity to a curve point E_(Fp) + +ECn hash_and_map(char *ID,Big cof) +{ + ECn Q; + Big x0=H1(ID); + + while (!Q.set(x0)) x0+=1; + Q*=cof; + return Q; +} + +ECn hash(char *ID) +{ + ECn Q; + Big x0=H1(ID); + + while (!Q.set(x0)) x0+=1; + + return Q; +} + +ECn map_f(ECn& P,ZZn& zeta) +{ + ECn R; + Big x,y; + P.get(x,y); + ZZn X=x; + X=zeta*X; x=Big(X); + if (!R.set(x,y)) cout << "something wrong in map_f" << endl; + return R; +} + +ECn pi1(ECn P,ZZn& zeta,Big lambda) +{ + ECn T,R; + T=lambda*P; + R=map_f(P,zeta); + R-=T; + return R; +} + +ECn pi2(ECn P,ZZn& zeta,Big lambda) +{ + ECn T,R; + T=lambda*P; + T=lambda*T; + R=map_f(P,zeta); + R-=T; + return R; +} + +int main() +{ + ifstream common("xk1.ecs"); // elliptic curve parameters + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn B2,Server,sS; + ZZn X,Y,res,sp,ap,bp,c,third,zeta; + Big r,a,b,s,ss,p,q,x,y,B,cf,t,lambda,cofactor; + int i,bts,A; + time_t seed; + + common >> bts; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B; + +// q=pow((Big)2,159)+pow((Big)2,17)+1; + + lambda=pow((Big)2,80)+pow((Big)2,16); + q=lambda*lambda+lambda+1; + + cofactor=sqrt((p-1)/(3*q*q)); + cf=3*cofactor; + cout << "cofactor in bits= " << bits(cf) << endl; +// cout << "cf= " << cf << endl; + + i=1; + do + { + zeta=(ZZn)pow((Big)++i,(p-1)/3,p); + } while (zeta==1); +// cout << "zeta= " << zeta << endl; +// zeta*=zeta; // may be needed to get right root... + + i=2; + do + { + lambda=pow((Big)++i,(q-1)/3,q); + } while (lambda==1); +// cout << "lambda= " << lambda << endl; + + time(&seed); + irand((long)seed); + + ecurve(A,B,p,MR_PROJECTIVE); + + mip->IOBASE=16; + +// hash Identities to curve point + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + + Server=hash_and_map("Server",cf); +// Server=hash("Server"); //Server*=3; + Server=pi2(Server,zeta,lambda); // Place Server into distinguised group 2 +// cout << "Server= " << Server << endl; + + cout << "Mapping Alice & Bob ID's to points" << endl; + + Alice=hash_and_map("Alice",cf); + Alice=pi1(Alice,zeta,lambda); // got to put Alice and Bob into David's "distinguished" group + // so that endomorphism applies + Bob= hash_and_map("Robert",cf); + Bob=pi1(Bob,zeta,lambda); + +// ecap(Alice,map_f(Bob,zeta),q,zeta,cofactor,res); +// cout << "e(Alice,phi(Bob)) = " << res << endl; +// ecap(Bob,map_f(Alice,zeta),q,zeta,cofactor,res); +// cout << "e(Bob,phi(Alice)) = " << res << endl; + +// exit(0); + +// Calculating e(P,P) != 1 ?? + + third=inverse((ZZn)3,q); // 1/3 mod q + ecap(Alice,3*Alice,q,zeta,cofactor,res); // Note the 3 + cout << "e(Alice,Alice)= " << pow(res,third) << endl; +//exit(0); + ecap(Alice,Bob,q,zeta,cofactor,res); + cout << "e(Alice,Bob)= " << res << endl; + ecap(Bob,Alice,q,zeta,cofactor,res); + cout << "e(Bob,Alice)= " << res << endl; + + ecap(Alice,Server,q,zeta,cofactor,res); + cout << "e(Alice,Server)= " << res << endl; + +// The pairing is symmetric! + zeta*=zeta; // (its the "other" cube root) needed with ENDO + ecap(Server,Alice,q,zeta,cofactor,res); + cout << "e(Server,Alice)= " << res << endl; + zeta*=zeta; + + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=ss*Server; + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number +//#ifndef MR_COUNT_OPS +//for (i=0;i<1000;i++) +//#endif + if (!ecap(sA,Server,q,zeta,cofactor,res)) cout << "Trouble" << endl; + ap=pow(res,a); + + if (!ecap(Alice,sS,q,zeta,cofactor,res)) cout << "Trouble" << endl; + sp=pow(res,s); + + cout << "Alice Key= " << H2(pow(sp,a)) << endl; + cout << "Server Key= " << H2(pow(ap,s)) << endl; + + cout << "Bob and Server Key exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!ecap(sB,Server,q,zeta,cofactor,res)) cout << "Trouble" << endl; + bp=pow(res,b); + + if (!ecap(Bob,sS,q,zeta,cofactor,res)) cout << "Trouble" << endl; + sp=pow(res,s); + + cout << "Bob's Key= " << H2(pow(sp,b)) << endl; + cout << "Server Key= " << H2(pow(bp,s)) << endl; + + cout << "Alice and Bob's attempted Key exchange" << endl; + + ecap(sB,Alice,q,zeta,cofactor,res); + ap=pow(res,a); + + ecap(Bob,sA,q,zeta,cofactor,res); + bp=pow(res,b); + + if (ap==1) cout << "Bob's Key = 1" << endl; + else cout << "Bob's Key= " << H2(pow(ap,b)) << endl; + if (bp==1) cout << "Alice's Key = 1" << endl; + else cout << "Alice's Key= " << H2(pow(bp,a)) << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/ake24blsa.cpp b/miracl/source/curve/pairing/ake24blsa.cpp new file mode 100644 index 0000000..c018752 --- /dev/null +++ b/miracl/source/curve/pairing/ake24blsa.cpp @@ -0,0 +1,711 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + On Windows compile as + cl /O2 /GX /DZZNS=10 ake24blsa.cpp zzn24.cpp zzn8.cpp zzn4.cpp zzn2.cpp zzn.cpp ecn.cpp ecn4.cpp big.cpp miracl.lib + + for 64-bit computer. Change to /DZZNS=20 for 32-bit computer + + On Linux compile as + g++ -O2 -DZZNS=10 ake24blsa.cpp zzn24.cpp zzn8.cpp zzn4.cpp zzn2.cpp zzn.cpp ecn.cpp ecn4.cpp big.cpp miracl.a -o ake24blsa + + Barreto-Lynn-Scott k=24 Curve - ate pairing + + The BLS curve generated is generated from an x parameter + This version implements the ate pairing (which is optimal in this case) + + See bls24.cpp for a program to generate suitable bls24 curves + + Modified to prevent sub-group confinement attack +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn4.h" +#include "zzn24.h" + +using namespace std; + +#ifdef MR_COUNT_OPS +extern "C" +{ + int fpc=0; + int fpa=0; + int fpx=0; + int fpm2=0; + int fpi2=0; + int fpaq=0; + int fpsq=0; + int fpmq=0; +} +#endif + +#if MIRACL==64 +Miracl precision(10,0); +#else +Miracl precision(20,0); +#endif + +// Using SHA-256 as basic hash algorithm + +#define HASH_LEN 32 + +ZZn24 Frobenius(ZZn24 P, ZZn2 &X, int k) +{ + ZZn24 Q=P; + for (int i=0; i return (Qy-y)-slope.(Qx-x) +// + +ZZn24 line(ECn4& A,ECn4& C,ZZn4& slope,ZZn& Qx,ZZn& Qy) +{ + ZZn24 w; + ZZn8 nn,dd; + ZZn4 X,Y; + + A.get(X,Y); + + nn.set((ZZn4)-Qy,Y-slope*X); + dd.set(slope*Qx); + w.set(nn,dd); + + return w; +} + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn24 g(ECn4& A,ECn4& B,ZZn& Qx,ZZn& Qy) +{ + ZZn4 lam; + ZZn24 r; + ECn4 P=A; + +// Evaluate line from A + A.add(B,lam); + if (A.iszero()) return (ZZn24)1; + r=line(P,A,lam,Qx,Qy); + + return r; +} + +// +// This calculates p.A = (X^p,Y^p) quickly using Frobenius +// 1. Extract A(x,y) from twisted curve to point on curve over full extension, as X=i^2.x and Y=i^3.y +// where i=NR^(1/k) +// 2. Using Frobenius calculate (X^p,Y^p) +// 3. map back to twisted curve +// Here we simplify things by doing whole calculation on the twisted curve +// +// Note we have to be careful as in detail it depends on w where p=w mod k +// Its simplest if w=1. +// + +ECn4 psi(ECn4 &A,ZZn2 &F,int n) +{ + int i; + ECn4 R; + ZZn4 X,Y; + ZZn2 FF,W; +// Fast multiplication of A by q^n + A.get(X,Y); + FF=F*F; + W=txx(txx(txx(FF*FF*FF))); + + for (i=0;i=0;i--) + { + r*=r; + r*=g(A,A,Qx,Qy); + + if (bit(n,i)) + r*=g(A,P,Qx,Qy); + } + + if (r.iszero()) return FALSE; +#ifdef MR_COUNT_OPS +cout << "Miller fpc= " << fpc << endl; +cout << "Miller fpa= " << fpa << endl; +cout << "Miller fpx= " << fpx << endl; +fpa=fpc=fpx=0; +#endif + SoftExpo(r,X); + r=HardExpo(r,X,x); +#ifdef MR_COUNT_OPS +cout << "FE fpc= " << fpc << endl; +cout << "FE fpa= " << fpa << endl; +cout << "FE fpx= " << fpx << endl; +fpa=fpc=fpx=0; +#endif + return TRUE; +} + +// +// ecap(.) function +// + +BOOL ecap(ECn4& P,ECn& Q,Big& x,ZZn2 &X,ZZn24& r) +{ + BOOL Ok; + Big xx,yy; + ZZn Qx,Qy; + + Q.get(xx,yy); Qx=xx; Qy=yy; + + Ok=fast_pairing(P,Qx,Qy,x,X,r); + + if (Ok) return TRUE; + return FALSE; +} + +// Automatically generated by Luis Dominguez + +ECn4 HashG2(ECn4& Qx0, Big& x, ZZn2& X){ +//vector=[ 1, 2, 3, 4 ] + ECn4 r; + ECn4 xA; + ECn4 xB; + ECn4 xC; + ECn4 t0; + ECn4 t1; + ECn4 Qx0_; + ECn4 Qx1; + ECn4 Qx1_; + ECn4 Qx2; + ECn4 Qx2_; + ECn4 Qx3; + ECn4 Qx3_; + ECn4 Qx4; + ECn4 Qx4_; + ECn4 Qx5; + ECn4 Qx5_; + ECn4 Qx6; + ECn4 Qx6_; + ECn4 Qx7; + ECn4 Qx7_; + ECn4 Qx8; + ECn4 Qx8_; + + Qx0_=-(Qx0); + Qx1=x*Qx0; + Qx1_=-(Qx1); + Qx2=x*Qx1; + Qx2_=-(Qx2); + Qx3=x*Qx2; + Qx3_=-(Qx3); + Qx4=x*Qx3; + Qx4_=-(Qx4); + Qx5=x*Qx4; + Qx5_=-(Qx5); + Qx6=x*Qx5; + Qx6_=-(Qx6); + Qx7=x*Qx6; + Qx7_=-(Qx7); + Qx8=x*Qx7; + Qx8_=-(Qx8); + + xA=Qx0; + xC=Qx7; + xA+=xC; + xC=psi(Qx2,X,4); + xA+=xC; + xB=Qx0; + xC=Qx7; + xB+=xC; + xC=psi(Qx2,X,4); + xB+=xC; + t0=xA+xB; + xB=Qx2_; + xC=Qx3_; + xB+=xC; + xC=Qx8_; + xB+=xC; + xC=psi(Qx2,X,1); + xB+=xC; + xC=psi(Qx3_,X,1); + xB+=xC; + xC=psi(Qx1,X,6); + xB+=xC; + t0=t0+xB; + xB=Qx4; + xC=Qx5_; + xB+=xC; + xC=psi(Qx0_,X,4); + xB+=xC; + xC=psi(Qx4_,X,4); + xB+=xC; + xC=psi(Qx0,X,5); + xB+=xC; + xC=psi(Qx1_,X,5); + xB+=xC; + xC=psi(Qx2_,X,5); + xB+=xC; + xC=psi(Qx3,X,5); + xB+=xC; + t0=t0+xB; + xA=Qx1; + xC=psi(Qx0_,X,1); + xA+=xC; + xC=psi(Qx1,X,1); + xA+=xC; + xC=psi(Qx4_,X,1); + xA+=xC; + xC=psi(Qx5,X,1); + xA+=xC; + xC=psi(Qx0,X,2); + xA+=xC; + xC=psi(Qx1_,X,2); + xA+=xC; + xC=psi(Qx4_,X,2); + xA+=xC; + xC=psi(Qx5,X,2); + xA+=xC; + xC=psi(Qx0,X,3); + xA+=xC; + xC=psi(Qx1_,X,3); + xA+=xC; + xC=psi(Qx4_,X,3); + xA+=xC; + xC=psi(Qx5,X,3); + xA+=xC; + xC=psi(Qx1,X,4); + xA+=xC; + xC=psi(Qx3,X,4); + xA+=xC; + xC=psi(Qx0_,X,6); + xA+=xC; + xC=psi(Qx2_,X,6); + xA+=xC; + xB=Qx4; + xC=Qx5_; + xB+=xC; + xC=psi(Qx0_,X,4); + xB+=xC; + xC=psi(Qx4_,X,4); + xB+=xC; + xC=psi(Qx0,X,5); + xB+=xC; + xC=psi(Qx1_,X,5); + xB+=xC; + xC=psi(Qx2_,X,5); + xB+=xC; + xC=psi(Qx3,X,5); + xB+=xC; + t1=xA+xB; + t0=t0+t0; + t0=t0+t1; + +r=t0; +return r; +} + +// +// Hash functions +// + +Big H2(ZZn24 x) +{ // Compress and hash an Fp24 to a big number + sha256 sh; + ZZn8 u; + ZZn4 h,l; + ZZn2 t,b; + Big a,hash,p; + ZZn xx[8]; + char s[HASH_LEN]; + int i,j,m; + + shs256_init(&sh); + x.get(u); // compress to single ZZn4 + u.get(l,h); + + l.get(t,b); + + t.get(xx[0],xx[1]); + b.get(xx[2],xx[3]); + + h.get(t,b); + + t.get(xx[4],xx[5]); + b.get(xx[6],xx[7]); + + for (i=0;i<8;i++) + { + a=(Big)xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&sh,m); + a/=256; + } + } + shs256_hash(&sh,s); + hash=from_binary(HASH_LEN,s); + return hash; +} + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha256 sh; + + shs256_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs256_process(&sh,string[i]); + } + shs256_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +// Hash and map a Server Identity to a curve point E_(Fp4) + +ECn4 hash_and_map4(char *ID) +{ + int i; + ECn4 S; + ZZn4 X; + ZZn2 t; + + Big x0=H1(ID); + + forever + { + x0+=1; + t.set((ZZn)0,(ZZn)x0); + X.set(t,(ZZn2)0); + if (!S.set(X)) continue; + break; + } + + return S; +} + +// Hash and Map a Client Identity to a curve point E_(Fp) of order q + +ECn hash_and_map(char *ID,Big cf) +{ + ECn Q; + Big x0=H1(ID); + while (!Q.set(x0,x0)) x0+=1; + Q*=cf; + return Q; +} + +void endomorph(ECn &A,ZZn &Beta) +{ // apply endomorphism P(x,y) = (Beta*x,y) where Beta is cube root of unity + // Actually (Beta*x,-y) = x^4.P + ZZn x,y; + x=(A.get_point())->X; + y=(A.get_point())->Y; + y=-y; + x*=Beta; + copy(getbig(x),(A.get_point())->X); + copy(getbig(y),(A.get_point())->Y); +} + +// Use GLV endomorphism idea for multiplication in G1. + +ECn G1_mult(ECn &P,Big &e,Big &x,ZZn &Beta) +{ +// return e*P; + int i; + ECn Q; + Big x4,u[2]; + x4=x*x; x4*=x4; + u[0]=e%x4; u[1]=e/x4; + + Q=P; + endomorph(Q,Beta); + Q=mul(u[0],P,u[1],Q); + + return Q; +} + +//.. for multiplication in G2 + +ECn4 G2_mult(ECn4 &P,Big e,Big &x,ZZn2 &X) +{ +// return e*P; + int i; + ECn4 Q[8]; + Big u[8]; + + for (i=0;i<8;i++) {u[i]=e%x; e/=x;} + + Q[0]=P; + for (i=1;i<8;i++) + Q[i]=psi(Q[i-1],X,1); + +// simple multi-addition + + return mul(8,Q,u); +} + +//.. and for exponentiation in GT + +ZZn24 GT_pow(ZZn24 &res,Big e,Big &x,ZZn2 &X) +{ +// return pow(res,e); + int i,j; + ZZn24 Y[8]; + Big u[8]; + + for (i=0;i<8;i++) {u[i]=e%x; e/=x;} + + Y[0]=res; + for (i=1;i<8;i++) + {Y[i]=Y[i-1]; Y[i].powq(X);} + +// simple multi-exponentiation + return pow(8,Y,u); +} + +// Fast group membership check for GT +// check if r is of order q +// Test r^q=r^{(p+1-t)/cf}= 1 +// so test r^p=r^x and r^cf !=1 +// exploit cf=(x-1)*(x-1)/3 + +BOOL member(ZZn24 &r,Big &x,ZZn2 &X) +{ + ZZn24 w=r; + ZZn24 rx; + if (r*conj(r)!=(ZZn24)1) return FALSE; // not unitary + w.powq(X); + rx=pow(r,x); + if (w!=rx) return FALSE; + if (r*pow(rx,x)==rx*rx) return FALSE; + return TRUE; +} + +int main() +{ + miracl* mip=&precision; + ZZn2 X; + ECn Alice,Bob,sA,sB; + ECn4 Server,sS; + ZZn24 sp,ap,bp,res; + Big a,b,s,ss,p,q,x,y,B,cf,t,n; + ZZn Beta; + int i; + time_t seed; + + mip->IOBASE=16; + x="E000000000058400"; // low Hamming weight = 7 + t=1+x; + p=(1+x+x*x-pow(x,4)+2*pow(x,5)-pow(x,6)+pow(x,8)-2*pow(x,9)+pow(x,10))/3; + q=1-pow(x,4)+pow(x,8); + + n=p+1-t; + cf=(x-1)*(x-1)/3; //=n/q + + cf=(x-1); // Neat trick! Whole group is non-cyclic - just has (x-1)^2 as a factor + // So multiplication by x-1 is sufficient to create a point of order q + + ecurve((Big)0,(Big)6,p,MR_AFFINE); + set_frobenius_constant(X); + Beta=pow((ZZn)2,(p-1)/3); + Beta*=Beta; // right cube root of unity + + time(&seed); + irand((long)seed); + + ss=rand(q); // TA's super-secret + + mip->TWIST=MR_SEXTIC_D; // map Server to point on twisted curve E(Fp4) + + Server=hash_and_map4((char *)"Server"); + Server=HashG2(Server,x,X); // fast multiplication by co-factor + +// Should be point at infinity +// cout << "psi^2(Server-t*psi(Server)+p*Server= " << psi(Server,X,2)-t*psi(Server,X,1)+p*Server << endl; + + Alice=hash_and_map((char *)"Alice",cf); + Bob= hash_and_map((char *)"Robert",cf); + + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=G2_mult(Server,ss,x,X); + sA=G1_mult(Alice,ss,x,Beta); + sB=G1_mult(Bob,ss,x,Beta); + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + if (!ecap(Server,sA,x,X,res)) cout << "Trouble" << endl; + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + ap=GT_pow(res,a,x,X); + + if (!ecap(sS,Alice,x,X,res)) cout << "Trouble" << endl; + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + sp=GT_pow(res,s,x,X); + + cout << "Alice Key= " << H2(GT_pow(sp,a,x,X)) << endl; + cout << "Server Key= " << H2(GT_pow(ap,s,x,X)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!ecap(Server,sB,x,X,res)) cout << "Trouble" << endl; + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + bp=GT_pow(res,b,x,X); + + if (!ecap(sS,Bob,x,X,res)) cout << "Trouble" << endl; + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + sp=GT_pow(res,s,x,X); + + cout << "Bob's Key= " << H2(GT_pow(sp,b,x,X)) << endl; + cout << "Server Key= " << H2(GT_pow(bp,s,x,X)) << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/ake2cpt.cpp b/miracl/source/curve/pairing/ake2cpt.cpp new file mode 100644 index 0000000..65d6ea3 --- /dev/null +++ b/miracl/source/curve/pairing/ake2cpt.cpp @@ -0,0 +1,451 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=16 ake2cpt.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + using COMBA build + + Cocks-Pinch curve - Tate Pairing + + Requires file k2.ecs which contains details of non-supersingular + elliptic curve, with order divisible by q=2^159+2^17+1, and security + multiplier k=2. The prime p is 512 bits + + CHANGES: Use twisted curve to avoid ECn2 arithmetic completely + Use Lucas functions to evaluate powers. + Output of tate pairing is now a ZZn (half-size) + + Modified to prevent sub-group confinement attack + + Speeded up using ideas from + "Efficient Computation of Tate Pairing in Projective Coordinate over General Characteristic Fields" + by Sanjit Chatterjee1, Palash Sarkar1 and Rana Barua1 + +*/ + +#include +#include +#include "ecn.h" +#include +#include "zzn2.h" + +using namespace std; + +Miracl precision(16,0); + +// Using SHA-512 as basic hash algorithm + +#define HASH_LEN 64 + +// +// Define one or the other of these +// +// Which is faster depends on the I/M ratio - See imratio.c +// Roughly if I/M ratio > 16 use PROJECTIVE, otherwise use AFFINE +// + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +#ifdef PROJECTIVE +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} +#endif + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn2 line(ECn& A,ECn& C,ECn& B,int type,ZZn& slope,ZZn& ex1,ZZn& ex2,ZZn& a,ZZn& d) +{ + ZZn2 w; + ZZn n=a; + +#ifdef AFFINE + ZZn x,y; + extract(A,x,y); + n+=x; n*=slope; + w.set(y,-d); w-=n; +#endif +#ifdef PROJECTIVE + if (type==MR_ADD) + { + ZZn x2,y2,x3,z3; + extract(B,x2,y2); + extract(C,x3,x3,z3); + w.set(slope*(a+x2)-z3*y2,z3*d); + } + if (type==MR_DOUBLE) + { + ZZn x,y,x3,z3; + extract(A,x,y); + extract(C,x3,x3,z3); + w.set(-(slope*ex2)*a-slope*x+ex1,-(z3*ex2)*d); + } +/* + extract(A,x,y,z); + x*=z; t=z; z*=z; z*=t; + n*=z; + n+=x; + z*=d; w.set(y,-z); + extract(C,x,y,z); // only need z - its the denominator of the slope + w*=z; + n*=slope; + w-=n; +*/ +#endif + return w; +} + +// +// Add A=A+B (or A=A+A) +// Bump up num +// + +ZZn2 g(ECn& A,ECn& B,ZZn& a,ZZn& d) +{ + int type; + ZZn lam,extra1,extra2; + ECn P=A; + big ptr,ex1,ex2; + +// Evaluate line from A - lam is line slope + type=A.add(B,&ptr,&ex1,&ex2); + if (!type) return (ZZn2)1; + lam=ptr; // in projective case slope = lam/A.z + extra1=ex1; + extra2=ex2; + + return line(P,A,B,type,lam,extra1,extra2,a,d); +} + +// +// Tate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order q. +// Note that P is a point on the curve over Fp, Q(x,y) a point on the +// curve E(Fp^2) -> Q([Qx,0],[0,Qy]) +// Here we have morphed Q onto the twisted curve E'(Fp) +// + +BOOL tate(ECn& P,ECn& Q,Big& q,ZZn& r) +{ + int i,nb,qnr; + ZZn2 res; + ZZn a,d; + Big p,x,y,n; + ECn A; + + p=get_modulus(); + +// Note that q is fixed - q.P=2^17*(2^142.P + P) + P + + normalise(P); + normalise(Q); // make sure z=1 + extract(Q,a,d); + + qnr=get_mip()->qnr; + if (qnr==-2) + { + a=a/2; /* Convert off twist */ + d=d/4; + } + + A=P; // remember A + + n=q-1; + nb=bits(n); + + res=1; + + for (i=nb-2;i>=0;i--) + { + res*=res; // 2 modmul + res*=g(A,A,a,d); + + if (bit(n,i)) + res*=g(A,P,a,d); // executed just once + } + + if (A != -P || res.iszero()) return FALSE; + + res=conj(res)/res; // raise to power of (p-1) + + r=powl(real(res),(p+1)/q); // raise to power of (p+1)/q + + if (r==1) return FALSE; + return TRUE; +} + +/* +void rmul(ECn& P,Big &q) +{ + Big n; + ECn A; + int i,nb; + + A=P; + n=q-1; + nb=bits(n); + + for (i=nb-2;i>=0;i--) + { + A.add(A); + if (bit(n,i)) + A.add(P); + } +} +*/ + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha512 sh; + + shs512_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs512_process(&sh,string[i]); + } + shs512_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn x) +{ // Hash an Fp to a big number + sha sh; + Big a,h,p; + char s[20]; + int m; + + shs_init(&sh); + a=(Big)x; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + shs_hash(&sh,s); + h=from_binary(20,s); + return h; +} + +// Hash an Identity to a curve point in G2 + +ECn Hash(char *ID) +{ + ECn T; + Big a=H1(ID); + + while (!is_on_curve(a)) a+=1; + T.set(a); // Make sure its on E(F_p) + + return T; +} + +// Hash an Identity to a curve point and map to point of order q in G1 + +ECn hash_and_map(char *ID,Big cof) +{ + ECn T; + Big a=H1(ID); + + while (!is_on_curve(a)) a+=1; + T.set(a); + + T*=cof; + + return T; +} + +/* Note that if #E(Fp) = p+1-t + then #E(Fp2) = (p+1-t)(p+1+t) (a multiple of #E(Fp)) + (Weil's Theorem) + */ + +int main() +{ + ifstream common("k2.ecs"); // elliptic curve parameters + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn Server,sS; + ZZn res,sp,ap,bp; + Big r,a,b,s,ss,p,q,x,y,B,cof; + int i,nbits,A,qnr; + time_t seed; + + common >> nbits; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B; + common >> cof; + common >> q; // number of points on curve = cof*q + + time(&seed); + irand((long)seed); + +// +// initialise twisted curve for points in G2 +// Server ID is hashed to points on this +// + + modulo(p); + qnr=mip->qnr; + +#ifdef AFFINE + ecurve(qnr*qnr*A,qnr*qnr*qnr*B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(qnr*qnr*A,qnr*qnr*qnr*B,p,MR_PROJECTIVE); +#endif + + mip->IOBASE=16; + +// hash Identity to curve point in G2 +// Server does not need to be of order q (its order is a multiple of q) + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point on twisted curve" << endl; + Server=Hash((char *)"Server"); + +cout << "Server= " << Server << endl; +cout << "Server*cof= " << (2*(p+1)-cof*q)*Server << endl; + + cout << "Server visits trusted authority" << endl; + sS=ss*Server; + +// initialise curve for points in G1 + +#ifdef AFFINE + ecurve(A,B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(A,B,p,MR_PROJECTIVE); +#endif + + cout << "Mapping Alice & Bob ID's to points on curve" << endl; + + Alice=hash_and_map((char *)"Alice",cof); + Bob= hash_and_map((char *)"Robert",cof); + +// Alice, Bob are points of order q + + cout << "Alice and Bob visit Trusted Authority" << endl; + + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + if (!tate(sA,Server,q,res)) cout << "Trouble" << endl; + + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + ap=powl(res,a); + + if (!tate(Alice,sS,q,res)) cout << "Trouble" << endl; + + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + sp=powl(res,s); + + cout << "Alice Key= " << H2(powl(sp,a)) << endl; + cout << "Server Key= " << H2(powl(ap,s)) << endl; + + cout << "Bob and Server Key exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + +//for (i=0;i<10000;i++) + if (!tate(sB,Server,q,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powl(res,b); + + if (!tate(Bob,sS,q,res)) cout << "Trouble" << endl; + sp=powl(res,s); + + cout << "Bob Key= " << H2(powl(sp,b)) << endl; + cout << "Server Key= " << H2(powl(bp,s)) << endl; + + cout << "Alice and Bob's attempted Key exchange" << endl; + + if (!tate(Alice,sB,q,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powl(res,b); + + if (!tate(sA,Bob,q,res)) cout << "Trouble" << endl; + ap=powl(res,a); + + cout << "Alice Key= " << H2(powl(bp,a)) << endl; + cout << "Bob Key= " << H2(powl(ap,b)) << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/ake2cpt2.cpp b/miracl/source/curve/pairing/ake2cpt2.cpp new file mode 100644 index 0000000..f21638c --- /dev/null +++ b/miracl/source/curve/pairing/ake2cpt2.cpp @@ -0,0 +1,459 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=16 ake2cpt2.cpp ecn2.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + using COMBA build + + Cocks-Pinch curve - Type 2 Tate pairing + + Requires file k2.ecs which contains details of non-supersingular + elliptic curve, with order divisible by q=2^159+2^17+1, and security + multiplier k=2. The prime p is 512 bits + + CHANGES: This version uses a Type 2 pairing + Use Lucas functions to evaluate powers. + Output of tate pairing is now a ZZn (half-size) + + Modified to prevent sub-group confinement attack + + For a Type 2 curve ecap(P,Q) = e(Trace(P),Q) + + ecap(P,Q) = ecap(Q,P) + +*/ + +#include +#include +#include "ecn.h" +#include +#include "zzn2.h" +#include "ecn2.h" + +using namespace std; + +Miracl precision(32,0); + +// Using SHA-512 as basic hash algorithm + +#define HASH_LEN 64 + +// +// Define one or the other of these +// +// Which is faster depends on the I/M ratio - See imratio.c +// Roughly if I/M ratio > 16 use PROJECTIVE, otherwise use AFFINE +// + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +#ifdef PROJECTIVE +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} +#endif + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn2 line(ECn& A,ECn& C,ZZn& slope,ZZn2& Qx,ZZn2& Qy) +{ + ZZn2 w=Qy,n=Qx; + ZZn x,y,z,t; + +#ifdef AFFINE + extract(A,x,y); + n-=x; n*=slope; + w-=y; w-=n; + +#endif +#ifdef PROJECTIVE + extract(A,x,y,z); + x*=z; t=z; z*=z; z*=t; + n*=z; + n-=x; + w*=z;; w-=y; + extract(C,x,y,z); // only need z - its the denominator of the slope + w*=z; + n*=slope; + w-=n; + +#endif + return w; +} + +/* + +ZZn2 vertical(ECn& A,ZZn2& Qx) +{ + ZZn2 n=Qx; + ZZn x,y,z; +#ifdef AFFINE + extract(A,x,y); + n-=x; +#endif +#ifdef PROJECTIVE + extract(A,x,y,z); + z*=z; + n*=z; n-=x; +#endif + return n; +} + +*/ + +// +// Add A=A+B (or A=A+A) +// Bump up num +// + +ZZn2 g(ECn& A,ECn& B,ZZn2& Qx,ZZn2& Qy) +{ + int type; + ZZn lam; + ECn P=A; + big ptr; + +// Evaluate line from A - lam is line slope + type=A.add(B,&ptr); + if (!type) return (ZZn2)1; + lam=ptr; // in projective case slope = lam/A.z + + return line(P,A,lam,Qx,Qy) /* *conj(vertical(A,Qx)) */ ; +} + +ECn2 Trace2(ECn2 P) +{ + ECn R; + ECn2 Q; + ZZn2 x,y; + Big X,Y; + P.get(x,y); + x=conj(x); y=conj(y); + Q.set(x,y); + P+=Q; + P.norm(); + return P; +} + +// +// Tate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order q. +// Note that P is a point on the curve over Fp, Q(x,y) a general point on the +// curve E(Fp^2) +// + +BOOL tate(ECn& P,ECn2& Q,Big& q,ZZn& r) +{ + int i,nb,qnr; + ZZn2 res; + ZZn2 Qx,Qy; + Big p,x,y; + ECn A; + ECn2 NQ,TQ; + + p=get_modulus(); + +// Note that q is fixed - q.P=2^17*(2^142.P + P) + P + +// Now set Q = kQ-Tr(Q) so we can use denominator elimination + normalise(P); + Q.norm(); + NQ=Q; + + NQ=2*NQ; + TQ=Trace2(Q); + NQ-=TQ; + NQ.get(Qx,Qy); + + A=P; // remember A + nb=bits(q); + res=1; + + for (i=nb-2;i>=0;i--) + { + res*=res; // 2 modmul + res*=g(A,A,Qx,Qy); + + if (bit(q,i)) + res*=g(A,P,Qx,Qy); // executed just once + } + + if (!A.iszero() || res.iszero()) return FALSE; + res=conj(res)/res; // raise to power of (p-1) + + r=powl(real(res),(p+1)/q); // raise to power of (p+1)/q + + if (r==1) return FALSE; + return TRUE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha512 sh; + + shs512_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs512_process(&sh,string[i]); + } + shs512_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn x) +{ // Hash an Fp to a big number + sha sh; + Big a,h,p; + char s[20]; + int m; + + shs_init(&sh); + a=(Big)x; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + shs_hash(&sh,s); + h=from_binary(20,s); + return h; +} + +// hash to a *general* point of order q on E(F_p^2) + +ECn2 hash2(char *ID) +{ + ECn2 T; + ZZn2 x; + Big x0,y0=1; // Note y0 !=0 + + x0=H1(ID); + do + { + x.set(x0,y0); + x0+=1; + } + while (!is_on_curve(x)); + T.set(x); + + return T; +} + +// Trace function + +ECn Trace(ECn2 P) +{ + ECn R; + ECn2 Q; + ZZn2 x,y; + Big X,Y; + P.get(x,y); + x=conj(x); y=conj(y); + Q.set(x,y); + P+=Q; + + P.get(x,y); + X=real(x); + Y=real(y); + R.set(X,Y); + return R; +} + +/* Note that if #E(Fp) = p+1-t + then #E(Fp2) = (p+1-t)(p+1+t) (a multiple of #E(Fp)) + (Weil's Theorem) + */ + +int main() +{ + ifstream common("k2.ecs"); // elliptic curve parameters + miracl* mip=&precision; + ECn2 Alice,Bob,sA,sB,Ps,Pt; + ECn2 Server,sS; + ECn T; + ZZn res,sp,ap,bp; + Big r,a,b,s,ss,p,q,n,x,y,B,cof,cf1,cf2,t; + int nbits,A,qnr; + time_t seed; + + common >> nbits; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B; + common >> cof; + common >> q; + + time(&seed); +// seed=1; + irand((long)seed); + +// +// initialise twisted curve... +// Server ID is hashed to points on this +// + + modulo(p); + + mip->IOBASE=16; + t=p+1-cof*q; + + cf1=(p+1-t)/q; + cf2=(p+1+t)/q; + +// initialise curve... + +#ifdef AFFINE + ecurve(A,B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(A,B,p,MR_PROJECTIVE); +#endif + +// hash Identity to curve point + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point on curve" << endl; + Server=hash2((char *)"Server"); + + + cout << "Server visits trusted authority" << endl; + sS=ss*Server; + sS*=cf1; sS*=cf2; + + cout << "Mapping Alice & Bob ID's to points on curve" << endl; + + Alice=hash2((char *)"Alice"); + Bob=hash2((char *)"Bob"); + +// Alice, Bob are points of order q + + cout << "Alice and Bob visit Trusted Authority" << endl; + + sA=ss*Alice; + sA*=cf1; sA*=cf2; + sB=ss*Bob; + sB*=cf1; sB*=cf2; + + cout << "Alice and Server Key exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + T=Trace(sA); T*=cf1; + if (!tate(T,Server,q,res)) cout << "Trouble" << endl; + + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + ap=powl(res,a); + + T=Trace(Alice); T*=cf1; + if (!tate(T,sS,q,res)) cout << "Trouble" << endl; + + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + sp=powl(res,s); + + cout << "Alice Key= " << H2(powl(sp,a)) << endl; + cout << "Server Key= " << H2(powl(ap,s)) << endl; + + cout << "Bob and Server Key exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + T=Trace(sB); T*=cf1; + if (!tate(T,Server,q,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powl(res,b); + + T=Trace(Bob); T*=cf1; + if (!tate(T,sS,q,res)) cout << "Trouble" << endl; + sp=powl(res,s); + + cout << "Bob Key= " << H2(powl(sp,b)) << endl; + cout << "Server Key= " << H2(powl(bp,s)) << endl; + + cout << "Alice and Bob's attempted Key exchange" << endl; + + T=Trace(sB); T*=cf1; + if (!tate(T,Alice,q,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powl(res,b); + + T=Trace(Bob); T*=cf1; + if (!tate(T,sA,q,res)) cout << "Trouble" << endl; + ap=powl(res,a); + + cout << "Alice Key= " << H2(powl(bp,a)) << endl; + cout << "Bob Key= " << H2(powl(ap,b)) << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/ake2cpw.cpp b/miracl/source/curve/pairing/ake2cpw.cpp new file mode 100644 index 0000000..cbff0aa --- /dev/null +++ b/miracl/source/curve/pairing/ake2cpw.cpp @@ -0,0 +1,284 @@ +/* + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DBIGS=18 ake2cpw.cpp zzn2.cpp big.cpp monty.cpp elliptic.cpp miracl.lib + using COMBA build + + Cocks-Pinch curve - Weil pairing + + Requires file k2.ecs which contains details of non-supersingular + elliptic curve, with order divisible by q=2^159+2^17+1, and security + multiplier k=2. The prime p is 512 bits + + NOTE: Key exchange bandwidth could be reduced by halve using ideas from + "Doing more with Fewer Bits", Brouwer, Pellikaan & Verheul, Asiacrypt + '99 + +*/ + +#include +#include +#include +#include "ecn.h" +#include "zzn.h" +#include "zzn2.h" + +using namespace std; + +Miracl precision(34,0); + +// Using SHA-512 as basic hash algorithm + +#define HASH_LEN 64 + +// +// Weil Pairing Code +// +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +ZZn2 g(ECn& A,ECn& B,ECn& C,ECn& D,ECn& P,ECn& Q) +{ + ZZn x,y,Ax,Ay,Cx,Cy,lam1,lam2; + ZZn2 u,w; + big ptr1,ptr2; + + extract(A,Ax,Ay); + extract(C,Cx,Cy); + + double_add(B,A,D,C,ptr1,ptr2); // adds B to A and D to C + // uses Montgomery's trick + // returns line slopes in ptr1 and ptr2 + + if (A.iszero() || C.iszero()) return (ZZn2)1; + if (ptr1==NULL || ptr2==NULL) return (ZZn2)0; + +// +// Recall that Q and C are "really" of the form [(-x,0),(0,y)] +// The slope of the real curve is -i*slope of the twist +// [(iQy-Ay) - m1(-Qx-Ax)]/(Py-iCy)+i.m2(Px+Cx) +// Instead of division, calculate conjugate and multiply (remember Fermat!) +// + + lam1=ptr1; + lam2=ptr2; + + extract(Q,x,y); + + Ax+=x; // numerator + Ax*=lam1; + u.set(Ax-Ay,y); + + extract(P,x,y); + + Cx+=x; // denominator + Cx*=lam2; + + w.set(y,Cy-Cx); // conjugate trick ! + // and don't forget the -i on the slope! + return (w*u); +} + +// +// New Weil Pairing - note denominator elimination has been applied +// +// nw(P,Q) = [m(P,Q)/m(Q,P)]^(p-1) +// +// P(x,y) is a point of order q. Q(x,y) is a point of order q. +// + +BOOL nw(ECn& P,ECn& Q,Big& q,ZZn& r) +{ + ZZn2 m=1; + int i,nb; + ECn A=P; + ECn B=Q; + + nb=bits(q); + for (i=nb-2;i>=0;i--) + { // one loop ! + m*=m; + m*=g(A,A,B,B,P,Q); + if (bit(q,i)) + m*=g(A,P,B,Q,P,Q); + } + + m=conj(m)/m; // raise to power of (p-1) + + if (!A.iszero() || m.iszero()) return FALSE; + if (m.isunity()) return FALSE; + + r=real(m); + return TRUE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha512 sh; + + shs512_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs512_process(&sh,string[i]); + } + shs512_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn x) +{ // Hash an Fp to a big number + sha sh; + Big a,h,p; + char s[20]; + int m; + + shs_init(&sh); + a=(Big)x; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + shs_hash(&sh,s); + h=from_binary(20,s); + return h; +} + +// Hash and map a Client Identity to a curve point E_(Fp) + +ECn hash_and_map(char *ID,Big cof) +{ + ECn Q; + Big x0=H1(ID); + + while (!Q.set(x0)) x0+=1; + Q*=cof; + + return Q; +} + +/* Note that if #E(Fp) = p+1-t + then #E(Fp2) = (p+1-t)(p+1+t) (a multiple of #E(Fp)) + (Weil's Theorem) + */ + +int main() +{ + ifstream common("k2.ecs"); // elliptic curve parameters + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn B2,Server,sS; + ZZn res,sp,ap,bp; + Big t,r,a,b,s,ss,p,q,x,y,B,cof,cf,cf2; + int bits,A; + time_t seed; + + common >> bits; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B; + common >> cof; + common >> q; + + t=p+1-cof*q; + + cf= (p+1-t)/q; // q divides p+1 (for k=2 condition) + cf2=(p+1+t)/q; // and therefore also divides t (as it divides r) + +// this co-factor is in fact not needed.... + + time(&seed); + irand((long)seed); + + + mip->IOBASE=16; + +// hash Identities to curve point + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + + ecurve(A,-B,p,MR_AFFINE); // twist curve + + Server=hash_and_map((char *)"Server",cf2); + + cout << "Mapping Alice & Bob ID's to points" << endl; + + ecurve(A,B,p,MR_AFFINE); + + Alice=hash_and_map((char *)"Alice",cf); + Bob= hash_and_map((char *)"Robert",cf); + +// Alice, Bob are points of order q +// Server does not need to be (its order is a multiple of q) + + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=ss*Server; + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + if (!nw(sA,Server,q,res)) cout << "Trouble" << endl; + + ap=powl(res,a); + + if (!nw(Alice,sS,q,res)) cout << "Trouble" << endl; + sp=powl(res,s); + + cout << "Alice Key= " << H2(powl(sp,a)) << endl; + cout << "Server Key= " << H2(powl(ap,s)) << endl; + + cout << "Bob and Server Key exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!nw(sB,Server,q,res)) cout << "Trouble" << endl; + bp=powl(res,b); + + if (!nw(Bob,sS,q,res)) cout << "Trouble" << endl; + sp=powl(res,s); + + cout << "Bob's Key= " << H2(powl(sp,b)) << endl; + cout << "Server Key= " << H2(powl(bp,s)) << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/ake2nsst.cpp b/miracl/source/curve/pairing/ake2nsst.cpp new file mode 100644 index 0000000..f27574b --- /dev/null +++ b/miracl/source/curve/pairing/ake2nsst.cpp @@ -0,0 +1,489 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + This implementation uses an NSS curve - see http://eprint.iacr.org/2005/252 + + Compile as + cl /O2 /GX /DZZNS=16 ake2nsst.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + using COMBA build + + Not-Super Singular curve - Tate pairing + + Requires file bk2.ecs which contains details of non-supersingular + elliptic curve, with order divisible by q=r*r+r+1, where r=2^80+2^16, and security + multiplier k=2. The prime p is 512 bits + + CHANGES: Use twisted curve to avoid ECn2 arithmetic completely + Use Lucas functions to evaluate powers. + Output of tate pairing is now a ZZn (half-size) + + NOTE: Key exchange bandwidth could be reduced by halve using ideas from + "Doing more with Fewer Bits", Brouwer, Pellikaan & Verheul, Asiacrypt + '99 + + Modified to prevent sub-group confinement attack + +*/ + +#include +#include +#include "ecn.h" +#include +#include "zzn2.h" + +using namespace std; + +Miracl precision(18,0); + +// Using SHA-512 as basic hash algorithm + +#define HASH_LEN 64 + +// +// Define one or the other of these +// +// Which is faster depends on the I/M ratio - See imratio.c +// Roughly if I/M ratio > 16 use PROJECTIVE, otherwise use AFFINE +// + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +#ifdef PROJECTIVE +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} +#endif + +ZZn beta; + + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// +// Calculate the "second half" values at the same time, and store them +// + +ZZn2 line(ECn& A,ECn& C,ZZn& slope,ZZn& Qx,ZZn& Qy,ZZn& bQx,ZZn2& w2) +{ + ZZn2 w; + ZZn x,y,z,t; + ZZn a=Qx; ZZn d=Qy; ZZn a2=bQx; + +#ifdef AFFINE + extract(A,x,y); + a-=x; a*=slope; a2-=x; a2*=slope; + w.set(-y,d); w-=a; w2.set(-y,-d); w2-=a2; + +#endif +#ifdef PROJECTIVE + extract(A,x,y,z); + x*=z; t=z; z*=z; z*=t; + a*=z; a2*=z; + a-=x; a2-=x; + z*=d; w.set(-y,z); w2.set(-y,-z); + extract(C,x,y,z); // only need z - its the denominator of the slope + w*=z; w2*=z; + a*=slope; a2*=slope; + w-=a; w2-=a2; +#endif + return w; +} + +// +// Add A=A+B (or A=A+A) +// Bump up num +// + +ZZn2 g(ECn& A,ECn& B,ZZn& Qx,ZZn& Qy,ZZn& bQx,ZZn2& w2) +{ + int type; + ZZn lam; + ECn P=A; + big ptr; + +// Evaluate line from A - lam is line slope + type=A.add(B,&ptr); + if (!type) return (ZZn2)1; + lam=ptr; // in projective case slope = lam/A.z + return line(P,A,lam,Qx,Qy,bQx,w2); +} + +ECn Phi(ECn A,ZZn beta) +{ + ZZn xx,yy; + + extract(A,xx,yy); + xx=beta*xx; yy=yy; + A.set(xx,yy); + return A; +} + +// +// Tate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order q. +// Note that P is a point on the curve over Fp, Q(x,y) a point on the +// curve E(Fp^2) -> Q([Qx,0],[0,Qy]) +// Here we have morphed Q onto the twisted curve E'(Fp) +// + +BOOL tate(ECn& P,ECn Q,Big& q,ZZn& r) +{ + int i,nb,k; + ZZn2 res,resb,res1,res2; + ZZn2 store[82]; + ZZn xx,yy,Qx,Qy,bQx; + Big p,x,y,n,lambda; + ECn W,A,B; + + p=get_modulus(); + + normalise(Q); // make sure z=1 + extract(Q,Qx,Qy); + Qx=-Qx; // untwist + bQx=beta*Qx; + + A=P; // remember P + res=res1=res2=1; + k=0; +/* + for (i=64;i>=1;i--) + { + res*=res; + res*=g(A,A,Qx,Qy,bQx,store[k++]); + } + res*=g(A,P,Qx,Qy,bQx,store[k++]); + for (i=16;i>=1;i--) + { + res*=res; + res*=g(A,A,Qx,Qy,bQx,store[k++]); + } + res*=g(A,P,Qx,Qy,bQx,store[k++]); + + resb=res; + + k=0; + + for (i=64;i>=1;i--) + { + res*=res; + res*=store[k++]; //g(A,A,Q,beta,store[k++]); + } + res*=store[k++]; //g(A,P,Q,beta,store[k++]); + + res*=resb; // This is easy to overlook! + + for (i=16;i>=1;i--) + { + res*=res; + res*=store[k++]; // g(A,A,Q,beta,store[k++]); + } +*/ + +// lambda=pow((Big)2,80)+pow((Big)2,16); + + for (i=64;i>=1;i--) + { + res1*=res1; + res2*=res2; + res1*=g(A,A,Qx,Qy,bQx,store[0]); + res2*=store[0]; + } + res1*=g(A,P,Qx,Qy,bQx,store[0]); + res2*=store[0]; + for (i=16;i>=1;i--) + { + res1*=res1; + res2*=res2; + res1*=g(A,A,Qx,Qy,bQx,store[0]); + res2*=store[0]; + } + + res1*=g(A,P,Qx,Qy,bQx,store[0]); + +// res1=pow(res1,lambda); + + resb=res1; + for (i=64;i>=1;i--) res1*=res1; + res1*=resb; + for (i=16;i>=1;i--) res1*=res1; + + res=res1*res2; + + res=conj(res)/res; // raise to power of (p-1) + r=powl(real(res),(p+1)/q); // raise to power of (p+1)/q + + if (r==1) return FALSE; + return TRUE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha512 sh; + + shs512_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs512_process(&sh,string[i]); + } + shs512_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn x) +{ // Hash an Fp to a big number + sha sh; + Big a,h,p; + char s[20]; + int m; + + shs_init(&sh); + a=(Big)x; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + shs_hash(&sh,s); + h=from_binary(20,s); + return h; +} + +// Hash an Identity to a curve point + +ECn Hash(char *ID) +{ + ECn T; + Big a=H1(ID); + + while (!is_on_curve(a)) a+=1; + T.set(a); // Make sure its on E(F_p) + + return T; +} + +// Hash an Identity to a curve point and map to point of order q + +ECn hash_and_map(char *ID,Big cof) +{ + ECn T; + Big a=H1(ID); + + while (!is_on_curve(a)) a+=1; + T.set(a); + + T*=cof; + + return T; +} + +/* Note that if #E(Fp) = p+1-t + then #E(Fp2) = (p+1-t)(p+1+t) (a multiple of #E(Fp)) + (Weil's Theorem) + */ + +int main() +{ + ifstream common("bk2.ecs"); // elliptic curve parameters + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn Server,sS; + ZZn res,sp,ap,bp; + Big r,a,b,s,ss,p,q,x,y,B,cof; + int i,nbits,A; + time_t seed; + + common >> nbits; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B; + common >> cof; + common >> q; + + time(&seed); + irand((long)seed); + +// r=pow((Big)2,80)+pow((Big)2,16); +// q=r*r+r+1 + +// must get the right beta - recall that there are two solutions for lambda.. + i=3; + do + { + beta=(ZZn)pow((Big)++i,(p-1)/3,p); + } while (beta==1); + +// +// initialise twisted curve... +// Server ID is hashed to points on this +// + +#ifdef AFFINE + ecurve(A,-B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(A,-B,p,MR_PROJECTIVE); +#endif + + mip->IOBASE=16; + +// hash Identity to curve point +// Server does not need to be of order q (its order is a multiple of q) + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point on twisted curve" << endl; + Server=Hash((char *)"Server"); + + cout << "Server visits trusted authority" << endl; + sS=ss*Server; + + +// initialise curve... + +#ifdef AFFINE + ecurve(A,B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(A,B,p,MR_PROJECTIVE); +#endif + + cout << "Mapping Alice & Bob ID's to points on curve" << endl; + + Alice=hash_and_map((char *)"Alice",cof); + Bob= hash_and_map((char *)"Robert",cof); + +// Alice, Bob are points of order q + + cout << "Alice and Bob visit Trusted Authority" << endl; + +//for (i=0;i<10000;i++) +// sA=ss*Alice; + +/* Use GLV method - faster */ +//cout << "sA= " << sA << endl; + Big k1,k2,lambda; + lambda=pow((Big)2,80)+pow((Big)2,16); + k1=ss%lambda; + k2=ss/lambda; +//for (i=0;i<100000;i++) + sA=mul(k1,Alice,k2,Phi(Alice,beta)); +//cout << "sA= " << mul(k1,Alice,k2,Phi(Alice,beta)) << endl; + + sB=ss*Bob; + + cout << "Alice and Server Key exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + +//for (i=0;i<10000;i++) + if (!tate(sA,Server,q,res)) cout << "Trouble" << endl; + + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + ap=powl(res,a); + + if (!tate(Alice,sS,q,res)) cout << "Trouble" << endl; + + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + sp=powl(res,s); + + cout << "Alice Key= " << H2(powl(sp,a)) << endl; + cout << "Server Key= " << H2(powl(ap,s)) << endl; + + cout << "Bob and Server Key exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!tate(sB,Server,q,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powl(res,b); + + if (!tate(Bob,sS,q,res)) cout << "Trouble" << endl; + sp=powl(res,s); + + cout << "Bob Key= " << H2(powl(sp,b)) << endl; + cout << "Server Key= " << H2(powl(bp,s)) << endl; + + cout << "Alice and Bob's attempted Key exchange" << endl; + + if (!tate(Alice,sB,q,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powl(res,b); + + if (!tate(sA,Bob,q,res)) cout << "Trouble" << endl; + ap=powl(res,a); + + cout << "Alice Key= " << H2(powl(bp,a)) << endl; + cout << "Bob Key= " << H2(powl(ap,b)) << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/ake2sst.cpp b/miracl/source/curve/pairing/ake2sst.cpp new file mode 100644 index 0000000..6bb4959 --- /dev/null +++ b/miracl/source/curve/pairing/ake2sst.cpp @@ -0,0 +1,415 @@ +/* + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=16 ake2sst.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + using COMBA build + + Super-Singular curve - Tate pairing + + Requires file k2ss.ecs which contains details of supersingular + elliptic curve, with order divisible by q=2^159+2^17+1, and security + multiplier k=2. The prime p is 512 bits + + CHANGES: Use twisted curve to avoid ECn2 arithmetic completely + Use Lucas functions to evaluate powers. + Output of tate pairing is now a ZZn (half-size) + + + Modified to prevent sub-group confinement attack + +*/ + +#include +#include +#include "ecn.h" +#include +#include "zzn2.h" + +using namespace std; + +Miracl precision(16,0); + +// Using SHA-512 as basic hash algorithm + +#define HASH_LEN 64 + +// +// Define one or the other of these +// +// Which is faster depends on the I/M ratio - See imratio.c +// Roughly if I/M ratio > 16 use PROJECTIVE, otherwise use AFFINE +// + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +#ifdef PROJECTIVE +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} +#endif + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn2 line(ECn& A,ECn& C,ECn& B,int type,ZZn& slope,ZZn& ex1,ZZn& ex2,ZZn& a,ZZn& d) +{ + ZZn2 w; + ZZn x,y,z,t,n=a; + +#ifdef AFFINE + extract(A,x,y); + n+=x; n*=slope; + w.set(y,-d); w-=n; + +#endif +#ifdef PROJECTIVE + if (type==MR_ADD) + { + ZZn x2,y2,x3,z3; + extract(B,x2,y2); + extract(C,x3,x3,z3); + w.set(slope*(a+x2)-z3*y2,z3*d); + return w; + } + if (type==MR_DOUBLE) + { + ZZn x,y,x3,z3; + extract(A,x,y); + extract(C,x3,x3,z3); + w.set(-(slope*ex2)*a-slope*x+ex1,-(z3*ex2)*d); + return w; + } +#endif + return w; +} + +// +// Add A=A+B (or A=A+A) +// Bump up num +// + +ZZn2 g(ECn& A,ECn& B,ZZn& a,ZZn& d) +{ + int type; + ZZn lam,extra1,extra2; + ECn P=A; + big ptr,ex1,ex2; + +// Evaluate line from A - lam is line slope + + type=A.add(B,&ptr,&ex1,&ex2); + if (!type) return (ZZn2)1; + lam=ptr; // in projective case slope = lam/A.z + extra1=ex1; + extra2=ex2; + return line(P,A,B,type,lam,extra1,extra2,a,d); +} + +// +// Tate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order q. +// Note that P is a point on the curve over Fp, Q(x,y) a point on the +// curve E(Fp^2) -> Q([Qx,0],[0,Qy]) +// Here we have morphed Q onto the twisted curve E'(Fp) +// + +BOOL tate(ECn& P,ECn& Q,Big& q,ZZn& r) +{ + int i,nb,qnr; + ZZn2 res; + ZZn a,d; + Big p,x,y,n; + ECn A; + + p=get_modulus(); + +// Note that q is fixed - q.P=2^17*(2^142.P + P) + P + + normalise(Q); // make sure z=1 + extract(Q,a,d); + + qnr=get_mip()->qnr; + if (qnr==-2) + { + a=a/2; /* Convert off twist */ + d=d/4; + } + + normalise(P); + A=P; // remember A + + n=q-1; + nb=bits(n); + + res=1; + + for (i=nb-2;i>=0;i--) + { + res*=res; // 2 modmul + res*=g(A,A,a,d); + + if (bit(n,i)) + res*=g(A,P,a,d); // executed just once + } + + if (A != -P || res.iszero()) return FALSE; + res=conj(res)/res; // raise to power of (p-1) + + r=powl(real(res),(p+1)/q); // raise to power of (p+1)/q + + if (r==1) return FALSE; + return TRUE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha512 sh; + + shs512_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs512_process(&sh,string[i]); + } + shs512_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn x) +{ // Hash an Fp to a big number + sha sh; + Big a,h,p; + char s[20]; + int m; + + shs_init(&sh); + a=(Big)x; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + shs_hash(&sh,s); + h=from_binary(20,s); + return h; +} + +// Hash an Identity to a curve point + +ECn Hash(char *ID) +{ + ECn T; + Big a=H1(ID); + + while (!is_on_curve(a)) a+=1; + T.set(a); // Make sure its on E(F_p) + + return T; +} + +// Hash an Identity to a curve point and map to point of order q + +ECn hash_and_map(char *ID,Big cof) +{ + ECn T; + Big a=H1(ID); + + while (!is_on_curve(a)) a+=1; + T.set(a); + + T*=cof; + + return T; +} + +/* Note that if #E(Fp) = p+1-t + then #E(Fp2) = (p+1-t)(p+1+t) (a multiple of #E(Fp)) + (Weil's Theorem) + */ + +int main() +{ + ifstream common("k2ss.ecs"); // elliptic curve parameters + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn Server,sS; + ZZn res,sp,ap,bp; + Big r,a,b,s,ss,p,q,x,y,B,cof; + int i,nbits,A,qnr; + time_t seed; + + common >> nbits; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B; + common >> cof; + common >> q; + +//cout << "p= " << p << endl; +//cout << "q%cof= " << q*cof << endl; + + time(&seed); + irand((long)seed); + +// +// initialise twisted curve... +// Server ID is hashed to points on this +// + + modulo(p); + qnr=mip->qnr; +#ifdef AFFINE + ecurve(qnr*qnr*A,qnr*qnr*qnr*B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(qnr*qnr*A,qnr*qnr*qnr*B,p,MR_PROJECTIVE); +#endif + + mip->IOBASE=16; + +// hash Identity to curve point +// Server does not need to be of order q (its order is a multiple of q) + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point on twisted curve" << endl; + Server=Hash((char *)"Server"); + + cout << "Server visits trusted authority" << endl; + sS=ss*Server; + +// initialise curve... + +#ifdef AFFINE + ecurve(A,B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(A,B,p,MR_PROJECTIVE); +#endif + + cout << "Mapping Alice & Bob ID's to points on curve" << endl; + + Alice=hash_and_map((char *)"Alice",cof); + Bob= hash_and_map((char *)"Robert",cof); + +// Alice, Bob are points of order q + + cout << "Alice and Bob visit Trusted Authority" << endl; + + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number +//for (i=0;i<10000;i++) + if (!tate(sA,Server,q,res)) cout << "Trouble" << endl; + + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + ap=powl(res,a); + + if (!tate(Alice,sS,q,res)) cout << "Trouble" << endl; + + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + sp=powl(res,s); + + cout << "Alice Key= " << H2(powl(sp,a)) << endl; + cout << "Server Key= " << H2(powl(ap,s)) << endl; + + cout << "Bob and Server Key exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!tate(sB,Server,q,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powl(res,b); + + if (!tate(Bob,sS,q,res)) cout << "Trouble" << endl; + sp=powl(res,s); + + cout << "Bob Key= " << H2(powl(sp,b)) << endl; + cout << "Server Key= " << H2(powl(bp,s)) << endl; + + cout << "Alice and Bob's attempted Key exchange" << endl; + + if (!tate(Alice,sB,q,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powl(res,b); + + if (!tate(Bob,sA,q,res)) cout << "Trouble" << endl; + ap=powl(res,a); + + cout << "Alice Key= " << H2(powl(bp,a)) << endl; + cout << "Bob Key= " << H2(powl(ap,b)) << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/ake4cpt.cpp b/miracl/source/curve/pairing/ake4cpt.cpp new file mode 100644 index 0000000..28a9b3a --- /dev/null +++ b/miracl/source/curve/pairing/ake4cpt.cpp @@ -0,0 +1,407 @@ +/* + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=16 ake4cpt.cpp zzn4.cpp zzn2.cpp ecn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + Fastest using COMBA build for 512-bit mod-mul + + Cocks-Pinch curve - Tate pairing + + The file k4.ecs is required + Security is G192/F2048 (192-bit group, 2048-bit field) + + Modified to prevent sub-group confinement attack + +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn2.h" +#include "zzn4.h" + +using namespace std; + +Miracl precision(16,0); + +// Using SHA-1 as basic hash algorithm + +#define HASH_LEN 20 + +// +// Define one or the other of these +// +// Which is faster depends on the I/M ratio - See imratio.c +// Roughly if I/M ratio > 16 use PROJECTIVE, otherwise use AFFINE +// + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +#ifdef PROJECTIVE +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} +#endif + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn4 line(ECn& A,ECn& C,ZZn& slope,ZZn2& Qx,ZZn2& Qy) +{ + ZZn4 w; + ZZn2 m=Qx; + ZZn x,y,z,t; +#ifdef AFFINE + extract(A,x,y); + m-=x; m*=slope; + w.set((ZZn2)-y,Qy); w-=m; +#endif +#ifdef PROJECTIVE + extract(A,x,y,z); + + x*=z; + t=z; z*=z; z*=t; + x*=slope; + t=slope*z; + m*=t; + m-=x; t=z; + extract(C,x,x,z); + m+=(z*y); t*=z; + + w.set(m,-Qy*t); + +#endif + + return w; +} + +// +// Add A=A+B (or A=A+A) +// Bump up num +// + +ZZn4 g(ECn& A,ECn& B,ZZn2& Qx,ZZn2& Qy) +{ + int type; + ZZn lam; + ZZn4 val; + big ptr; + ECn P=A; + +// Evaluate line from A + type=A.add(B,&ptr); + if (!type) return (ZZn4)1; + lam=ptr; + val=line(P,A,lam,Qx,Qy); + //cout << "val= " << val << endl; + //exit(0); + return val; +} + +// +// Tate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order m.q. +// Note that P is a point on the curve over Fp, Q(x,y) a point on the +// extension field Fp^2 +// + +BOOL tate(ECn& P,ECn2 Q,Big& q,Big *cf,ZZn2 &Fr,ZZn2& r) +{ + int i,nb; + ECn A; + ZZn4 w,res; + ZZn4 a[2]; + ZZn2 Qx,Qy; +// ZZn4 X,Y; + + Q.get(Qx,Qy); + + Qx=txd(Qx); + Qy=txd(txd(Qy)); + + res=1; + +/* Left to right method */ + A=P; + nb=bits(q); + for (i=nb-2;i>=0;i--) + { + res*=res; + res*=g(A,A,Qx,Qy); + if (bit(q,i)) + res*=g(A,P,Qx,Qy); + } + + if (!A.iszero() || res.iszero()) return FALSE; + w=res; + + w.conj(); // ^(p^2-1) + + res=w/res; + + res.mark_as_unitary(); + + a[0]=a[1]=res; + a[0].powq(Fr); + res=pow(2,a,cf); + + r=real(res); // compression + +// r=powl(real(res),cf[0]*get_modulus()+cf[1]); // ^(p*p+1)/q + + if (r.isunity()) return FALSE; + return TRUE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha sh; + + shs_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs_process(&sh,string[i]); + } + shs_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn2 x) +{ // Hash an Fp2 to a big number + sha sh; + Big a,u,v; + char s[HASH_LEN]; + int m; + + shs_init(&sh); + x.get(u,v); + + a=u; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + a=v; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + shs_hash(&sh,s); + a=from_binary(HASH_LEN,s); + return a; +} + +// Hash and map a Server Identity to a curve point E(Fp2) + +ECn2 hash2(char *ID) +{ + ECn2 T; + ZZn2 x; + Big x0,y0=0; + + x0=H1(ID); + do + { + x.set(x0,y0); + x0+=1; + } + while (!is_on_curve(x)); + T.set(x); + + return T; +} + +// Hash and map a Client Identity to a curve point E(Fp) + +ECn hash_and_map(char *ID,Big cof) +{ + ECn Q; + Big x0=H1(ID); + + while (!is_on_curve(x0)) x0+=1; + Q.set(x0); // Make sure its on E(F_p) + + Q*=cof; + return Q; +} + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + X.set((Big)0,(Big)1); // = (sqrt(-2)^(p-1)/2 + break; + case 3: // = (1+sqrt(-1))^(p-1)/2 + X.set((Big)1,(Big)1); + break; + case 7: + X.set((Big)2,(Big)1); // = (2+sqrt(-1))^(p-1)/2 + default: break; + } + X=pow(X,(p-1)/2); +} + +int main() +{ + ifstream common("k4.ecs"); // elliptic curve parameters + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn2 Server,sS; + ZZn2 res,sp,ap,bp,Fr; + Big a,b,s,ss,p,q,r,B,cof; + Big cf[2]; + + int bits,A; + time_t seed; + + common >> bits; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B; + common >> cof; // #E/q + common >> q; // low hamming weight q + common >> cf[0]; // [(p^2+1)/q]/p + common >> cf[1]; // [(p^2+1)/q]%p + + cout << "Initialised... " << p%8 << endl; + + time(&seed); + irand(1L /*(long)seed*/); + +#ifdef AFFINE + ecurve(A,B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(A,B,p,MR_PROJECTIVE); +#endif + + set_frobenius_constant(Fr); + + mip->IOBASE=16; + mip->TWIST=MR_QUADRATIC; // map Server to point on twisted curve E(Fp2) + +// hash Identities to curve point + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + Server=hash2((char *)"Server"); + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice",cof); + + Bob= hash_and_map((char *)"Robert",cof); + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=ss*Server; + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + if (!tate(sA,Server,q,cf,Fr,res)) cout << "Trouble" << endl; + + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + ap=powl(res,a); + + if (!tate(Alice,sS,q,cf,Fr,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powl(res,s); + + cout << "Alice Key= " << H2(powl(sp,a)) << endl; + cout << "Server Key= " << H2(powl(ap,s)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!tate(sB,Server,q,cf,Fr,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powl(res,b); + + if (!tate(Bob,sS,q,cf,Fr,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powl(res,s); + + cout << "Bob's Key= " << H2(powl(sp,b)) << endl; + cout << "Server Key= " << H2(powl(bp,s)) << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/ake4fsta.cpp b/miracl/source/curve/pairing/ake4fsta.cpp new file mode 100644 index 0000000..a9bd1b2 --- /dev/null +++ b/miracl/source/curve/pairing/ake4fsta.cpp @@ -0,0 +1,409 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=8 ake4fsta.cpp zzn4.cpp zzn2.cpp ecn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + Fastest using COMBA build for 256-bit mod-mul + + Freeman-Scott-Teske Curve - Ate pairing + + The file nk4.ecs is required + Security is G160/F1024 (160-bit group, 1024-bit field) + + Modified to prevent sub-group confinement attack + + NOTE: assumes p = 5 mod 8, p is 256-bits + + **** NEW **** Based on the observation by R. Granger and D. Page and N.P. Smart in "High Security + Pairing-Based Cryptography Revisited" that multi-exponentiation can be used for the final exponentiation + of the Tate pairing, we suggest the Power Pairing, which calculates E(P,Q,e) = e(P,Q)^e, where the + exponentiation by e is basically for free, as it can be folded into the multi-exponentiation. + + **** NEW **** ATE pairing implementation - see The Eta Pairing revisited by Hess, Smart and Vercauteren + +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn2.h" +#include "zzn4.h" + +using namespace std; + +Miracl precision(16,0); + +// Using SHA-1 as basic hash algorithm + +#define HASH_LEN 20 + +// +// Define one or the other of these +// +// Which is faster depends on the I/M ratio - See imratio.c +// Roughly if I/M ratio > 16 use PROJECTIVE, otherwise use AFFINE +// + + +// This program works with AFFINE only.. + +#define AFFINE + +// +// Ate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +// +// Get x/i^2, y/i^4, where i is 4th root of -2 +// + +void untwist(ECn2& P,ZZn2& U,ZZn2& V) +{ + P.get(U,V); + U=-tx(U)/2; + V=-V/2; +} + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn4 line(ECn2& A,ZZn2& lam,ZZn& Qx,ZZn& Qy) +{ + ZZn4 w; + ZZn2 x,y,z,t; + + untwist(A,x,y); + + w.set(ZZn2(0,Qy),tx(y)-lam*(x-Qx)); + + return w; +} + +// +// Add A=A+B (or A=A+A) +// Bump up num +// + + +ZZn4 g(ECn2& A,ECn2& B,ZZn& Qx,ZZn& Qy) +{ + ZZn2 lam; + ECn2 P=A; + +// Evaluate line from A + A.add(B,lam); + if (A.iszero()) return (ZZn4)1; + +//cout << "lam= " << lam << endl; + + return line(P,lam,Qx,Qy); +} + +// +// Ate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order m.q. +// Note that P is a point on the curve over Fp, Q(x,y) a point on the +// extension field Fp^2 +// +// New! Power Pairing calculates E(P,Q,e) = e(P,Q)^e at no extra cost! +// + +BOOL power_pairing(ECn2& P,ECn Q,Big& T,Big *cf,ZZn2 &Fr,Big &e,Big q,ZZn2& r) +{ + int i,nb; + ECn2 A; + ZZn4 w,res,a[2]; + ZZn Qx,Qy; + Big carry,ex[2],p=get_modulus(); + + extract(Q,Qx,Qy); + + res=1; + +/* Left to right method */ + A=P; + nb=bits(T); + for (i=nb-2;i>=0;i--) + { + res*=res; + res*=g(A,A,Qx,Qy); + if (bit(T,i)) + res*=g(A,P,Qx,Qy); + } + +// if (!A.iszero() || res.iszero()) return FALSE; + + w=res; + w.powq(Fr); w.powq(Fr); // ^(p^2-1) + res=w/res; + + + res.mark_as_unitary(); + + if (e.isone()) + { + ex[0]=cf[0]; + ex[1]=cf[1]; + } + else + { // cf *= e + carry=mad(cf[1],e,(Big)0,p,ex[1]); + mad(cf[0],e,carry,p,ex[0]); + } + + a[0]=a[1]=res; + a[0].powq(Fr); + res=pow(2,a,ex); + + r=real(res); // compression + + if (r.isunity()) return FALSE; + return TRUE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha sh; + + shs_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs_process(&sh,string[i]); + } + shs_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn2 x) +{ // Hash an Fp2 to a big number + sha sh; + Big a,u,v; + char s[HASH_LEN]; + int m; + + shs_init(&sh); + x.get(u,v); + + a=u; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + a=v; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + shs_hash(&sh,s); + a=from_binary(HASH_LEN,s); + return a; +} + +// Hash and map a Server Identity to a curve point E(Fp2) + +ECn2 hash2(char *ID,Big cof2) +{ + ECn2 T; + ZZn2 x; + Big x0,y0=0; + x0=H1(ID); + do + { + x.set(x0,y0); + x0+=1; + } + while (!is_on_curve(x)); + T.set(x); + T*=cof2; + return T; +} + +// Hash and map a Client Identity to a curve point E(Fp) + +ECn hash_and_map(char *ID,Big cof) +{ + ECn Q; + Big x0=H1(ID); + + while (!is_on_curve(x0)) x0+=1; + Q.set(x0); // Make sure its on E(F_p) + + Q*=cof; + return Q; +} + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + X.set((Big)0,(Big)1); // = (sqrt(-2)^(p-1)/2 + break; + case 3: // = (1+sqrt(-1))^(p-1)/2 + X.set((Big)1,(Big)1); + break; + case 7: // = (2+sqrt(-1))^(p-1)/2 + X.set((Big)2,(Big)1); + break; + default: break; + } + X=pow(X,(p-1)/2); +} + +int main() +{ + ifstream common("nk4.ecs"); // elliptic curve parameters + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn2 Server,sS; + ZZn2 res,sp,ap,bp,wa,wb,w1,w2,Fr; + ZZn ww; + ZZn4 w; + Big a,b,s,ss,p,q,r,B,cof,n,t1; + Big cf[2]; + + int i,bitz,A; + time_t seed; + + cout << "Started" << endl; + common >> bitz; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B; + common >> cof; // #E/q + common >> q; // low hamming weight q + common >> cf[0]; // [(p^2+1)/q]/p + common >> cf[1]; // [(p^2+1)/q]%p + + cout << "Initialised... " << p%8 << endl; + + Big t=p+1-cof*q; + Big cof2=(p*p+1)/q+(t*t-2*p)/q; + + t1=p-cof*q; // t-1 + + time(&seed); + irand((long)seed); + + ecurve(A,B,p,MR_AFFINE); + + set_frobenius_constant(Fr); + + mip->IOBASE=16; + mip->TWIST=TRUE; // map Server to point on twisted curve E(Fp2) + +// hash Identities to curve point + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + Server=hash2((char *)"Server",cof2); + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice",cof); + + Bob= hash_and_map((char *)"Robert",cof); + + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=ss*Server; + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + if (!power_pairing(Server,sA,t1,cf,Fr,a,q,res)) cout << "Trouble" << endl; + + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + ap=res; + + if (!power_pairing(sS,Alice,t1,cf,Fr,s,q,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + sp=res; + + cout << "Alice Key= " << H2(powl(sp,a)) << endl; + cout << "Server Key= " << H2(powl(ap,s)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!power_pairing(Server,sB,t1,cf,Fr,b,q,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=res; + + if (!power_pairing(sS,Bob,t1,cf,Fr,s,q,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=res; + + cout << "Bob's Key= " << H2(powl(sp,b)) << endl; + cout << "Server Key= " << H2(powl(bp,s)) << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/ake4mnta.c b/miracl/source/curve/pairing/ake4mnta.c new file mode 100644 index 0000000..795932c --- /dev/null +++ b/miracl/source/curve/pairing/ake4mnta.c @@ -0,0 +1,951 @@ +/* C version of ake4mnta.cpp + * + +Example for embedded implementation. + +Should build immediately with standard mirdef.h file on a PC. For example using MS C + +cl /O2 ake4mnta.c ms32.lib + +To simulate performance on a PC of an 8-bit computer use + +#define MR_LITTLE_ENDIAN +#define MIRACL 8 +#define mr_utype char +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype short +#define MR_STATIC 20 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 20 +#define MR_NOASM +#define MR_BITSINCHAR 8 +#define MR_NOSUPPORT_COMPRESSION + +rem Compile MIRACL modules +mex 20 c mrcomba +cl /c /O2 /W3 mrzzn2.c +cl /c /O2 /W3 mrcore.c +cl /c /O2 /W3 mrarth0.c +cl /c /O2 /W3 mrarth1.c +cl /c /O2 /W3 mrarth2.c +cl /c /O2 /W3 mrxgcd.c +cl /c /O2 /W3 mrbits.c +cl /c /O2 /W3 mrmonty.c +cl /c /O2 /W3 mrcomba.c +cl /c /O2 /W3 mrcurve.c +cl /c /O2 /W3 mrio1.c +cl /c /O2 /W3 mrpower.c + + +rem +rem Create library 'miracl.lib' +del miracl.lib + + +lib /OUT:miracl.lib mrxgcd.obj mrarth2.obj mrio1.obj mrcomba.obj +lib /OUT:miracl.lib miracl.lib mrmonty.obj mrarth1.obj mrarth0.obj mrcore.obj +lib /OUT:miracl.lib miracl.lib mrcurve.obj mrbits.obj mrzzn2.obj mrpower.obj + +del mr*.obj + +cl /O2 ake4mnta.c miracl.lib + +For Atmel AVR (atmega128) use + +#define MR_LITTLE_ENDIAN +#define MIRACL 8 +#define mr_utype char +#define MR_IBITS 16 +#define MR_LBITS 32 +#define mr_unsign32 unsigned long +#define mr_dltype int +#define mr_qltype long +#define MR_STATIC 20 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 20 +#define MR_NOASM +#define MR_BITSINCHAR 8 +#define MR_NO_STANDARD_IO +#define MR_NO_FILE_IO +#define MR_NOSUPPORT_COMPRESSION +#define MR_AVR + +This last line must be added manually - config.c will not do it automatically + +and execute + +mex 20 avr4 mrcomba + +On an ARM use a header like + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype long long +#define MR_STATIC 5 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 5 +#define MR_BITSINCHAR 8 +#define MR_NOSUPPORT_COMPRESSION + +and possible + +#define MR_NO_STANDARD_IO +#define MR_NO_FILE_IO + +and execute + +mex 5 arm mrcomba + + Speeded up using ideas from + "Efficient Computation of Tate Pairing in Projective Coordinate over General Characteristic Fields" + by Sanjit Chatterjee1, Palash Sarkar1 and Rana Barua1 + +*/ + +#include +#include +#include "miracl.h" + +#ifdef MR_COUNT_OPS +int fpm2,fpi2,fpc,fpa,fpx; +#endif + +/* Fix the contents of k4mnt.ecs */ +/* ROM contains details of a k=4 MNT pairing-friendly curve. In this case p is 160-bits, and + =5 mod 8. The pairing friendly prime-order group is of order (p+1-t)/34 */ + +#define CF 34 + +#if MIRACL==32 + +#define WORDS 5 +#define NPW 8 /* Nibbles per Word */ +#define ROMSZ 30 + +static const mr_small romp[]={ +0x76A5755D,0x245769E6,0xF33DC5F3,0x42C82027,0xE3F367D5, +0x866BA034,0x14DB64EB,0xDF4CF677,0xE45200C4,0xDABC0397, +0x58290FC5,0x0BD4BB42,0x0EAEF730,0xA014F1E3,0x6B455E0, +0xC1315D34,0x92168B16,0xF191,0x0,0x0, +0xB79C2B47,0x10BEC9C5,0xE0BF4D14,0x67B5A4AC,0xB3657D09, +0xC1315D33,0x92168B16,0xF191,0x0,0x0}; + +/* Points - in n-residue form */ + +#define PROMSZ 30 + +static const mr_small Prom[]={ +0x1E6EA84F,0xE7CE6B23,0x7B6AC239,0x805022A9,0x260BF17B, +0x90898C7E,0x9D8C9BC9,0xD482E11C,0x2D4D3F68,0x1D1DA150, +0xC8501310,0x524DD4A,0x3DED1AE2,0x3094317B,0x9DB2C44C, +0x23E533B2,0xC8BD73FB,0xF3D25667,0x1CEE805C,0x24EDB45C, +0x21E3CEBD,0x625F7B2E,0xF924576E,0x35FCAA2,0x67DE6249, +0xF780367B,0x43AD112B,0xD9F11765,0xF0BA13D1,0x1F0355FE}; + +#endif + +#if MIRACL==8 + +#define WORDS 20 +#define NPW 2 /* Nibbles per Word */ +#define ROMSZ 120 + +#ifdef MR_AVR +__attribute__((__progmem__)) +#endif +static const mr_small romp[]={ + +0x5D,0x75,0xA5,0x76,0xE6,0x69,0x57,0x24,0xF3,0xC5,0x3D,0xF3,0x27,0x20,0xC8,0x42,0xD5,0x67,0xF3,0xE3, +0x34,0xA0,0x6B,0x86,0xEB,0x64,0xDB,0x14,0x77,0xF6,0x4C,0xDF,0xC4,0x00,0x52,0xE4,0x97,0x03,0xBC,0xDA, +0xC5,0x0F,0x29,0x58,0x42,0xBB,0xD4,0x0B,0x30,0xF7,0xAE,0x0E,0xE3,0xF1,0x14,0xA0,0xE0,0x55,0xB4,0x06, +0x34,0x5D,0x31,0xC1,0x16,0x8B,0x16,0x92,0x91,0xF1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x47,0x2B,0x9C,0xB7,0xC5,0xC9,0xBE,0x10,0x14,0x4D,0xBF,0xE0,0xAC,0xA4,0xB5,0x67,0x09,0x7D,0x65,0xB3, +0x33,0x5D,0x31,0xC1,0x16,0x8B,0x16,0x92,0x91,0xF1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; + +#define PROMSZ 120 + +#ifdef MR_AVR +__attribute__((__progmem__)) +#endif +static const mr_small Prom[]={ +0x4F,0xA8,0x6E,0x1E,0x23,0x6B,0xCE,0xE7,0x39,0xC2,0x6A,0x7B,0xA9,0x22,0x50,0x80,0x7B,0xF1,0xB,0x26, +0x7E,0x8C,0x89,0x90,0xC9,0x9B,0x8C,0x9D,0x1C,0xE1,0x82,0xD4,0x68,0x3F,0x4D,0x2D,0x50,0xA1,0x1D,0x1D, +0x10,0x13,0x50,0xC8,0x4A,0xDD,0x24,0x5,0xE2,0x1A,0xED,0x3D,0x7B,0x31,0x94,0x30,0x4C,0xC4,0xB2,0x9D, +0xB2,0x33,0xE5,0x23,0xFB,0x73,0xBD,0xC8,0x67,0x56,0xD2,0xF3,0x5C,0x80,0xEE,0x1C,0x5C,0xB4,0xED,0x24, +0xBD,0xCE,0xE3,0x21,0x2E,0x7B,0x5F,0x62,0x6E,0x57,0x24,0xF9,0xA2,0xCA,0x5F,0x3,0x49,0x62,0xDE,0x67, +0x7B,0x36,0x80,0xF7,0x2B,0x11,0xAD,0x43,0x65,0x17,0xF1,0xD9,0xD1,0x13,0xBA,0xF0,0xFE,0x55,0x3,0x1F}; + +#endif + +/* Fp4 support functions */ + +typedef struct +{ + zzn2 x; + zzn2 y; + BOOL unitary; +} zzn4; + +#ifndef MR_NO_STANDARD_IO +void zzn2_out(_MIPD_ char *p,zzn2 *x) +{ + printf(p); printf("\n"); + redc(_MIPP_ x->a,x->a); + redc(_MIPP_ x->b,x->b); + otnum(_MIPP_ x->a,stdout); + otnum(_MIPP_ x->b,stdout); + nres(_MIPP_ x->a,x->a); + nres(_MIPP_ x->b,x->b); +} +#endif + +/* Irreducible over zzn2 is x^2+n */ +/* zzn4 is towered on top of this with irreducible X^2+sqrt(n) p=5 mod 8, or X^2+(1+sqrt(n)) p=3,7 mod 8 */ +/* same as txx(.) function in C++ */ + +void zzn2_times_irp(_MIPD_ zzn2 *u) +{ + zzn2 t; + + switch (mr_mip->pmod8) + { + case 5: /* times sqrt(n) */ + zzn2_timesi(_MIPP_ u); + break; + case 3: /* times 1+sqrt(n) */ + case 7: + t.a=mr_mip->w5; + t.b=mr_mip->w6; + zzn2_copy(u,&t); + zzn2_timesi(_MIPP_ &t); + zzn2_add(_MIPP_ u,&t,u); + break; + default: + break; + } +} + +void zzn4_copy(zzn4 *u,zzn4 *w) +{ + if (u==w) return; + zzn2_copy(&(u->x),&(w->x)); + zzn2_copy(&(u->y),&(w->y)); + w->unitary=u->unitary; +} + +void zzn4_from_int(_MIPD_ int i,zzn4 *w) +{ + zzn2_from_int(_MIPP_ i,&(w->x)); + zzn2_zero(&(w->y)); + if (i==1) w->unitary=TRUE; + else w->unitary=FALSE; + +} + +void zzn4_conj(_MIPD_ zzn4 *u,zzn4 *w) +{ + zzn4_copy(u,w); + zzn2_negate(_MIPP_ &(w->y),&(w->y)); +} + +void zzn4_mul(_MIPD_ zzn4 *u,zzn4 *v,zzn4 *w) +{ + zzn2 t1,t2,t3; + t1.a=mr_mip->w3; + t1.b=mr_mip->w4; + t2.a=mr_mip->w8; + t2.b=mr_mip->w9; + if (u==v) + { + if (u->unitary) + { /* this is faster.. - see Lenstra & Stam */ + zzn4_copy(u,w); + zzn2_mul(_MIPP_ &(w->y),&(w->y),&t1); + zzn2_add(_MIPP_ &(w->y),&(w->x),&(w->y)); + zzn2_mul(_MIPP_ &(w->y),&(w->y),&(w->y)); + zzn2_sub(_MIPP_ &(w->y),&t1,&(w->y)); + zzn2_timesi(_MIPP_ &t1); + zzn2_copy(&t1,&(w->x)); + zzn2_sub(_MIPP_ &(w->y),&(w->x),&(w->y)); + zzn2_add(_MIPP_ &(w->x),&(w->x),&(w->x)); + zzn2_sadd(_MIPP_ &(w->x),mr_mip->one,&(w->x)); + zzn2_ssub(_MIPP_ &(w->y),mr_mip->one,&(w->y)); + } + else + { + zzn4_copy(u,w); + zzn2_copy(&(w->y),&t2); // t2=b; + zzn2_add(_MIPP_ &(w->x),&t2,&t1); // t1=a+b + zzn2_times_irp(_MIPP_ &t2); // t2=txx(b); + zzn2_add(_MIPP_ &t2,&(w->x),&t2); // t2=a+txx(b) + zzn2_mul(_MIPP_ &(w->y),&(w->x),&(w->y)); // b*=a + zzn2_mul(_MIPP_ &t1,&t2,&(w->x)); // a=t1*t2 + zzn2_copy(&(w->y),&t2); //t2=b + zzn2_sub(_MIPP_ &(w->x),&t2,&(w->x)); //a-=b + zzn2_times_irp(_MIPP_ &t2); // t2=txx(b) + zzn2_sub(_MIPP_ &(w->x),&t2,&(w->x)); // a-=txx(b); + zzn2_add(_MIPP_ &(w->y),&(w->y),&(w->y)); // b+=b; + } + } + else + { + t3.a=mr_mip->w10; + t3.b=mr_mip->w11; + zzn2_copy(&(u->x),&t1); + zzn2_copy(&(u->y),&t2); + zzn2_mul(_MIPP_ &t1,&(v->x),&t1); + zzn2_mul(_MIPP_ &t2,&(v->y),&t2); + zzn2_copy(&(v->x),&t3); + zzn2_add(_MIPP_ &t3,&(v->y),&t3); + + zzn2_add(_MIPP_ &(u->y),&(u->x),&(w->y)); + zzn2_mul(_MIPP_ &(w->y),&t3,&(w->y)); + zzn2_sub(_MIPP_ &(w->y),&t1,&(w->y)); + zzn2_sub(_MIPP_ &(w->y),&t2,&(w->y)); + zzn2_copy(&t1,&(w->x)); + zzn2_times_irp(_MIPP_ &t2); + zzn2_add(_MIPP_ &(w->x),&t2,&(w->x)); + if (u->unitary && v->unitary) w->unitary=TRUE; + else w->unitary=FALSE; + } +} + +/* zzn4 powering of unitary elements */ + +void zzn4_powu(_MIPD_ zzn4 *x,big k,zzn4 *u) +{ + zzn4 t[5],u2; + big k3; + int i,j,n,nb,nbw,nzs; +#ifndef MR_STATIC + char *mem=memalloc(_MIPP_ 25); +#else + char mem[MR_BIG_RESERVE(25)]; + memset(mem,0,MR_BIG_RESERVE(25)); +#endif + + if (size(k)==0) + { + zzn4_from_int(_MIPP_ 1,u); + return; + } + zzn4_copy(x,u); + if (size(k)==1) return; + + for (j=i=0;i<5;i++) + { + t[i].x.a=mirvar_mem(_MIPP_ mem,j++); + t[i].x.b=mirvar_mem(_MIPP_ mem,j++); + t[i].y.a=mirvar_mem(_MIPP_ mem,j++); + t[i].y.b=mirvar_mem(_MIPP_ mem,j++); + t[i].unitary=FALSE; + } + u2.x.a=mirvar_mem(_MIPP_ mem,j++); + u2.x.b=mirvar_mem(_MIPP_ mem,j++); + u2.y.a=mirvar_mem(_MIPP_ mem,j++); + u2.y.b=mirvar_mem(_MIPP_ mem,j++); + u2.unitary=FALSE; + k3=mirvar_mem(_MIPP_ mem,j); + + premult(_MIPP_ k,3,k3); + zzn4_mul(_MIPP_ u,u,&u2); + zzn4_copy(u,&t[0]); + + for (i=1;i<=4;i++) + zzn4_mul(_MIPP_ &u2,&t[i-1],&t[i]); + + nb=logb2(_MIPP_ k3); + + for (i=nb-2;i>=1;) + { + n=mr_naf_window(_MIPP_ k,k3,i,&nbw,&nzs,5); + + for (j=0;j0) zzn4_mul(_MIPP_ u,&t[n/2],u); + if (n<0) + { + zzn4_conj(_MIPP_ &t[-n/2],&u2); + zzn4_mul(_MIPP_ u,&u2,u); + } + i-=nbw; + if (nzs) + { + for (j=0;jw7; + t1.b=mr_mip->w8; + t3.a=mr_mip->w10; + t3.b=mr_mip->w11; + t4.a=mr_mip->w13; + t4.b=mr_mip->w14; + + zzn2_from_int(_MIPP_ 1,&t1); + + s=size(e); + if (s==0) + { + zzn2_copy(&t1,w); + return; + } + zzn2_copy(x,w); + if (s==1 || s==(-1)) return; + + i=logb2(_MIPP_ e)-1; + + zzn2_copy(w,&t3); + zzn2_mul(_MIPP_ w,w,&t4); + zzn2_add(_MIPP_ &t4,&t4,&t4); + zzn2_sub(_MIPP_ &t4,&t1,&t4); + + while (i--) + { + if (mr_testbit(_MIPP_ e,i)) + { + zzn2_mul(_MIPP_ &t3,&t4,&t3); + zzn2_add(_MIPP_ &t3,&t3,&t3); + zzn2_sub(_MIPP_ &t3,w,&t3); + zzn2_mul(_MIPP_ &t4,&t4,&t4); + zzn2_add(_MIPP_ &t4,&t4,&t4); + zzn2_sub(_MIPP_ &t4,&t1,&t4); + } + else + { + zzn2_mul(_MIPP_ &t4,&t3,&t4); + zzn2_add(_MIPP_ &t4,&t4,&t4); + zzn2_sub(_MIPP_ &t4,w,&t4); + zzn2_mul(_MIPP_ &t3,&t3,&t3); + zzn2_add(_MIPP_ &t3,&t3,&t3); + zzn2_sub(_MIPP_ &t3,&t1,&t3); + } + } + zzn2_copy(&t3,w); +} + +void zzn4_powq(_MIPD_ big fr,zzn4 *w) +{ + zzn2_conj(_MIPP_ &(w->x),&(w->x)); + zzn2_conj(_MIPP_ &(w->y),&(w->y)); + nres(_MIPP_ fr,mr_mip->w1); + zzn2_smul(_MIPP_ &(w->y),mr_mip->w1,&(w->y)); +} + +void zzn4_inv(_MIPD_ zzn4 *u) +{ + zzn2 t1,t2; + if (u->unitary) + { + zzn4_conj(_MIPP_ u,u); + return; + } + t1.a=mr_mip->w8; + t1.b=mr_mip->w9; + t2.a=mr_mip->w3; + t2.b=mr_mip->w4; + zzn2_mul(_MIPP_ &(u->x),&(u->x),&t1); + zzn2_mul(_MIPP_ &(u->y),&(u->y),&t2); + zzn2_times_irp(_MIPP_ &t2); + zzn2_sub(_MIPP_ &t1,&t2,&t1); + zzn2_inv(_MIPP_ &t1); + zzn2_mul(_MIPP_ &(u->x),&t1,&(u->x)); + zzn2_negate(_MIPP_ &t1,&t1); + zzn2_mul(_MIPP_ &(u->y),&t1,&(u->y)); +} + +/* Original from A. Devegili. Thanks Augusto! Projective point addition */ + +BOOL ecurve_fp2_add(_MIPD_ zzn2 *Zx, zzn2 *Zy, zzn2 *Zz, zzn2 *x, zzn2 *y, zzn2 *z, zzn2 *lam,zzn2 *ex1,zzn2 *ex2) +{ + BOOL doubling,normed; + zzn2 Xzz, Yzzz, xZZ, yZZZ, zz, ZZ; + zzn2 t1, t2, t3, x3; +#ifndef MR_STATIC + char *mem = memalloc(_MIPP_ 20); +#else + char mem[MR_BIG_RESERVE(20)]; + memset(mem, 0, MR_BIG_RESERVE(20)); +#endif + + Xzz.a = mirvar_mem(_MIPP_ mem, 0); + Xzz.b = mirvar_mem(_MIPP_ mem, 1); + Yzzz.a = mirvar_mem(_MIPP_ mem, 2); + Yzzz.b = mirvar_mem(_MIPP_ mem, 3); + xZZ.a = mirvar_mem(_MIPP_ mem, 4); + xZZ.b = mirvar_mem(_MIPP_ mem, 5); + yZZZ.a = mirvar_mem(_MIPP_ mem, 6); + yZZZ.b = mirvar_mem(_MIPP_ mem, 7); + zz.a = mirvar_mem(_MIPP_ mem, 8); + zz.b = mirvar_mem(_MIPP_ mem, 9); + ZZ.a = mirvar_mem(_MIPP_ mem, 10); + ZZ.b = mirvar_mem(_MIPP_ mem, 11); + t1.a = mirvar_mem(_MIPP_ mem, 12); + t1.b = mirvar_mem(_MIPP_ mem, 13); + t2.a = mirvar_mem(_MIPP_ mem, 14); + t2.b = mirvar_mem(_MIPP_ mem, 15); + t3.a = mirvar_mem(_MIPP_ mem, 16); + t3.b = mirvar_mem(_MIPP_ mem, 17); + x3.a = mirvar_mem(_MIPP_ mem, 18); + x3.b = mirvar_mem(_MIPP_ mem, 19); + + doubling=FALSE; + if (z==Zz) doubling=TRUE; + + if (!doubling) + { // maybe we are really doubling? Or P-=P? + if (!zzn2_isunity(_MIPP_ Zz)) + { + zzn2_mul(_MIPP_ Zz, Zz, &ZZ); // ZZ = Zz^2 + zzn2_mul(_MIPP_ x, &ZZ, &xZZ); // xZZ = x * Zz^2 + zzn2_mul(_MIPP_ &ZZ, Zz, &yZZZ); // yZZZ = Zz^3 + zzn2_mul(_MIPP_ &yZZZ, y, &yZZZ); // yZZZ = y * Zz^3 + normed=FALSE; + } + else + { + zzn2_copy(x,&xZZ); + zzn2_copy(y,&yZZZ); + normed=TRUE; + } + if (!zzn2_isunity(_MIPP_ z)) + { + zzn2_mul(_MIPP_ z, z, &zz); // zz = z^2 + zzn2_mul(_MIPP_ Zx, &zz, &Xzz); // Xzz = Zx * z^2 + zzn2_mul(_MIPP_ &zz, z, &Yzzz); // Yzzz = z^3 + zzn2_mul(_MIPP_ &Yzzz, Zy, &Yzzz); // Yzzz = Zy * z^3 + } + else + { + zzn2_copy(Zx,&Xzz); + zzn2_copy(Zy,&Yzzz); + } + + if (zzn2_compare(&Xzz,&xZZ)) + { + if (!zzn2_compare(&Yzzz,&yZZZ) || zzn2_iszero(y)) + { + zzn2_zero(x); + zzn2_zero(y); + zzn2_zero(z); + zzn2_from_int(_MIPP_ 1,lam); +#ifndef MR_STATIC + memkill(_MIPP_ mem, 20); +#else + memset(mem, 0, MR_BIG_RESERVE(20)); +#endif + return doubling; + } + else + doubling=TRUE; + } + } + + if (!doubling) + { // point addition + zzn2_sub(_MIPP_ &xZZ, &Xzz, &t1); // t1 = Xzz - xZZ + zzn2_sub(_MIPP_ &yZZZ, &Yzzz, lam); // lam = yZZZ - yZZZ + zzn2_mul(_MIPP_ z,&t1,z); + if (!normed) zzn2_mul(_MIPP_ z,&ZZ,z); + + zzn2_mul(_MIPP_ &t1,&t1,&t2); + zzn2_add(_MIPP_ &xZZ,&Xzz,&t3); + zzn2_mul(_MIPP_ &t3,&t2,&t3); + zzn2_mul(_MIPP_ lam, lam, &x3); // x3 = lam^2 + zzn2_sub(_MIPP_ &x3,&t3,&x3); + zzn2_sub(_MIPP_ &t3,&x3,&t3); + zzn2_sub(_MIPP_ &t3,&x3,&t3); + + zzn2_mul(_MIPP_ &t3,lam,&t3); + zzn2_mul(_MIPP_ &t2,&t1,&t2); + zzn2_add(_MIPP_ &yZZZ,&Yzzz,&t1); + zzn2_mul(_MIPP_ &t1,&t2,&t1); + zzn2_sub(_MIPP_ &t3,&t1,y); + zzn2_div2(_MIPP_ y); + zzn2_copy(&x3,x); + } + else + { // point doubling + zzn2_mul(_MIPP_ y, y, &t2); // t2 = y^2 + +/* its on the twist so A=6! */ + + zzn2_mul(_MIPP_ z,z,ex2); + zzn2_mul(_MIPP_ x,x,lam); + zzn2_mul(_MIPP_ ex2,ex2,&t1); + zzn2_add(_MIPP_ &t1,&t1,&t1); + zzn2_add(_MIPP_ lam,&t1,lam); + zzn2_copy(lam,&t1); + zzn2_add(_MIPP_ lam,lam,lam); + zzn2_add(_MIPP_ lam,&t1,lam); + + zzn2_mul(_MIPP_ x, &t2, &t1); // t1 = x * y^2 + zzn2_add(_MIPP_ &t1, &t1, &t1); // t1 = 2(x*y^2) + zzn2_add(_MIPP_ &t1, &t1, &t1); // t1 = 4(x*y^2) + + // x = lam^2 - t1 - t1 + zzn2_mul(_MIPP_ lam, lam, x); // x = lam^2 + zzn2_sub(_MIPP_ x, &t1, x); // x = lam^2 - t1 + zzn2_sub(_MIPP_ x, &t1, x); // x = lam^2 - 2t1 + + zzn2_mul(_MIPP_ z, y , z); // z = yz + zzn2_add(_MIPP_ z, z, z); // z = 2yz + + // 8 * y^2 + zzn2_add(_MIPP_ &t2, &t2, &t2); // t2 = 2y^2 + zzn2_copy(&t2,ex1); + zzn2_mul(_MIPP_ &t2, &t2, &t2); // t2 = 4y^2 + zzn2_add(_MIPP_ &t2, &t2, &t2); // t2 = 8y^2 + + // y = lam*(t - x) - y^2 + zzn2_sub(_MIPP_ &t1, x, y); // y = t1 - x + zzn2_mul(_MIPP_ y, lam, y); // y = lam(t1 - x) + zzn2_sub(_MIPP_ y, &t2, y); // y = lam(t1 - x) * y^2 + } + +#ifndef MR_STATIC + memkill(_MIPP_ mem, 20); +#else + memset(mem, 0, MR_BIG_RESERVE(20)); +#endif + return doubling; +} + +void g(_MIPD_ zzn2 *Ax,zzn2 *Ay,zzn2 *Az,zzn2 *Bx,zzn2 *By,zzn2 *Bz,big Px,big Py,zzn4 *w) +{ + BOOL Doubling; + zzn2 lam,extra1,extra2,Kx,nn,dd; + +#ifndef MR_STATIC + char *mem = memalloc(_MIPP_ 12); +#else + char mem[MR_BIG_RESERVE(12)]; + memset(mem, 0, MR_BIG_RESERVE(12)); +#endif + lam.a=mirvar_mem(_MIPP_ mem,0); + lam.b=mirvar_mem(_MIPP_ mem,1); + extra1.a=mirvar_mem(_MIPP_ mem,2); + extra1.b=mirvar_mem(_MIPP_ mem,3); + extra2.a=mirvar_mem(_MIPP_ mem,4); + extra2.b=mirvar_mem(_MIPP_ mem,5); + Kx.a=mirvar_mem(_MIPP_ mem,6); + Kx.b=mirvar_mem(_MIPP_ mem,7); + nn.a=mirvar_mem(_MIPP_ mem,8); + nn.b=mirvar_mem(_MIPP_ mem,9); + dd.a=mirvar_mem(_MIPP_ mem,10); + dd.b=mirvar_mem(_MIPP_ mem,11); + + zzn2_copy(Ax,&Kx); + + Doubling=ecurve_fp2_add(_MIPP_ Bx,By,Bz,Ax,Ay,Az,&lam,&extra1,&extra2); + +/* Get extra information from the point addition, for use in the line functions */ + + if (!Doubling) + { + zzn2_smul(_MIPP_ Az,Py,&nn); + zzn2_timesi(_MIPP_ &nn); + zzn2_copy(Bx,&dd); + zzn2_timesi(_MIPP_ &dd); + zzn2_sadd(_MIPP_ &dd,Px,&dd); + zzn2_mul(_MIPP_ &lam,&dd,&lam); + zzn2_copy(By,&dd); + zzn2_timesi(_MIPP_ &dd); + zzn2_mul(_MIPP_ &dd,Az,&dd); + zzn2_sub(_MIPP_ &lam,&dd,&dd); + } + else + { + zzn2_smul(_MIPP_ &extra2,Py,&nn); + zzn2_mul(_MIPP_ &nn,Az,&nn); + zzn2_timesi(_MIPP_ &nn); + zzn2_timesi(_MIPP_ &Kx); + zzn2_smul(_MIPP_ &extra2,Px,&dd); + zzn2_add(_MIPP_ &dd,&Kx,&dd); + zzn2_mul(_MIPP_ &lam,&dd,&lam); + zzn2_timesi(_MIPP_ &extra1); + zzn2_sub(_MIPP_ &lam,&extra1,&dd); + + } + zzn2_copy(&nn,&(w->x)); + zzn2_copy(&dd,&(w->y)); + +#ifndef MR_STATIC + memkill(_MIPP_ mem,12); +#else + memset(mem,0,MR_BIG_RESERVE(12)); +#endif + return; +} + +void fast_tate_pairing(_MIPD_ zzn2 *Qx,zzn2 *Qy,epoint *P,big T,big fr,big delta,zzn4 *w,zzn4* res) +{ + int i,j,nb; + zzn2 Ax,Ay,Az,Qz; + zzn Px,Py; + +#ifndef MR_STATIC + char *mem=memalloc(_MIPP_ 10); +#else + char mem[MR_BIG_RESERVE(10)]; + memset(mem,0,MR_BIG_RESERVE(10)); +#endif + +#ifdef MR_COUNT_OPS +fpa=fpc=fpx=0; +#endif + + Ax.a=mirvar_mem(_MIPP_ mem,0); + Ax.b=mirvar_mem(_MIPP_ mem,1); + Ay.a=mirvar_mem(_MIPP_ mem,2); + Ay.b=mirvar_mem(_MIPP_ mem,3); + Az.a=mirvar_mem(_MIPP_ mem,4); + Az.b=mirvar_mem(_MIPP_ mem,5); + Qz.a=mirvar_mem(_MIPP_ mem,6); + Qz.b=mirvar_mem(_MIPP_ mem,7); + Px=mirvar_mem(_MIPP_ mem,8); + Py=mirvar_mem(_MIPP_ mem,9); + + copy(P->X,Px); + copy(P->Y,Py); + + nres_modadd(_MIPP_ Px,Px,Px); /* removes a factor of 2 from g() */ + nres_modadd(_MIPP_ Py,Py,Py); + + zzn2_from_int(_MIPP_ 1,&Qz); + zzn2_copy(Qx,&Ax); + zzn2_copy(Qy,&Ay); + zzn2_copy(&Qz,&Az); + + zzn4_from_int(_MIPP_ 1,res); + +/* Simple Miller loop */ + nb=logb2(_MIPP_ T); + for (i=nb-2;i>=0;i--) + { + zzn4_mul(_MIPP_ res,res,res); + g(_MIPP_ &Ax,&Ay,&Az,&Ax,&Ay,&Az,Px,Py,w); + zzn4_mul(_MIPP_ res,w,res); + if (mr_testbit(_MIPP_ T,i)) + { + g(_MIPP_ &Ax,&Ay,&Az,Qx,Qy,&Qz,Px,Py,w); + zzn4_mul(_MIPP_ res,w,res); + } + } + +#ifdef MR_COUNT_OPS +printf("Millers loop Cost\n"); +printf("fpc= %d\n",fpc); +printf("fpa= %d\n",fpa); +printf("fpx= %d\n",fpx); + +fpa=fpc=fpx=0; +#endif + + zzn4_copy(res,w); + zzn4_powq(_MIPP_ fr,w); zzn4_powq(_MIPP_ fr,w); + zzn4_inv(_MIPP_ res); + zzn4_mul(_MIPP_ res,w,res); /* ^(p*p-1) */ + + res->unitary=TRUE; + + zzn4_mul(_MIPP_ res,res,res); + zzn4_copy(res,w); + zzn4_mul(_MIPP_ res,res,res); + zzn4_mul(_MIPP_ res,res,res); + zzn4_mul(_MIPP_ res,res,res); + zzn4_mul(_MIPP_ res,res,res); + zzn4_mul(_MIPP_ res,w,res); /* res=powu(res,CF) for CF=34 */ + +#ifndef MR_STATIC + memkill(_MIPP_ mem,10); +#else + memset(mem,0,MR_BIG_RESERVE(10)); +#endif +} + +void ecap(_MIPD_ zzn2 *Qx,zzn2 *Qy,epoint *P,big T,big fr,big delta,zzn2* r) +{ + zzn4 res,w; +#ifndef MR_STATIC + char *mem=memalloc(_MIPP_ 8); +#else + char mem[MR_BIG_RESERVE(8)]; + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + res.x.a=mirvar_mem(_MIPP_ mem,0); + res.x.b=mirvar_mem(_MIPP_ mem,1); + res.y.a=mirvar_mem(_MIPP_ mem,2); + res.y.b=mirvar_mem(_MIPP_ mem,3); + w.x.a=mirvar_mem(_MIPP_ mem,4); + w.x.b=mirvar_mem(_MIPP_ mem,5); + w.y.a=mirvar_mem(_MIPP_ mem,6); + w.y.b=mirvar_mem(_MIPP_ mem,7); + + res.unitary=FALSE; + w.unitary=FALSE; + + epoint_norm(_MIPP_ P); + + fast_tate_pairing(_MIPP_ Qx,Qy,P,T,fr,delta,&w,&res); + + zzn4_copy(&res,&w); + zzn4_powq(_MIPP_ fr,&res); + + zzn4_powu(_MIPP_ &w,delta,&w); + zzn4_mul(_MIPP_ &res,&w,&res); + + zzn2_copy(&(res.x),r); + +#ifdef MR_COUNT_OPS +printf("Final Exponentiation cost\n"); +printf("fpc= %d\n",fpc); +printf("fpa= %d\n",fpa); +printf("fpx= %d\n",fpx); + +fpa=fpc=fpx=0; +#endif + +#ifndef MR_STATIC + memkill(_MIPP_ mem,8); +#else + memset(mem,0,MR_BIG_RESERVE(8)); +#endif +} + +int main() +{ +#ifdef MR_GENERIC_MT + miracl instance; +#endif + big p,A,B,fr,q,delta,t,T; + zzn2 res,Qx,Qy; + epoint *P; + int i,romptr; +#ifndef MR_STATIC +#ifdef MR_GENERIC_MT + miracl *mr_mip=mirsys(&instance,WORDS*NPW,16); +#else + miracl *mr_mip=mirsys(WORDS*NPW,16); +#endif + char *mem=memalloc(_MIPP_ 14); + +#else +#ifdef MR_GENERIC_MT + miracl *mr_mip=mirsys(&instance,MR_STATIC*NPW,16); +#else + miracl *mr_mip=mirsys(MR_STATIC*NPW,16); +#endif + char mem[MR_BIG_RESERVE(14)]; /* reserve space on the stack for 14 bigs */ + char mem1[MR_ECP_RESERVE(1)]; /* reserve space on stack for 1 curve points */ + memset(mem,0,MR_BIG_RESERVE(14)); /* clear this memory */ + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + p=mirvar_mem(_MIPP_ mem,0); + A=mirvar_mem(_MIPP_ mem,1); + B=mirvar_mem(_MIPP_ mem,2); + T=mirvar_mem(_MIPP_ mem,3); + q=mirvar_mem(_MIPP_ mem,4); + fr=mirvar_mem(_MIPP_ mem,5); + delta=mirvar_mem(_MIPP_ mem,6); + res.a=mirvar_mem(_MIPP_ mem,7); + res.b=mirvar_mem(_MIPP_ mem,8); + t=mirvar_mem(_MIPP_ mem,9); + Qx.a=mirvar_mem(_MIPP_ mem,10); + Qx.b=mirvar_mem(_MIPP_ mem,11); + Qy.a=mirvar_mem(_MIPP_ mem,12); + Qy.b=mirvar_mem(_MIPP_ mem,13); + + P=epoint_init_mem(_MIPP_ mem1,0); + convert(_MIPP_ -3,A); + + romptr=0; + init_big_from_rom(p,WORDS,romp,ROMSZ,&romptr); + init_big_from_rom(B,WORDS,romp,ROMSZ,&romptr); + init_big_from_rom(q,WORDS,romp,ROMSZ,&romptr); + init_big_from_rom(delta,WORDS,romp,ROMSZ,&romptr); + init_big_from_rom(fr,WORDS,romp,ROMSZ,&romptr); + init_big_from_rom(T,WORDS,romp,ROMSZ,&romptr); + +#ifndef MR_NO_STANDARD_IO +printf("ROM size= %d\n",sizeof(romp)+sizeof(Prom)); +printf("sizeof(miracl)= %d\n",sizeof(miracl)); +#endif + + ecurve_init(_MIPP_ A,B,p,MR_PROJECTIVE); + + romptr=0; + init_point_from_rom(P,WORDS,Prom,PROMSZ,&romptr); + init_big_from_rom(Qx.a,WORDS,Prom,PROMSZ,&romptr); + init_big_from_rom(Qx.b,WORDS,Prom,PROMSZ,&romptr); + init_big_from_rom(Qy.a,WORDS,Prom,PROMSZ,&romptr); + init_big_from_rom(Qy.b,WORDS,Prom,PROMSZ,&romptr); +#ifdef MR_COUNT_OPS +fpa=fpc=fpx=0; +#endif + + ecap(_MIPP_ &Qx,&Qy,P,T,fr,delta,&res); +/* +#ifdef MR_COUNT_OPS +printf("fpc= %d\n",fpc); +printf("fpa= %d\n",fpa); +printf("fpx= %d\n",fpx); + +fpa=fpc=fpx=0; +#endif +*/ + bigbits(_MIPP_ 160,t); + + zzn2_powl(_MIPP_ &res,t,&res); + +#ifndef MR_NO_STANDARD_IO + zzn2_out(_MIPP_ "res= ",&res); +#endif + + ecurve_mult(_MIPP_ t,P,P); + + ecap(_MIPP_ &Qx,&Qy,P,T,fr,delta,&res); + +#ifndef MR_NO_STANDARD_IO + zzn2_out(_MIPP_ "res= ",&res); +#endif + +#ifndef MR_STATIC + memkill(_MIPP_ mem,14); + ecp_memkill(_MIPP_ mem1,1); +#else + memset(mem,0,MR_BIG_RESERVE(14)); /* clear this stack memory */ + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + return 0; +} + + diff --git a/miracl/source/curve/pairing/ake4mnta.cpp b/miracl/source/curve/pairing/ake4mnta.cpp new file mode 100644 index 0000000..7ecb880 --- /dev/null +++ b/miracl/source/curve/pairing/ake4mnta.cpp @@ -0,0 +1,446 @@ +/* + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=16 ake4mnta.cpp zzn4.cpp zzn2.cpp ecn2.cpp big.cpp zzn.cpp + ecn.cpp miracl.lib + Fastest using COMBA build for 160-bit mod-mul + + The file k4mnt.ecs is required + Security is G155/F640 (155-bit group, 640-bit field) + + Speeded up using ideas from + "Efficient Computation of Tate Pairing in Projective Coordinate over General Characteristic Fields" + by Sanjit Chatterjee1, Palash Sarkar1 and Rana Barua1 + + Modified to prevent sub-group confinement attack + +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn2.h" +#include "zzn4.h" + +using namespace std; + +Miracl precision(10,0); + +// Using SHA-1 as basic hash algorithm + +#define HASH_LEN 20 +#define COF 34 + +#ifdef MR_COUNT_OPS +extern "C" +{ + int fpc,fpa,fpx; +} +#endif + +// +// Define one or the other of these +// +// Which is faster depends on the I/M ratio - See imratio.c +// Roughly if I/M ratio > 16 use PROJECTIVE, otherwise use AFFINE +// + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +ZZn4 line(ECn2& A,ECn2& C,ECn2& B,BOOL Doubling,ZZn2& lam,ZZn2& extra1,ZZn2& extra2,ZZn& Qx,ZZn& Qy) +{ + ZZn4 w; + ZZn2 z3; + +#ifdef AFFINE + + ZZn2 x,y; + A.get(x,y); + w.set(ZZn2(0,Qy),lam*(tx(x)+Qx)-tx(y)); + +#endif + +#ifdef PROJECTIVE + + C.getZ(z3); + + if (!Doubling) + { + ZZn2 x2,y2; + B.get(x2,y2); + w.set(tx(z3*Qy),lam*(tx(x2)+Qx)-z3*tx(y2)); + } + else + { + ZZn2 x,y,z; + A.get(x,y,z); + w.set(tx(z3*extra2*Qy),lam*(extra2*Qx+tx(x))-tx(extra1)); + } +/* + A.get(x,y,z); + x=tx(x); y=tx(y); + t=z; x*=z; z*=z; z*=t; + w.set(z3*z*ZZn2(0,Qy),lam*(x+z*Qx)-y*z3); +*/ +#endif + + return w; +} + +ZZn4 g(ECn2& A,ECn2& B,ZZn& Qx,ZZn& Qy) +{ + BOOL Doubling; + ZZn2 lam,extra1,extra2; + ECn2 P=A; + + ZZn2 x,y,z; + +// Evaluate line from A + + Doubling=A.add(B,lam,extra1,extra2); + if (A.iszero()) return (ZZn4)1; + + return line(P,A,B,Doubling,lam,extra1,extra2,Qx,Qy); +} + +// +// Ate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order m.q. +// Note that P is a point on the curve over Fp, Q(x,y) a point on the +// extension field Fp^2 +// + +BOOL ate(ECn2& P,ECn Q,Big& t1,ZZn2 &Fr,Big cof,ZZn2& r) +{ + int i,j,n,nb; + ECn2 A; + ZZn4 w,res; + ZZn Qx,Qy; + +#ifdef MR_COUNT_OPS +fpc=fpa=fpx=0; +#endif + + P.norm(); + normalise(Q); + extract(Q,Qx,Qy); + + Qx+=Qx; // because x^4+2 is irreducible.. + Qy+=Qy; + + res=1; + +/* Miller loop - Left to right method */ + A=P; + nb=bits(t1); + for (i=nb-2;i>=0;i--) + { + res*=res; + res*=g(A,A,Qx,Qy); + if (bit(t1,i)) + res*=g(A,P,Qx,Qy); + } + +#ifdef MR_COUNT_OPS +printf("After Miller fpc= %d fpa= %d fpx= %d\n",fpc,fpa,fpx); +fpa=fpc=fpx=0; +#endif + + w=res; + w.powq(Fr); w.powq(Fr); // ^(p^2-1) + res=w/res; + + res.mark_as_unitary(); + + res*=res; w=res; res*=res; res*=res; res*=res; res*=res; res*=w; // res=powu(res,34); + + + w=res; + res.powq(Fr); + res*=powu(w,cof); + +#ifdef MR_COUNT_OPS +printf("After Final exp. fpc= %d fpa= %d fpx= %d\n",fpc,fpa,fpx); +fpa=fpc=fpx=0; +#endif + + r=real(res); + + if (r.isunity()) return FALSE; + return TRUE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha sh; + + shs_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs_process(&sh,string[i]); + } + shs_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn2 x) +{ // Hash an Fp2 to a big number + sha sh; + Big a,u,v; + char s[HASH_LEN]; + int m; + + shs_init(&sh); + x.get(u,v); + + a=u; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + a=v; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + shs_hash(&sh,s); + a=from_binary(HASH_LEN,s); + return a; +} + +// Hash and map a Server Identity to a curve point E(Fp2) + +ECn2 hash2(char *ID) +{ + ECn2 T; + ZZn2 x; + Big x0,y0=0; + + x0=H1(ID); + do + { + x.set(x0,y0); + x0+=1; + } + while (!is_on_curve(x)); + T.set(x); + +// cout << "T= " << T << endl; + + return T; +} + +// Hash and map a Client Identity to a curve point E(Fp) + +ECn hash_and_map(char *ID,Big cof) +{ + ECn Q; + Big x0=H1(ID); + + while (!is_on_curve(x0)) x0+=1; + Q.set(x0); // Make sure its on E(F_p) + + Q*=cof; + return Q; +} + +// +// fast multiplication by p-1+t +// We know F^2-tF+p = 0 +// So p.S=t.F(S)-F^2(S), where F is Frobenius Endomorphism +// So (p-1+t).S = t(F(S)+S)-F^2(S)-S +// This is just multiplication by t, which is half size of (p-1+t) +// + +void cofactor(ECn2& S,ZZn2& Fr,Big& t) +{ + ECn2 T,K; + ZZn2 x,y,tx,tty; + + K=S; + S.get(x,y); + x=txd(x); + y=txd(txd(y)); // untwist + + x.conj(); + y.conj(); y*=Fr; // ^p + + tx=txx(x); tty=txx(txx(y)); + S.set(tx,tty); // twist again + + x.conj(); + y.conj(); y*=Fr; // ^(p^2) + + tx=txx(x); tty=txx(txx(y)); + T.set(tx,tty); // twist + + S+=K; + S*=t; + S-=T; + S-=K; +} + +int main() +{ + ifstream common("k4mnt.ecs"); // elliptic curve parameters + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn2 Server,sS,tP; + ZZn2 res,sp,ap,bp,Fr,x,y; + ZZn4 X,Y,X2,Y2; + Big a,b,s,ss,p,q,r,B,delta,fr,t,t1; + + int bits,A; + time_t seed; + + cout << "Started" << endl; + common >> bits; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B; + common >> q >> delta; + common >> fr; + + cout << "Initialised... " << p%24 << endl; + + t=p+1-COF*q; + t1=p-COF*q; + +//cout << "p= " << p << endl; +//cout << "p%8= " << p%8 << endl; +cout << "t= " << t << endl; +//cout << "delta= " << delta << endl; + + time(&seed); + irand((long)seed); + +#ifdef AFFINE + ecurve(A,B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(A,B,p,MR_PROJECTIVE); +#endif + + // Fr=get_frobenius_constant(); + + Fr=(ZZn2)fr; + mip->IOBASE=16; + mip->TWIST=MR_QUADRATIC; // map Server to point on twisted curve E(Fp2) + +// hash Identities to curve point + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + Server=hash2((char *)"Server"); + cofactor(Server,Fr,t); // multiply by cofactor (p-1+t) + Server*=COF; + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice",COF); + + Bob= hash_and_map((char *)"Robert",COF); + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=ss*Server; + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + if (!ate(Server,sA,t1,Fr,delta,res)) cout << "Trouble" << endl; + + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + ap=powl(res,a); + + if (!ate(sS,Alice,t1,Fr,delta,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powl(res,s); + + cout << "Alice Key= " << H2(powl(sp,a)) << endl; + cout << "Server Key= " << H2(powl(ap,s)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!ate(Server,sB,t1,Fr,delta,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powl(res,b); + + if (!ate(sS,Bob,t1,Fr,delta,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powl(res,s); + + cout << "Bob's Key= " << H2(powl(sp,b)) << endl; + cout << "Server Key= " << H2(powl(bp,s)) << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/ake4mntt.c b/miracl/source/curve/pairing/ake4mntt.c new file mode 100644 index 0000000..3c0ee1f --- /dev/null +++ b/miracl/source/curve/pairing/ake4mntt.c @@ -0,0 +1,793 @@ +/* C version of ake4mntt.cpp + +Example for embedded implementation. + +Should build immediately with standard mirdef.h file on a PC. For example using MS C + +cl /O2 ake4mntt.c ms32.lib + +To simulate performance on a PC of an 8-bit computer use + +#define MR_LITTLE_ENDIAN +#define MIRACL 8 +#define mr_utype char +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype short +#define MR_STATIC 20 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 20 +#define MR_NOASM +#define MR_BITSINCHAR 8 +#define MR_NOSUPPORT_COMPRESSION + +rem Compile MIRACL modules +mex 20 c mrcomba +cl /c /O2 /W3 mrzzn2.c +cl /c /O2 /W3 mrcore.c +cl /c /O2 /W3 mrarth0.c +cl /c /O2 /W3 mrarth1.c +cl /c /O2 /W3 mrarth2.c +cl /c /O2 /W3 mrxgcd.c +cl /c /O2 /W3 mrbits.c +cl /c /O2 /W3 mrmonty.c +cl /c /O2 /W3 mrcurve.c +cl /c /O2 /W3 mrcomba.c +cl /c /O2 /W3 mrio1.c +cl /c /O2 /W3 mrpower.c + + +rem +rem Create library 'miracl.lib' +del miracl.lib + + +lib /OUT:miracl.lib mrxgcd.obj mrarth2.obj mrio1.obj mrcomba.obj +lib /OUT:miracl.lib miracl.lib mrmonty.obj mrarth1.obj mrarth0.obj mrcore.obj +lib /OUT:miracl.lib miracl.lib mrcurve.obj mrbits.obj mrzzn2.obj mrpower.obj + +del mr*.obj + +cl /O2 ake4mntt.c miracl.lib + +For Atmel AVR (atmega128) use + +#define MR_LITTLE_ENDIAN +#define MIRACL 8 +#define mr_utype char +#define MR_IBITS 16 +#define MR_LBITS 32 +#define mr_unsign32 unsigned long +#define mr_dltype int +#define mr_qltype long +#define MR_STATIC 20 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 20 +#define MR_NOASM +#define MR_BITSINCHAR 8 +#define MR_NO_STANDARD_IO +#define MR_NO_FILE_IO +#define MR_NOSUPPORT_COMPRESSION +#define MR_AVR + +This last line must be added manually - config.c will not do it automatically + +and execute + +mex 20 avr4 mrcomba + +On an ARM use a header like + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype long long +#define MR_STATIC 5 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 5 +#define MR_BITSINCHAR 8 +#define MR_NOSUPPORT_COMPRESSION + +and possible + +#define MR_NO_STANDARD_IO +#define MR_NO_FILE_IO + +and execute + +mex 5 arm mrcomba + +*/ + +#include +#include +#include "miracl.h" + +#ifdef MR_COUNT_OPS +int fpm2,fpi2,fpc,fpa,fpx; +#endif + +/* Fix the contents of k4mnt.ecs */ + +#if MIRACL==32 + +#define WORDS 5 +#define NPW 8 /* Nibbles per Word */ +#define ROMSZ 25 + +static const mr_small romp[]={ +0x76A5755D,0x245769E6,0xF33DC5F3,0x42C82027,0xE3F367D5, +0x866BA034,0x14DB64EB,0xDF4CF677,0xE45200C4,0xDABC0397, +0x58290FC5,0x0BD4BB42,0x0EAEF730,0xA014F1E3,0x6B455E0, +0xC1315D34,0x92168B16,0xF191,0x0,0x0, +0xB79C2B47,0x10BEC9C5,0xE0BF4D14,0x67B5A4AC,0xB3657D09}; + +/* Points - in n-residue form */ + +#define PROMSZ 30 + +static const mr_small Prom[]={ +0x1E6EA84F,0xE7CE6B23,0x7B6AC239,0x805022A9,0x260BF17B, +0x90898C7E,0x9D8C9BC9,0xD482E11C,0x2D4D3F68,0x1D1DA150, +0x0,0x0,0x0,0x0,0x0, +0xFC6F2323,0x4F909200,0x3CA3C030,0x162C2DE5,0x64E3CD65, +0x83EF6EA2,0x3AD75EB7,0x995AF708,0x20ED6DAA,0x6C8A7C3B, +0xE6CB7028,0x41A0F382,0x41C677A4,0x67F9C577,0x5F28122A}; + +#endif + +#if MIRACL==8 + +#define WORDS 20 +#define NPW 2 /* Nibbles per Word */ +#define ROMSZ 100 + +#ifdef MR_AVR +__attribute__((__progmem__)) +#endif +static const mr_small romp[]={ + +0x5D,0x75,0xA5,0x76,0xE6,0x69,0x57,0x24,0xF3,0xC5,0x3D,0xF3,0x27,0x20,0xC8,0x42,0xD5,0x67,0xF3,0xE3, +0x34,0xA0,0x6B,0x86,0xEB,0x64,0xDB,0x14,0x77,0xF6,0x4C,0xDF,0xC4,0x00,0x52,0xE4,0x97,0x03,0xBC,0xDA, +0xC5,0x0F,0x29,0x58,0x42,0xBB,0xD4,0x0B,0x30,0xF7,0xAE,0x0E,0xE3,0xF1,0x14,0xA0,0xE0,0x55,0xB4,0x06, +0x34,0x5D,0x31,0xC1,0x16,0x8B,0x16,0x92,0x91,0xF1,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x47,0x2B,0x9C,0xB7,0xC5,0xC9,0xBE,0x10,0x14,0x4D,0xBF,0xE0,0xAC,0xA4,0xB5,0x67,0x09,0x7D,0x65,0xB3}; + +#define PROMSZ 120 + +#ifdef MR_AVR +__attribute__((__progmem__)) +#endif +static const mr_small Prom[]={ + +0x4F,0xA8,0x6E,0x1E,0x23,0x6B,0xCE,0xE7,0x39,0xC2,0x6A,0x7B,0xA9,0x22,0x50,0x80,0x7B,0xF1,0xB,0x26, +0x7E,0x8C,0x89,0x90,0xC9,0x9B,0x8C,0x9D,0x1C,0xE1,0x82,0xD4,0x68,0x3F,0x4D,0x2D,0x50,0xA1,0x1D,0x1D, +0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x23,0x23,0x6F,0xFC,0x0,0x92,0x90,0x4F,0x30,0xC0,0xA3,0x3C,0xE5,0x2D,0x2C,0x16,0x65,0xCD,0xE3,0x64, +0xA2,0x6E,0xEF,0x83,0xB7,0x5E,0xD7,0x3A,0x8,0xF7,0x5A,0x99,0xAA,0x6D,0xED,0x20,0x3B,0x7C,0x8A,0x6C, +0x28,0x70,0xCB,0xE6,0x82,0xF3,0xA0,0x41,0xA4,0x77,0xC6,0x41,0x77,0xC5,0xF9,0x67,0x2A,0x12,0x28,0x5F}; + +#endif + +#define CF 34 + +/* Fp4 support functions */ + +typedef struct +{ + zzn2 x; + zzn2 y; + BOOL unitary; +} zzn4; + +#ifndef MR_NO_STANDARD_IO +void zzn2_out(_MIPD_ char *p,zzn2 *x) +{ + printf(p); printf("\n"); + redc(_MIPP_ x->a,x->a); + redc(_MIPP_ x->b,x->b); + otnum(_MIPP_ x->a,stdout); + otnum(_MIPP_ x->b,stdout); + nres(_MIPP_ x->a,x->a); + nres(_MIPP_ x->b,x->b); +} +#endif + +/* Irreducible over zzn2 is x^2+n */ +/* zzn4 is towered on top of this with irreducible X^2+sqrt(n) p=5 mod 8, or X^2+(1+sqrt(n)) p=3,7 mod 8 */ +/* same as txx(.) function in C++ */ + +void zzn2_times_irp(_MIPD_ zzn2 *u) +{ + zzn2 t; + + switch (mr_mip->pmod8) + { + case 5: /* times sqrt(n) */ + zzn2_timesi(_MIPP_ u); + break; + case 3: /* times 1+sqrt(n) */ + case 7: + t.a=mr_mip->w5; + t.b=mr_mip->w6; + zzn2_copy(u,&t); + zzn2_timesi(_MIPP_ &t); + zzn2_add(_MIPP_ u,&t,u); + break; + default: + break; + } +} + +void zzn4_copy(zzn4 *u,zzn4 *w) +{ + if (u==w) return; + zzn2_copy(&(u->x),&(w->x)); + zzn2_copy(&(u->y),&(w->y)); + w->unitary=u->unitary; +} + +void zzn4_from_int(_MIPD_ int i,zzn4 *w) +{ + zzn2_from_int(_MIPP_ i,&(w->x)); + zzn2_zero(&(w->y)); + if (i==1) w->unitary=TRUE; + else w->unitary=FALSE; + +} + +void zzn4_conj(_MIPD_ zzn4 *u,zzn4 *w) +{ + zzn4_copy(u,w); + zzn2_negate(_MIPP_ &(w->y),&(w->y)); +} + +void zzn4_mul(_MIPD_ zzn4 *u,zzn4 *v,zzn4 *w) +{ + zzn2 t1,t2,t3; + t1.a=mr_mip->w3; + t1.b=mr_mip->w4; + t2.a=mr_mip->w8; + t2.b=mr_mip->w9; + if (u==v) + { + if (u->unitary) + { /* this is a lot faster.. - see Lenstra & Stam */ + zzn4_copy(u,w); + zzn2_mul(_MIPP_ &(w->y),&(w->y),&t1); + zzn2_add(_MIPP_ &(w->y),&(w->x),&(w->y)); + zzn2_mul(_MIPP_ &(w->y),&(w->y),&(w->y)); + zzn2_sub(_MIPP_ &(w->y),&t1,&(w->y)); + zzn2_timesi(_MIPP_ &t1); + zzn2_copy(&t1,&(w->x)); + zzn2_sub(_MIPP_ &(w->y),&(w->x),&(w->y)); + zzn2_add(_MIPP_ &(w->x),&(w->x),&(w->x)); + zzn2_sadd(_MIPP_ &(w->x),mr_mip->one,&(w->x)); + zzn2_ssub(_MIPP_ &(w->y),mr_mip->one,&(w->y)); + } + else + { + zzn4_copy(u,w); + zzn2_copy(&(w->y),&t2); // t2=b; + zzn2_add(_MIPP_ &(w->x),&t2,&t1); // t1=a+b + zzn2_times_irp(_MIPP_ &t2); // t2=txx(b); + zzn2_add(_MIPP_ &t2,&(w->x),&t2); // t2=a+txx(b) + zzn2_mul(_MIPP_ &(w->y),&(w->x),&(w->y)); // b*=a + zzn2_mul(_MIPP_ &t1,&t2,&(w->x)); // a=t1*t2 + zzn2_copy(&(w->y),&t2); //t2=b + zzn2_sub(_MIPP_ &(w->x),&t2,&(w->x)); //a-=b + zzn2_times_irp(_MIPP_ &t2); // t2=txx(b) + zzn2_sub(_MIPP_ &(w->x),&t2,&(w->x)); // a-=txx(b); + zzn2_add(_MIPP_ &(w->y),&(w->y),&(w->y)); // b+=b; + } + } + else + { + t3.a=mr_mip->w10; + t3.b=mr_mip->w11; + zzn2_copy(&(u->x),&t1); + zzn2_copy(&(u->y),&t2); + zzn2_mul(_MIPP_ &t1,&(v->x),&t1); + zzn2_mul(_MIPP_ &t2,&(v->y),&t2); + zzn2_copy(&(v->x),&t3); + zzn2_add(_MIPP_ &t3,&(v->y),&t3); + + zzn2_add(_MIPP_ &(u->y),&(u->x),&(w->y)); + zzn2_mul(_MIPP_ &(w->y),&t3,&(w->y)); + zzn2_sub(_MIPP_ &(w->y),&t1,&(w->y)); + zzn2_sub(_MIPP_ &(w->y),&t2,&(w->y)); + zzn2_copy(&t1,&(w->x)); + zzn2_times_irp(_MIPP_ &t2); + zzn2_add(_MIPP_ &(w->x),&t2,&(w->x)); + if (u->unitary && v->unitary) w->unitary=TRUE; + else w->unitary=FALSE; + } +} + +/* zzn4 powering of unitary elements */ + +void zzn4_powu(_MIPD_ zzn4 *x,big k,zzn4 *u) +{ + zzn4 t[5],u2; + big k3; + int i,j,n,nb,nbw,nzs; +#ifndef MR_STATIC + char *mem=memalloc(_MIPP_ 25); +#else + char mem[MR_BIG_RESERVE(25)]; + memset(mem,0,MR_BIG_RESERVE(25)); +#endif + + if (size(k)==0) + { + zzn4_from_int(_MIPP_ 1,u); + return; + } + zzn4_copy(x,u); + if (size(k)==1) return; + + for (j=i=0;i<5;i++) + { + t[i].x.a=mirvar_mem(_MIPP_ mem,j++); + t[i].x.b=mirvar_mem(_MIPP_ mem,j++); + t[i].y.a=mirvar_mem(_MIPP_ mem,j++); + t[i].y.b=mirvar_mem(_MIPP_ mem,j++); + t[i].unitary=FALSE; + } + u2.x.a=mirvar_mem(_MIPP_ mem,j++); + u2.x.b=mirvar_mem(_MIPP_ mem,j++); + u2.y.a=mirvar_mem(_MIPP_ mem,j++); + u2.y.b=mirvar_mem(_MIPP_ mem,j++); + u2.unitary=FALSE; + k3=mirvar_mem(_MIPP_ mem,j); + + premult(_MIPP_ k,3,k3); + zzn4_mul(_MIPP_ u,u,&u2); + zzn4_copy(u,&t[0]); + + for (i=1;i<=4;i++) + zzn4_mul(_MIPP_ &u2,&t[i-1],&t[i]); + + nb=logb2(_MIPP_ k3); + + for (i=nb-2;i>=1;) + { + n=mr_naf_window(_MIPP_ k,k3,i,&nbw,&nzs,5); + + for (j=0;j0) zzn4_mul(_MIPP_ u,&t[n/2],u); + if (n<0) + { + zzn4_conj(_MIPP_ &t[-n/2],&u2); + zzn4_mul(_MIPP_ u,&u2,u); + } + i-=nbw; + if (nzs) + { + for (j=0;jw7; + t1.b=mr_mip->w8; + t3.a=mr_mip->w10; + t3.b=mr_mip->w11; + t4.a=mr_mip->w13; + t4.b=mr_mip->w14; + + zzn2_from_int(_MIPP_ 1,&t1); + + s=size(e); + if (s==0) + { + zzn2_copy(&t1,w); + return; + } + zzn2_copy(x,w); + if (s==1 || s==(-1)) return; + + i=logb2(_MIPP_ e)-1; + + zzn2_copy(w,&t3); + zzn2_mul(_MIPP_ w,w,&t4); + zzn2_add(_MIPP_ &t4,&t4,&t4); + zzn2_sub(_MIPP_ &t4,&t1,&t4); + + while (i--) + { + if (mr_testbit(_MIPP_ e,i)) + { + zzn2_mul(_MIPP_ &t3,&t4,&t3); + zzn2_add(_MIPP_ &t3,&t3,&t3); + zzn2_sub(_MIPP_ &t3,w,&t3); + zzn2_mul(_MIPP_ &t4,&t4,&t4); + zzn2_add(_MIPP_ &t4,&t4,&t4); + zzn2_sub(_MIPP_ &t4,&t1,&t4); + } + else + { + zzn2_mul(_MIPP_ &t4,&t3,&t4); + zzn2_add(_MIPP_ &t4,&t4,&t4); + zzn2_sub(_MIPP_ &t4,w,&t4); + zzn2_mul(_MIPP_ &t3,&t3,&t3); + zzn2_add(_MIPP_ &t3,&t3,&t3); + zzn2_sub(_MIPP_ &t3,&t1,&t3); + } + + } + zzn2_copy(&t3,w); +} + +void zzn4_powq(_MIPD_ big fr,zzn4 *w) +{ + zzn2_conj(_MIPP_ &(w->x),&(w->x)); + zzn2_conj(_MIPP_ &(w->y),&(w->y)); + nres(_MIPP_ fr,mr_mip->w1); + zzn2_smul(_MIPP_ &(w->y),mr_mip->w1,&(w->y)); +} + +void zzn4_inv(_MIPD_ zzn4 *u) +{ + zzn2 t1,t2; + if (u->unitary) + { + zzn4_conj(_MIPP_ u,u); + return; + } + t1.a=mr_mip->w8; + t1.b=mr_mip->w9; + t2.a=mr_mip->w3; + t2.b=mr_mip->w4; + zzn2_mul(_MIPP_ &(u->x),&(u->x),&t1); + zzn2_mul(_MIPP_ &(u->y),&(u->y),&t2); + zzn2_times_irp(_MIPP_ &t2); + zzn2_sub(_MIPP_ &t1,&t2,&t1); + zzn2_inv(_MIPP_ &t1); + zzn2_mul(_MIPP_ &(u->x),&t1,&(u->x)); + zzn2_negate(_MIPP_ &t1,&t1); + zzn2_mul(_MIPP_ &(u->y),&t1,&(u->y)); +} + +void g(_MIPD_ epoint *A,epoint *B,zzn2 *Qx,zzn2 *Qy,zzn4 *w) +{ + int type; + big slope; + zzn2 nn,dd; + + copy(A->X,mr_mip->w10); + + type=ecurve_add(_MIPP_ B,A); + if (!type) + { + zzn4_from_int(_MIPP_ 1,w); + return; + } + slope=mr_mip->w8; /* slope in w8 */ + + nn.a=mr_mip->w13; + nn.b=mr_mip->w14; + + dd.a=mr_mip->w5; + dd.b=mr_mip->w11; + + zzn2_copy(Qx,&nn); + zzn2_copy(Qy,&dd); + zzn2_negate(_MIPP_ &dd,&dd); + + if (A->marker!=MR_EPOINT_GENERAL) + copy(mr_mip->one,mr_mip->w12); + else copy(A->Z,mr_mip->w12); + + if (type==MR_ADD) + { + zzn2_ssub(_MIPP_ &nn,B->X,&nn); + zzn2_smul(_MIPP_ &nn,slope,&nn); + nres_modmult(_MIPP_ mr_mip->w12,B->Y,mr_mip->w2); + zzn2_sadd(_MIPP_ &nn,mr_mip->w2,&nn); + zzn2_smul(_MIPP_ &dd,mr_mip->w12,&dd); + zzn2_copy(&nn,&(w->x)); + zzn2_copy(&dd,&(w->y)); + return; + } + + if (type==MR_DOUBLE) + { /* note that ecurve_add has left useful things for us in w6 and w7! */ + nres_modmult(_MIPP_ slope,mr_mip->w6,mr_mip->w2); + zzn2_smul(_MIPP_ &nn,mr_mip->w2,&nn); + nres_modmult(_MIPP_ slope,mr_mip->w10,slope); + zzn2_ssub(_MIPP_ &nn,slope,&nn); + zzn2_sadd(_MIPP_ &nn,mr_mip->w7,&nn); + nres_modmult(_MIPP_ mr_mip->w12,mr_mip->w6,mr_mip->w12); + zzn2_smul(_MIPP_ &dd,mr_mip->w12,&dd); + zzn2_copy(&nn,&(w->x)); + zzn2_copy(&dd,&(w->y)); + return; + } +} + +void fast_tate_pairing(_MIPD_ epoint *P,zzn2 *Qx,zzn2 *Qy,big q,big fr,big delta,zzn4 *w,zzn4* res) +{ + int i,j,n,nb,nbw,nzs; + epoint *t[4],*A,*P2; + zzn4 zn[4]; + big work[4]; + +#ifndef MR_STATIC + char *mem=memalloc(_MIPP_ 20); + char *mem1=ecp_memalloc(_MIPP_ 6); +#else + char mem[MR_BIG_RESERVE(20)]; + char mem1[MR_ECP_RESERVE(6)]; + memset(mem,0,MR_BIG_RESERVE(20)); + memset(mem1,0,MR_ECP_RESERVE(6)); +#endif + +#ifdef MR_COUNT_OPS +fpa=fpc=fpx=0; +#endif + + for (i=0;i<4;i++) + t[i]=epoint_init_mem(_MIPP_ mem1,i); + A=epoint_init_mem(_MIPP_ mem1,4); + P2=epoint_init_mem(_MIPP_ mem1,5); + + for (j=i=0;i<4;i++) + { + work[i]=mirvar_mem(_MIPP_ mem,j++); + zn[i].x.a=mirvar_mem(_MIPP_ mem,j++); + zn[i].x.b=mirvar_mem(_MIPP_ mem,j++); + zn[i].y.a=mirvar_mem(_MIPP_ mem,j++); + zn[i].y.b=mirvar_mem(_MIPP_ mem,j++); + zn[i].unitary=FALSE; + } + + zzn4_from_int(_MIPP_ 1,&zn[0]); + epoint_copy(P,A); + epoint_copy(P,P2); + epoint_copy(P,t[0]); + + g(_MIPP_ P2,P2,Qx,Qy,res); + + epoint_norm(_MIPP_ P2); + + for (i=1;i<4;i++) + { + g(_MIPP_ A,P2,Qx,Qy,w); + epoint_copy(A,t[i]); + zzn4_mul(_MIPP_ &zn[i-1],w,&zn[i]); + zzn4_mul(_MIPP_ &zn[i],res,&zn[i]); + } + + epoint_multi_norm(_MIPP_ 4,work,t); + + epoint_copy(P,A); + zzn4_from_int(_MIPP_ 1,res); + + nb=logb2(_MIPP_ q); + for (i=nb-2;i>=0;i-=(nbw+nzs)) + { + n=mr_window(_MIPP_ q,i,&nbw,&nzs,3); + for (j=0;j0) + { + zzn4_mul(_MIPP_ res,&zn[n/2],res); + g(_MIPP_ A,t[n/2],Qx,Qy,w); + zzn4_mul(_MIPP_ res,w,res); + } + for (j=0;junitary=TRUE; + + zzn4_mul(_MIPP_ res,res,res); + zzn4_copy(res,w); + zzn4_mul(_MIPP_ res,res,res); + zzn4_mul(_MIPP_ res,res,res); + zzn4_mul(_MIPP_ res,res,res); + zzn4_mul(_MIPP_ res,res,res); + zzn4_mul(_MIPP_ res,w,res); /* res=powu(res,CF) */ + +#ifndef MR_STATIC + memkill(_MIPP_ mem,20); + ecp_memkill(_MIPP_ mem1,6); +#else + memset(mem,0,MR_BIG_RESERVE(20)); + memset(mem1,0,MR_ECP_RESERVE(6)); +#endif +} + +void ecap(_MIPD_ epoint *P,zzn2 *Qx,zzn2 *Qy,big q,big fr,big delta,zzn2* r) +{ + zzn4 res,w; +#ifndef MR_STATIC + char *mem=memalloc(_MIPP_ 8); +#else + char mem[MR_BIG_RESERVE(8)]; + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + res.x.a=mirvar_mem(_MIPP_ mem,0); + res.x.b=mirvar_mem(_MIPP_ mem,1); + res.y.a=mirvar_mem(_MIPP_ mem,2); + res.y.b=mirvar_mem(_MIPP_ mem,3); + w.x.a=mirvar_mem(_MIPP_ mem,4); + w.x.b=mirvar_mem(_MIPP_ mem,5); + w.y.a=mirvar_mem(_MIPP_ mem,6); + w.y.b=mirvar_mem(_MIPP_ mem,7); + + res.unitary=FALSE; + w.unitary=FALSE; + + epoint_norm(_MIPP_ P); + + fast_tate_pairing(_MIPP_ P,Qx,Qy,q,fr,delta,&w,&res); + + zzn4_copy(&res,&w); + zzn4_powq(_MIPP_ fr,&res); + + zzn4_powu(_MIPP_ &w,delta,&w); + zzn4_mul(_MIPP_ &res,&w,&res); + + zzn2_copy(&(res.x),r); + +#ifdef MR_COUNT_OPS +printf("Final Exponentiation cost\n"); +printf("fpc= %d\n",fpc); +printf("fpa= %d\n",fpa); +printf("fpx= %d\n",fpx); + +fpa=fpc=fpx=0; + +#endif +#ifndef MR_STATIC + memkill(_MIPP_ mem,8); +#else + memset(mem,0,MR_BIG_RESERVE(8)); +#endif +} + +int main() +{ +#ifdef MR_GENERIC_MT + miracl instance; +#endif + big p,A,B,fr,q,delta,t,T; + zzn2 res,Qx,Qy; + epoint *P; + int i,romptr; +#ifndef MR_STATIC +#ifdef MR_GENERIC_MT + miracl *mr_mip=mirsys(&instance,WORDS*NPW,16); +#else + miracl *mr_mip=mirsys(WORDS*NPW,16); +#endif + char *mem=memalloc(_MIPP_ 14); + char *mem1=ecp_memalloc(_MIPP_ 1); +#else +#ifdef MR_GENERIC_MT + miracl *mr_mip=mirsys(&instance,MR_STATIC*NPW,16); +#else + miracl *mr_mip=mirsys(MR_STATIC*NPW,16); +#endif + char mem[MR_BIG_RESERVE(14)]; /* reserve space on the stack for 14 bigs */ + char mem1[MR_ECP_RESERVE(1)]; /* reserve space on stack for 1 curve points */ + memset(mem,0,MR_BIG_RESERVE(14)); /* clear this memory */ + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + p=mirvar_mem(_MIPP_ mem,0); + A=mirvar_mem(_MIPP_ mem,1); + B=mirvar_mem(_MIPP_ mem,2); + T=mirvar_mem(_MIPP_ mem,3); + q=mirvar_mem(_MIPP_ mem,4); + fr=mirvar_mem(_MIPP_ mem,5); + delta=mirvar_mem(_MIPP_ mem,6); + res.a=mirvar_mem(_MIPP_ mem,7); + res.b=mirvar_mem(_MIPP_ mem,8); + t=mirvar_mem(_MIPP_ mem,9); + Qx.a=mirvar_mem(_MIPP_ mem,10); + Qx.b=mirvar_mem(_MIPP_ mem,11); + Qy.a=mirvar_mem(_MIPP_ mem,12); + Qy.b=mirvar_mem(_MIPP_ mem,13); + + P=epoint_init_mem(_MIPP_ mem1,0); + convert(_MIPP_ -3,A); + + romptr=0; + init_big_from_rom(p,WORDS,romp,ROMSZ,&romptr); + init_big_from_rom(B,WORDS,romp,ROMSZ,&romptr); + init_big_from_rom(q,WORDS,romp,ROMSZ,&romptr); + init_big_from_rom(delta,WORDS,romp,ROMSZ,&romptr); + init_big_from_rom(fr,WORDS,romp,ROMSZ,&romptr); + +#ifndef MR_NO_STANDARD_IO +printf("ROM size= %d\n",sizeof(romp)+sizeof(Prom)); +printf("sizeof(miracl)= %d\n",sizeof(miracl)); +#endif + + ecurve_init(_MIPP_ A,B,p,MR_PROJECTIVE); + + romptr=0; + init_point_from_rom(P,WORDS,Prom,PROMSZ,&romptr); + init_big_from_rom(Qx.a,WORDS,Prom,PROMSZ,&romptr); + init_big_from_rom(Qx.b,WORDS,Prom,PROMSZ,&romptr); + init_big_from_rom(Qy.a,WORDS,Prom,PROMSZ,&romptr); + init_big_from_rom(Qy.b,WORDS,Prom,PROMSZ,&romptr); + +#ifdef MR_COUNT_OPS +fpa=fpc=fpx=0; +#endif + + ecap(_MIPP_ P,&Qx,&Qy,q,fr,delta,&res); + + bigbits(_MIPP_ 160,t); + zzn2_powl(_MIPP_ &res,t,&res); + +#ifndef MR_NO_STANDARD_IO + zzn2_out(_MIPP_ "res= ",&res); +#endif + + ecurve_mult(_MIPP_ t,P,P); + ecap(_MIPP_ P,&Qx,&Qy,q,fr,delta,&res); + +#ifndef MR_NO_STANDARD_IO + zzn2_out(_MIPP_ "res= ",&res); +#endif + +#ifndef MR_STATIC + memkill(_MIPP_ mem,14); + ecp_memkill(_MIPP_ mem1,1); +#else + memset(mem,0,MR_BIG_RESERVE(14)); /* clear this stack memory */ + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + return 0; +} + + diff --git a/miracl/source/curve/pairing/ake4mntt.cpp b/miracl/source/curve/pairing/ake4mntt.cpp new file mode 100644 index 0000000..6e292b9 --- /dev/null +++ b/miracl/source/curve/pairing/ake4mntt.cpp @@ -0,0 +1,463 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=16 ake4mntt.cpp zzn4.cpp zzn2.cpp ecn2.cpp big.cpp zzn.cpp + ecn.cpp miracl.lib + Fastest using COMBA build for 160-bit mod-mul + + The file k4mnt.ecs is required + Security is G155/F640 (155-bit group, 640-bit field) + + Modified to prevent sub-group confinement attack + +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn2.h" +#include "zzn4.h" + +using namespace std; + +Miracl precision(5,0); + +// Using SHA-1 as basic hash algorithm + +#define HASH_LEN 20 +#define COF 34 + +#ifdef MR_COUNT_OPS +extern "C" +{ + int fpc,fpa,fpx; +} +#endif + +// +// Define one or the other of these +// +// Which is faster depends on the I/M ratio - See imratio.c +// Roughly if I/M ratio > 16 use PROJECTIVE, otherwise use AFFINE +// + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +#ifdef PROJECTIVE +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} +#endif + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn4 line(ECn& A,ECn& C,ECn& B,int type,ZZn& slope,ZZn& ex1,ZZn& ex2,ZZn2& Qx,ZZn2& Qy) +{ + ZZn4 w; +#ifdef AFFINE + ZZn2 m=Qx; + ZZn x,y + extract(A,x,y); + m-=x; m*=slope; + w.set((ZZn2)-y,Qy); w-=m; +#endif +#ifdef PROJECTIVE + if (type==MR_ADD) + { + ZZn x2,y2,x3,z3; + extract(B,x2,y2); + extract(C,x3,x3,z3); + w.set(slope*(Qx-x2)+z3*y2,-z3*Qy); + } + if (type==MR_DOUBLE) + { + ZZn x,y,x3,z3; + extract(A,x,y); + extract(C,x3,x3,z3); + w.set((slope*ex2)*Qx-slope*x+ex1,-(z3*ex2)*Qy); + } +#endif + + return w; +} + +// +// Add A=A+B (or A=A+A) +// Bump up num +// + +ZZn4 g(ECn& A,ECn& B,ZZn2& Qx,ZZn2& Qy) +{ + int type; + ZZn lam,extra1,extra2; + big ptr,ex1,ex2; + ECn P=A; + +// Evaluate line from A + type=A.add(B,&ptr,&ex1,&ex2); + if (!type) return (ZZn4)1; + lam=ptr; + extra1=ex1; + extra2=ex2; + return line(P,A,B,type,lam,extra1,extra2,Qx,Qy); +} + +// +// Tate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order m.q. +// Note that P is a point on the curve over Fp, Q(x,y) a point on the +// extension field Fp^2 +// + +BOOL tate(ECn& P,ECn2 Q,Big& q,ZZn2 &Fr,Big cof,ZZn2& r) +{ + int i,j,n,nb,nbw,nzs; + ECn A,P2,t[8]; + ZZn4 w,hc,z2n,zn[8],res; + ZZn2 Qx,Qy; + +#ifdef MR_COUNT_OPS +fpc=fpa=fpx=0; +#endif + + Q.get(Qx,Qy); + Qx=txd(Qx); + Qy=txd(txd(Qy)); + + normalise(P); + + res=zn[0]=1; + t[0]=P2=A=P; + z2n=g(P2,P2,Qx,Qy); // P2=P+P + + normalise(P2); + + + +// +// Build windowing table +// + for (i=1;i<8;i++) + { + hc=g(A,P2,Qx,Qy); + t[i]=A; + zn[i]=z2n*zn[i-1]*hc; + } + multi_norm(8,t); // make t points Affine + + A=P; + nb=bits(q); + for (i=nb-2;i>=0;i-=(nbw+nzs)) + { + n=window(q,i,&nbw,&nzs,4); // standard MIRACL windowing + for (j=0;j0) + { + res*=zn[n/2]; + res*=g(A,t[n/2],Qx,Qy); + } + + for (j=0;j=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn2 x) +{ // Hash an Fp2 to a big number + sha sh; + Big a,u,v; + char s[HASH_LEN]; + int m; + + shs_init(&sh); + x.get(u,v); + + a=u; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + a=v; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + shs_hash(&sh,s); + a=from_binary(HASH_LEN,s); + return a; +} + +// Hash and map a Server Identity to a curve point E(Fp2) + +ECn2 hash2(char *ID) +{ + ECn2 T; + ZZn2 x; + Big x0,y0=0; + + x0=H1(ID); + do + { + x.set(x0,y0); + x0+=1; + } + while (!is_on_curve(x)); + T.set(x); + +// cout << "T= " << T << endl; + + return T; +} + +// Hash and map a Client Identity to a curve point E(Fp) + +ECn hash_and_map(char *ID,Big cof) +{ + ECn Q; + Big x0=H1(ID); + + while (!is_on_curve(x0)) x0+=1; + Q.set(x0); // Make sure its on E(F_p) + + Q*=cof; + return Q; +} + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + X.set((Big)0,(Big)1); // = (sqrt(-2)^(p-1)/2 + break; + case 3: // = (1+sqrt(-1))^(p-1)/2 + X.set((Big)1,(Big)1); + break; + case 7: + X.set((Big)2,(Big)1); // = (2+sqrt(-1))^(p-1)/2 + default: break; + } + X=pow(X,(p-1)/2); +} + +int main() +{ + ifstream common("k4mnt.ecs"); // elliptic curve parameters + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn2 Server,sS; + ZZn2 res,sp,ap,bp,Fr; + Big a,b,s,ss,p,q,r,B,delta,fr; + + int bits,A; + time_t seed; + + cout << "Started" << endl; + common >> bits; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B; + common >> q >> delta; + common >> fr; + + cout << "Initialised... " << endl; + + time(&seed); + irand((long)seed); + +#ifdef AFFINE + ecurve(A,B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(A,B,p,MR_PROJECTIVE); +#endif + + // set_frobenius_constant(Fr); + + Fr=(ZZn2)fr; + mip->IOBASE=16; + mip->TWIST=MR_QUADRATIC; // map Server to point on twisted curve E(Fp2) + + //cout << "p= " << p << endl; + //cout << "delta*delta+delta+1= " << delta*delta-delta+1 << endl; + +// hash Identities to curve point + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + Server=hash2((char *)"Server"); + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice",COF); +//cout << "Server= " << Server << endl; +//cout << "Alice= " << Alice << endl; + Bob= hash_and_map((char *)"Robert",COF); + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=ss*Server; + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + if (!tate(sA,Server,q,Fr,delta,res)) cout << "Trouble" << endl; + + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + ap=powl(res,a); + + if (!tate(Alice,sS,q,Fr,delta,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powl(res,s); + + cout << "Alice Key= " << H2(powl(sp,a)) << endl; + cout << "Server Key= " << H2(powl(ap,s)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!tate(sB,Server,q,Fr,delta,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powl(res,b); + + if (!tate(Bob,sS,q,Fr,delta,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powl(res,s); + + cout << "Bob's Key= " << H2(powl(sp,b)) << endl; + cout << "Server Key= " << H2(powl(bp,s)) << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/ake4sbt.cpp b/miracl/source/curve/pairing/ake4sbt.cpp new file mode 100644 index 0000000..2c7e8a5 --- /dev/null +++ b/miracl/source/curve/pairing/ake4sbt.cpp @@ -0,0 +1,450 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=8 ake4sbt.cpp zzn4.cpp zzn2.cpp ecn2.cpp big.cpp zzn.cpp + ecn.cpp miracl.lib + Fastest using COMBA build for 256-bit mod-mul + + Scott-Barreto Curve - Tate pairing + + The file kw4.ecs is required + Security is G160/F1024 (160-bit group, 1024-bit field) + + Modified to prevent sub-group confinement attack + + NOTE: assumes p = 3 mod 8, p is 256-bits + + **** NEW **** Based on the observation by R. Granger and D. Page and N.P. Smart in "High Security + Pairing-Based Cryptography Revisited" that multi-exponentiation can be used for the final exponentiation + of the Tate pairing, we suggest the Power Pairing, which calculates E(P,Q,e) = e(P,Q)^e, where the + exponentiation by e is basically for free, as it can be folded into the multi-exponentiation. + +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn2.h" +#include "zzn4.h" + +using namespace std; + +Miracl precision(12,0); + +// Using SHA-1 as basic hash algorithm + +#define HASH_LEN 20 + +// +// Define one or the other of these +// +// Which is faster depends on the I/M ratio - See imratio.c +// Roughly if I/M ratio > 16 use PROJECTIVE, otherwise use AFFINE +// + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +#ifdef PROJECTIVE +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} +#endif + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn4 line(ECn& A,ECn& C,ZZn& slope,ZZn2& Qx,ZZn2& Qy) +{ + ZZn4 w; + ZZn2 m=Qx; + ZZn x,y,z,t; +#ifdef AFFINE + extract(A,x,y); + m-=x; m*=slope; + w.set((ZZn2)-y,Qy); w-=m; +#endif +#ifdef PROJECTIVE + extract(A,x,y,z); + x*=z; t=z; z*=z; z*=t; + x*=slope; t=slope*z; + m*=t; m-=x; t=z; + extract(C,x,x,z); + m+=(z*y); t*=z; + + w.set(m,-Qy*t); + +#endif + return w; +} + +// +// Add A=A+B (or A=A+A) +// Bump up num +// + +ZZn4 g(ECn& A,ECn& B,ZZn2& Qx,ZZn2& Qy) +{ + int type; + ZZn lam; + big ptr; + ECn P=A; + +// Evaluate line from A + type=A.add(B,&ptr); + if (!type) return (ZZn4)1; + lam=ptr; + return line(P,A,lam,Qx,Qy); +} + +// +// Tate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order m.q. +// Note that P is a point on the curve over Fp, Q(x,y) a point on the +// extension field Fp^2 +// +// New! Power Pairing calculates E(P,Q,e) = e(P,Q)^e at no extra cost! +// + +BOOL power_tate(ECn& P,ECn2 Q,Big& q,Big *cf,ZZn2 &Fr,Big &e,ZZn2& r) +{ + int i,nb; + ECn A; + ZZn4 w,res,a[2]; + ZZn2 Qx,Qy; + Big carry,ex[2],p=get_modulus(); +// ZZn4 Y,X; + + Q.get(Qx,Qy); +// Qx=-tx(Qx)/2; // convert from twist to (x,0),(0,y) +// Qy/=2; + + Qx=txd(Qx); + Qy=txd(txd(Qy)); + +// cout << "Qx= " << Qx << endl; +// cout << "Qy= " << Qy << endl; + +// X.set(Qx,(ZZn2)0); +// Y.set((ZZn2)0,Qy); + +// cout << "Y^2= " << Y*Y << endl; +// cout << "X^3+AX+B= " << X*X*X+getA()*X+getB() << endl; + + res=1; + +/* Left to right method */ + A=P; + nb=bits(q); + for (i=nb-2;i>=0;i--) + { + res*=res; + res*=g(A,A,Qx,Qy); + if (bit(q,i)) + res*=g(A,P,Qx,Qy); + } + + if (!A.iszero() || res.iszero()) return FALSE; + w=res; + w.powq(Fr); w.powq(Fr); // ^(p^2-1) + res=w/res; + + res.mark_as_unitary(); + + if (e.isone()) + { + ex[0]=cf[0]; + ex[1]=cf[1]; + } + else + { // cf *= e + carry=mad(cf[1],e,(Big)0,p,ex[1]); + mad(cf[0],e,carry,p,ex[0]); + } + + a[0]=a[1]=res; + a[0].powq(Fr); + res=pow(2,a,ex); + + r=real(res); // compression + + if (r.isunity()) return FALSE; + return TRUE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha sh; + + shs_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs_process(&sh,string[i]); + } + shs_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn2 x) +{ // Hash an Fp2 to a big number + sha sh; + Big a,u,v; + char s[HASH_LEN]; + int m; + + shs_init(&sh); + x.get(u,v); + + a=u; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + a=v; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + shs_hash(&sh,s); + a=from_binary(HASH_LEN,s); + return a; +} + +// Hash and map a Server Identity to a curve point E(Fp2) + +ECn2 hash2(char *ID) +{ + ECn2 T; + ZZn2 x; + Big x0,y0=0; + + x0=H1(ID); + do + { + x.set(x0,y0); + x0+=1; + } + while (!is_on_curve(x)); + T.set(x); + +// cout << "T= " << T << endl; + + return T; +} + +// Hash and map a Client Identity to a curve point E(Fp) + +ECn hash_and_map(char *ID,Big cof) +{ + ECn Q; + Big x0=H1(ID); + + while (!is_on_curve(x0)) x0+=1; + Q.set(x0); // Make sure its on E(F_p) + + Q*=cof; + return Q; +} + +ZZn2 get_frobenius_constant() +{ + ZZn2 Fr; + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + Fr.set((Big)0,(Big)1); // = (sqrt(-2)^(p-1)/2 + break; + case 3: // = (1+sqrt(-1))^(p-1)/2 + case 7: // = (1+sqrt(-2))^(p-1)/2 + Fr.set((Big)1,(Big)1); + default: break; + } + return pow(Fr,(p-1)/2); +} + +#define COF 58 + +int main() +{ + ifstream common("kw4.ecs"); // elliptic curve parameters + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn2 Server,sS; + ZZn2 res,sp,ap,bp,wa,wb,w1,w2; + ZZn ww; + ZZn4 w; + ZZn2 Fr; + Big a,b,s,ss,p,q,r,B,cof,t,qcof; + Big cf[2]; + // this is read-only + // and never copied. + int i,bitz,A; + time_t seed; + + cout << "Started" << endl; + common >> bitz; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B; + common >> cof; // #E/q + common >> q; // low hamming weight q + common >> cf[0]; // [(p^2+1)/q]/p + common >> cf[1]; // [(p^2+1)/q]%p + + cout << "Initialised... " << p%8 << endl; + cout << "cf= " << cf[0]*p+cf[1] << endl; + +// +// Note: COF*q has a low hamming weight for this particular curve - so use this instead.. +// + + qcof=q*COF; + + time(&seed); + irand((long)seed); + +#ifdef AFFINE + ecurve(A,B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(A,B,p,MR_PROJECTIVE); +#endif + + Fr=get_frobenius_constant(); + +// cout << "qnr= " << get_mip()->qnr << endl; + + mip->IOBASE=16; + mip->TWIST=MR_QUADRATIC; // map Server to point on twisted curve E(Fp2) + +// hash Identities to curve point + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + Server=hash2((char *)"Server"); + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice",cof); + + Bob= hash_and_map((char *)"Robert",cof); + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=ss*Server; + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + if (!power_tate(sA,Server,qcof,cf,Fr,a,res)) cout << "Trouble" << endl; + + if (powl(res,q)!=(ZZn2)1) + { + cout << "res= " << res << endl; + cout << "Wrong group order - aborting" << endl; + exit(0); + } +// ap=powl(res,a); + ap=res; + + if (!power_tate(Alice,sS,qcof,cf,Fr,s,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } +// sp=powl(res,s); + sp=res; + + cout << "Alice Key= " << H2(powl(sp,a)) << endl; + cout << "Server Key= " << H2(powl(ap,s)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!power_tate(sB,Server,qcof,cf,Fr,b,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } +// bp=powl(res,b); + bp=res; + + if (!power_tate(Bob,sS,qcof,cf,Fr,s,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn2)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } +// sp=powl(res,s); + sp=res; + + cout << "Bob's Key= " << H2(powl(sp,b)) << endl; + cout << "Server Key= " << H2(powl(bp,s)) << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/ake6fsta.cpp b/miracl/source/curve/pairing/ake6fsta.cpp new file mode 100644 index 0000000..a5f87ca --- /dev/null +++ b/miracl/source/curve/pairing/ake6fsta.cpp @@ -0,0 +1,424 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=16 ake6fsta.cpp zzn6a.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + using COMBA build + + Freeman-Scott-Teske curve - Ate pairing + + This version uses the sextic twist and the Ate pairing + No elliptic curve operations over an extension field! + + p=1+3*x+3*x*x+9*pow(x,3)+27*pow(x,4) + r=1+3*x+9*x*x + t=2+3*x + + For this curve k=6, rho=2 (which is bad...) + p is 512 bits, 6p = 3072 bits, r is 256 bits + + For this program p MUST be 13 mod 24 + + final exponent = (1+9*x^3)*p^0 + 3x^2*p^1 + + Modified to prevent sub-group confinement attack + +*/ + +#include +#include +#include +#include +#include "ecn.h" +#include "zzn6a.h" + +using namespace std; + +Miracl precision(16,0); + +// Using SHA-1 as basic hash algorithm + +#define HASH_LEN 20 + +// +// Define one or the other of these +// +// Which is faster depends on the I/M ratio - See imratio.c +// Roughly if I/M ratio > 16 use PROJECTIVE, otherwise use AFFINE +// + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +#ifdef PROJECTIVE +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} +#endif + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + X.set((Big)0,(Big)1); // = (sqrt(-2)^(p-1)/2 + break; + case 3: // = (1+sqrt(-1))^(p-1)/2 + X.set((Big)1,(Big)1); + break; + case 7: + X.set((Big)2,(Big)1); // = (2+sqrt(-1))^(p-1)/2 + default: break; + } + X=pow(Fr,(p-1)/3); +} + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn6 line(ECn& A,ECn& C,ZZn& slope,ECn& Q) +{ + ZZn6 n; + ZZn2 p; + ZZn x,y,z,t,Qx,Qy; + extract(Q,Qx,Qy); +#ifdef AFFINE + extract(A,x,y); + n.set(-Qx,0,x); + p.set(-Qy,y); + n*=slope; n=tx(n); + n-=p; +#endif +#ifdef PROJECTIVE + extract(A,x,y,z); + x*=z; t=z; z*=z; z*=t; + Qx*=z; Qy*=z; + p.set(-Qy,y); + t=-Qx*slope; + x*=slope; + n.set(t,0,x); + n=tx(n); + extract(C,x,y,z); + p*=z; n-=p; +#endif + return n; +} + +// +// Add A=A+B (or A=A+A) +// Evaluate line function +// + +ZZn6 g(ECn& A,ECn& B,ECn& Q) +{ + int type; + ZZn lam; + big ptr; + ECn P=A; + +// Evaluate line from A + type=A.add(B,&ptr); + if (!type) return (ZZn6)1; + else lam=ptr; + + return line(P,A,lam,Q); +} + +// +// Ate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order q. +// Note that P is a point on the sextic twist curve over Fp, +// Q(x,y) a point on the base curve +// + +BOOL fast_pairing(ECn& P,ECn& Q,Big& q,Big &x,ZZn2 &X, ZZn6 &res) +{ + int i,j,n,nb,nbw,nzs; + ECn A; + Big T=3*x+1; + ZZn6 w,t; + + res=1; + A=P; + normalise(Q); + + nb=bits(T); + +// Miller Loop + for (i=nb-2;i>=0;i--) + { + res*=res; + t=g(A,A,Q); + res*=t; + if (bit(T,i)) + { + t=g(A,P,Q); + res*=t; + } + } + + if (res.iszero()) return FALSE; + +// Final Exponentiation + w=res; + w.powq(X); + + res*=w; // ^(p+1) + + w=res; + + w.conj(); + res=w/res; // ^(p^3-1) + + res.mark_as_unitary(); + + t=w=res; + w.powq(X); + + res=pow(res,3*x); // specially tailored final exponentiation + res*=w; + res=pow(res,3*x); + res=pow(res,x); + res*=t; + + if (res==(ZZn6)1) return FALSE; + return TRUE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha sh; + + shs_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs_process(&sh,string[i]); + } + shs_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn6 y) +{ // Compress and Hash an Fp6 to a big number + sha sh; + Big a,h,p,xx[2]; + ZZn u,v,w; + ZZn2 x; + char s[HASH_LEN]; + int i,j,m; + + shs_init(&sh); + y.get(x); + x.get(u,v); + xx[0]=u; xx[1]=v; + for (i=0;i<2;i++) + { + a=xx[i]; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + } + shs_hash(&sh,s); + h=from_binary(HASH_LEN,s); + return h; +} + +// Hash and map a Client Identity to a curve point E_(Fp) + +ECn hash_and_map(char *ID,Big& cof) +{ + ECn Q; + Big x0=H1(ID); + forever + { + while (!Q.set(x0)) x0+=1; + x0+=1; + Q*=cof; + if (!Q.iszero()) break; + } + return Q; +} + +int main() +{ + miracl* mip=&precision; + ECn Alice,Bob,sA,sB,Server,sS; + ZZn6 res,sp,ap,bp; + ZZn2 X; + Big a,b,s,ss,p,q,x,y,B,cof,t,cf,cof1; + int i,bits,A; + time_t seed; + + mip->IOBASE=16; + x="60000000000000000000000000012014"; // Low Hamming weight + q=1+3*x+9*x*x; + p=1+3*x+3*x*x+9*pow(x,3)+27*pow(x,4); + t=2+3*x; + cof=(p+1-t)/q; + A=0; B=1; + + cout << "Initialised... " << endl; + cout << "p%24= " << p%24 << endl; + + time(&seed); + irand((long)seed); + mip->IOBASE=16; + cof1=cof+1; + + ss=rand(q); // TA's super-secret + +#ifdef AFFINE + ecurve(A,B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(A,B,p,MR_PROJECTIVE); +#endif + + set_frobenius_constant(X); + + cout << "Mapping Server ID to point" << endl; + Server=hash_and_map((char *)"Server",cof); + sS=ss*Server; + +// sextic twist + +#ifdef AFFINE + ecurve(A,B*(p-1)/2,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(A,B*(p-1)/2,p,MR_PROJECTIVE); +#endif + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice",cof1); // cof+1 is the co-factor for the sextic twist (?) + Bob= hash_and_map((char *)"Robert",cof1); + + cout << "Alice and Bob visit Trusted Authority" << endl; + + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + if (!fast_pairing(sA,Server,q,x,X,res)) cout << "Trouble" << endl; + if (pow(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + ap=powu(res,a); + + if (!fast_pairing(Alice,sS,q,x,X,res)) cout << "Trouble" << endl; + if (pow(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powu(res,s); + + cout << "Alice Key= " << H2(pow(sp,a)) << endl; + cout << "Server Key= " << H2(pow(ap,s)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!fast_pairing(sB,Server,q,x,X,res)) cout << "Trouble" << endl; + if (pow(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powu(res,b); + + if (!fast_pairing(Bob,sS,q,x,X,res)) cout << "Trouble" << endl; + if (pow(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powu(res,s); + + cout << "Bob's Key= " << H2(powu(sp,b)) << endl; + cout << "Server Key= " << H2(powu(bp,s)) << endl; + + cout << "Alice and Bob's attempted Key exchange" << endl; + + if (!fast_pairing(Alice,sB,q,x,X,res)) cout << "Trouble" << endl; + if (pow(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powu(res,b); + + if (!fast_pairing(sA,Bob,q,x,X,res)) cout << "Trouble" << endl; + if (pow(res,q)!=(ZZn6)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + ap=powu(res,a); + + cout << "Alice Key= " << H2(powu(ap,b)) << endl; + cout << "Bob's Key= " << H2(powu(bp,a)) << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/ake6mnta.cpp b/miracl/source/curve/pairing/ake6mnta.cpp new file mode 100644 index 0000000..88d661d --- /dev/null +++ b/miracl/source/curve/pairing/ake6mnta.cpp @@ -0,0 +1,510 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=5 ake6mnta.cpp zzn6a.cpp ecn3.cpp zzn3.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + using COMBA build + + MNT Curve - ate pairing + + Thanks to Drew Sutherland for providing the MNT curve + + Irreducible binomial MUST be of the form x^6+2. This excludes many of the curves + found using the mnt utility! + + Modified to prevent sub-group confinement attack + + NOTE: Key exchange bandwidth could be reduced further using ideas from + "Doing more with Fewer Bits", Brouwer, Pellikaan & Verheul, Asiacrypt + '99 + + NOTE: This version uses a "compositum". That is the ZZn6 class is a cubic tower over ZZn2, but can + also be considered as a quadratic tower over ZZn3. The routine shuffle converts from one form to the other. + The former is fastest for ZZn6 arithmetic, the latter form is required for handling the second parameter + to the pairing, which is on the quadratic twist E(Fp3) + +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn3.h" +#include "zzn6a.h" + +Miracl precision(5,0); + +#define AFFINE +//#define PROJECTIVE + +#ifdef MR_COUNT_OPS +extern "C" +{ + int fpc,fpa,fpx,fpm2,fpi2,fpaq,fpsq,fpmq; +} +#endif + +// Using SHA-1 as basic hash algorithm + +#define HASH_LEN 20 + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +#ifdef PROJECTIVE +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} +#endif + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + X.set((Big)0,(Big)1); // = (sqrt(-2)^(p-1)/2 + break; + case 3: // = (1+sqrt(-1))^(p-1)/2 + X.set((Big)1,(Big)1); + break; + case 7: + X.set((Big)2,(Big)1); // = (2+sqrt(-1))^(p-1)/2 + default: break; + } + X=pow(X,(p-1)/3); +} + +ZZn6 shuffle(ZZn3 &first, ZZn3 &second) +{ // shuffle from a pair ZZn3's to three ZZn2's, as required by ZZn6 + ZZn6 w; + ZZn x0,x1,x2,x3,x4,x5; + ZZn2 t0,t1,t2; + first.get(x0,x2,x4); + second.get(x1,x3,x5); + t0.set(x0,x3); + t1.set(x1,x4); + t2.set(x2,x5); + w.set(t0,t1,t2); + return w; +} + +void unshuffle(ZZn6 &S,ZZn3 &first,ZZn3 &second) +{ // unshuffle a ZZn6 into two ZZn3's + ZZn x0,x1,x2,x3,x4,x5; + ZZn2 t0,t1,t2; + S.get(t0,t1,t2); + t0.get(x0,x3); + t1.get(x1,x4); + t2.get(x2,x5); + first.set(x0,x2,x4); + second.set(x1,x3,x5); +} + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn6 line(ECn3& A,ECn3& C,ECn3& B,int type,ZZn3& slope,ZZn3& ex1,ZZn3& ex2,ZZn& Px,ZZn& Py) +{ + ZZn6 w; + ZZn3 d; +#ifdef AFFINE + ZZn3 x,y; + A.get(x,y); + d.set1(Py); + w=shuffle(y-slope*(Px+x),d); + +#endif +#ifdef PROJECTIVE + ZZn3 x,y,z,z3,t; + C.getZ(z3); + d.set1(Py); + + if (type==MR_ADD) + { // exploit that B is in affine + ZZn3 x2,y2; + B.get(x2,y2); + y2*=z3; d*=z3; + w=shuffle(y2-slope*(Px+x2),d); + } + if (type==MR_DOUBLE) + { // use extra information from point doubling + A.get(x,y,z); + w=shuffle(ex1-slope*(Px*ex2+x),d*z3*ex2); + } +#endif + + return w; +} + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn6 g(ECn3& A,ECn3& B,ZZn& Px,ZZn& Py) +{ + BOOL type; + ZZn3 lam,ex1,ex2; + ECn3 Q=A; + +// Evaluate line from A to A+B + type=A.add(B,lam,&ex1,&ex2); + + return line(Q,A,B,type,lam,ex1,ex2,Px,Py); +} + +// +// ate Pairing - note denominator elimination has been applied +// +// Q(x,y) is a point of order q. +// Note that P is a point on the curve over Fp, Q(x,y) a point on the +// twisted curve over the extension field Fp^3 +// + +BOOL ate(ECn3& Q,ECn& P,Big &x,ZZn2& X,ZZn6& res) +{ + int i,j,n,nb,nbw,nzs; + ECn3 A; + ZZn Px,Py; + ZZn6 w; + Big q=x*x-x+1; + +#ifdef MR_COUNT_OPS +fpc=fpa=fpx=0; +#endif + + normalise(P); +#ifdef PROJECTIVE + Q.norm(); +#endif + extract(P,Px,Py); + + Px+=Px; // because x^6+2 is irreducible.. simplifies line function calculation + Py+=Py; + + res=1; + + A=Q; // reset A + nb=bits(x); + res.mark_as_miller(); + + for (i=nb-2;i>=0;i--) + { + res*=res; + res*=g(A,A,Px,Py); + if (bit(x,i)==1) + res*=g(A,Q,Px,Py); + if (res.iszero()) return FALSE; + } + +#ifdef MR_COUNT_OPS +printf("After Miller fpc= %d fpa= %d fpx= %d\n",fpc,fpa,fpx); +#endif + // if (!A.iszero() || res.iszero()) return FALSE; + + w=res; + w.powq(X); + res*=w; // ^(p+1) + + w=res; + w.powq(X); w.powq(X); w.powq(X); + res=w/res; // ^(p^3-1) + +// exploit the clever "trick" for a half-length exponentiation! + + res.mark_as_unitary(); + + w=res; + res.powq(X); // res*=res; // res=pow(res,CF); + + if (x<0) res/=powu(w,-x); + else res*=powu(w,x); +#ifdef MR_COUNT_OPS +printf("After pairing fpc= %d fpa= %d fpx= %d\n",fpc,fpa,fpx); +fpa=fpc=fpx=0; +#endif + + if (res==(ZZn6)1) return FALSE; + return TRUE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha sh; + + shs_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs_process(&sh,string[i]); + } + shs_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn6 y) +{ // Hash and compress an Fp6 to a big number + sha sh; + ZZn u,v,w; + ZZn2 x; + Big a,h,p,xx[2]; + char s[HASH_LEN]; + int i,j,m; + + shs_init(&sh); + y.get(x); + x.get(u,v); + xx[0]=u; xx[1]=v; + + for (i=0;i<2;i++) + { + a=xx[i]; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + } + shs_hash(&sh,s); + h=from_binary(HASH_LEN,s); + return h; +} + +// Hash and map a Server Identity to a curve point E_(Fp3) + +ECn3 hash_and_map3(char *ID) +{ + int i; + ECn3 S; + ZZn3 X; + + Big x0=H1(ID); + forever + { + x0+=1; + X.set2((ZZn)x0); + if (!S.set(X)) continue; + + break; + } + +// cout << "S= " << S << endl; + return S; +} + +// Hash and map a Client Identity to a curve point E_(Fp) of order q + +ECn hash_and_map(char *ID) +{ + ECn Q; + Big x0=H1(ID); + + while (!Q.set(x0,x0)) x0+=1; + + return Q; +} + +BOOL member(ZZn6 r,Big &x,ZZn2 &X) +{ // check its an element of order q + ZZn6 w=r; + w.powq(X); + if (x<0) r=powu(inverse(r),-x); + else r=powu(r,x); + if (r==w) return TRUE; + return FALSE; +} + +// Use Scott et al. idea - http://eprint.iacr.org/2008/530.pdf + +void cofactor(ECn3 &S,Big &x, ZZn2& X) +{ // S=Phi(2xP)+phi^2(2xP) + ZZn6 X1,X2,Y1,Y2; + ZZn3 Sx,Sy,T; + ECn3 S2; + int qnr=get_mip()->cnr; + + S*=x; S+=S; // hard work done here + + S.get(Sx,Sy); + + // untwist + Sx=Sx/qnr; + Sy=tx(Sy); + Sy=Sy/(qnr*qnr); + + X1=shuffle(Sx,(ZZn3)0); Y1=shuffle((ZZn3)0,Sy); + X1.powq(X); Y1.powq(X); + X2=X1; Y2=Y1; + X2.powq(X); Y2.powq(X); + unshuffle(X1,Sx,T); unshuffle(Y1,T,Sy); + + // twist + Sx=qnr*Sx; + Sy=txd(Sy*qnr*qnr); + S.set(Sx,Sy); + unshuffle(X2,Sx,T); unshuffle(Y2,T,Sy); + + //twist (again, like we did last summer...) + Sx=qnr*Sx; + Sy=txd(Sy*qnr*qnr); + S2.set(Sx,Sy); + S+=S2; +} + +int main() +{ + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn3 B6,Server,sS; + ZZn6 sp,ap,bp; + ZZn6 res,XX,YY; + ZZn2 X; + ZZn3 Qx,Qy; + Big a,b,s,ss,p,q,x,y,B,cf,t,sru,T; + int i,A; + time_t seed; + int qnr; + + mip->IOBASE=16; + x="-D285DA0CFEF02F06F812"; // MNT elliptic curve parameters (Thanks to Drew Sutherland) + p=x*x+1; + q=x*x-x+1; + t=x+1; + cf=x*x+x+1; + + T=t-1; +// cout << "t-1= " << T << endl; +// cout << "p%24= " << p%24 << endl; + + time(&seed); + irand((long)seed); + + A=-3; + B="77479D33943B5B1F590B54258B72F316B3261D45"; + + ecurve(A,B,p,MR_PROJECTIVE); + + set_frobenius_constant(X); + sru=pow((ZZn)-2,(p-1)/6); // x^6+2 is irreducible + set_zzn3(-2,sru); + + mip->IOBASE=16; + mip->TWIST=MR_QUADRATIC; // map Server to point on twisted curve E(Fp3) + //See ftp://ftp.computing.dcu.ie/pub/resources/crypto/twists.pdf + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + Server=hash_and_map3((char *)"Server"); + +// Multiply by the cofactor - thank you NTL! +// Server*=(p-1); +// Server*=(p+1+t); + + cofactor(Server,x,X); + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice"); + Bob= hash_and_map((char *)"Robert"); + + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=ss*Server; + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + if (!ate(Server,sA,x,X,res)) cout << "Trouble" << endl; + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + ap=powu(res,a); + + if (!ate(sS,Alice,x,X,res)) cout << "Trouble" << endl; + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + sp=powu(res,s); + + cout << "Alice Key= " << H2(powu(sp,a)) << endl; + cout << "Server Key= " << H2(powu(ap,s)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!ate(Server,sB,x,X,res)) cout << "Trouble" << endl; + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powu(res,b); + + if (!ate(sS,Bob,x,X,res)) cout << "Trouble" << endl; + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powu(res,s); + + cout << "Bob's Key= " << H2(powu(sp,b)) << endl; + cout << "Server Key= " << H2(powu(bp,s)) << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/ake6mntt.c b/miracl/source/curve/pairing/ake6mntt.c new file mode 100644 index 0000000..202acae --- /dev/null +++ b/miracl/source/curve/pairing/ake6mntt.c @@ -0,0 +1,803 @@ +/* C version of ake6mntt.cpp + +Example for embedded implementation. + +Should build immediately with standard mirdef.h file on a PC. For example using MS C + +cl /O2 ake6mntt.c ms32.lib + +To simulate performance on a PC of an 8-bit computer use + +#define MR_LITTLE_ENDIAN +#define MIRACL 8 +#define mr_utype char +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype short +#define MR_STATIC 20 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 20 +#define MR_NOASM +#define MR_BITSINCHAR 8 +#define MR_NOSUPPORT_COMPRESSION + +rem Compile MIRACL modules +mex 20 c mrcomba +cl /c /O2 /W3 mrzzn3.c +cl /c /O2 /W3 mrcore.c +cl /c /O2 /W3 mrarth0.c +cl /c /O2 /W3 mrarth1.c +cl /c /O2 /W3 mrarth2.c +cl /c /O2 /W3 mrxgcd.c +cl /c /O2 /W3 mrbits.c +cl /c /O2 /W3 mrmonty.c +cl /c /O2 /W3 mrcurve.c +cl /c /O2 /W3 mrcomba.c +cl /c /O2 /W3 mrio1.c +cl /c /O2 /W3 mrpower.c + + +rem +rem Create library 'miracl.lib' +del miracl.lib + + +lib /OUT:miracl.lib mrxgcd.obj mrarth2.obj mrio1.obj mrcomba.obj +lib /OUT:miracl.lib miracl.lib mrmonty.obj mrarth1.obj mrarth0.obj mrcore.obj +lib /OUT:miracl.lib miracl.lib mrcurve.obj mrbits.obj mrzzn3.obj mrpower.obj + +del mr*.obj + +cl /O2 ake6mntt.c miracl.lib + +For Atmel AVR (atmega128) use + +#define MR_LITTLE_ENDIAN +#define MIRACL 8 +#define mr_utype char +#define MR_IBITS 16 +#define MR_LBITS 32 +#define mr_unsign32 unsigned long +#define mr_dltype int +#define mr_qltype long +#define MR_STATIC 20 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 20 +#define MR_NOASM +#define MR_BITSINCHAR 8 +#define MR_NO_STANDARD_IO +#define MR_NO_FILE_IO +#define MR_NOSUPPORT_COMPRESSION +#define MR_AVR + +This last line must be added manually - config.c will not do it automatically + +and execute + +mex 20 avr4 mrcomba + +On an ARM use a header like + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype long long +#define MR_STATIC 5 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 5 +#define MR_BITSINCHAR 8 +#define MR_NOSUPPORT_COMPRESSION + +and possible + +#define MR_NO_STANDARD_IO +#define MR_NO_FILE_IO + +and execute + +mex 5 arm mrcomba + +*/ + +#include +#include +#include "miracl.h" + +#ifdef MR_COUNT_OPS + + int fpc=0; + int fpa=0; + int fpx=0; + +#endif + +/* Fix the contents of mnt.ecs */ + +#if MIRACL==64 + +NOT SUPPORTED + +/* Note: n-residue formats are not the same for different word lengths ...*/ + +#endif + +#if MIRACL==32 + +#define WORDS 5 +#define NPW 8 /* Nibbles per Word */ +#define ROMSZ 25 + +static const mr_small romp[]={ +0x44626303,0xBB9F14CF,0x749D0195,0xA2E3DDB1,0x7DDCA613, +0x7D8CFD4E,0xF828D365,0xF99273D0,0x7864D1F1,0x21C3F3AC, +0x17D369B7,0xF44414FD,0xBA4E12DE,0xD171EED8,0x3EEE5309, +0xB23BE531,0x1D6BFF48,0xE93BBADB,0x45C7BB62,0xFBB94C27, +0xA92DB540,0x24C6F8B9,0x5913FCF1,0x9EA2B8F4,0x3AA6D7A2 +}; + +/* Points - in n-residue form */ + +#define PROMSZ 40 + +static const mr_small Prom[]={ +0xB6EF1A16,0x074251AD,0xF062F710,0xD679E3D1,0x2EEEF8B2, +0x8DF7059B,0x3882F3BF,0x92A4F4AA,0xE9D835E6,0x265FB32, +0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0, +0x0C05C29F,0xF8512956,0xBD6A3234,0xA3C6C536,0x758EE3E4, +0x3282E036,0xCAC39E95,0x775F3F11,0x1E4FED9B,0x311F2F09, +0x5EBDAB43,0xD4EC58B7,0x406EDA4D,0x294137C6,0x57BD4583, +0x1B936DC6,0xD4A63AB3,0x05026F3B,0x1D4FA7B1,0x5CC7D4CC +}; + +#endif + +#if MIRACL==8 + +#define WORDS 20 +#define NPW 2 /* Nibbles per Word */ +#define ROMSZ 100 + +#ifdef MR_AVR +__attribute__((__progmem__)) +#endif +static const mr_small romp[]={ +0x3,0x63,0x62,0x44,0xcf,0x14,0x9f,0xbb,0x95,0x1,0x9d,0x74,0xb1,0xdd,0xe3,0xa2,0x13,0xa6,0xdc,0x7d, +0x4e,0xfd,0x8c,0x7d,0x65,0xd3,0x28,0xf8,0xd0,0x73,0x92,0xf9,0xf1,0xd1,0x64,0x78,0xac,0xf3,0xc3,0x21, +0xb7,0x69,0xd3,0x17,0xfd,0x14,0x44,0xf4,0xde,0x12,0x4e,0xba,0xd8,0xee,0x71,0xd1,0x9,0x53,0xee,0x3e, +0x31,0xe5,0x3b,0xb2,0x48,0xff,0x6b,0x1d,0xdb,0xba,0x3b,0xe9,0x62,0xbb,0xc7,0x45,0x27,0x4c,0xb9,0xfb, +0x40,0xb5,0x2d,0xa9,0xb9,0xf8,0xc6,0x24,0xf1,0xfc,0x13,0x59,0xf4,0xb8,0xa2,0x9e,0xa2,0xd7,0xa6,0x3a}; + +#define PROMSZ 160 + +#ifdef MR_AVR +__attribute__((__progmem__)) +#endif +static const mr_small Prom[]={ +0x16,0x1a,0xef,0xb6,0xad,0x51,0x42,0x7,0x10,0xf7,0x62,0xf0,0xd1,0xe3,0x79,0xd6,0xb2,0xf8,0xee,0x2e, +0x9b,0x5,0xf7,0x8d,0xbf,0xf3,0x82,0x38,0xaa,0xf4,0xa4,0x92,0xe6,0x35,0xd8,0xe9,0x32,0xfb,0x65,0x2, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x9f,0xc2,0x5,0xc,0x56,0x29,0x51,0xf8,0x34,0x32,0x6a,0xbd,0x36,0xc5,0xc6,0xa3,0xe4,0xe3,0x8e,0x75, +0x36,0xe0,0x82,0x32,0x95,0x9e,0xc3,0xca,0x11,0x3f,0x5f,0x77,0x9b,0xed,0x4f,0x1e,0x9,0x2f,0x1f,0x31, +0x43,0xab,0xbd,0x5e,0xb7,0x58,0xec,0xd4,0x4d,0xda,0x6e,0x40,0xc6,0x37,0x41,0x29,0x83,0x45,0xbd,0x57, +0xc6,0x6d,0x93,0x1b,0xb3,0x3a,0xa6,0xd4,0x3b,0x6f,0x2,0x5,0xb1,0xa7,0x4f,0x1d,0xcc,0xd4,0xc7,0x5c}; + +#endif + +#define CNR 2 +#define CF 2 + +/* Fp6 support functions */ + +typedef struct +{ + zzn3 x; + zzn3 y; + BOOL unitary; +} zzn6; + +#ifndef MR_NO_STANDARD_IO +void zzn3_out(_MIPD_ char *p,zzn3 *x) +{ + printf(p); printf("\n"); + redc(_MIPP_ x->a,x->a); + redc(_MIPP_ x->b,x->b); + redc(_MIPP_ x->c,x->c); + otnum(_MIPP_ x->a,stdout); + otnum(_MIPP_ x->b,stdout); + otnum(_MIPP_ x->c,stdout); + nres(_MIPP_ x->a,x->a); + nres(_MIPP_ x->b,x->b); + nres(_MIPP_ x->c,x->c); +} +#endif + +void zzn6_copy(zzn6 *u,zzn6 *w) +{ + if (u==w) return; + zzn3_copy(&(u->x),&(w->x)); + zzn3_copy(&(u->y),&(w->y)); + w->unitary=u->unitary; +} + +void zzn6_from_int(_MIPD_ int i,zzn6 *w) +{ + zzn3_from_int(_MIPP_ i,&(w->x)); + zzn3_zero(&(w->y)); + if (i==1) w->unitary=TRUE; + else w->unitary=FALSE; +} + +void zzn6_conj(_MIPD_ zzn6 *u,zzn6 *w) +{ + zzn6_copy(u,w); + zzn3_negate(_MIPP_ &(w->y),&(w->y)); +} + +void zzn6_mul(_MIPD_ zzn6 *u,zzn6 *v,zzn6 *w) +{ + zzn3 t1,t2,t3; + t1.a=mr_mip->w7; + t1.b=mr_mip->w8; + t1.c=mr_mip->w9; + t2.a=mr_mip->w10; + t2.b=mr_mip->w11; + t2.c=mr_mip->w12; + t3.a=mr_mip->w13; + t3.b=mr_mip->w14; + t3.c=mr_mip->w15; + if (u==v) + { +/* See Stam & Lenstra, "Efficient subgroup exponentiation in Quadratic .. Extensions", CHES 2002 */ + if (u->unitary) + { /* this is a lot faster.. */ + zzn6_copy(u,w); + zzn3_mul(_MIPP_ &(w->y),&(w->y),&t1); + zzn3_add(_MIPP_ &(w->y),&(w->x),&(w->y)); + zzn3_mul(_MIPP_ &(w->y),&(w->y),&(w->y)); + zzn3_sub(_MIPP_ &(w->y),&t1,&(w->y)); + zzn3_timesi(_MIPP_ &t1); + zzn3_copy(&t1,&(w->x)); + zzn3_sub(_MIPP_ &(w->y),&(w->x),&(w->y)); + zzn3_add(_MIPP_ &(w->x),&(w->x),&(w->x)); + zzn3_sadd(_MIPP_ &(w->x),mr_mip->one,&(w->x)); + zzn3_ssub(_MIPP_ &(w->y),mr_mip->one,&(w->y)); + } + else + { + zzn6_copy(u,w); + zzn3_add(_MIPP_ &(w->x),&(w->y),&t1); + zzn3_copy(&(w->y),&t3); + zzn3_timesi(_MIPP_ &t3); + zzn3_add(_MIPP_ &(w->x),&t3,&t2); + zzn3_mul(_MIPP_ &t1,&t2,&t1); + zzn3_mul(_MIPP_ &(w->y),&(w->x),&(w->y)); + zzn3_sub(_MIPP_ &t1,&(w->y),&t1); + zzn3_copy(&(w->y),&t3); + zzn3_timesi(_MIPP_ &t3); + zzn3_sub(_MIPP_ &t1,&t3,&t1); + zzn3_add(_MIPP_ &(w->y),&(w->y),&(w->y)); + zzn3_copy(&t1,&(w->x)); + } + } + else + { + zzn3_mul(_MIPP_ &(u->x),&(v->x),&t1); + zzn3_mul(_MIPP_ &(u->y),&(v->y),&t2); + zzn3_add(_MIPP_ &(v->x),&(v->y),&t3); + zzn3_add(_MIPP_ &(u->x),&(u->y),&(w->y)); + zzn3_mul(_MIPP_ &(w->y),&t3,&(w->y)); + zzn3_sub(_MIPP_ &(w->y),&t1,&(w->y)); + zzn3_sub(_MIPP_ &(w->y),&t2,&(w->y)); + zzn3_copy(&t1,&(w->x)); + zzn3_timesi(_MIPP_ &t2); + zzn3_add(_MIPP_ &(w->x),&t2,&(w->x)); + if (u->unitary && v->unitary) w->unitary=TRUE; + else w->unitary=FALSE; + } +} + +/* zzn6 powering of unitary elements */ + +void zzn6_powu(_MIPD_ zzn6 *x,big k,zzn6 *u) +{ + zzn6 t[5],u2; + big k3; + int i,j,n,nb,nbw,nzs; +#ifndef MR_STATIC + char *mem=memalloc(_MIPP_ 37); +#else + char mem[MR_BIG_RESERVE(37)]; + memset(mem,0,MR_BIG_RESERVE(37)); +#endif + + if (size(k)==0) + { + zzn6_from_int(_MIPP_ 1,u); + return; + } + zzn6_copy(x,u); + if (size(k)==1) return; + + for (j=i=0;i<5;i++) + { + t[i].x.a=mirvar_mem(_MIPP_ mem,j++); + t[i].x.b=mirvar_mem(_MIPP_ mem,j++); + t[i].x.c=mirvar_mem(_MIPP_ mem,j++); + t[i].y.a=mirvar_mem(_MIPP_ mem,j++); + t[i].y.b=mirvar_mem(_MIPP_ mem,j++); + t[i].y.c=mirvar_mem(_MIPP_ mem,j++); + t[i].unitary=FALSE; + } + u2.x.a=mirvar_mem(_MIPP_ mem,j++); + u2.x.b=mirvar_mem(_MIPP_ mem,j++); + u2.x.c=mirvar_mem(_MIPP_ mem,j++); + u2.y.a=mirvar_mem(_MIPP_ mem,j++); + u2.y.b=mirvar_mem(_MIPP_ mem,j++); + u2.y.c=mirvar_mem(_MIPP_ mem,j++); + u2.unitary=FALSE; + k3=mirvar_mem(_MIPP_ mem,j); + + premult(_MIPP_ k,3,k3); + zzn6_mul(_MIPP_ u,u,&u2); + zzn6_copy(u,&t[0]); + + for (i=1;i<=4;i++) + zzn6_mul(_MIPP_ &u2,&t[i-1],&t[i]); + + nb=logb2(_MIPP_ k3); + + for (i=nb-2;i>=1;) + { + n=mr_naf_window(_MIPP_ k,k3,i,&nbw,&nzs,5); + + for (j=0;j0) zzn6_mul(_MIPP_ u,&t[n/2],u); + if (n<0) + { + zzn6_conj(_MIPP_ &t[-n/2],&u2); + zzn6_mul(_MIPP_ u,&u2,u); + } + i-=nbw; + if (nzs) + { + for (j=0;jw7; + t1.b=mr_mip->w8; + t1.c=mr_mip->w9; + t3.a=mr_mip->w10; + t3.b=mr_mip->w11; + t3.c=mr_mip->w12; + t4.a=mr_mip->w13; + t4.b=mr_mip->w14; + t4.c=mr_mip->w15; + + zzn3_from_int(_MIPP_ 1,&t1); + + s=size(e); + if (s==0) + { + zzn3_copy(&t1,w); + return; + } + zzn3_copy(x,w); + if (s==1 || s==(-1)) return; + + i=logb2(_MIPP_ e)-1; + + zzn3_copy(w,&t3); + zzn3_mul(_MIPP_ w,w,&t4); + zzn3_add(_MIPP_ &t4,&t4,&t4); + zzn3_sub(_MIPP_ &t4,&t1,&t4); + + while (i--) + { + if (mr_testbit(_MIPP_ e,i)) + { + zzn3_mul(_MIPP_ &t3,&t4,&t3); + zzn3_add(_MIPP_ &t3,&t3,&t3); + zzn3_sub(_MIPP_ &t3,w,&t3); + zzn3_mul(_MIPP_ &t4,&t4,&t4); + zzn3_add(_MIPP_ &t4,&t4,&t4); + zzn3_sub(_MIPP_ &t4,&t1,&t4); + } + else + { + zzn3_mul(_MIPP_ &t4,&t3,&t4); + zzn3_add(_MIPP_ &t4,&t4,&t4); + zzn3_sub(_MIPP_ &t4,w,&t4); + zzn3_mul(_MIPP_ &t3,&t3,&t3); + zzn3_add(_MIPP_ &t3,&t3,&t3); + zzn3_sub(_MIPP_ &t3,&t1,&t3); + } + } + zzn3_copy(&t3,w); +} + +void zzn6_powq(_MIPD_ zzn6 *w) +{ + zzn3_powq(_MIPP_ &(w->x),&(w->x)); + zzn3_powq(_MIPP_ &(w->y),&(w->y)); + zzn3_smul(_MIPP_ &(w->y),mr_mip->sru,&(w->y)); +} + +void zzn6_inv(_MIPD_ zzn6 *w) +{ + zzn3 t1,t2; + if (w->unitary) + { + zzn6_conj(_MIPP_ w,w); + return; + } + t1.a=mr_mip->w7; + t1.b=mr_mip->w8; + t1.c=mr_mip->w9; + t2.a=mr_mip->w10; + t2.b=mr_mip->w11; + t2.c=mr_mip->w12; + + zzn3_copy(&(w->x),&t1); + zzn3_copy(&(w->y),&t2); + zzn3_mul(_MIPP_ &t1,&t1,&t1); + zzn3_mul(_MIPP_ &t2,&t2,&t2); + zzn3_timesi(_MIPP_ &t2); + zzn3_sub(_MIPP_ &t1,&t2,&t2); + zzn3_inv(_MIPP_ &t2); + zzn3_mul(_MIPP_ &(w->x),&t2,&(w->x)); + zzn3_negate(_MIPP_ &(w->y),&(w->y)); + zzn3_mul(_MIPP_ &(w->y),&t2,&(w->y)); +} + +void g(_MIPD_ epoint *A,epoint *B,zzn3 *Qx,zzn3 *Qy,zzn6 *w) +{ + int type; + big slope; + zzn3 nn,dd; + + copy(A->X,mr_mip->w10); + + type=ecurve_add(_MIPP_ B,A); + if (!type) + { + zzn6_from_int(_MIPP_ 1,w); + return; + } + slope=mr_mip->w8; /* slope in w8 */ + + nn.a=mr_mip->w13; + nn.b=mr_mip->w14; + nn.c=mr_mip->w15; + + dd.a=mr_mip->w5; + dd.b=mr_mip->w11; + dd.c=mr_mip->w9; + + zzn3_copy(Qx,&nn); + zzn3_copy(Qy,&dd); + zzn3_negate(_MIPP_ &dd,&dd); + +#ifndef MR_AFFINE_ONLY + if (A->marker!=MR_EPOINT_GENERAL) + copy(mr_mip->one,mr_mip->w12); + else copy(A->Z,mr_mip->w12); +#else + copy(mr_mip->one,mr_mip->w12); +#endif + if (type==MR_ADD) + { + zzn3_ssub(_MIPP_ &nn,B->X,&nn); + zzn3_smul(_MIPP_ &nn,slope,&nn); + nres_modmult(_MIPP_ mr_mip->w12,B->Y,mr_mip->w2); + zzn3_sadd(_MIPP_ &nn,mr_mip->w2,&nn); + zzn3_smul(_MIPP_ &dd,mr_mip->w12,&dd); + zzn3_copy(&nn,&(w->x)); + zzn3_copy(&dd,&(w->y)); + return; + } + + if (type==MR_DOUBLE) + { /* note that ecurve_add has left useful things for us in w6 and w7! */ + nres_modmult(_MIPP_ slope,mr_mip->w6,mr_mip->w2); + zzn3_smul(_MIPP_ &nn,mr_mip->w2,&nn); + nres_modmult(_MIPP_ slope,mr_mip->w10,slope); + zzn3_ssub(_MIPP_ &nn,slope,&nn); + zzn3_sadd(_MIPP_ &nn,mr_mip->w7,&nn); + nres_modmult(_MIPP_ mr_mip->w12,mr_mip->w6,mr_mip->w12); + zzn3_smul(_MIPP_ &dd,mr_mip->w12,&dd); + zzn3_copy(&nn,&(w->x)); + zzn3_copy(&dd,&(w->y)); + return; + } +} + +void fast_tate_pairing(_MIPD_ epoint *P,zzn3 *Qx,zzn3 *Qy,big q,big cf,zzn6 *w,zzn6* res) +{ + int i,j,n,nb,nbw,nzs; + epoint *t[4],*A,*P2; + zzn6 zn[4]; + big work[4]; + +#ifndef MR_STATIC + char *mem=memalloc(_MIPP_ 28); + char *mem1=ecp_memalloc(_MIPP_ 6); +#else + char mem[MR_BIG_RESERVE(28)]; + char mem1[MR_ECP_RESERVE(6)]; + memset(mem,0,MR_BIG_RESERVE(28)); + memset(mem1,0,MR_ECP_RESERVE(6)); +#endif + + for (i=0;i<4;i++) + t[i]=epoint_init_mem(_MIPP_ mem1,i); + A=epoint_init_mem(_MIPP_ mem1,4); + P2=epoint_init_mem(_MIPP_ mem1,5); + + for (j=i=0;i<4;i++) + { + work[i]=mirvar_mem(_MIPP_ mem,j++); + zn[i].x.a=mirvar_mem(_MIPP_ mem,j++); + zn[i].x.b=mirvar_mem(_MIPP_ mem,j++); + zn[i].x.c=mirvar_mem(_MIPP_ mem,j++); + zn[i].y.a=mirvar_mem(_MIPP_ mem,j++); + zn[i].y.b=mirvar_mem(_MIPP_ mem,j++); + zn[i].y.c=mirvar_mem(_MIPP_ mem,j++); + zn[i].unitary=FALSE; + } + + zzn6_from_int(_MIPP_ 1,&zn[0]); + epoint_copy(P,A); + epoint_copy(P,P2); + epoint_copy(P,t[0]); + + g(_MIPP_ P2,P2,Qx,Qy,res); + epoint_norm(_MIPP_ P2); + + for (i=1;i<4;i++) + { + g(_MIPP_ A,P2,Qx,Qy,w); + epoint_copy(A,t[i]); + zzn6_mul(_MIPP_ &zn[i-1],w,&zn[i]); + zzn6_mul(_MIPP_ &zn[i],res,&zn[i]); + } + + epoint_multi_norm(_MIPP_ 4,work,t); + + epoint_copy(P,A); + zzn6_from_int(_MIPP_ 1,res); + + nb=logb2(_MIPP_ q); + for (i=nb-2;i>=0;i-=(nbw+nzs)) + { + n=mr_window(_MIPP_ q,i,&nbw,&nzs,3); + for (j=0;j0) + { + zzn6_mul(_MIPP_ res,&zn[n/2],res); + g(_MIPP_ A,t[n/2],Qx,Qy,w); + zzn6_mul(_MIPP_ res,w,res); + } + for (j=0;junitary=TRUE; + +#ifndef MR_STATIC + memkill(_MIPP_ mem,28); + ecp_memkill(_MIPP_ mem1,6); +#else + memset(mem,0,MR_BIG_RESERVE(28)); + memset(mem1,0,MR_ECP_RESERVE(6)); +#endif +} + +void ecap(_MIPD_ epoint *P,zzn3 *Qx,zzn3 *Qy,big q,big cf,zzn3* r) +{ + zzn6 res,w; +#ifndef MR_STATIC + char *mem=memalloc(_MIPP_ 12); +#else + char mem[MR_BIG_RESERVE(12)]; + memset(mem,0,MR_BIG_RESERVE(12)); +#endif + res.x.a=mirvar_mem(_MIPP_ mem,0); + res.x.b=mirvar_mem(_MIPP_ mem,1); + res.x.c=mirvar_mem(_MIPP_ mem,2); + res.y.a=mirvar_mem(_MIPP_ mem,3); + res.y.b=mirvar_mem(_MIPP_ mem,4); + res.y.c=mirvar_mem(_MIPP_ mem,5); + w.x.a=mirvar_mem(_MIPP_ mem,6); + w.x.b=mirvar_mem(_MIPP_ mem,7); + w.x.c=mirvar_mem(_MIPP_ mem,8); + w.y.a=mirvar_mem(_MIPP_ mem,9); + w.y.b=mirvar_mem(_MIPP_ mem,10); + w.y.c=mirvar_mem(_MIPP_ mem,11); + res.unitary=FALSE; + w.unitary=FALSE; + + epoint_norm(_MIPP_ P); + fast_tate_pairing(_MIPP_ P,Qx,Qy,q,cf,&w,&res); + + zzn6_copy(&res,&w); + zzn6_powq(_MIPP_ &res); + zzn6_mul(_MIPP_ &res,&res,&res); + + zzn6_powu(_MIPP_ &w,cf,&w); + zzn6_mul(_MIPP_ &res,&w,&res); + + zzn3_copy(&(res.x),r); + +#ifndef MR_STATIC + memkill(_MIPP_ mem,12); +#else + memset(mem,0,MR_BIG_RESERVE(12)); +#endif +} + +int main() +{ +#ifdef MR_GENERIC_MT + miracl instance; +#endif + big p,A,B,Fr,q,cf,sru,t,T; + zzn3 res,Qx,Qy; + epoint *P; + int i,romptr; +#ifndef MR_STATIC +#ifdef MR_GENERIC_MT + miracl *mr_mip=mirsys(&instance,WORDS*NPW,16); +#else + miracl *mr_mip=mirsys(WORDS*NPW,16); +#endif + char *mem=memalloc(_MIPP_ 18); + char *mem1=ecp_memalloc(_MIPP_ 1); +#else +#ifdef MR_GENERIC_MT + miracl *mr_mip=mirsys(&instance,MR_STATIC*NPW,16); +#else + miracl *mr_mip=mirsys(MR_STATIC*NPW,16); +#endif + char mem[MR_BIG_RESERVE(18)]; /* reserve space on the stack for 18 bigs */ + char mem1[MR_ECP_RESERVE(1)]; /* reserve space on stack for 1 curve points */ + memset(mem,0,MR_BIG_RESERVE(18)); /* clear this memory */ + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + p=mirvar_mem(_MIPP_ mem,0); + A=mirvar_mem(_MIPP_ mem,1); + B=mirvar_mem(_MIPP_ mem,2); + T=mirvar_mem(_MIPP_ mem,3); + q=mirvar_mem(_MIPP_ mem,4); + Fr=mirvar_mem(_MIPP_ mem,5); + cf=mirvar_mem(_MIPP_ mem,6); + res.a=mirvar_mem(_MIPP_ mem,7); + res.b=mirvar_mem(_MIPP_ mem,8); + res.c=mirvar_mem(_MIPP_ mem,9); + sru=mirvar_mem(_MIPP_ mem,10); + t=mirvar_mem(_MIPP_ mem,11); + Qx.a=mirvar_mem(_MIPP_ mem,12); + Qx.b=mirvar_mem(_MIPP_ mem,13); + Qx.c=mirvar_mem(_MIPP_ mem,14); + Qy.a=mirvar_mem(_MIPP_ mem,15); + Qy.b=mirvar_mem(_MIPP_ mem,16); + Qy.c=mirvar_mem(_MIPP_ mem,17); + + P=epoint_init_mem(_MIPP_ mem1,0); + convert(_MIPP_ -3,A); + + romptr=0; + init_big_from_rom(p,WORDS,romp,ROMSZ,&romptr); + init_big_from_rom(B,WORDS,romp,ROMSZ,&romptr); + init_big_from_rom(q,WORDS,romp,ROMSZ,&romptr); + init_big_from_rom(cf,WORDS,romp,ROMSZ,&romptr); + init_big_from_rom(sru,WORDS,romp,ROMSZ,&romptr); + + +#ifndef MR_NO_STANDARD_IO +printf("ROM size= %ld\n",sizeof(romp)+sizeof(Prom)); +printf("sizeof(miracl)= %ld\n",sizeof(miracl)); +#endif + + premult(_MIPP_ p,CF,t); + subtract(_MIPP_ cf,t,cf); + ecurve_init(_MIPP_ A,B,p,MR_BEST); + zzn3_set(_MIPP_ CNR,sru); + + romptr=0; + init_point_from_rom(P,WORDS,Prom,PROMSZ,&romptr); + init_big_from_rom(Qx.a,WORDS,Prom,PROMSZ,&romptr); + init_big_from_rom(Qx.b,WORDS,Prom,PROMSZ,&romptr); + init_big_from_rom(Qx.c,WORDS,Prom,PROMSZ,&romptr); + init_big_from_rom(Qy.a,WORDS,Prom,PROMSZ,&romptr); + init_big_from_rom(Qy.b,WORDS,Prom,PROMSZ,&romptr); + init_big_from_rom(Qy.c,WORDS,Prom,PROMSZ,&romptr); + +#ifdef MR_COUNT_OPS +fpa=fpc=fpx=0; +#endif + + ecap(_MIPP_ P,&Qx,&Qy,q,cf,&res); + +#ifdef MR_COUNT_OPS +printf("fpc= %d\n",fpc); +printf("fpa= %d\n",fpa); +printf("fpx= %d\n",fpx); +fpa=fpc=fpx=0; +#endif + + bigbits(_MIPP_ 160,t); + zzn3_powl(_MIPP_ &res,t,&res); + +#ifndef MR_NO_STANDARD_IO + zzn3_out(_MIPP_ "res= ",&res); +#endif + + ecurve_mult(_MIPP_ t,P,P); + ecap(_MIPP_ P,&Qx,&Qy,q,cf,&res); + +#ifndef MR_NO_STANDARD_IO + zzn3_out(_MIPP_ "res= ",&res); +#endif + +#ifndef MR_STATIC + memkill(_MIPP_ mem,18); + ecp_memkill(_MIPP_ mem1,1); +#else + memset(mem,0,MR_BIG_RESERVE(18)); /* clear this stack memory */ + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + return 0; +} + + diff --git a/miracl/source/curve/pairing/ake6mntt.cpp b/miracl/source/curve/pairing/ake6mntt.cpp new file mode 100644 index 0000000..94b393d --- /dev/null +++ b/miracl/source/curve/pairing/ake6mntt.cpp @@ -0,0 +1,551 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=5 ake6mntt.cpp zzn6.cpp ecn3.cpp zzn3.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + using COMBA build + + MNT Curve - Tate pairing + + The required file mnt.ecs is created from a curve generated by the mnt + utility, and created by the cm utility. For convenience the value of + (p^2-p+1)/q and the 6th root of unity (cnr^(p-1)/6) have been manually + calculated and appended to this file (replacing the x,y values in the + original .ecs file) + + NOTE: Irreducible polynomial MUST be of the form x^6+CNR. This excludes many of the curves + found using the mnt utility! + + Use the irred utility + + Modified to prevent sub-group confinement attack + + NOTE: Key exchange bandwidth could be reduced further using ideas from + "Doing more with Fewer Bits", Brouwer, Pellikaan & Verheul, Asiacrypt + '99 + + Speeded up using ideas from + "Efficient Computation of Tate Pairing in Projective Coordinate over General Characteristic Fields" + by Sanjit Chatterjee1, Palash Sarkar1 and Rana Barua1 + +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn3.h" +#include "zzn6.h" + +// fix a couple of things for this particular curve +// cofactor - number of points on curve=CF.q +// Cubic non-residue mod p + +#define CF 2 +#define CNR 2 // irreducible is x^6-2 + +using namespace std; + +Miracl precision(5,0); + +#ifdef MR_COUNT_OPS +extern "C" +{ + int fpc,fpa,fpx,fpm2,fpi2; +} +#endif + +// Using SHA-1 as basic hash algorithm + +#define HASH_LEN 20 + +// +// Define one or the other of these +// +// Which is faster depends on the I/M ratio - See imratio.c +// Roughly if I/M ratio > 16 use PROJECTIVE, otherwise use AFFINE +// + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +#ifdef PROJECTIVE +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} +#endif + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn6 line(ECn& A,ECn& C,ECn& B,int type,ZZn& slope,ZZn& ex1,ZZn& ex2,ZZn3& Qx,ZZn3& Qy) +{ + ZZn6 w; +#ifdef AFFINE + ZZn3 nn=Qx; + ZZn x,y; + extract(A,x,y); + nn-=x; + nn*=slope; + nn+=y; + w.set(-nn,Qy); +#endif +#ifdef PROJECTIVE + if (type==MR_ADD) + { + ZZn x2,y2,x3,z3; + extract(B,x2,y2); + extract(C,x3,x3,z3); + w.set(slope*(Qx-x2)+z3*y2,-z3*Qy); + } + if (type==MR_DOUBLE) + { + ZZn x,y,x3,z3; + extract(A,x,y); + extract(C,x3,x3,z3); + w.set((slope*ex2)*Qx-slope*x+ex1,-(z3*ex2)*Qy); + } +/* extract(A,x,y,z); + x*=z; t=z; z*=z; z*=t; + x*=slope; t=slope*z; + nn*=t; nn-=x; t=z; + extract(C,x,x,z); + nn+=(z*y); t*=z; + w.set(nn,-Qy*t); +*/ +#endif + return w; +} + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn6 g(ECn& A,ECn& B,ZZn3& Qx,ZZn3& Qy) +{ + ZZn lam,extra1,extra2; + int type; + ZZn6 u; + big ptr,ex1,ex2; + ECn P=A; + +// Evaluate line from A + type=A.add(B,&ptr,&ex1,&ex2); + if (!type) return (ZZn6)1; + lam=ptr; + extra1=ex1; + extra2=ex2; + return line(P,A,B,type,lam,extra1,extra2,Qx,Qy); +} + +// +// Tate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order m.q. +// Note that P is a point on the curve over Fp, Q(x,y) a point on the +// twisted curve over the extension field Fp^3 +// + +BOOL fast_tate_pairing(ECn& P,ZZn3& Qx,ZZn3& Qy,Big& q,Big &cf,ZZn6& res) +{ + int i,j,n,nb,nbw,nzs; + ECn A,P2,t[8]; + ZZn6 w,hc,z2n,zn[8]; + + res=zn[0]=1; + + t[0]=P2=A=P; + z2n=g(P2,P2,Qx,Qy); + + normalise(P2); +// +// Build windowing table +// + + for (i=1;i<8;i++) + { + hc=g(A,P2,Qx,Qy); + t[i]=A; + zn[i]=z2n*zn[i-1]*hc; + } + + multi_norm(8,t); // make t points Affine + + A=P; // reset A + nb=bits(q); + + for (i=nb-2;i>=0;i-=(nbw+nzs)) + { + n=window(q,i,&nbw,&nzs,4); // standard MIRACL windowing + + for (j=0;j0) + { + res*=zn[n/2]; + res*=g(A,t[n/2],Qx,Qy); + } + + for (j=0;j=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn3 x) +{ // Hash an Fp3 to a big number + sha sh; + ZZn u,v,w; + Big a,h,p,xx[3]; + char s[HASH_LEN]; + int i,j,m; + + shs_init(&sh); + x.get(u,v,w); + xx[0]=u; xx[1]=v; xx[2]=w; + for (i=0;i<3;i++) + { + a=xx[i]; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + } + shs_hash(&sh,s); + h=from_binary(HASH_LEN,s); + return h; +} + +// Hash and map a Server Identity to a curve point E_(Fp3) + +ECn3 hash_and_map3(char *ID) +{ + int i; + ECn3 S; + ZZn3 X; + + Big x0=H1(ID); + forever + { + x0+=1; + X.set2((ZZn)x0); + if (!S.set(X)) continue; + + break; + } + +// cout << "S= " << S << endl; + return S; +} + +// Hash and map a Client Identity to a curve point E_(Fp) of order q + +ECn hash_and_map(char *ID) +{ + ECn Q; + Big x0=H1(ID); + + while (!Q.set(x0,x0)) x0+=1; + Q*=CF; + return Q; +} + +// Use Galbraith & Scott Homomorphism idea + +ZZn3 mypow(ZZn6& res,Big &e,Big &T) +{ + ZZn6 w=res; + ZZn3 ra,rp,r=real(res); + Big e0,e1; + e0=e%T; e1=e/T; + w.powq(); rp=real(w); w/=res; ra=real(w); +// Use GLV method, and double exponentiation a la Lucas (see ZZn3.cpp) + return powl(rp,e1,r,e0,ra); +} + +int main() +{ + ifstream common("mnt.ecs"); // MNT elliptic curve parameters + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn3 B6,Server,sS; + ZZn3 sp,ap,bp; + ZZn6 res; + Big a,b,s,ss,p,q,x,y,B,cf,cfp,t,sru,T; + int i,bits,A; + time_t seed; + + common >> bits; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B >> q >> cf >> sru; + + T=p-q*CF; + + time(&seed); + irand((long)seed); + +#ifdef AFFINE + ecurve(A,B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(A,B,p,MR_PROJECTIVE); +#endif + + set_zzn3(CNR,sru); + cfp=cf-CF*p; // ~ (t-1) + + mip->IOBASE=16; + mip->TWIST=MR_QUADRATIC; // map Server to point on twisted curve E(Fp3) + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + Server=hash_and_map3((char *)"Server"); + sS=ss*Server; + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice"); + Bob= hash_and_map((char *)"Robert"); + + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + if (!ecap(sA,Server,q,cfp,res)) cout << "Trouble" << endl; + + if (powl(real(res),q)!=(ZZn3)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } +// ap=powl(real(res),a); + ap=mypow(res,a,T); + +//for (i=0;i<10000;i++) + if (!ecap(Alice,sS,q,cfp,res)) cout << "Trouble" << endl; + if (powl(real(res),q)!=(ZZn3)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } +// sp=powl(real(res),s); + sp=mypow(res,s,T); + + cout << "Alice Key= " << H2(powl(sp,a)) << endl; + cout << "Server Key= " << H2(powl(ap,s)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!ecap(sB,Server,q,cfp,res)) cout << "Trouble" << endl; + if (powl(real(res),q)!=(ZZn3)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=powl(real(res),b); + + if (!ecap(Bob,sS,q,cfp,res)) cout << "Trouble" << endl; + if (powl(real(res),q)!=(ZZn3)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=powl(real(res),s); + + cout << "Bob's Key= " << H2(powl(sp,b)) << endl; + cout << "Server Key= " << H2(powl(bp,s)) << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/ake6mntx.cpp b/miracl/source/curve/pairing/ake6mntx.cpp new file mode 100644 index 0000000..905c2d2 --- /dev/null +++ b/miracl/source/curve/pairing/ake6mntx.cpp @@ -0,0 +1,625 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=5 ake6mntx.cpp zzn6a.cpp ecn3.cpp zzn3.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + using COMBA build + + MNT Curve - Tate pairing + + Thanks to Drew Sutherland for providing the MNT curve + + Irreducible binomial MUST be of the form x^6+2. This excludes many of the curves + found using the mnt utility! + + Modified to prevent sub-group confinement attack + + NOTE: Key exchange bandwidth could be reduced further using ideas from + "Doing more with Fewer Bits", Brouwer, Pellikaan & Verheul, Asiacrypt + '99 + + NOTE: This version uses a "compositum". That is the ZZn6 class is a cubic tower over ZZn2, but can + also be considered as a quadratic tower over ZZn3. The routine shuffle converts from one form to the other. + The former is fastest for ZZn6 arithmetic, the latter form is required for handling the second parameter + to the pairing, which is on the quadratic twist E(Fp3) + +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn3.h" +#include "zzn6a.h" + +Miracl precision(5,0); + +#ifdef MR_COUNT_OPS +extern "C" +{ + int fpc,fpa,fpx,fpm2,fpi2; +} +#endif + +// Using SHA-1 as basic hash algorithm + +#define HASH_LEN 20 + +// +// Define one or the other of these +// +// Which is faster depends on the I/M ratio - See imratio.c +// Roughly if I/M ratio > 16 use PROJECTIVE, otherwise use AFFINE +// + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +#ifdef PROJECTIVE +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} +#endif + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + X.set((Big)0,(Big)1); // = (sqrt(-2)^(p-1)/2 + break; + case 3: // = (1+sqrt(-1))^(p-1)/2 + X.set((Big)1,(Big)1); + break; + case 7: + X.set((Big)2,(Big)1); // = (2+sqrt(-1))^(p-1)/2 + default: break; + } + X=pow(X,(p-1)/3); +} + +ZZn6 shuffle(const ZZn3 &first, const ZZn3 &second) +{ // shuffle from a pair ZZn3's to three ZZn2's, as required by ZZn6 + ZZn6 w; + ZZn x0,x1,x2,x3,x4,x5; + ZZn2 t0,t1,t2; + first.get(x0,x2,x4); + second.get(x1,x3,x5); + t0.set(x0,x3); + t1.set(x1,x4); + t2.set(x2,x5); + w.set(t0,t1,t2); + return w; +} + +void unshuffle(ZZn6 &S,ZZn3 &first,ZZn3 &second) +{ // unshuffle a ZZn6 into two ZZn3's + ZZn x0,x1,x2,x3,x4,x5; + ZZn2 t0,t1,t2; + S.get(t0,t1,t2); + t0.get(x0,x3); + t1.get(x1,x4); + t2.get(x2,x5); + first.set(x0,x2,x4); + second.set(x1,x3,x5); +} + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn6 line(ECn& A,ECn& C,ECn& B,int type,ZZn& slope,ZZn& ex1,ZZn& ex2,ZZn3& Qx,ZZn3& Qy) +{ + ZZn6 w; +#ifdef AFFINE + ZZn3 nn=Qx; + ZZn x,y; + extract(A,x,y); + nn-=x; + nn*=slope; + nn+=y; + nn=-nn; + w=shuffle(nn,Qy); + +#endif +#ifdef PROJECTIVE + if (type==MR_ADD) + { + ZZn x2,y2,x3,z3; + extract(B,x2,y2); + extract(C,x3,x3,z3); + w=shuffle(slope*(Qx-x2)+z3*y2,-z3*Qy); + } + if (type==MR_DOUBLE) + { + ZZn x,y,x3,z3; + extract(A,x,y); + extract(C,x3,x3,z3); + w=shuffle((slope*ex2)*Qx-slope*x+ex1,-(z3*ex2)*Qy); + } + +#endif + return w; +} + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn6 g(ECn& A,ECn& B,ZZn3& Qx,ZZn3& Qy) +{ + ZZn lam,extra1,extra2; + int type; + big ptr,ex1,ex2; + ECn P=A; + +// Evaluate line from A + type=A.add(B,&ptr,&ex1,&ex2); + if (!type) return (ZZn6)1; + lam=ptr; + extra1=ex1; + extra2=ex2; + return line(P,A,B,type,lam,extra1,extra2,Qx,Qy); +} + +// +// Tate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order m.q. +// Note that P is a point on the curve over Fp, Q(x,y) a point on the +// twisted curve over the extension field Fp^3 +// + +#define WINDOW_SIZE 4 +#define PRECOMP (1<<(WINDOW_SIZE-1)) + +BOOL fast_tate_pairing(ECn& P,ZZn3& Qx,ZZn3& Qy,Big &x,ZZn2& X,ZZn6& res) +{ + int i,j,n,nb,nbw,nzs; + ECn A,P2,t[PRECOMP]; + ZZn6 w,hc,z2n,zn[PRECOMP]; + Big q=x*x-x+1; + + res=zn[0]=1; + + t[0]=P2=A=P; + z2n=g(P2,P2,Qx,Qy); // P2=P+P + normalise(P2); +// +// Build windowing table +// + for (i=1;i=0;i--) + { + res*=res; + res*=g(A,A,Qx,Qy); + if (bit(q,i)==1) + res*=g(A,P,Qx,Qy); + if (res.iszero()) return FALSE; + } +*/ + + A=P; // reset A + nb=bits(q); + for (i=nb-2;i>=0;i-=(nbw+nzs)) + { // windowing helps a little.. + n=window(q,i,&nbw,&nzs,WINDOW_SIZE); // standard MIRACL windowing + for (j=0;j0) + { + res*=zn[n/2]; + res*=g(A,t[n/2],Qx,Qy); + } + + for (j=0;jcnr; + + normalise(PP); + Q.get(Qx,Qy); + +// untwist + Qx=Qx/qnr; + Qy=tx(Qy); + Qy=Qy/(qnr*qnr); + +#ifdef MR_COUNT_OPS +fpc=fpa=fpx=0; +#endif + + Ok=fast_tate_pairing(PP,Qx,Qy,x,X,res); + +#ifdef MR_COUNT_OPS +printf("After pairing fpc= %d fpa= %d fpx= %d\n",fpc,fpa,fpx); +fpa=fpc=fpx=0; +#endif + + if (Ok) return TRUE; + return FALSE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha sh; + + shs_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs_process(&sh,string[i]); + } + shs_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H2(ZZn6 y) +{ // Hash and compress an Fp6 to a big number + sha sh; + ZZn u,v,w; + ZZn2 x; + Big a,h,p,xx[2]; + char s[HASH_LEN]; + int i,j,m; + + shs_init(&sh); + y.get(x); + x.get(u,v); + xx[0]=u; xx[1]=v; + + for (i=0;i<2;i++) + { + a=xx[i]; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + } + shs_hash(&sh,s); + h=from_binary(HASH_LEN,s); + return h; +} + +// Hash and map a Server Identity to a curve point E_(Fp3) + +ECn3 hash_and_map3(char *ID) +{ + int i; + ECn3 S; + ZZn3 X; + + Big x0=H1(ID); + forever + { + x0+=1; + X.set2((ZZn)x0); + if (!S.set(X)) continue; + + break; + } + +// cout << "S= " << S << endl; + return S; +} + +// Hash and map a Client Identity to a curve point E_(Fp) of order q + +ECn hash_and_map(char *ID) +{ + ECn Q; + Big x0=H1(ID); + + while (!Q.set(x0,x0)) x0+=1; + + return Q; +} + +BOOL member(ZZn6 r,Big &x,ZZn2 &X) +{ // check its an element of order q + ZZn6 w=r; + w.powq(X); + if (x<0) r=powu(inverse(r),-x); + else r=powu(r,x); + if (r==w) return TRUE; + return FALSE; +} + +void q_power_frobenius(ECn3 &S,ZZn2& X) +{ + ZZn6 X1,X2,Y1,Y2; + ZZn3 Sx,Sy,T; + + int qnr=get_mip()->cnr; + + S.get(Sx,Sy); + + // untwist + Sx=Sx/qnr; + Sy=tx(Sy); + Sy=Sy/(qnr*qnr); + + X1=shuffle(Sx,(ZZn3)0); Y1=shuffle((ZZn3)0,Sy); + X1.powq(X); Y1.powq(X); + unshuffle(X1,Sx,T); unshuffle(Y1,T,Sy); + + // twist + Sx=qnr*Sx; + Sy=txd(Sy*qnr*qnr); + S.set(Sx,Sy); +} + +// Use Scott et al. idea - http://eprint.iacr.org/2008/530.pdf + +void cofactor(ECn3 &S,Big &x, ZZn2& X) +{ // S=Phi(2xP)+phi^2(2xP) + ZZn6 X1,X2,Y1,Y2; + ZZn3 Sx,Sy,T; + ECn3 S2; + int qnr=get_mip()->cnr; + + S*=x; S+=S; // hard work done here + + S.get(Sx,Sy); + + // untwist + Sx=Sx/qnr; + Sy=tx(Sy); + Sy=Sy/(qnr*qnr); + + X1=shuffle(Sx,(ZZn3)0); Y1=shuffle((ZZn3)0,Sy); + X1.powq(X); Y1.powq(X); + X2=X1; Y2=Y1; + X2.powq(X); Y2.powq(X); + unshuffle(X1,Sx,T); unshuffle(Y1,T,Sy); + + // twist + Sx=qnr*Sx; + Sy=txd(Sy*qnr*qnr); + S.set(Sx,Sy); + unshuffle(X2,Sx,T); unshuffle(Y2,T,Sy); + + //twist (again, like we did last summer...) + Sx=qnr*Sx; + Sy=txd(Sy*qnr*qnr); + S2.set(Sx,Sy); + S+=S2; +} + +// GLV + Galbraith-Scott + +ZZn6 GT_pow(ZZn6& u,Big& k,Big& x,ZZn2& X) +{ + ZZn6 v=u; + v.powq(X); + v=powu(v,k/x,u,k%x); + return v; +} + +ECn3 G2_mul(ECn3& P,Big& k,Big& x,ZZn2& X) +{ + ECn3 V=P; + q_power_frobenius(V,X); + V=mul(V,k/x,P,k%x); + return V; +} + +int main() +{ + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn3 B6,Server,sS; + ZZn6 sp,ap,bp; + ZZn6 res; + ZZn2 X; + Big a,b,s,ss,p,q,x,y,B,cf,t,sru,T; + int i,A; + time_t seed; + + mip->IOBASE=16; + x="-D285DA0CFEF02F06F812"; // MNT elliptic curve parameters (Thanks to Drew Sutherland) + p=x*x+1; + q=x*x-x+1; + t=x+1; + cf=x*x+x+1; + + T=t-1; +// cout << "t-1= " << T << endl; +// cout << "p%24= " << p%24 << endl; + + time(&seed); + irand((long)seed); + + A=-3; + B="77479D33943B5B1F590B54258B72F316B3261D45"; + +#ifdef AFFINE + ecurve(A,B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(A,B,p,MR_PROJECTIVE); +#endif + + set_frobenius_constant(X); + sru=pow((ZZn)-2,(p-1)/6); // x^6+2 is irreducible + set_zzn3(-2,sru); + + mip->IOBASE=16; + mip->TWIST=MR_QUADRATIC; // map Server to point on twisted curve E(Fp3) + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + Server=hash_and_map3((char *)"Server"); + cofactor(Server,x,X); + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice"); + Bob= hash_and_map((char *)"Robert"); + + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=G2_mul(Server,ss,x,X); + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + if (!ecap(sA,Server,x,X,res)) cout << "Trouble" << endl; + + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + ap=GT_pow(res,a,x,X);//powu(res,a); + + if (!ecap(Alice,sS,x,X,res)) cout << "Trouble" << endl; + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + + sp=GT_pow(res,s,x,X); + + cout << "Alice Key= " << H2(powu(sp,a)) << endl; + cout << "Server Key= " << H2(powu(ap,s)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!ecap(sB,Server,x,X,res)) cout << "Trouble" << endl; + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + bp=GT_pow(res,b,x,X); + + if (!ecap(Bob,sS,x,X,res)) cout << "Trouble" << endl; + if (!member(res,x,X)) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } + sp=GT_pow(res,s,x,X); + + cout << "Bob's Key= " << H2(powu(sp,b)) << endl; + cout << "Server Key= " << H2(powu(bp,s)) << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/ake8bwt.cpp b/miracl/source/curve/pairing/ake8bwt.cpp new file mode 100644 index 0000000..ad10dc0 --- /dev/null +++ b/miracl/source/curve/pairing/ake8bwt.cpp @@ -0,0 +1,520 @@ +/* + + Scott's AKE Client/Server testbed + + See http://eprint.iacr.org/2002/164 + + Compile as + cl /O2 /GX /DZZNS=8 ake8bwt.cpp zzn8.cpp zzn4.cpp zzn2.cpp ecn4.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + Fastest using COMBA build for 256-bit mod-mul + + Brezing-Weng Curve - Tate pairing + + The file weng.ecs is required. + This curve was constructed using the method described in + http://eprint.iacr.org/2003/143/ + + Security is 192/2048 + + Modified to prevent sub-group confinement attack + + NOTE: assumes p = 5 mod 8, p is 256-bits + + **** NEW **** Based on the observation by R. Granger and D. Page and N.P. Smart in "High Security + Pairing-Based Cryptography Revisited" that multi-exponentiation can be used for the final exponentiation + of the Tate pairing, we suggest the Power Pairing, which calculates E(P,Q,e) = e(P,Q)^e, where the + exponentiation by e is basically for free, as it can be folded into the multi-exponentiation. + + NOTE: Irreducible polynomial is x^8+2 : p = 5 mod 8 + +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn4.h" +#include "zzn8.h" + +using namespace std; + +Miracl precision(8,0); + +// Using SHA-1 as basic hash algorithm + +#define HASH_LEN 20 + +// +// Define one or the other of these +// +// Which is faster depends on the I/M ratio - See imratio.c +// Roughly if I/M ratio > 16 use PROJECTIVE, otherwise use AFFINE +// + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +#ifdef PROJECTIVE +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} +#endif + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn8 line(ECn& A,ECn& C,ZZn& slope,ZZn4& Qx,ZZn4& Qy) +{ + ZZn8 w; + ZZn4 m=Qx; + ZZn x,y,z,t; +#ifdef AFFINE + extract(A,x,y); + m-=x; m*=slope; + w.set((ZZn4)-y,Qy); w-=m; +#endif +#ifdef PROJECTIVE + extract(A,x,y,z); + x*=z; t=z; z*=z; z*=t; + + x*=slope; t=slope*z; + m*=t; m-=x; t=z; + extract(C,x,x,z); + m+=(z*y); t*=z; + w.set(m,-Qy*t); + +#endif + return w; +} + +// +// Add A=A+B (or A=A+A) +// Bump up num +// + +void g(ECn& A,ECn& B,ZZn4& Qx,ZZn4& Qy,ZZn8& num,BOOL first) +{ + int type; + ZZn lam; + ZZn8 u; + big ptr; + ECn P=A; + +// Evaluate line from A + + type=A.add(B,&ptr); + if (!type) return; + + lam=ptr; + u=line(P,A,lam,Qx,Qy); + if (first) num= u; + else num*=u; +} + +// +// Tate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order m.q. +// Note that P is a point on the curve over Fp, Q(x,y) a point on the +// extension field Fp^4 +// +// New! Power Pairing calculates E(P,Q,e) = e(P,Q)^e at no extra cost! +// +// + +BOOL power_tate(ECn& P,ECn4 Q,Big& q,Big *cf,ZZn2 &Fr,Big &e,ZZn4& r) +{ + int i,nb,j,n,nbw,nzs; + ECn A,P2,t[8]; + ZZn8 w,res,hc,z2n,zn[8],a[4]; + ZZn4 Qx,Qy; + ZZn2 x,y; + Big p=get_modulus(); + Big carry,ex[4]; + + Q.get(Qx,Qy); + // convert from twist + Qx=tx(Qx); + Qx.get(x,y); + Qx.set(tx(x),tx(y)); + Qx=-Qx/2; // Qx=-2.i^6.Qx, i is 8th root of -2 + Qy.get(x,y); + Qy.set(tx(x),tx(y)); + Qy=-Qy/2; // Qy=-2.i^4.Qx + + res=zn[0]=1; + +/* Left to right method */ + t[0]=P2=A=P; + + g(P2,P2,Qx,Qy,z2n,TRUE); + + normalise(P2); + + for (i=1;i<8;i++) + { + g(A,P2,Qx,Qy,hc,TRUE); + t[i]=A; + zn[i]=z2n*zn[i-1]*hc; + } + + multi_norm(8,t); + A=P; + + nb=bits(q); + + for (i=nb-2;i>=0;i-=(nbw+nzs)) + { + n=window(q,i,&nbw,&nzs,4); + for (j=0;j0) + { + res*=zn[n/2]; + g(A,t[n/2],Qx,Qy,res,FALSE); + } + for (j=0;j=0;i--) + carry=mad(cf[i],e,carry,p,ex[i]); + } + + res=pow(4,a,ex); + r=real(res); // compression + + // r=powl(real(res),cf[0]*p*p*p+cf[1]*p*p+cf[2]*p+cf[3]); // ^(p*p*p*p+1)/q + + if (r.isunity()) return FALSE; + return TRUE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha sh; + + shs_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs_process(&sh,string[i]); + } + shs_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H4(ZZn4 x) +{ // Hash an Fp2 to a big number + sha sh; + Big a,u,v; + ZZn2 X,Y; + char s[HASH_LEN]; + int m; + + shs_init(&sh); + x.get(X,Y); + + X.get(u,v); + + a=u; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + a=v; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + + Y.get(u,v); + + a=u; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + a=v; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + shs_hash(&sh,s); + a=from_binary(HASH_LEN,s); + return a; +} + +// Hash and map a Server Identity to a curve point E(Fp4) + +ECn4 hash4(char *ID) +{ + ECn4 T; + ZZn4 x; + ZZn2 X,Y; + Big x0,y0; + + x0=y0=1; + X.set(x0,y0); + + y0=1; + x0=H1(ID); + do + { + Y.set(x0,y0); + x.set(X,Y); + x0+=1; + } + while (!is_on_curve(x)) ; + T.set(x); + +// while (!T.set(x)); + return T; +} + +// Hash and map a Client Identity to a curve point E(Fp) + +ECn hash_and_map(char *ID,Big cof) +{ + ECn Q; + Big x0=H1(ID); + + while (!is_on_curve(x0)) x0+=1; + Q.set(x0); // Make sure its on E(F_p) + + Q*=cof; + return Q; +} + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + X.set((Big)0,(Big)1); // = (sqrt(sqrt(-2))^(p-1)/4 + X=pow(X,(p-1)/4); + break; + case 3: + X.set((Big)1,(Big)1); + X=pow(X,(p-3)/4); + break; + case 7: + X.set((Big)2,(Big)1); + X=pow(X,(p-3)/4); // note that 4 does not divide p-1, so this is the best we can do... + default: break; + } +} + +int main() +{ + ifstream common("weng.ecs"); // elliptic curve parameters + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn4 Server,sS; + ZZn4 res,sp,ap,bp; + ZZn2 Fr; + Big a,b,s,ss,p,q,r,B,cof,t,ii; + int i,bitz,A; + time_t seed; + Big cf[4]; + + cout << "Started" << endl; + common >> bitz; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B; + common >> cof; + common >> q; + common >> cf[0]; + common >> cf[1]; + common >> cf[2]; + common >> cf[3]; + + cout << "Initialised... " << p%24 << endl; + +// cout << "ham(q)= " << ham(q) << endl; + +// q*=(Big)"5B51"; + +// cout << "q= " << q << endl; +/* +ii=1; +forever +{ + t=ii*q; + t=4*t-3; + if (sqrt(t)*sqrt(t)==t) break; + ii=ii+1; +} +cout << "ii= " << ii << endl; +*/ + time(&seed); + irand((long)seed); + +#ifdef AFFINE + ecurve(A,B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(A,B,p,MR_PROJECTIVE); +#endif + + set_frobenius_constant(Fr); + + mip->IOBASE=16; + mip->TWIST=MR_QUADRATIC; // map Server to point on twisted curve E(Fp2) + +// hash Identities to curve point + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + Server=hash4((char *)"Server"); + + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice",cof); + + Bob= hash_and_map((char *)"Robert",cof); + + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=ss*Server; + + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + if (!power_tate(sA,Server,q,cf,Fr,a,res)) cout << "Trouble" << endl; + + if (powl(res,q)!=(ZZn4)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } +// ap=powl(res,a); + ap=res; + + if (!power_tate(Alice,sS,q,cf,Fr,s,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn4)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } +// sp=powl(res,s); + sp=res; + + cout << "Alice Key= " << H4(powl(sp,a)) << endl; + cout << "Server Key= " << H4(powl(ap,s)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!power_tate(sB,Server,q,cf,Fr,b,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn4)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } +// bp=powl(res,b); + bp=res; + + if (!power_tate(Bob,sS,q,cf,Fr,s,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn4)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } +// sp=powl(res,s); + sp=res; + + cout << "Bob's Key= " << H4(powl(sp,b)) << endl; + cout << "Server Key= " << H4(powl(bp,s)) << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/ake8cpt.cpp b/miracl/source/curve/pairing/ake8cpt.cpp new file mode 100644 index 0000000..f741714 --- /dev/null +++ b/miracl/source/curve/pairing/ake8cpt.cpp @@ -0,0 +1,451 @@ +/* + Scott's AKE Client/Server testbed + + See http://www.compapp.dcu.ie/research/CA_Working_Papers/wp02.html#0202 + + Compile as + cl /O2 /GX /DZZNS=16 ake8cpt.cpp zzn8.cpp zzn4.cpp zzn2.cpp ecn4.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + Fastest using COMBA build for 512-bit mod-mul + + Cocks-Pinch Curve - Tate pairing + + The file k8.ecs is required + Security is G224/F4096 (224-bit group, 4096-bit field) + + Modified to prevent sub-group confinement attack + + **** NEW **** Based on the observation by R. Granger and D. Page and N.P. Smart in "High Security + Pairing-Based Cryptography Revisited" that multi-exponentiation can be used for the final exponentiation + of the Tate pairing, we suggest the Power Pairing, which calculates E(P,Q,e) = e(P,Q)^e, where the + exponentiation by e is basically for free, as it can be folded into the multi-exponentiation. + +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn4.h" +#include "zzn8.h" + +using namespace std; + +Miracl precision(16,0); + +// Using SHA-1 as basic hash algorithm + +#define HASH_LEN 20 + +// +// Define one or the other of these +// +// Which is faster depends on the I/M ratio - See imratio.c +// Roughly if I/M ratio > 16 use PROJECTIVE, otherwise use AFFINE +// + +#ifdef MR_AFFINE_ONLY + #define AFFINE +#else + #define PROJECTIVE +#endif + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +#ifdef PROJECTIVE +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} +#endif + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn8 line(ECn& A,ECn& C,ZZn& slope,ZZn4& Qx,ZZn4& Qy) +{ + ZZn8 w; + ZZn4 m=Qx; + ZZn x,y,z,t; +#ifdef AFFINE + extract(A,x,y); + m-=x; m*=slope; + w.set((ZZn4)-y,Qy); w-=m; +#endif +#ifdef PROJECTIVE + extract(A,x,y,z); + x*=z; t=z; z*=z; z*=t; + + x*=slope; t=slope*z; + m*=t; m-=x; t=z; + extract(C,x,x,z); + m+=(z*y); t*=z; + w.set(m,-Qy*t); + +#endif + return w; +} + +// +// Add A=A+B (or A=A+A) +// Bump up num +// + +ZZn8 g(ECn& A,ECn& B,ZZn4& Qx,ZZn4& Qy) +{ + int type; + ZZn lam; + big ptr; + ECn P=A; + +// Evaluate line from A + type=A.add(B,&ptr); + if (!type) return (ZZn8)1; + + lam=ptr; + return line(P,A,lam,Qx,Qy); +} + +// +// Tate Pairing - note denominator elimination has been applied +// +// P is a point of order q. Q(x,y) is a point of order m.q. +// Note that P is a point on the curve over Fp, Q(x,y) a point on the +// extension field Fp^2 +// +// New! Power Pairing calculates E(P,Q,e) = e(P,Q)^e at no extra cost! +// + +BOOL power_tate(ECn& P,ECn4 Q,Big& q,Big *cf,ZZn2 &Fr,Big &e,ZZn4& r) +{ + int i,nb; + ECn A; + ZZn8 w,res,a[4]; + ZZn4 Qx,Qy; + ZZn2 x,y; + Big carry,ex[4]; + Big p=get_modulus(); + + Q.get(Qx,Qy); + Qx=txd(Qx); + Qy=txd(txd(Qy)); + + res=1; + +/* Left to right method */ + A=P; + nb=bits(q); + + for (i=nb-2;i>=0;i--) + { + res*=res; + res*=g(A,A,Qx,Qy); + if (bit(q,i)) + res*=g(A,P,Qx,Qy); + + } + + if (!A.iszero() || res.iszero()) return FALSE; + w=res; + + w.powq(Fr); w.powq(Fr); // ^(p^4-1) + w.powq(Fr); w.powq(Fr); + + res=w/res; + + res.mark_as_unitary(); + + a[3]=res; + a[2]=a[3]; a[2].powq(Fr); + a[1]=a[2]; a[1].powq(Fr); + a[0]=a[1]; a[0].powq(Fr); + + if (e.isone()) for (i=0;i<4;i++) ex[i]=cf[i]; + else + { // cf *= e + carry=0; + for (i=3;i>=0;i--) + carry=mad(cf[i],e,carry,p,ex[i]); + } + + res=pow(4,a,ex); + r=real(res); // compression + +// r=powl(real(res),cf); // ^(p*p*p*p+1)/q + + if (r.isunity()) return FALSE; + return TRUE; +} + +// +// Hash functions +// + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha sh; + + shs_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs_process(&sh,string[i]); + } + shs_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +Big H4(ZZn4 x) +{ // Hash an Fp2 to a big number + sha sh; + Big a,u,v; + ZZn2 X,Y; + char s[HASH_LEN]; + int m; + + shs_init(&sh); + x.get(X,Y); + + X.get(u,v); + + a=u; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + a=v; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + + Y.get(u,v); + + a=u; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + a=v; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + shs_hash(&sh,s); + a=from_binary(HASH_LEN,s); + return a; +} + +// Hash and map a Server Identity to a curve point E(Fp4) + +ECn4 hash4(char *ID) +{ + ECn4 T; + ZZn4 x; + ZZn2 X,Y=0; + Big x0,y0=0; + + x0=H1(ID); + do + { + X.set(x0,y0); + x.set(X,Y); + x0+=1; + } + while (!is_on_curve(x)); + T.set(x); + return T; +} + +// Hash and map a Client Identity to a curve point E(Fp) + +ECn hash_and_map(char *ID,Big cof) +{ + ECn Q; + Big x0=H1(ID); + + while (!is_on_curve(x0)) x0+=1; + Q.set(x0); // Make sure its on E(F_p) + + Q*=cof; + return Q; +} + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + X.set((Big)0,(Big)1); // = (sqrt(sqrt(-2))^(p-1)/4 + X=pow(X,(p-1)/4); + break; + case 3: + X.set((Big)1,(Big)1); + X=pow(X,(p-3)/4); + break; + case 7: + X.set((Big)2,(Big)1); + X=pow(X,(p-3)/4); // note that 4 does not divide p-1, so this is the best we can do... + default: break; + } +} + +int main() +{ + ifstream common("k8.ecs"); // elliptic curve parameters + miracl* mip=&precision; + ECn Alice,Bob,sA,sB; + ECn4 Server,sS; + ZZn4 res,sp,ap,bp; + ZZn2 Fr; + Big a,b,s,ss,p,q,B,cof; + Big cf[4]; + int i,bitz,A; + time_t seed; + + cout << "Started" << endl; + common >> bitz; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B; + common >> cof; // #E/q + common >> q; // low hamming weight q + common >> cf[0]; // [(p^4+1)/q]/(p*p*p) + common >> cf[1]; // [(p^4+1)/q]/(p*p) + common >> cf[2]; // [(p^4+1)/q]/p + common >> cf[3]; // [(p^4+1)/q]%p + + cout << "Initialised... " << p%8 << endl; + + time(&seed); + irand((long)seed); + +#ifdef AFFINE + ecurve(A,B,p,MR_AFFINE); +#endif +#ifdef PROJECTIVE + ecurve(A,B,p,MR_PROJECTIVE); +#endif + + set_frobenius_constant(Fr); +//cout << "Fr= " << Fr << endl; + mip->IOBASE=16; + mip->TWIST=MR_QUADRATIC; // map Server to point on twisted curve E(Fp4) + +// hash Identities to curve point + + ss=rand(q); // TA's super-secret + + cout << "Mapping Server ID to point" << endl; + Server=hash4((char *)"Server"); + cout << "Mapping Alice & Bob ID's to points" << endl; + Alice=hash_and_map((char *)"Alice",cof); + + Bob= hash_and_map((char *)"Robert",cof); + + cout << "Alice, Bob and the Server visit Trusted Authority" << endl; + + sS=ss*Server; + + sA=ss*Alice; + sB=ss*Bob; + + cout << "Alice and Server Key Exchange" << endl; + + a=rand(q); // Alice's random number + s=rand(q); // Server's random number + + if (!power_tate(sA,Server,q,cf,Fr,a,res)) cout << "Trouble" << endl; + + if (powl(res,q)!=(ZZn4)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } +// ap=powl(res,a); + ap=res; + + if (!power_tate(Alice,sS,q,cf,Fr,s,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn4)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } +// sp=powl(res,s); + sp=res; + + cout << "Alice Key= " << H4(powl(sp,a)) << endl; + cout << "Server Key= " << H4(powl(ap,s)) << endl; + + cout << "Bob and Server Key Exchange" << endl; + + b=rand(q); // Bob's random number + s=rand(q); // Server's random number + + if (!power_tate(sB,Server,q,cf,Fr,b,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn4)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } +// bp=powl(res,b); + bp=res; + + if (!power_tate(Bob,sS,q,cf,Fr,s,res)) cout << "Trouble" << endl; + if (powl(res,q)!=(ZZn4)1) + { + cout << "Wrong group order - aborting" << endl; + exit(0); + } +// sp=powl(res,s); + sp=res; + + cout << "Bob's Key= " << H4(powl(sp,b)) << endl; + cout << "Server Key= " << H4(powl(bp,s)) << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/bandw.cpp b/miracl/source/curve/pairing/bandw.cpp new file mode 100644 index 0000000..30cab55 --- /dev/null +++ b/miracl/source/curve/pairing/bandw.cpp @@ -0,0 +1,563 @@ +// +// Program to find Brezing & Weng pairing friendly curves +// http://eprint.iacr.org/2003/143 +// +// Finds families of elliptic curves with groups of points of order r over the prime field p with +// embedding degree k, where k>2. The program tries to find curves with minimum rho=log(p)/log(r), +// as such curves may be optimal for fast implementation. The total number of points on the curve is +// p+1-t, where t is the trace. +// +// To get an actual curve, substitute for x, (ensure p(x) is prime and that r(x) has a large prime factor) +// and use the CM program to find actual curve parameters. +// +// This method is based on the fact that (t(x)-1) should be a k-th root of unity mod r(x), and r(x) +// only has k-th roots of unity if it is a divisor of phi_k(t(x)-1), as x^k=1 mod Phi_k(x) +// A simple way to generate t(x) and r(x) is to choose r(x) as Phi_{nk}(x) and then t(x)-1=x^n is a +// k-th root of unity. However this method is not exhaustive, and there could be better solutions. +// (That is there may be suitable r(x) which are not of the form Phi_{nk}(x), so these curves are not +// necessarily optimal). +// +// Omega indicates the degree of loop reduction possible compared to the Tate pairing, with the Ate +// or Eta pairing +// +// This program uses the NTL number theoretic library available from http://www.shoup.net/ntl/ +// +// Nov. 2007 - modified to search for the best Ate or Eta Omega +// +// Mike Scott (2007) +// + +#include +#include "NTL/ZZXFactoring.h" + +NTL_CLIENT +using namespace std; + +#define POWER +#define MAXK 64 +#define BM 10 // these limits have been tested as sufficient for K<=64 +#define BD 20 + +void output(ZZX& p) +{ + int i,leading=1; + ZZ c; + if (p==0) + { + cout << "0" << endl; + return; + } + int len=p.rep.length(); + + if (p.rep[0]!=0) + { + leading=0; + cout << p.rep[0]; + } + + if (len==1) return; + + c=p.rep[1]; + if (c<0) + { + c=-c; + cout << "-"; + } + else if (c>0 && !leading) + cout << "+"; + if (c!=0) + { + leading=0; + if (c==1) + cout << "x"; + else + cout << c << "*x"; + } + + if (len==2) return; + + for (i=2;i0 && !leading) + cout << "+"; + if (c!=0) + { + leading=0; + if (c!=1) cout << c << "*"; + if (i==2) cout << "x*x"; + else +#ifdef POWER + cout << "pow(x," << i << ")"; +#else + cout << "x^" << i; +#endif + } + } +} + +int outputfactors(ZZX &f) +{ + int i; + ZZ c; + vec_pair_ZZX_long factors; + factor(c,factors,f); + if (c!=1) cout << c << "."; + for (i=0;i1) cout << "^" << factors[i].b; + } + return factors.length(); +} + +// +// Composition. Give g(x) return f(x)=g(b(x)) +// + +ZZX compose(ZZX &g,ZZX &b) +{ + ZZX c; + int i,d=deg(g); + +// vec_ZZX table(INIT_SIZE,d+1); + ZZX table[100]; + table[0]=1; + for (i=1;i<=d;i++) table[i]=(table[i-1]*b); + clear(c); + + for (i=0;i<=d;i++) + { + c+=g.rep[i]*table[i]; + // table(i).kill(); + } + + return c; +} + +int omega(ZZX &p,ZZX &pkr) +{ // input phi(k)/r + ZZX t,f=pkr; + int biggest=0; + + while (deg(f)>=0) + { + t=f%p; + if (deg(t)>biggest) biggest=deg(t); + f/=p; + } + return biggest; +} + +// evaluate f(x) + +ZZ eval(ZZX &f,int x) +{ + ZZ y,xx; + y=0; + xx=1; + for (int i=0;i<=deg(f);i++) + { + y+=coeff(f,i)*xx; + xx*=x; + } + return y; +} + +unsigned int igcd(unsigned int x,unsigned int y) +{ /* integer GCD, returns GCD of x and y */ + unsigned int r; + if (y==0) return x; + while ((r=x%y)!=0) + x=y,y=r; + return y; +} + +// for given x evaluate f(x) mod m + +int evalmod(ZZX &f,int x,int m) +{ + int y,xx; + y=0; + xx=1; + for (int i=0;i<=deg(f);i++) + { + y+=(to_long(coeff(f,i))%m)*xx; + y%=m; + xx=(x*xx)%m; + } + if (y<0) y+=m; + + return y; +} + +// check if f(x)/m has integer solutions + +int solutions(ZZX &f,int m) +{ + int s=0; + for (int x=0;xd) break; + } + if (sqr) return 0; + return 1; +} + +// basis for prime p + +ZZX rib(long p,long n,ZZX& phi) +{ + int j; + ZZ r; + ZZX s,t,b; + ZZX zeta,z,iz,izeta,f,inf; + + b=1; + SetCoeff(zeta,n/p,1); + z=zeta; + + t=InvTrunc(phi,n/p); + izeta=(1-phi*t)/zeta; + iz=izeta; + + for (j=1;j<=(p-1)/2;j++) + { + b=MulMod(b,(z-iz)%phi,phi); + z*=zeta; + iz*=izeta; + } + return b; +} + +// +// square root of -d in Q(x), D is negative +// Murphy & Fitzpatrick +// http://eprint.iacr.org/2005/302 +// + +int sqrt(ZZX& r,long n,long d,ZZX& phi) +{ + long p,dd; + ZZX zeta4,zeta8; + if (d<=0 || (d>1 && n%d!=0)) return 0; + if (d%2==0 && n%8!=0) return 0; + if (d%4!=3 && n%4!=0) return 0; + + if (n%4==0) {SetCoeff(zeta4,n/4,1);zeta4%=phi;} + if (n%8==0) {SetCoeff(zeta8,n/8,1);zeta8%=phi;} + + if (d==1) + { + r=zeta4; + return 1; + } + + r=1; + dd=d; + for (p=2;p<=dd;p++) + { + if (d%p!=0) continue; + dd/=p; + if (p==2) + { + r=MulMod(zeta8,r,phi); + r=MulMod((1+zeta4),r,phi); + } + else + { + r=MulMod(rib(p,n,phi),r,phi); + } + } + if (d%4==1) r=MulMod(zeta4,r,phi); + if (d%2==0 && (4-(d/2)%4)%4==1) r=MulMod(zeta4,r,phi); + + return 1; +} + +int main(int argc,char **argv) +{ + int nn,i,j,m,K,mode,min_K,max_K,fp,fast; + long ww,d,W,x,bd,bn; +// ZZ m; + ZZX h,g,a,b,p,r,ff,q,kg; + ZZX pru,w,T,lambda; + int twist,small_ate,small_eta; + unsigned int rho_n,rho_d,best_rho_n,best_rho_d,omega_n,omega_d,best_omega_n,best_omega_d,gcd; + unsigned int delta_n,delta_d,best_delta_n,best_delta_d; + argv++; argc--; + + fast=0; + if (argc!=1) {K=0; mode=0;} + else {K=atoi(argv[0]); mode=1; if (K<0) {K=-K; fast=1;}} + + if (K!=0 && (K<3 || K>MAXK)) return 0; + +// generate cyclotomic polynomials + + vec_ZZX phi(INIT_SIZE, BM*MAXK); + for (i = 1; i <= BM*MAXK; i++) + { + ZZX t; + t = 1; + for (j = 1; j <= i-1; j++) + if (i % j == 0) + t *= phi(j); + phi(i) = (ZZX(i, 1) - 1)/t; // ZZX(i, a) == X^i * a + } +/* +ZZX bnp=ZZX(4,36)+ZZX(3,36)+ZZX(2,24)+ZZX(1,6)+ZZX(0,1); +ZZX bntm1=ZZX(2,6); +ZZX bnq=bnp-bntm1; + +ZZX cof=(bnp*bnp*bnp*bnp-bnp*bnp+ZZX(0,1))/bnq; + +cout << "cof= ";outputfactors(cof); cout << endl; +exit(0); +*/ + if (mode==0) + { + cout << "Finds best Brezing and Weng families of pairing friendly elliptic curves" << endl; + cout << "To find all individual curves - bandw K, where 3<=K<=" << MAXK << endl; + cout << "To just see best curves (smallest rho found so far) = bandw -K" << endl; + cout << "A smaller omega means a shorter Miller loop for ETA or ATE pairing" << endl; + cout << "Note that sometimes the ETA pairing is possible, as well as ATE" << endl; + // cout << "A smaller delta means a faster Ate pairing" << endl; + min_K=3; + max_K=MAXK; + } + else {min_K=max_K=K;} + + for (K=min_K;K<=max_K; K++) + { + best_rho_n=2; best_rho_d=1; bd=0; bn=0; + best_omega_n=1; best_omega_d=1; +// best_delta_n=1; best_delta_d=1; +// Try r(x) as Phi_{nK}(x) - why? Because thats what B&W did. + for (nn=1;nn<=BM;nn++) + { + r=phi(nn*K); + +// set K-th root of unity + + clear(g); + SetCoeff(g,nn,1); + kg=g%r; + +// Try for small discriminants... + + for (d=1;d<=BD;d++) + { + if (!squarefree(d)) continue; + W=4*d; + +// find square root of -d mod r + + if (!sqrt(h,nn*K,d,r)) continue; + +// try for all the other K-th roots... + g=kg; + for (j=1;j +#include "big.h" +#include "ecn.h" +#include "ecn2.h" +#include "ecn4.h" +#include "ecn8.h" + +#define BN 0 +#define BLS12 1 +#define BLS24 2 +#define BLS48 3 + +using namespace std; + +Miracl precision=500; + +// Number of ways of selecting k items from n +Big combo(int n,int k) +{ // calculate n C k + int i; + Big c,d; + + d=1; + for (i=2;i<=k;i++) + d*=i; + + c=1; + for (i=n;i>n-k;i--) + c*=i; + + c/=d; + return c; +} + +// Number of candidates to be searched. +Big count(int b,int h) +{ + Big c=combo(b-h+1,h-1)+combo(b-h+1,h-2); + c*=pow((Big)2,h); + return c; +} + +// Move to next NAF pattern +int iterate(int *x,int n) +{ + int i,j,k,gotone=0; + for (i=0;i30 and <200)" << endl; + cout << "and hamming-weight is the number of non-zero bits (>1 and <10)" << endl; + cout << "e.g. bestpair BLS12 77 3" << endl; + cout << "Use flag /GT for GT-Strong curves" << endl; + cout << "Use flag /G2 for G2-Strong curves" << endl; + cout << "Use flag /P to show progress" << endl; + + exit(0); + } + + ip=0; HW=0; BITS=0; + G2=GT=gotB=gotH=gotT=progress=FALSE; + + while (ip9 || HW<2 || BITS>=200 || BITS<30) + { + cout << "Error in command line" << endl; + return 0; + } + + hw=HW-1; + msb=pow((Big)2,BITS); + + for (i=0;i<=BITS;i++) + xb[i]=0; + + for (i=0;i0 && !iterate(xb,BITS)) break; + for (i=j=0;i=-20) + { + nb-=1; + ecurve(0,nb,p,MR_AFFINE); + while (!P.set(rand(p))) ; + P*=cof; + if ((q*P).iszero()) + cb[m++]=nb; + } + + ecurve(0,b,p,MR_AFFINE); +// find number of points on sextic twist.. + twist=MR_SEXTIC_D; + mip->TWIST=MR_SEXTIC_D; + + if (type==BLS12 || type==BN) + { + ECn2 Q; + ZZn2 rr; + + do + { + rr=randn2(); + } while (!Q.set(rr)); + + Q*=cof2; + if (!(n*Q).iszero()) + { + twist=MR_SEXTIC_M; + mip->TWIST=MR_SEXTIC_M; + do + { + rr=randn2(); + } while (!Q.set(rr)); + + Q*=cof2; + if (!(n*Q).iszero()) + { + cout << "Never Happens" << endl; + continue; + } + } + } + if (type==BLS24) + { + ECn4 Q; + ZZn4 rr; + do + { + rr=randn4(); + } while (!Q.set(rr)); + + Q*=cof2; + if (!(n*Q).iszero()) + { + twist=MR_SEXTIC_M; + mip->TWIST=MR_SEXTIC_M; + do + { + rr=randn4(); + } while (!Q.set(rr)); + + Q*=cof2; + if (!(n*Q).iszero()) + { + cout << "Never Happens" << endl; + continue; + } + } + } + if (type==BLS48) + { + ECn8 Q; + ZZn8 rr; + do + { + rr=randn8(); + } while (!Q.set(rr)); + + Q*=cof2; + if (!(n*Q).iszero()) + { + twist=MR_SEXTIC_M; + mip->TWIST=MR_SEXTIC_M; + do + { + rr=randn8(); + } while (!Q.set(rr)); + + Q*=cof2; + if (!(n*Q).iszero()) + { + cout << "Never Happens" << endl; + continue; + } + } + } + S++; + cout << endl; + cout << "Solution " << S << endl; + x=0; + bt=1; + mip->IOBASE=16; + + cout << "x= "; + for (k=0;k0) + { + cout << "(or) "; + for (jj=0;jjIOBASE=10; + // cout << "twist= " << p+1+t << endl; + } + } + + cout << endl; + cout << cnt << " solutions searched" << endl; + + if (S==0) + { + cout << "No solutions found" << endl; + return 0; + } + if (S==1) + { + cout << "One solution found" << endl; + return 0; + } + cout << S << " solutions found" << endl; + return 0; +} diff --git a/miracl/source/curve/pairing/bgw.cpp b/miracl/source/curve/pairing/bgw.cpp new file mode 100644 index 0000000..f6f103b --- /dev/null +++ b/miracl/source/curve/pairing/bgw.cpp @@ -0,0 +1,104 @@ +/* + Boneh-Gentry-Waters + Collusion Resistant Broadcast Encryption With Short Ciphertexts and Private Keys + Implemented on Type-1 pairing + + Compile with modules as specified below + + For MR_PAIRING_SSP curves + cl /O2 /GX bgw.cpp ssp_pair.cpp ecn.cpp zzn2.cpp zzn.cpp big.cpp miracl.lib + + For MR_PAIRING_SS2 curves + cl /O2 /GX bgw.cpp ss2_pair.cpp ec2.cpp gf2m4x.cpp gf2m.cpp big.cpp miracl.lib + + or of course + + g++ -O2 bgw.cpp ss2_pair.cpp ec2.cpp gf2m4x.cpp gf2m.cpp big.cpp miracl.a -o bgw + + See http://eprint.iacr.org/2005/018.pdf + Section 3.1 + +*/ + +#include +#include + +//********* CHOOSE JUST ONE OF THESE ********** +#define MR_PAIRING_SS2 // AES-80 or AES-128 security GF(2^m) curve +//#define AES_SECURITY 80 // OR +#define AES_SECURITY 128 + +//#define MR_PAIRING_SSP // AES-80 or AES-128 security GF(p) curve +//#define AES_SECURITY 80 // OR +//#define AES_SECURITY 128 +//********************************************* + +#include "pairing_1.h" + +#define N 20 // total number of potential recipients + +#define NS 5 // number of recipients for this broadcast +int S[NS]={2,4,5,6,14}; // group of recipients +#define PERSON 6 // sample recipient + +int main() +{ + PFC pfc(AES_SECURITY); // initialise pairing-friendly curve + time_t seed; + + int i,j; + G1 g,v,gi[2*N],d[N],Hdr[2],s; + GT K; + Big alpha,gamma,t; + + time(&seed); // initialise (insecure!) random numbers + irand((long)seed); + +//setup + pfc.random(g); + pfc.random(alpha); + gi[0]=pfc.mult(g,alpha); + for (i=1;i<2*N;i++) + gi[i]=pfc.mult(gi[i-1],alpha); + + pfc.random(gamma); + v=pfc.mult(g,gamma); + + for (i=0;iIOBASE=256; + M=(char *)"test message"; // to be signcrypted from Alice to Bob + cout << "Signed Message= " << M << endl; + mip->IOBASE=16; + + pfc.precomp_for_mult(S1a); + pfc.random(x); + r=pfc.power(g,x); + c=lxor(M,pfc.hash_to_aes_key(r)); + pfc.start_hash(); + pfc.add_to_hash(M); + pfc.add_to_hash(r); + h=pfc.finish_hash_to_group(); + S=pfc.mult(S1a,x+h); + T=pfc.mult(pfc.mult(P,b)+Q1pub,x); + +// Unsigncrypt + + pfc.precomp_for_pairing(S2b); // Bob can precompute on his private key + r=pfc.pairing(S2b,T); + M=lxor(c,pfc.hash_to_aes_key(r)); + pfc.start_hash(); + pfc.add_to_hash(M); + pfc.add_to_hash(r); + h=pfc.finish_hash_to_group(); + rhs=pfc.pairing(pfc.mult(Q2,a)+Q2pub,S)*pfc.power(g,-h); + mip->IOBASE=256; + if (r==rhs) + { + cout << "Message is OK" << endl; + cout << "Verified Message= " << M << endl; + } + else + cout << "Message is bad " << c << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/bls.cpp b/miracl/source/curve/pairing/bls.cpp new file mode 100644 index 0000000..e8ab3e0 --- /dev/null +++ b/miracl/source/curve/pairing/bls.cpp @@ -0,0 +1,100 @@ +/* + Boneh-Lynn-Shacham short signature + + Compile with modules as specified in the selected header file + + For MR_PAIRING_CP curve + cl /O2 /GX bls.cpp cp_pair.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + (Note this really doesn't make much sense as the signature will not be "short") + + For MR_PAIRING_MNT curve + cl /O2 /GX bls.cpp mnt_pair.cpp zzn6a.cpp ecn3.cpp zzn3.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_BN curve + cl /O2 /GX bls.cpp bn_pair.cpp zzn12a.cpp ecn2.cpp zzn4.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_KSS curve + cl /O2 /GX bls.cpp kss_pair.cpp zzn18.cpp zzn6.cpp ecn3.cpp zzn3.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_BLS curve + cl /O2 /GX bls.cpp bls_pair.cpp zzn24.cpp zzn8.cpp zzn4.cpp zzn2.cpp ecn4.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + Test program +*/ + +#include +#include + +//********* choose just one of these pairs ********** +//#define MR_PAIRING_CP // AES-80 security +//#define AES_SECURITY 80 + +//#define MR_PAIRING_MNT // AES-80 security +//#define AES_SECURITY 80 + +#define MR_PAIRING_BN // AES-128 or AES-192 security +#define AES_SECURITY 128 +//#define AES_SECURITY 192 + +//#define MR_PAIRING_KSS // AES-192 security +//#define AES_SECURITY 192 + +//#define MR_PAIRING_BLS // AES-256 security +//#define AES_SECURITY 256 +//********************************************* + +#include "pairing_3.h" + +int main() +{ + PFC pfc(AES_SECURITY); // initialise pairing-friendly curve + + G2 Q,V; + G1 S,R; + int lsb; + Big s,X; + time_t seed; + + time(&seed); + irand((long)seed); + +// Create system-wide G2 constant + pfc.random(Q); + + pfc.random(s); // private key + V=pfc.mult(Q,s); // public key + +// signature + pfc.hash_and_map(R,(char *)"Test Message to sign"); + S=pfc.mult(R,s); + + lsb=S.g.get(X); // signature is lsb bit and X + + cout << "Signature= " << lsb << " " << X << endl; + +// verification - first recover full point S + if (!S.g.set(X,1-lsb)) + { + cout << "Signature is invalid" << endl; + exit(0); + } + pfc.hash_and_map(R,(char *)"Test Message to sign"); + + +// Observe that Q is a constant +// Interesting that this optimization doesn't work for the Tate pairing, only the Ate + + pfc.precomp_for_pairing(Q); + + G1 *g1[2]; + G2 *g2[2]; + g1[0]=&S; g1[1]=&R; + g2[0]=&Q; g2[1]=&V; + + if (pfc.multi_pairing(2,g2,g1)==1) + cout << "Signature verifies" << endl; + else + cout << "Signature is bad" << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/bls12.cpp b/miracl/source/curve/pairing/bls12.cpp new file mode 100644 index 0000000..a49dcfc --- /dev/null +++ b/miracl/source/curve/pairing/bls12.cpp @@ -0,0 +1,146 @@ +// +// cl /O2 /GX bls12.cpp zzn2.cpp zzn.cpp ecn2.cpp ecn.cpp big.cpp miracl.lib +// Program to generate Barreto-Lynn-Scott k=12 rho=1.5 curves for use by ake12blsa.cpp +// + +#include +#include "big.h" +#include "ecn.h" +#include "ecn2.h" + +using namespace std; + +Miracl precision=100; + +int main() +{ + int ns,twist,best_ham=1000; + int sign; + BOOL got_one; + Big cof,r,m1,m2,n,p,t,s,x,y,b,w,best_s; + Big PP,TT,FF; + miracl*mip=&precision; + ECn P; + ECn2 Q; + ZZn2 xi; + + mip->IOBASE=16; + + s=(char *)"C000000000000000"; + + ns=1; + forever + { + s+=1; + for (sign=1;sign<=2;sign++) + { + if (sign==1) x=s; + else x=-s; + + if (x<0 || ham(x)>9) continue; // filter out difficult or poor solutions + + p=pow(x,6)-2*pow(x,5)+2*pow(x,3)+x+1; + + + if (p%3!=0) continue; // check congruence conditions + p/=3; + + if (p%8==1) continue; + if (p%8==7 && (p%5==1 || p%5==4)) continue; + + t=x+1; + + n=p+1-t; + r=pow(x,4)-x*x+1; + + if (!prime(r)) continue; + + if (!prime(p)) continue; + modulo(p); + + if (p%8==5) xi.set(0,1); + if (p%8==3) xi.set(1,1); + if (p%8==7) xi.set(2,1); + if (pow(xi,(p*p-1)/2)==1) continue; + if (pow(xi,(p*p-1)/3)==1) continue; // make sure that x^6+c is irreducible + + cof=n/r; + +// find number of points on sextic twist.. + + TT=t*t-2*p; + PP=p*p; + + FF=sqrt((4*PP-TT*TT)/3); + + m1=PP+1-(-3*FF+TT)/2; // 2 possibilities... + +// m2=PP+1-(3*FF+TT)/2; // wrong one + + b=0; + forever + { + b+=1; + ecurve(0,b,p,MR_AFFINE); + while (!P.set(rand(p))) ; + P*=cof; + if ((r*P).iszero()) break; // right curve + } + got_one=FALSE; + + mip->TWIST=MR_SEXTIC_M; + while (!Q.set(randn2())) ; + + Q*=(m1/r); + + if ((r*Q).iszero()) got_one=TRUE; + else + { + mip->TWIST=MR_SEXTIC_D; + while (!Q.set(randn2())) ; + + Q*=(m1/r); + + if ((r*Q).iszero()) got_one=TRUE; + } + if (!got_one) {cout << "Bad twist" << endl; exit(0);} // Huh? + + if (mip->TWIST==MR_SEXTIC_M) continue; // not interested just now + + cout << "solution " << ns << endl; + cout << "irreducible polynomial = X^6 + " << xi << endl; + cout << "p=" << p << endl; + cout << "p mod 72 = " << p%72 << endl; + cout << "x mod 72 = " << x%72 << endl; + + cout << "x= " << x << endl; + cout << "bits(p)= " << bits(p) << endl; + cout << "r=" << r << endl; + cout << "t=" << t << endl; + cout << "m1= " << m1 << endl; + cout << "cof= " << m1/r << endl; + + cout << "bits(t)= " << bits(t) << endl; + cout << "ham(t-1) = " << ham(t-1) << " (small is better for Ate pairing)" << endl; + cout << "bits(r)= " << bits(r) << endl; + + cout << "p%8= " << p%8 << endl; + mip->IOBASE=10; + cout << "E(Fp): y^2=x^3+" << b << endl; + mip->IOBASE=16; + if (mip->TWIST==MR_SEXTIC_M) cout << "Twist type M" << endl; + if (mip->TWIST==MR_SEXTIC_D) cout << "Twist type D" << endl; + + Q*=r; + cout << "check - if right twist should be O - r*Q= " << Q << endl; + ns++; + if (ham(x)IOBASE=16; + s=(char *)"E000000000000000"; + + ns=1; + + forever + { + s+=1; + for (sign=1;sign<=2;sign++) + { + + if (sign==1) x=s; + else x=-s; + + if (x<0 || ham(x)>7) continue; // filter out difficult or poor solutions + + t=1+x; + p=1+x+x*x-pow(x,4)+2*pow(x,5)-pow(x,6)+pow(x,8)-2*pow(x,9)+pow(x,10); + q=1-pow(x,4)+pow(x,8); + + if (p%3!=0) continue; + p/=3; + + if (p%8==1) continue; + if (!prime(p)) continue; + if (!prime(q)) continue; + + modulo(p); + if (p%8==5) xi.set(0,1); + if (p%8==3) xi.set(1,1); + if (p%8==7) xi.set(2,1); + +// make sure its irreducible + if (pow(xi,(p*p-1)/2)==1) {/*cout << "Failed - not a square" << endl; */ continue;} + if (pow(xi,(p*p-1)/3)==1) {/*cout << "Failed - not a cube" << endl; */ continue;} // make sure that x^6-c is irreducible + + n=p+1-t; + cf=n/q; + + tau[0]=2; // count points on twist over extension p^4 + tau[1]=t; + for (i=1;i<4;i++ ) tau[i+1]=t*tau[i]-p*tau[i-1]; + P=p*p*p*p; + TAU=tau[4]; + + F=(4*P-TAU*TAU)/3; + F=sqrt(F); + + m2=P+1-(3*F+TAU)/2; + + // cout << "m2%q= " << m2%q << endl; + + B=1; // find curve equation + + forever + { + B+=1; + if (B==2) + { + X=-1; Y=1; + } + else if (B==3) + { + X=1; Y=2; + } + else if (B==8) + { + X=1; Y=3; + } + else if (B==15) + { + X=1; Y=4; + } + else + { + do + { + X=rand(p); + Y=sqrt(X*X*X+B,p); + } while (Y==0); + } + + ecurve(0,B,p,MR_AFFINE); + W.set(X,Y); + W*=cf; + if ((q*W).iszero()) break; + } + + mip->TWIST=MR_SEXTIC_M; // is it an M-type twist...? + do + { + r=randn4(); + } while (!Q.set(r)); + got_one=FALSE; + + Q*=(m2/q); + + if ((q*Q).iszero()) got_one=TRUE; + +// cout << "m1*Q= " << m1*Q << endl; +// cout << "m1%q= " << m1%q << endl; + else + { + mip->TWIST=MR_SEXTIC_D; // no, so it must be D-type. + do + { + r=randn4(); + } while (!Q.set(r)); + + Q*=(m2/q); + + if ((q*Q).iszero()) got_one=TRUE; + } + if (!got_one) {cout << "Bad twist" << endl; exit(0);} // Huh? + + if (mip->TWIST==MR_SEXTIC_M) continue; // not interested just now + + cout << "solution " << ns << endl; + + cout << "x= " << x << " ham(x)= " << ham(x) << endl; + cout << "x%72= " << x%72 << endl; + cout << "p= " << p << " bits(p)= " << bits(p) << endl; + cout << "q= " << q << " bits(q)= " << bits(q) << endl; + cout << "n= " << n << endl; + cout << "t= " << t << endl; + cout << "cf= " << cf << endl; + + + cout << "W= " << W << endl; + cout << "q*W= " << q*W << endl; + mip->IOBASE=10; + cout << "E(Fp): y^2=x^3+" << B << endl; + cout << "(p-1)%24= " << (p-1)%24 << endl; + cout << "p%8= " << p%8 << endl; + mip->IOBASE=16; + if (mip->TWIST==MR_SEXTIC_M) cout << "Twist type M" << endl; + if (mip->TWIST==MR_SEXTIC_D) cout << "Twist type D" << endl; + + Q*=q; + cout << "check - if right twist should be O - q*Q= " << Q << endl; + + if (ham(x) + +using namespace std; + +// cofactor - number of points on curve=CF.q + +#define CF 2 +#define CNR 2 + +int main() +{ + ifstream common("mnt.ecs"); // MNT elliptic curve parameters + ofstream public_key("bls_public.key"); + ofstream private_key("bls_private.key"); + miracl* mip=mirsys(40,16); + ECn3 P,R; + ECn Q; + ZZn3 x,y,z; + ZZn a,b,c; + Big w,s,p,q,B,cf,sru; + int i,bits,A; + time_t seed; + + common >> bits; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B >> q >> cf >> sru; + + time(&seed); + irand((long)seed); + + ecurve(A,B,p,MR_PROJECTIVE); + set_zzn3(CNR,sru); + + mip->TWIST=MR_QUADRATIC; // map to point on twisted curve E(Fp3) + +// find a random point on the curve + + cout << "generating keys - keys in bls_private.key and bls_public.key" << endl; + + forever + { + w=rand(p); + x.set((ZZn)0,(ZZn)w,(ZZn)0); + if (P.set(x)) break; + } + + s=rand(q); + +// generate public values. + + R=P; R*=s; + + P.get(x,y); + + x.get(a,b,c); + + public_key << a << endl; + public_key << b << endl; + public_key << c << endl; + + y.get(a,b,c); + + public_key << a << endl; + public_key << b << endl; + public_key << c << endl; + + R.get(x,y); + + x.get(a,b,c); + + public_key << a << endl; + public_key << b << endl; + public_key << c << endl; + + y.get(a,b,c); + + public_key << a << endl; + public_key << b << endl; + public_key << c << endl; + + private_key << s << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/bls_pair.cpp b/miracl/source/curve/pairing/bls_pair.cpp new file mode 100644 index 0000000..b13fef9 --- /dev/null +++ b/miracl/source/curve/pairing/bls_pair.cpp @@ -0,0 +1,1703 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * bls_pair.cpp + * + * BLS curve, ate pairing embedding degree 24, ideal for security level AES-256 + * + * Irreducible poly is X^3+n, where n=sqrt(w+sqrt(m)), m= {-1,-2} and w= {0,1,2} + * if p=5 mod 8, n=sqrt(-2) + * if p=3 mod 8, n=1+sqrt(-1) + * if p=7 mod 8, p=2,3 mod 5, n=2+sqrt(-1) + * + * Provides high level interface to pairing functions + * + * GT=pairing(G2,G1) + * + * This is calculated on a Pairing Friendly Curve (PFC), which must first be defined. + * + * G1 is a point over the base field, and G2 is a point over an extension field of degree 3 + * GT is a finite field point over the 18-th extension, where 18 is the embedding degree. + * + */ + +#define MR_PAIRING_BLS +#include "pairing_3.h" + +// BLS curve +//static char param[]= "E000000000058400"; +//static char curveB[]="6"; + +//Better BLS curve + +static char param[]= "8010000A00000000"; +static char curveB[]="A"; + +void read_only_error(void) +{ + cout << "Attempt to write to read-only object" << endl; + exit(0); +} + +// Suitable for p=7 mod 12 + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + X.set((Big)1,(Big)1); // p=3 mod 8 + X=pow(X,(p-7)/12); +} + +ZZn24 Frobenius(ZZn24 P, ZZn2 &X, int k) +{ + ZZn24 Q=P; + for (int i=0; i=p) break; + } + h%=p; + return h; +} + +void PFC::start_hash(void) +{ + shs256_init(&SH); +} + +Big PFC::finish_hash_to_group(void) +{ + Big hash; + char s[HASH_LEN]; + shs256_hash(&SH,s); + hash=from_binary(HASH_LEN,s); + return hash%(*ord); +} + +void PFC::add_to_hash(const GT& x) +{ + ZZn8 u; + ZZn24 v=x.g; + ZZn4 h,l; + ZZn2 t,b; + Big a; + ZZn xx[8]; + + int i,j,m; + v.get(u); + u.get(l,h); + l.get(t,b); + t.get(xx[0],xx[1]); + b.get(xx[2],xx[3]); + h.get(t,b); + t.get(xx[4],xx[5]); + b.get(xx[6],xx[7]); + for (i=0;i<8;i++) + { + a=(Big)xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } + } +} + +void PFC::add_to_hash(const G2& x) +{ + ZZn4 X,Y; + ECn4 v=x.g; + Big a; + ZZn2 t,b; + ZZn xx[8]; + + int i,m; + + v.get(X,Y); + X.get(t,b); + t.get(xx[0],xx[1]); + b.get(xx[2],xx[3]); + Y.get(t,b); + t.get(xx[4],xx[5]); + b.get(xx[6],xx[7]); + + for (i=0;i<8;i++) + { + a=(Big)xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } + } +} + +void PFC::add_to_hash(const G1& x) +{ + Big a,X,Y; + int i,m; + x.g.get(X,Y); + a=X; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } + a=Y; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } +} + +void PFC::add_to_hash(const Big& x) +{ + int m; + Big a=x; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } +} + + +void PFC::add_to_hash(char *x) +{ + int i=0; + while (x[i]!=0) + { + shs256_process(&SH,x[i]); + i++; + } +} + +Big H2(ZZn24 x) +{ // Compress and hash an Fp24 to a big number + sha256 sh; + ZZn8 u; + ZZn4 h,l; + ZZn2 t,b; + Big a,hash,p; + ZZn xx[8]; + char s[HASH_LEN]; + int i,j,m; + + shs256_init(&sh); + x.get(u); // compress to single ZZn4 + u.get(l,h); + + l.get(t,b); + + t.get(xx[0],xx[1]); + b.get(xx[2],xx[3]); + + h.get(t,b); + + t.get(xx[4],xx[5]); + b.get(xx[6],xx[7]); + + for (i=0;i<8;i++) + { + a=(Big)xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&sh,m); + a/=256; + } + } + shs256_hash(&sh,s); + hash=from_binary(HASH_LEN,s); + return hash; +} + + +#ifndef MR_AFFINE_ONLY + +void force(ZZn& x,ZZn& y,ZZn& z,ECn& A) +{ // A=(x,y,z) + copy(getbig(x),A.get_point()->X); + copy(getbig(y),A.get_point()->Y); + copy(getbig(z),A.get_point()->Z); + A.get_point()->marker=MR_EPOINT_GENERAL; +} + +void extract(ECn &A, ZZn& x,ZZn& y,ZZn& z) +{ // (x,y,z) <- A + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} + +#endif + +void force(ZZn& x,ZZn& y,ECn& A) +{ // A=(x,y) + copy(getbig(x),A.get_point()->X); + copy(getbig(y),A.get_point()->Y); + A.get_point()->marker=MR_EPOINT_NORMALIZED; +} + +void extract(ECn& A,ZZn& x,ZZn& y) +{ // (x,y) <- A + if (A.iszero()) + { + x=0; y=0; + return; + } + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +// +// This calculates p.A = (X^p,Y^p) quickly using Frobenius +// 1. Extract A(x,y) from twisted curve to point on curve over full extension, as X=i^2.x and Y=i^3.y +// where i=NR^(1/k) +// 2. Using Frobenius calculate (X^p,Y^p) +// 3. map back to twisted curve +// Here we simplify things by doing whole calculation on the twisted curve +// +// Note we have to be careful as in detail it depends on w where p=w mod k +// Its simplest if w=1. +// + +ECn4 psi(ECn4 &A,ZZn2 &F,int n) +{ + int i; + ECn4 R; + ZZn4 X,Y; + ZZn2 FF,W; +// Fast multiplication of A by q^n + A.get(X,Y); + FF=F*F; + W=txx(txx(txx(FF*FF*FF))); + + for (i=0;i return (Qy-y)-slope.(Qx-x) +// + +ZZn24 line(ECn4& A,ECn4& C,ZZn4& slope,ZZn& Qx,ZZn& Qy) +{ + ZZn24 w; + ZZn8 nn,dd; + ZZn4 X,Y; + + A.get(X,Y); + + nn.set((ZZn4)Qy,Y-slope*X); + dd.set(slope*Qx); + w.set(nn,dd); + + return w; +} + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn24 g(ECn4& A,ECn4& B,ZZn& Qx,ZZn& Qy) +{ + ZZn4 lam; + ZZn24 r; + ECn4 P=A; + +// Evaluate line from A + A.add(B,lam); + if (A.iszero()) return (ZZn24)1; + r=line(P,A,lam,Qx,Qy); + + return r; +} + +// if multiples of G2 can be precalculated, its a lot faster! + +ZZn24 gp(ZZn4* ptable,int &j,ZZn& Px,ZZn& Py) +{ + ZZn24 w; + ZZn8 nn,dd; + + nn.set(Py,ptable[j+1]); + dd.set(ptable[j]*Px); + j+=2; + w.set(nn,dd); + return w; +} + +// +// Spill precomputation on pairing to byte array +// + +int PFC::spill(G2& w,char *& bytes) +{ + int i,j,len,m; + int bytes_per_big=(MIRACL/8)*(get_mip()->nib-1); + + Big n=*x; + if (w.ptable==NULL) return 0; + ZZn2 a,b; + Big X,Y; + + m=2*(bits(n)+ham(n)-2); + len=m*4*bytes_per_big; + + bytes=new char[len]; + for (i=j=0;inib-1); + + Big n=*x; + if (w.ptable!=NULL) return; + ZZn2 a,b; + Big X,Y; + + m=2*(bits(n)+ham(n)-2); + len=m*4*bytes_per_big; + + w.ptable=new ZZn4[m]; + for (i=j=0;i=0;i--) + { + Q=A; +// Evaluate line from A to A+A + A.add(A,lam); + Q.get(x1,y1); + w.ptable[j++]=lam; w.ptable[j++]=y1-lam*x1; + + if (bit(n,i)==1) + { + Q=A; + A.add(B,lam); + Q.get(x1,y1); + w.ptable[j++]=lam; w.ptable[j++]=y1-lam*x1; + } + } + return len; +} + +GT PFC::multi_miller(int n,G2** QQ,G1** PP) +{ + GT z; + ZZn *Px,*Py; + int i,j,*k,nb; + ECn4 *Q,*A; + ECn P; + ZZn24 res; + Big X=*x; + + Px=new ZZn[n]; + Py=new ZZn[n]; + Q=new ECn4[n]; + A=new ECn4[n]; + k=new int[n]; + + nb=bits(X); + res=1; + + for (j=0;jg; normalise(P); Q[j]=QQ[j]->g; + extract(P,Px[j],Py[j]); + } + + for (j=0;j=0;i--) + { + res*=res; + for (j=0;jptable==NULL) + res*=g(A[j],A[j],Px[j],Py[j]); + else + res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + if (bit(X,i)==1) + for (j=0;jptable==NULL) + res*=g(A[j],Q[j],Px[j],Py[j]); + else + res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + if (res.iszero()) return 0; + } + + delete [] k; + delete [] A; + delete [] Q; + delete [] Py; + delete [] Px; + + z.g=res; + return z; +} + +// +// R-ate Pairing G2 x G1 -> GT +// +// P is a point of order q in G1. Q(x,y) is a point of order q in G2. +// Note that Q is a point on the sextic twist of the curve over Fp^2, P(x,y) is a point on the +// curve over the base field Fp +// + +GT PFC::miller_loop(const G2& QQ,const G1& PP) +{ + GT z; + Big n; + int i,j,nb,nbw,nzs; + ECn4 A,Q; + ECn P; + ZZn Px,Py; + BOOL precomp; + ZZn24 r; + Big X=*x; + + Q=QQ.g; P=PP.g; + + precomp=FALSE; + if (QQ.ptable!=NULL) precomp=TRUE; + + normalise(P); + extract(P,Px,Py); + + n=X; + + A=Q; + nb=bits(n); + r=1; +// Short Miller loop + r.mark_as_miller(); + j=0; + + for (i=nb-2;i>=0;i--) + { + r*=r; + if (precomp) r*=gp(QQ.ptable,j,Px,Py); + else r*=g(A,A,Px,Py); + if (bit(n,i)) + { + if (precomp) r*=gp(QQ.ptable,j,Px,Py); + else r*=g(A,Q,Px,Py); + } + } + + z.g=r; + return z; +} +// Automatically generated by Luis Dominguez + +ZZn24 HardExpo(ZZn24 &f3x0, ZZn2 &X, Big &x){ +//vector=[ 1, 2, 3 ] + ZZn24 r; + ZZn24 xA; + ZZn24 xB; + ZZn24 t0; + ZZn24 t1; + ZZn24 f3x1; + ZZn24 f3x2; + ZZn24 f3x3; + ZZn24 f3x4; + ZZn24 f3x5; + ZZn24 f3x6; + ZZn24 f3x7; + ZZn24 f3x8; + ZZn24 f3x9; + + f3x1=pow(f3x0,x); + f3x2=pow(f3x1,x); + f3x3=pow(f3x2,x); + f3x4=pow(f3x3,x); + f3x5=pow(f3x4,x); + f3x6=pow(f3x5,x); + f3x7=pow(f3x6,x); + f3x8=pow(f3x7,x); + f3x9=pow(f3x8,x); + + xA=f3x4*inverse(f3x8)*Frobenius(f3x3,X,1)*Frobenius(inverse(f3x7),X,1)*Frobenius(f3x2,X,2)*Frobenius(inverse(f3x6),X,2)*Frobenius(f3x1,X,3)*Frobenius(inverse(f3x5),X,3)*Frobenius(inverse(f3x4),X,4)*Frobenius(inverse(f3x3),X,5)*Frobenius(inverse(f3x2),X,6)*Frobenius(inverse(f3x1),X,7); + xB=f3x0; + t0=xA*xB; + xA=inverse(f3x3)*inverse(f3x5)*f3x7*f3x9*Frobenius(inverse(f3x2),X,1)*Frobenius(inverse(f3x4),X,1)*Frobenius(f3x6,X,1)*Frobenius(f3x8,X,1)*Frobenius(inverse(f3x1),X,2)*Frobenius(inverse(f3x3),X,2)*Frobenius(f3x5,X,2)*Frobenius(f3x7,X,2)*Frobenius(inverse(f3x0),X,3)*Frobenius(inverse(f3x2),X,3)*Frobenius(f3x4,X,3)*Frobenius(f3x6,X,3)*Frobenius(f3x3,X,4)*Frobenius(f3x5,X,4)*Frobenius(f3x2,X,5)*Frobenius(f3x4,X,5)*Frobenius(f3x1,X,6)*Frobenius(f3x3,X,6)*Frobenius(f3x0,X,7)*Frobenius(f3x2,X,7); + xB=f3x0; + t1=xA*xB; + t0=t0*t0; + t0=t0*t1; + +r=t0; +return r; + +} + +void SoftExpo(ZZn24 &f3, ZZn2 &X){ + ZZn24 t0; + int i; + + t0=f3; f3.conj(); f3/=t0; + f3.mark_as_regular(); + t0=f3; for (i=1;i<=4;i++) f3.powq(X); f3*=t0; + f3.mark_as_unitary(); +} + +GT PFC::final_exp(const GT& z) +{ + GT y; + ZZn24 r=z.g; + Big X=*x; + + SoftExpo(r,*frob); + y.g=HardExpo(r,*frob,X); + + return y; +} + +PFC::PFC(int s, csprng *rng) +{ + int mod_bits,words; + if (s!=256) + { + cout << "No suitable curve available" << endl; + exit(0); + } + + mod_bits=(5*s)/2; + + if (mod_bits%MIRACL==0) + words=(mod_bits/MIRACL); + else + words=(mod_bits/MIRACL)+1; + +#ifdef MR_SIMPLE_BASE + miracl *mip=mirsys((MIRACL/4)*words,16); +#else + miracl *mip=mirsys(words,0); + mip->IOBASE=16; +#endif + + S=s; + + B=new Big; + x=new Big; + mod=new Big; + ord=new Big; + cof=new Big; + npoints=new Big; + trace=new Big; + Beta=new ZZn; + frob=new ZZn2; + + *B=curveB; + *x=param; + Big X=*x; + + *trace=1+X; + *mod=(1+X+X*X-pow(X,4)+2*pow(X,5)-pow(X,6)+pow(X,8)-2*pow(X,9)+pow(X,10))/3; + *ord=1-pow(X,4)+pow(X,8); + *npoints=*mod+1-*trace; + *cof=(X-1); // Neat trick! Whole group is non-cyclic - just has (x-1)^2 as a factor + // So multiplication by x-1 is sufficient to create a point of order q + ecurve(0,*B,*mod,MR_PROJECTIVE); + + *Beta=pow((ZZn)2,(*mod-1)/3); + *Beta*=(*Beta); // right cube root of unity + set_frobenius_constant(*frob); + + mip->TWIST=MR_SEXTIC_D; // map Server to point on twisted curve E(Fp2) + + RNG=rng; +} + +PFC::~PFC() +{ + delete B; + delete x; + delete mod; + delete ord; + delete cof; + delete npoints; + delete trace; + delete Beta; + delete frob; + mirexit(); +} + +void endomorph(ECn &A,ZZn &Beta) +{ // apply endomorphism P(x,y) = (Beta*x,y) where Beta is cube root of unity + // Actually (Beta*x,-y) = x^4.P + ZZn x,y; + x=(A.get_point())->X; + y=(A.get_point())->Y; + y=-y; + x*=Beta; + copy(getbig(x),(A.get_point())->X); + copy(getbig(y),(A.get_point())->Y); +} + +G1 PFC::mult(const G1& w,const Big& k) +{ + G1 z; + ECn Q; + Big X=*x; + if (w.mtable!=NULL) + { // we have precomputed values + Big e=k; + if (k<0) e=-e; + + int i,j,t=w.mtbits; // MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.mtable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g+=z.g; + if (j>0) z.g+=w.mtable[j]; + + } + if (k<0) z.g=-z.g; + } + else + { + Big x4,u[2],e=k; + x4=X*X; x4*=x4; + u[0]=e%x4; u[1]=e/x4; + Q=w.g; + endomorph(Q,*Beta); + + Q=mul(u[0],w.g,u[1],Q); + z.g=Q; + } + return z; +} + +// GLV + Galbraith-Scott + +G2 PFC::mult(const G2& w,const Big& k) +{ + G2 z; + int i,j; + Big X=*x; + + if (w.mtable!=NULL) + { // we have precomputed values + Big e=k; + if (k<0) e=-e; + + int i,j,t=w.mtbits; //MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.mtable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g+=z.g; + if (j>0) z.g+=w.mtable[j]; + } + if (k<0) z.g=-z.g; + } + else + { + ECn4 Q[8]; + Big u[8],e=k; + BOOL small=TRUE; + + for (i=0;i<8;i++) {u[i]=e%X; e/=X;} + Q[0]=w.g; + + for (i=1;i<8;i++) + { + if (u[i]!=0) + { + small=FALSE; + break; + } + } + + if (small) + { + if (u[0]<0) + { + u[0]=-u[0]; + Q[0]=-Q[0]; + } + z.g=Q[0]; + z.g*=u[0]; + return z; + } + + for (i=1;i<8;i++) + Q[i]=psi(Q[i-1],*frob,1); + + for (i=0;i<8;i++) + { + if (u[i]<0) + {u[i]=-u[i];Q[i]=-Q[i];} + } + +// simple multi-addition + + z.g=mul(8,Q,u); + } + return z; +} + + +// GLV method + Galbraith-Scott idea + +GT PFC::power(const GT& w,const Big& k) +{ + GT z; + Big X=*x; + + int i; + if (w.etable!=NULL) + { // precomputation is available + Big e=k; + if (k<0) e=-e; + + int i,j,t=w.etbits; // MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.etable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g*=z.g; + if (j>0) z.g*=w.etable[j]; + } + if (k<0) z.g=inverse(z.g); + } + else + { + ZZn24 Y[8]; + Big u[8],e=k; + + for (i=0;i<8;i++) {u[i]=e%X; e/=X;} + + Y[0]=w.g; + for (i=1;i<8;i++) + {Y[i]=Y[i-1]; Y[i].powq(*frob);} + +// deal with -ve exponents + for (i=0;i<8;i++) + { + if (u[i]<0) + {u[i]=-u[i];Y[i].conj();} + } + +// simple multi-exponentiation + z.g=pow(8,Y,u); + } + return z; +} + +// Automatically generated by Luis Dominguez + +ECn4 HashG2(ECn4& Qx0, Big& x, ZZn2& X){ +//vector=[ 1, 2, 3, 4 ] + ECn4 r; + ECn4 xA; + ECn4 xB; + ECn4 xC; + ECn4 t0; + ECn4 t1; + ECn4 Qx0_; + ECn4 Qx1; + ECn4 Qx1_; + ECn4 Qx2; + ECn4 Qx2_; + ECn4 Qx3; + ECn4 Qx3_; + ECn4 Qx4; + ECn4 Qx4_; + ECn4 Qx5; + ECn4 Qx5_; + ECn4 Qx6; + ECn4 Qx6_; + ECn4 Qx7; + ECn4 Qx7_; + ECn4 Qx8; + ECn4 Qx8_; + + Qx0_=-(Qx0); + Qx1=x*Qx0; + Qx1_=-(Qx1); + Qx2=x*Qx1; + Qx2_=-(Qx2); + Qx3=x*Qx2; + Qx3_=-(Qx3); + Qx4=x*Qx3; + Qx4_=-(Qx4); + Qx5=x*Qx4; + Qx5_=-(Qx5); + Qx6=x*Qx5; + Qx6_=-(Qx6); + Qx7=x*Qx6; + Qx7_=-(Qx7); + Qx8=x*Qx7; + Qx8_=-(Qx8); + + xA=Qx0; + xC=Qx7; + xA+=xC; + xC=psi(Qx2,X,4); + xA+=xC; + xB=Qx0; + xC=Qx7; + xB+=xC; + xC=psi(Qx2,X,4); + xB+=xC; + t0=xA+xB; + xB=Qx2_; + xC=Qx3_; + xB+=xC; + xC=Qx8_; + xB+=xC; + xC=psi(Qx2,X,1); + xB+=xC; + xC=psi(Qx3_,X,1); + xB+=xC; + xC=psi(Qx1,X,6); + xB+=xC; + t0=t0+xB; + xB=Qx4; + xC=Qx5_; + xB+=xC; + xC=psi(Qx0_,X,4); + xB+=xC; + xC=psi(Qx4_,X,4); + xB+=xC; + xC=psi(Qx0,X,5); + xB+=xC; + xC=psi(Qx1_,X,5); + xB+=xC; + xC=psi(Qx2_,X,5); + xB+=xC; + xC=psi(Qx3,X,5); + xB+=xC; + t0=t0+xB; + xA=Qx1; + xC=psi(Qx0_,X,1); + xA+=xC; + xC=psi(Qx1,X,1); + xA+=xC; + xC=psi(Qx4_,X,1); + xA+=xC; + xC=psi(Qx5,X,1); + xA+=xC; + xC=psi(Qx0,X,2); + xA+=xC; + xC=psi(Qx1_,X,2); + xA+=xC; + xC=psi(Qx4_,X,2); + xA+=xC; + xC=psi(Qx5,X,2); + xA+=xC; + xC=psi(Qx0,X,3); + xA+=xC; + xC=psi(Qx1_,X,3); + xA+=xC; + xC=psi(Qx4_,X,3); + xA+=xC; + xC=psi(Qx5,X,3); + xA+=xC; + xC=psi(Qx1,X,4); + xA+=xC; + xC=psi(Qx3,X,4); + xA+=xC; + xC=psi(Qx0_,X,6); + xA+=xC; + xC=psi(Qx2_,X,6); + xA+=xC; + xB=Qx4; + xC=Qx5_; + xB+=xC; + xC=psi(Qx0_,X,4); + xB+=xC; + xC=psi(Qx4_,X,4); + xB+=xC; + xC=psi(Qx0,X,5); + xB+=xC; + xC=psi(Qx1_,X,5); + xB+=xC; + xC=psi(Qx2_,X,5); + xB+=xC; + xC=psi(Qx3,X,5); + xB+=xC; + t1=xA+xB; + t0=t0+t0; + t0=t0+t1; + +r=t0; +return r; +} + +// random group element + +void PFC::random(Big& w) +{ + if (RNG==NULL) w=rand(*ord); + else w=strong_rand(RNG,*ord); +} + +// random AES key + +void PFC::rankey(Big& k) +{ + if (RNG==NULL) k=rand(S,2); + else k=strong_rand(RNG,S,2); +} + +void PFC::hash_and_map(G2& w,char *ID) +{ + int i; + ZZn4 XX; + ZZn2 t; + Big X=*x; + + Big x0=H1(ID); + + forever + { + x0+=1; + t.set((ZZn)0,(ZZn)x0); + XX.set(t,(ZZn2)0); + if (!w.g.set(XX)) continue; + break; + } + + w.g=HashG2(w.g,X,*frob); +} + +void PFC::random(G2& w) +{ + int i; + ECn4 S; + ZZn4 XX; + ZZn2 t; + Big X=*x; + + Big x0; + if (RNG==NULL) x0=rand(*mod); + else x0=strong_rand(RNG,*mod); + + forever + { + x0+=1; + t.set((ZZn)0,(ZZn)x0); + XX.set(t,(ZZn2)0); + if (!w.g.set(XX)) continue; + break; + } + + w.g=HashG2(w.g,X,*frob); + +} + +void PFC::hash_and_map(G1& w,char *ID) +{ + Big x0=H1(ID); + + while (!w.g.set(x0,x0)) x0+=1; + w.g*=*cof; +} + +void PFC::random(G1& w) +{ + Big x0; + if (RNG==NULL) x0=rand(*mod); + else x0=strong_rand(RNG,*mod); + + while (!w.g.set(x0,x0)) x0+=1; + + w.g*=*cof; +} + +Big PFC::hash_to_aes_key(const GT& w) +{ + Big m=pow((Big)2,S); + return H2(w.g)%m; +} + +Big PFC::hash_to_group(char *ID) +{ + Big m=H1(ID); + return m%(*ord); +} + +GT operator*(const GT& x,const GT& y) +{ + GT z=x; + z.g*=y.g; + return z; +} + +GT operator/(const GT& x,const GT& y) +{ + GT z=x; + z.g/=y.g; + return z; +} + +// +// spill precomputation on GT to byte array +// + +int GT::spill(char *& bytes) +{ + int i,j,n=(1<nib-1); + int len=n*24*bytes_per_big+1; + ZZn8 a,b,c; + ZZn4 f,s; + ZZn2 p,q; + Big x,y; + + if (etable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*24*bytes_per_big; + ZZn8 a,b,c; + ZZn4 f,s; + ZZn2 p,q; + Big x,y; + if (etable!=NULL) return; + + etable=new ZZn24[1<nib-1); + int len=n*2*bytes_per_big+1; + Big x,y; + + if (mtable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*2*bytes_per_big; + Big x,y; + if (mtable!=NULL) return; + + mtable=new ECn[1<nib-1); + int len=n*8*bytes_per_big+1; + ZZn4 a,b; + ZZn2 f,s; + Big x,y; + + if (mtable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*8*bytes_per_big; + ZZn4 a,b; + ZZn2 f,s; + Big x,y; + if (mtable!=NULL) return; + + mtable=new ECn4[1< +#include +#include +#include "ecn.h" +#include + +// cofactor - number of points on curve=CF.q + +#define CF 2 +#define CNR 2 + +using namespace std; + +Miracl precision(40,16); + +// Using SHA-1 as basic hash algorithm + +#define HASH_LEN 20 + +// +// Hash functions +// + +Big H1(char *string,int len) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha sh; + + shs_init(&sh); + + for (i=0;i=p) break; + } + h%=p; + return h; +} + +// Hash and map a Client Identity to a curve point E_(Fp) of order q + +ECn hash_and_map(char *ID,int len) +{ + ECn Q; + Big x0=H1(ID,len); + + while (!Q.set(x0,x0)) x0+=1; + Q*=CF; + return Q; +} + +int main() +{ + ifstream common("mnt.ecs"); // MNT elliptic curve parameters + ifstream private_key("bls_private.key"); + ofstream signature("bls_signature.sig"); + miracl* mip=&precision; + ECn PM; + Big x,s,p,q,B; + int bits,A,lsb; + + common >> bits; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B >> q; + + private_key >> s; + + ecurve(A,B,p,MR_PROJECTIVE); + + PM=hash_and_map((char *)"This a quick test of the method",32); + + cout << "Short message has been signed - signature in bls_signature.sig " << endl; + + PM*=s; + + lsb=PM.get(x); + + signature << x << endl; + signature << lsb << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/bls_ver.cpp b/miracl/source/curve/pairing/bls_ver.cpp new file mode 100644 index 0000000..e45c6cf --- /dev/null +++ b/miracl/source/curve/pairing/bls_ver.cpp @@ -0,0 +1,334 @@ +/* + + Boneh-Lynn-Shacham short signature scheme - verification phase + cl /O2 /GX bls_ver.cpp ecn3.cpp ecn.cpp zzn6.cpp zzn3.cpp zzn.cpp big.cpp miracl.lib + + The required file mnt.ecs is created from a curve generated by the mnt + utility, and created by the cm utility. For convenience the value of + (p^2-p+1)/q and the 6th root of unity (cnr^(p-1)/6) have been manually + calculated and appended to this file (replacing the x,y values in the + original .ecs file) + +*/ + +#include +#include +#include +#include "ecn.h" +#include +#include "ecn3.h" +#include "zzn6.h" + +// cofactor - number of points on curve=CF.q + +#define CF 2 +#define CNR 2 + +using namespace std; + +Miracl precision(40,16); + +// Using SHA-1 as basic hash algorithm + +#define HASH_LEN 20 + +// +// Tate Pairing Code +// +// Extract ECn point in internal ZZn format +// + +void extract(ECn& A,ZZn& x,ZZn& y,ZZn& z) +{ + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn6 line(ECn& A,ECn& C,ZZn& slope,ZZn3& Qx,ZZn3& Qy) +{ + ZZn6 w; + ZZn3 nn=Qx; + ZZn x,y,z,t; + + extract(A,x,y,z); + x*=z; t=z; z*=z; z*=t; + x*=slope; t=slope*z; + nn*=t; nn-=x; t=z; + extract(C,x,x,z); + nn+=(z*y); t*=z; + w.set(nn,-Qy*t); + + return w; +} + +ZZn6 g(ECn& A,ECn& B,ECn& C,ECn& D,ZZn3& Qx,ZZn3& Qy,ZZn3& Sx,ZZn3& Sy) +{ + ZZn6 u; + int type; + ZZn lam; + big ptr; + ECn P; + + P=A; + type=A.add(B,&ptr); + if (!type) return (ZZn6)1; + lam=ptr; + u=line(P,A,lam,Qx,Qy); + + P=C; + type=C.add(D,&ptr); + if (!type) return (ZZn6)1; + lam=ptr; + return u*line(P,C,lam,Sx,Sy); +} + +// +// Fast double-Tate-Pairing, with shared Miller variable and one final exponentiation +// + +BOOL fast_double_tate_pairing(ECn& P,ZZn3& Qx,ZZn3& Qy,ECn& R,ZZn3& Sx,ZZn3& Sy,Big& q,Big &cf) +{ + int i,j,n,nb,nbw,nzs; + ECn A1,A2,P2,R2,t1[16],*t2; + ZZn6 w,hc,zn[8],res; + Big m; + + t2=&t1[8]; + + res=zn[0]=1; + + t1[0]=P2=A1=P; + t2[0]=R2=A2=R; + + w=g(P2,P2,R2,R2,Qx,Qy,Sx,Sy); + + normalise(P2); + normalise(R2); +// +// Build windowing table +// + for (i=1;i<8;i++) + { + hc=g(A1,P2,A2,R2,Qx,Qy,Sx,Sy); + t1[i]=A1; + t2[i]=A2; + zn[i]=w*zn[i-1]*hc; + } + + multi_norm(16,t1); + + A1=P; + A2=R; + +/* Left to right method */ + m=q-1; // skip last iteration + nb=bits(m); + for (i=nb-2;i>=0;i-=(nbw+nzs)) + { + n=window(m,i,&nbw,&nzs,4); // standard MIRACL windowing + + for (j=0;j0) + { + res*=zn[n/2]; + res*=g(A1,t1[n/2],A2,t2[n/2],Qx,Qy,Sx,Sy); + } + for (j=0;jcnr; + + normalise(PP); + Q.get(Qx,Qy); + +// untwist + Qx=Qx/qnr; + Qy=tx(Qy); + Qy=Qy/(qnr*qnr); + + RR=R; + + normalise(RR); + S.get(Sx,Sy); + +// untwist + Sx=Sx/qnr; + Sy=tx(Sy); + Sy=Sy/(qnr*qnr); + + return fast_double_tate_pairing(PP,Qx,Qy,RR,Sx,Sy,order,cf); +} + +// +// Hash functions +// + +Big H1(char *string,int len) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha sh; + + shs_init(&sh); + + for (i=0;i=p) break; + } + h%=p; + return h; +} + +// Hash and map a Client Identity to a curve point E_(Fp) of order q + +ECn hash_and_map(char *ID,int len) +{ + ECn Q; + Big x0=H1(ID,len); + + while (!Q.set(x0,x0)) x0+=1; + Q*=CF; + return Q; +} + + +int main() +{ + ifstream common("mnt.ecs"); // MNT elliptic curve parameters + ifstream signature("bls_signature.sig"); + ifstream public_key("bls_public.key"); + + miracl* mip=&precision; + ECn S,HM; + ECn3 P,R; + ZZn3 u,v,x3,y3; + Big a,b,c; + Big p,q,x,B,cf,cfp,sru; + int bbits,A,lsb; + + common >> bbits; + mip->IOBASE=16; + common >> p; + common >> A; + common >> B >> q >> cf >> sru; + + ecurve(A,B,p,MR_PROJECTIVE); + set_zzn3(CNR,sru); + + cfp=cf-CF*p; // ~ (t-1) + mip->TWIST=MR_QUADRATIC; // map to point on twisted curve E(Fp3) + +// don't use compression here because it will be slower... + + public_key >> a; + public_key >> b; + public_key >> c; + + x3.set(a,b,c); + + public_key >> a; + public_key >> b; + public_key >> c; + + y3.set(a,b,c); + + P.set(x3,y3); + + public_key >> a; + public_key >> b; + public_key >> c; + + x3.set(a,b,c); + + public_key >> a; + public_key >> b; + public_key >> c; + + y3.set(a,b,c); + + R.set(x3,y3); + + signature >> x; + signature >> lsb; +//cout << "bits(x)= " << bits(x) << endl; +//cout << "x= " << x << endl; +//cout << "lsb= " << lsb << endl; + + if (!S.set(x,1-lsb)) + { + cout << "Signature is invalid" << endl; + exit(0); + } + + HM=hash_and_map((char *)"This a quick test of the method",32); + +//cout << "HM= " << HM << endl; +//cout << "S= " << S << endl; +//cout << "P= " << P << endl; +//cout << "R= " << R << endl; +//cout << "cfp= " << cfp << endl; +//cout << "q= " << q << endl; + + if (ecap2(S,P,HM,R,q,cfp)) cout << "Signature is TRUE" << endl; + else cout << "Signature is FALSE" << endl; + + return 0; +} + diff --git a/miracl/source/curve/pairing/bmc.cpp b/miracl/source/curve/pairing/bmc.cpp new file mode 100644 index 0000000..714e4d6 --- /dev/null +++ b/miracl/source/curve/pairing/bmc.cpp @@ -0,0 +1,123 @@ +/* + Barreto & McCullagh Signcryption + See http://eprint.iacr.org/2004/117.pdf + Section 5.2 + + Compile with modules as specified below + + For MR_PAIRING_CP curve + cl /O2 /GX bmc.cpp cp_pair.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_MNT curve + cl /O2 /GX bmc.cpp mnt_pair.cpp zzn6a.cpp ecn3.cpp zzn3.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_BN curve + cl /O2 /GX bmc.cpp bn_pair.cpp zzn12a.cpp ecn2.cpp zzn4.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_KSS curve + cl /O2 /GX bmc.cpp kss_pair.cpp zzn18.cpp zzn6.cpp ecn3.cpp zzn3.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_BLS curve + cl /O2 /GX bmc.cpp bls_pair.cpp zzn24.cpp zzn8.cpp zzn4.cpp zzn2.cpp ecn4.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + Test program +*/ + +#include +#include + +//********* choose just one of these pairs ********** +//#define MR_PAIRING_CP // AES-80 security +//#define AES_SECURITY 80 + +//#define MR_PAIRING_MNT // AES-80 security +//#define AES_SECURITY 80 + +#define MR_PAIRING_BN // AES-128 or AES-192 security +#define AES_SECURITY 128 +//#define AES_SECURITY 192 + +//#define MR_PAIRING_KSS // AES-192 security +//#define AES_SECURITY 192 + +//#define MR_PAIRING_BLS // AES-256 security +//#define AES_SECURITY 256 +//********************************************* + +#include "pairing_3.h" + +int main() +{ + PFC pfc(AES_SECURITY); // initialise pairing-friendly curve + miracl* mip=get_mip(); + Big order=pfc.order(); + + Big s,u,a,b,x,c,h,M; + G1 P,Ppub,Pa,Pb,R,S,U; + G2 Q,Qsa,Qsb,T; + GT g,N,V; + time_t seed; + + time(&seed); + irand((long)seed); + +//setup + pfc.random(s); + pfc.random(P); + pfc.random(Q); + + g=pfc.pairing(Q,P); + pfc.precomp_for_power(g); + Ppub=pfc.mult(P,s); + +//Keygen + a=pfc.hash_to_group((char *)"Alice"); + Qsa=pfc.mult(Q,inverse(modmult(s,a,order),order)); + b=pfc.hash_to_group((char *)"Bob"); + Qsb=pfc.mult(Q,inverse(modmult(s,b,order),order)); + Pa=pfc.mult(Ppub,a); + Pb=pfc.mult(Ppub,b); + +//Signcrypt + mip->IOBASE=256; + M=(char *)"test message"; // to be signcrypted from Alice to Bob + cout << "Signed Message= " << M << endl; + mip->IOBASE=16; + + pfc.precomp_for_mult(Pa); + pfc.precomp_for_mult(Qsa); + pfc.random(x); + N=pfc.power(g,inverse(x,order)); + R=pfc.mult(Pa,x); + S=pfc.mult(Pb,inverse(x,order)); + c=lxor(M,pfc.hash_to_aes_key(N)); + pfc.start_hash(); + pfc.add_to_hash(R); + pfc.add_to_hash(S); + pfc.add_to_hash(c); + h=pfc.finish_hash_to_group(); + T=pfc.mult(Qsa,inverse(x+h,order)); + +// Unsigncrypt + pfc.precomp_for_pairing(Qsb); // Bob can precompute on his private key + pfc.start_hash(); + pfc.add_to_hash(R); + pfc.add_to_hash(S); + pfc.add_to_hash(c); + h=pfc.finish_hash_to_group(); + + U=pfc.mult(Pa,h); + V=pfc.pairing(T,R+U); + N=pfc.pairing(Qsb,S); + M=lxor(c,pfc.hash_to_aes_key(N)); + mip->IOBASE=256; + if (V==g) + { + cout << "Message is OK" << endl; + cout << "Verified Message= " << M << endl; + } + else + cout << "Message is bad " << M << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/bn.cpp b/miracl/source/curve/pairing/bn.cpp new file mode 100644 index 0000000..8caafe5 --- /dev/null +++ b/miracl/source/curve/pairing/bn.cpp @@ -0,0 +1,193 @@ +// +// cl /O2 /GX bn.cpp zzn2.cpp zzn.cpp ecn2.cpp ecn.cpp big.cpp miracl.lib +// Program to generate BN curves for use by ake12*.cpp +// + +#include +#include "big.h" +#include "ecn.h" +#include "ecn2.h" +//#include "zzn12.h" + +using namespace std; + +Miracl precision=100; + +int main() +{ + int i,ns; + int sign; + BOOL ontwist; + Big m1,m2,n,p,t,x,cube,y,b,eta,w,cf[4],X,Y; + Big PP,TT,FF; + miracl*mip=&precision; + ECn P; + ECn2 Q,T; + ZZn2 xi,r; + + x=pow((Big)2,62)+pow((Big)2,55)-1; // x is this size to get right size for t, p and n + // x is low hamming weight + mip->IOBASE=16; + sign=1; // 1= positive, 2=negative for +/- x solutions + ns=1; + for (i=0;i<100;i++) + { + forever + { + forever + { + sign=3-sign; // always looking for +ve x solutions. + if (sign==1) x+=1; + + if (sign==1) p=36*pow(x,4)+36*pow(x,3)+24*x*x+6*x+1; + else p=36*pow(x,4)-36*pow(x,3)+24*x*x-6*x+1; + //cout << "x= " << x << " p%8= " << p%8 << " p%6= " << p%6 << " p%9= " << p%9 << endl; + //if (prime(p)) cout << "p is prime" << endl; + + // Now check congruence conditions + if (p%8==1) continue; + // if (p%9==1) continue; + + if (p%8==7 && (p%5==1 || p%5==4)) continue; + + if (!prime(p)) continue; + + modulo(p); + if (p%8==5) xi.set(0,1); + if (p%8==3) xi.set(1,1); + if (p%8==7) xi.set(2,1); + +// make sure its irreducible + if (pow(xi,(p*p-1)/2)==1) {/*cout << "Failed - not a square" << endl; */ continue;} + if (pow(xi,(p*p-1)/3)==1) {/*cout << "Failed - not a cube" << endl;*/ continue;} // make sure that x^6-c is irreducible + + t=6*x*x+1; + n=p+1-t; + if (prime(n)) break; + } + + cf[3]=1; + cf[2]=6*x*x+1; + cf[1]=36*x*x*x-18*x*x+12*x+1; + cf[0]=36*x*x*x-30*x*x+18*x-2; + +// find number of points on sextic twist.. + + TT=t*t-2*p; + PP=p*p; + + FF=(4*PP-TT*TT)/3; + FF=sqrt(FF); + + // m1=PP+1-(-3*FF+TT)/2; // 2 possibilities... This is the wrong curve. + m2=PP+1-(3*FF+TT)/2; + + b=1; + forever + { + b+=1; + if (b==2) + { + X=-1; Y=1; + } + else if (b==3) + { + X=1; Y=2; + } + else if (b==8) + { + X=1; Y=3; + } + else if (b==15) + { + X=1; Y=4; + } + else + { + do + { + X=rand(p); + Y=sqrt(X*X*X+b,p); + } while (Y==0); + } + + ecurve(0,b,p,MR_AFFINE); + + P.set(X,Y); + if ((n*P).iszero()) break; + } + + mip->TWIST=MR_SEXTIC_M; + + do + { + r=randn2(); + } while (!Q.set(r)); + + Q*=m2/n; + if ((n*Q).iszero()) break; + + mip->TWIST=MR_SEXTIC_D; + + do + { + r=randn2(); + } while (!Q.set(r)); + + Q*=m2/n; + if ((n*Q).iszero()) break; + + cout << "Something Wrong" << endl; + exit(0); + } +// Note that this program only produces BN curves for which y^2=x^3+B/D yields the correct twist +// It would be possible to modify to find curves on the other twist y^2=x^3+B*D- but a lot of changes required! + + + cout << "solution " << ns << endl; + cout << "irreducible polynomial = X^6 - " << xi << endl; + + if (sign==1) + { + cout << "x mod 12 = " << x%12 << endl; + cout << "x= +" << x << endl; + } + else + { + cout << "x mod 12 = " << 12-(x%12) << endl; + cout << "x= -" << x << endl; + } + cout << "p=" << p << endl; + cout << "p mod 72 = " << p%72 << endl; + + cout << "bits(p)= " << bits(p) << endl; + cout << "n=" << n << endl; + cout << "t=" << t << endl; + + cout << "ham(6*x+2)= " << ham(6*x+2) << " (small is better for R-ate pairing)" << endl; + + cout << "bits(t)= " << bits(t) << endl; + cout << "ham(t-1) = " << ham(t-1) << " (small is better for Ate pairing)" << endl; + + cout << "bits(n)= " << bits(n) << endl; + cout << "ham(n-1) = " << ham(n-1) << " (small is better for Tate pairing)" << endl; + mip->IOBASE=10; + cout << "E(Fp): y^2=x^3+" << b << endl; + mip->IOBASE=16; + if (mip->TWIST==MR_SEXTIC_M) cout << "Twist type M" << endl; + if (mip->TWIST==MR_SEXTIC_D) cout << "Twist type D" << endl; + + mip->IOBASE=10; + cout << "Hard part= " << (p*p*p*p-p*p+1)/n << endl; + mip->IOBASE=16; + + cout << "Point P= " << P << endl; + cout << "Point Q= " << Q << endl; + T=n*Q; + cout << "check - if right twist should be O - n*Q= " << T << endl << endl; + ns++; + + } + return 0; +} + diff --git a/miracl/source/curve/pairing/bn_pair.cpp b/miracl/source/curve/pairing/bn_pair.cpp new file mode 100644 index 0000000..89c1b26 --- /dev/null +++ b/miracl/source/curve/pairing/bn_pair.cpp @@ -0,0 +1,1609 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * + * bn_pair.cpp + * + * BN curve, ate pairing embedding degree 12, ideal for security level AES-128 + * + * Irreducible poly is X^3+n, where n=sqrt(w+sqrt(m)), m= {-1,-2} and w= {0,1,2} + * if p=5 mod 8, n=sqrt(-2) + * if p=3 mod 8, n=1+sqrt(-1) + * if p=7 mod 8, p=2,3 mod 5, n=2+sqrt(-1) + * + * Provides high level interface to pairing functions + * + * GT=pairing(G2,G1) + * + * This is calculated on a Pairing Friendly Curve (PFC), which must first be defined. + * + * G1 is a point over the base field, and G2 is a point over an extension field of degree 2 + * GT is a finite field point over the 12-th extension, where 12 is the embedding degree. + * + */ + +#define MR_PAIRING_BN +#include "pairing_3.h" + +// BN curve parameters x,A,B +static char param_128[]="-4080000000000001"; +// 766 - bit curve +static char param_192[]="-4000000000000000000000000000000000000000000ABBB5"; // Hamming weight of 6*x+2 = 8 +static char curveB[]="2"; + +void read_only_error(void) +{ + cout << "Attempt to write to read-only object" << endl; + exit(0); +} + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + X.set((Big)0,(Big)1); // = (sqrt(-2)^(p-1)/2 + break; + case 3: // = (1+sqrt(-1))^(p-1)/2 + X.set((Big)1,(Big)1); + break; + case 7: + X.set((Big)2,(Big)1); // = (2+sqrt(-1))^(p-1)/2 + default: break; + } + X=pow(X,(p-1)/6); +} + +// Using SHA256 as basic hash algorithm +// +// Hash function +// + +#define HASH_LEN 32 + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + unsigned char s[HASH_LEN]; + int i,j; + sha256 sh; + + shs256_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs256_process(&sh,string[i]); + } + shs256_hash(&sh,(char *)s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +void PFC::start_hash(void) +{ + shs256_init(&SH); +} + +Big PFC::finish_hash_to_group(void) +{ + Big hash; + char s[HASH_LEN]; + shs256_hash(&SH,s); + hash=from_binary(HASH_LEN,s); + return hash%(*ord); +} + +Big PFC::finish_hash_to_aes_key(void) +{ + Big hash; + char s[HASH_LEN]; + shs256_hash(&SH,s); + Big m=pow((Big)2,S); + hash=from_binary(HASH_LEN,s); + return hash%m; +} + +void PFC::add_to_hash(const GT& x) +{ + ZZn4 u; + ZZn12 v=x.g; + ZZn2 h,l; + Big a; + ZZn xx[6]; + + int i,j,m; + v.get(u); + u.get(l,h); + l.get(xx[0],xx[1]); + h.get(xx[2],xx[3]); + + for (i=0;i<4;i++) + { + a=(Big)xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } + } +} + +void PFC::add_to_hash(const G2& x) +{ + ZZn2 X,Y; + ECn2 v=x.g; + Big a; + ZZn xx[4]; + + int i,m; + + v.get(X,Y); + X.get(xx[0],xx[1]); + Y.get(xx[2],xx[3]); + for (i=0;i<4;i++) + { + a=(Big)xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } + } +} + +void PFC::add_to_hash(const G1& x) +{ + Big a,X,Y; + int i,m; + x.g.get(X,Y); + a=X; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } + a=Y; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } +} + +void PFC::add_to_hash(const Big& x) +{ + int m; + Big a=x; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } +} + + +void PFC::add_to_hash(char *x) +{ + int i=0; + while (x[i]!=0) + { + shs256_process(&SH,x[i]); + i++; + } +} + +Big H2(ZZn12 x) +{ // Compress and hash an Fp12 to a big number + sha256 sh; + ZZn4 u; + ZZn2 h,l; + Big a,hash,p,xx[4]; + char s[HASH_LEN]; + int i,j,m; + + shs256_init(&sh); + x.get(u); // compress to single ZZn4 + u.get(l,h); + xx[0]=real(l); xx[1]=imaginary(l); xx[2]=real(h); xx[3]=imaginary(h); + + for (i=0;i<4;i++) + { + a=xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&sh,m); + a/=256; + } + } + shs256_hash(&sh,s); + hash=from_binary(HASH_LEN,s); + return hash; +} + +#ifndef MR_AFFINE_ONLY + +void force(ZZn& x,ZZn& y,ZZn& z,ECn& A) +{ // A=(x,y,z) + copy(getbig(x),A.get_point()->X); + copy(getbig(y),A.get_point()->Y); + copy(getbig(z),A.get_point()->Z); + A.get_point()->marker=MR_EPOINT_GENERAL; +} + +void extract(ECn &A, ZZn& x,ZZn& y,ZZn& z) +{ // (x,y,z) <- A + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} + +#endif + +void force(ZZn& x,ZZn& y,ECn& A) +{ // A=(x,y) + copy(getbig(x),A.get_point()->X); + copy(getbig(y),A.get_point()->Y); + A.get_point()->marker=MR_EPOINT_NORMALIZED; +} + +void extract(ECn& A,ZZn& x,ZZn& y) +{ // (x,y) <- A + if (A.iszero()) + { + x=0; y=0; + return; + } + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + + +// Fast multiplication of A by q (for Trace-Zero group members only) +// Calculate q*P. P(X,Y) -> P(X^p,Y^p)) + +void q_power_frobenius(ECn2 &A,ZZn2 &F) +{ + ZZn2 x,y,z,w,r; + + A.get(x,y,z); + w=F*F; + r=F; + x=w*conj(x); + y=r*w*conj(y); + z.conj(); + A.set(x,y,z); +} + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn12 line(ECn2& A,ECn2& C,ECn2& B,ZZn2& slope,ZZn2& extra,BOOL Doubling,ZZn& Qx,ZZn& Qy) +{ + ZZn12 w; + ZZn4 nn,dd; + ZZn2 X,Y; + + ZZn2 Z3; + + C.getZ(Z3); + +// Thanks to A. Menezes for pointing out this optimization... + if (Doubling) + { + ZZn2 Z,ZZ; + A.get(X,Y,Z); + ZZ=Z; ZZ*=ZZ; + nn.set((Z3*ZZ)*Qy,slope*X-extra); + dd.set(-(ZZ*slope)*Qx); + } + else + { + ZZn2 X2,Y2; + B.get(X2,Y2); + nn.set(Z3*Qy,slope*X2-Y2*Z3); + dd.set(-slope*Qx); + } + w.set(nn,dd); + + return w; +} + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn12 g(ECn2& A,ECn2& B,ZZn& Qx,ZZn& Qy) +{ + ZZn2 lam,extra; + ZZn12 r; + ECn2 P=A; + BOOL Doubling; + +// Evaluate line from A + Doubling=A.add(B,lam,extra); + + if (A.iszero()) return (ZZn12)1; + r=line(P,A,B,lam,extra,Doubling,Qx,Qy); + + return r; +} + +// if multiples of G2 in e(G2,G1) can be precalculated, its a lot faster! + +ZZn12 gp(ZZn2* ptable,int &j,ZZn& Px,ZZn& Py) +{ + ZZn12 w; + ZZn4 nn,dd; + + nn.set(Py,ptable[j+1]); + dd.set(ptable[j]*Px); + j+=2; + w.set(nn,dd); + + return w; +} + +// +// Spill precomputation on pairing to byte array +// + +int PFC::spill(G2& w,char *& bytes) +{ + int i,j,len,m; + int bytes_per_big=(MIRACL/8)*(get_mip()->nib-1); + + Big a,b,n; + Big X=*x; + if (w.ptable==NULL) return 0; + + if (X<0) n=-(6*X+2); + else n=6*X+2; + + m=2*(bits(n)+ham(n)); + len=m*2*bytes_per_big; + + bytes=new char[len]; + for (i=j=0;inib-1); + + Big a,b,n; + Big X=*x; + if (w.ptable!=NULL) return; + + if (X<0) n=-(6*X+2); + else n=6*X+2; + + m=2*(bits(n)+ham(n)); // number of entries in ptable + len=m*2*bytes_per_big; + + w.ptable=new ZZn2[m]; + for (i=j=0;icoord=MR_AFFINE; // switch to affine + for (i=nb-2;i>=0;i--) + { + Q=A; +// Evaluate line from A to A+A + A.add(A,lam); + Q.get(x1,y1); + w.ptable[j++]=-lam; w.ptable[j++]=lam*x1-y1; + if (bit(n,i)==1) + { + Q=A; + A.add(B,lam); + Q.get(x1,y1); + w.ptable[j++]=-lam; w.ptable[j++]=lam*x1-y1; + } + } + + q_power_frobenius(KA,*frob); + if (X<0) A=-A; + Q=A; + A.add(KA,lam); + KA.get(x1,y1); + w.ptable[j++]=-lam; w.ptable[j++]=lam*x1-y1; + + q_power_frobenius(KA,*frob); KA=-KA; + + Q=A; + A.add(KA,lam); + KA.get(x1,y1); + w.ptable[j++]=-lam; w.ptable[j++]=lam*x1-y1; + + get_mip()->coord=MR_PROJECTIVE; + return len; +} + +GT PFC::multi_miller(int n,G2** QQ,G1** PP) +{ + GT z; + ZZn *Px,*Py; + int i,j,*k,nb; + ECn2 *Q,*A; + ECn P; + ZZn12 res; + Big m; + Big X=*x; + + Px=new ZZn[n]; + Py=new ZZn[n]; + Q=new ECn2[n]; + A=new ECn2[n]; + k=new int[n]; + + if (X<0) m=-(6*X+2); + else m=6*X+2; + + nb=bits(m); + res=1; + + for (j=0;jg; normalise(P); Q[j]=QQ[j]->g; Q[j].norm(); + extract(P,Px[j],Py[j]); + } + + for (j=0;j=0;i--) + { + res*=res; + for (j=0;jptable==NULL) + res*=g(A[j],A[j],Px[j],Py[j]); + else + res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + if (bit(m,i)==1) + for (j=0;jptable==NULL) + res*=g(A[j],Q[j],Px[j],Py[j]); + else + res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + if (res.iszero()) return 0; + } + + if (X<0) res.conj(); + for (j=0;jptable==NULL) + { + if (X<0) A[j]=-A[j]; + res*=g(A[j],Q[j],Px[j],Py[j]); + } + else + res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + q_power_frobenius(Q[j],*frob); + + if (QQ[j]->ptable==NULL) + { + Q[j]=-Q[j]; + res*=g(A[j],Q[j],Px[j],Py[j]); + } + else + res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + + delete [] k; + delete [] A; + delete [] Q; + delete [] Py; + delete [] Px; + + z.g=res; + return z; +} + +// +// R-ate Pairing G2 x G1 -> GT +// +// P is a point of order q in G1. Q(x,y) is a point of order q in G2. +// Note that Q is a point on the sextic twist of the curve over Fp^2, P(x,y) is a point on the +// curve over the base field Fp +// + +GT PFC::miller_loop(const G2& QQ,const G1& PP) +{ + GT z; + Big n; + int i,j,nb,nbw,nzs; + ECn2 A,KA,Q; + ECn P; + ZZn Px,Py; + BOOL precomp; + ZZn12 r; + Big X=*x; + + Q=QQ.g; P=PP.g; + + precomp=FALSE; + if (QQ.ptable!=NULL) precomp=TRUE; + else Q.norm(); + + normalise(P); + extract(P,Px,Py); + + if (X<0) n=-(6*X+2); + else n=6*X+2; + A=Q; + nb=bits(n); + r=1; +// Short Miller loop + r.mark_as_miller(); + j=0; + for (i=nb-2;i>=0;i--) + { + r*=r; + if (precomp) r*=gp(QQ.ptable,j,Px,Py); + else r*=g(A,A,Px,Py); + if (bit(n,i)) + { + if (precomp) r*=gp(QQ.ptable,j,Px,Py); + else r*=g(A,Q,Px,Py); + } + } +// Combining ideas due to Longa, Aranha et al. and Naehrig + KA=Q; + q_power_frobenius(KA,*frob); + if (X<0) {A=-A; r.conj();} + if (precomp) r*=gp(QQ.ptable,j,Px,Py); + else r*=g(A,KA,Px,Py); + q_power_frobenius(KA,*frob); KA=-KA; + if (precomp) r*=gp(QQ.ptable,j,Px,Py); + else r*=g(A,KA,Px,Py); + + z.g=r; + return z; +} + +GT PFC::final_exp(const GT& z) +{ + GT y; + ZZn12 r,t0,t1; + ZZn12 x0,x1,x2,x3,x4,x5; + Big X=*x; + +// The final exponentiation + r=z.g; + t0=r; + + r.conj(); + r/=t0; // r^(p^6-1) + r.mark_as_regular(); // no longer "miller" + t0=r; + r.powq(*frob); r.powq(*frob); + r*=t0; // r^[(p^6-1)*(p^2+1)] + + r.mark_as_unitary(); // from now on all inverses are just conjugates !! (and squarings are faster) + + t1=pow(r,-X); // x is sparse.. + + t0=r; t0.powq(*frob); + x0=t0; x0.powq(*frob); + + x0*=(r*t0); + x0.powq(*frob); + x1=inverse(r); // just a conjugation! + x3=t1; x3.powq(*frob); + x4=t1; + t1=pow(t1,-X); + x2=t1; x2.powq(*frob); + x4/=x2; + x2.powq(*frob); + x5=inverse(t1); + t0=pow(t1,-X); + t1=t0; t1.powq(*frob); t0*=t1; + + t0*=t0; + t0*=x4; + t0*=x5; + t1=x3*x5; + t1*=t0; + t0*=x2; + t1*=t1; + t1*=t0; + t1*=t1; + t0=t1*x1; + t1*=x0; + t0*=t0; + t0*=t1; + y.g=t0; + return y; +} + +PFC::PFC(int s, csprng *rng) +{ + int i,j,mod_bits,words; + if (s!=128 && s!=192) + { + cout << "No suitable curve available" << endl; + exit(0); + } + if (s==128) mod_bits=256; + if (s==192) mod_bits=768; + + if (mod_bits%MIRACL==0) + words=(mod_bits/MIRACL); + else + words=(mod_bits/MIRACL)+1; + +#ifdef MR_SIMPLE_BASE + miracl *mip=mirsys((MIRACL/4)*words,16); +#else + miracl *mip=mirsys(words,0); + mip->IOBASE=16; +#endif + + B=new Big; + x=new Big; + mod=new Big; + ord=new Big; + cof=new Big; + npoints=new Big; + trace=new Big; + + for (i=0;i<4;i++) + { + WB[i]=new Big; + for (j=0;j<4;j++) + { + BB[i][j]=new Big; + } + } + for (i=0;i<2;i++) + { + W[i]=new Big; + for (j=0;j<2;j++) + { + SB[i][j]=new Big; + } + } + + Beta=new ZZn; + frob=new ZZn2; + + Big A=0; + *B=curveB; + if (s==128) *x=param_128; + if (s==192) *x=param_192; + S=s; + + Big X=*x; + + *mod=36*pow(X,4)+36*pow(X,3)+24*X*X+6*X+1; + *trace=6*X*X+1; + *npoints=*mod+1-*trace; + *cof=*mod-1+*trace; + *ord=*npoints; + ecurve(A,*B,*mod,MR_PROJECTIVE); + +// Big Lambda=-(36*pow(x,3)+18*x*x+6*x+2); // cube root of unity mod q + *Beta=-(18*pow(X,3)+18*X*X+9*X+2); // cube root of unity mod p + set_frobenius_constant(*frob); + +// Use standard Gallant-Lambert-Vanstone endomorphism method for G1 + *W[0]=6*X*X+4*X+1; // This is first column of inverse of SB (without division by determinant) + *W[1]=-(2*X+1); + + *SB[0][0]=6*X*X+2*X; + *SB[0][1]=-(2*X+1); + *SB[1][0]=-(2*X+1); + *SB[1][1]=-(6*X*X+4*X+1); + +// Use Galbraith & Scott Homomorphism idea for G2 & GT ... (http://eprint.iacr.org/2008/117.pdf EXample 5) + *WB[0]=2*X*X+3*X+1; // This is first column of inverse of BB (without division by determinant) + *WB[1]=12*X*X*X+8*X*X+X; + *WB[2]=6*X*X*X+4*X*X+X; + *WB[3]=-2*X*X-X; + *BB[0][0]=X+1; *BB[0][1]=X; *BB[0][2]=X; *BB[0][3]=-2*X; + *BB[1][0]=2*X+1; *BB[1][1]=-X; *BB[1][2]=-(X+1); *BB[1][3]=-X; + *BB[2][0]=2*X; *BB[2][1]=2*X+1; *BB[2][2]=2*X+1; *BB[2][3]=2*X+1; + *BB[3][0]=X-1; *BB[3][1]=4*X+2; *BB[3][2]=-(2*X-1); *BB[3][3]=X-1; + mip->TWIST=MR_SEXTIC_D; // map Server to point on twisted curve E(Fp2) + + RNG = rng; +} + +PFC::~PFC() +{ + int i,j; + delete B; + delete x; + delete mod; + delete ord; + delete cof; + delete npoints; + delete trace; + + for (i=0;i<4;i++) + { + delete WB[i]; + for (j=0;j<4;j++) + delete BB[i][j]; + } + for (i=0;i<2;i++) + { + delete W[i]; + for (j=0;j<2;j++) + delete SB[i][j]; + } + + delete Beta; + delete frob; + mirexit(); +} + +// GLV method + +void glv(const Big &e,Big &r,Big *W[2],Big *B[2][2],Big u[2]) +{ + int i,j; + Big v[2],w; + for (i=0;i<2;i++) + { + v[i]=mad(*W[i],e,(Big)0,r,w); + u[i]=0; + } + u[0]=e; + for (i=0;i<2;i++) + for (j=0;j<2;j++) + u[i]-=v[j]*(*B[j][i]); + return; +} + +void endomorph(ECn &A,ZZn &Beta) +{ // apply endomorphism (x,y) = (Beta*x,y) where Beta is cube root of unity + ZZn x; + x=(A.get_point())->X; + x*=Beta; + copy(getbig(x),(A.get_point())->X); +} + +G1 PFC::mult(const G1& w,const Big& k) +{ + G1 z; + ECn Q; + if (w.mtable!=NULL) + { // we have precomputed values + Big e=k; + if (k<0) e=-e; + + int i,j,t=w.mtbits; //MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.mtable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g+=z.g; + if (j>0) z.g+=w.mtable[j]; + + } + if (k<0) z.g=-z.g; + } + else + { + Big u[2]; + Q=w.g; + glv(k,*ord,W,SB,u); + endomorph(Q,*Beta); + Q=mul(u[0],w.g,u[1],Q); + z.g=Q; + } + return z; +} + +// Use Galbraith & Scott Homomorphism idea ... + +void galscott(const Big &e,Big &r,Big *WB[4],Big *B[4][4],Big u[4]) +{ + int i,j; + Big v[4],w; + + for (i=0;i<4;i++) + { + v[i]=mad(*WB[i],e,(Big)0,r,w); + u[i]=0; + } + + u[0]=e; + for (i=0;i<4;i++) + for (j=0;j<4;j++) + u[i]-=v[j]*(*B[j][i]); + return; +} + +// GLV + Galbraith-Scott + +G2 PFC::mult(const G2& w,const Big& k) +{ + G2 z; + int i; + + if (w.mtable!=NULL) + { // we have precomputed values + Big e=k; + if (k<0) e=-e; + int i,j,t=w.mtbits; //MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.mtable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g+=z.g; + if (j>0) z.g+=w.mtable[j]; + } + if (k<0) z.g=-z.g; + } + else + { + ECn2 Q[4]; + Big u[4]; + BOOL small=TRUE; + galscott(k,*ord,WB,BB,u); + + Q[0]=w.g; Q[0].norm(); + + for (i=1;i<4;i++) + { + if (u[i]!=0) + { + small=FALSE; + break; + } + } + + if (small) + { + if (u[0]<0) + { + u[0]=-u[0]; + Q[0]=-Q[0]; + } + z.g=Q[0]; + z.g*=u[0]; + z.g.norm(); + return z; + } + + for (i=1;i<4;i++) + { + Q[i]=Q[i-1]; + q_power_frobenius(Q[i],*frob); + } + +// deal with -ve multipliers + for (i=0;i<4;i++) + { + if (u[i]<0) + {u[i]=-u[i];Q[i]=-Q[i];} + } + +// simple multi-addition + z.g= mul(4,Q,u); + } + z.g.norm(); + return z; +} + +// GLV method + Galbraith-Scott idea + +GT PFC::power(const GT& w,const Big& k) +{ + GT z; + + int i; + if (w.etable!=NULL) + { // precomputation is available + Big e=k; + if (k<0) e=-e; + + int i,j,t=w.etbits; // MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.etable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g*=z.g; + if (j>0) z.g*=w.etable[j]; + } + if (k<0) z.g=inverse(z.g); + } + else + { + ZZn12 Y[4]; + Big u[4]; + + galscott(k,*ord,WB,BB,u); + + Y[0]=w.g; + for (i=1;i<4;i++) + {Y[i]=Y[i-1]; Y[i].powq(*frob);} + +// deal with -ve exponents + for (i=0;i<4;i++) + { + if (u[i]<0) + {u[i]=-u[i];Y[i].conj();} + } + +// simple multi-exponentiation + z.g= pow(4,Y,u); + } + return z; +} + +// +// Faster Hashing to G2 - Fuentes-Castaneda, Knapp and Rodriguez-Henriquez +// + +void map(ECn2& S,Big &x,ZZn2 &F) +{ + ECn2 T,K; + T=S; + T*=x; // one multiplication by x only + T.norm(); + K=(T+T); + K+=T; + K.norm(); + q_power_frobenius(K,F); + q_power_frobenius(S,F); q_power_frobenius(S,F); q_power_frobenius(S,F); + S+=T; S+=K; + q_power_frobenius(T,F); q_power_frobenius(T,F); + S+=T; + S.norm(); +} + +// random group element + +void PFC::random(Big& w) +{ + if (RNG==NULL) w=rand(2*S,2); + else w=strong_rand(RNG,2*S,2); +} + +// random AES key + +void PFC::rankey(Big& k) +{ + if (RNG==NULL) k=rand(S,2); + else k=strong_rand(RNG,S,2); +} + +void PFC::hash_and_map(G2& w,char *ID) +{ + int i; + ZZn2 X; + + Big x0=H1(ID); + + forever + { + x0+=1; + X.set((ZZn)1,(ZZn)x0); + if (!w.g.set(X)) continue; + break; + } + + map(w.g,*x,*frob); +} + +void PFC::random(G2& w) +{ + int i; + ZZn2 X; + Big x0; + + if (RNG==NULL) x0=rand(*mod); + else x0=strong_rand(RNG, *mod); + + forever + { + x0+=1; + X.set((ZZn)1,(ZZn)x0); + if (!w.g.set(X)) continue; + break; + } + + map(w.g,*x,*frob); +} + +void PFC::hash_and_map(G1& w,char *ID) +{ + Big x0=H1(ID); + + while (!w.g.set(x0,x0)) x0+=1; +} + +void PFC::random(G1& w) +{ + Big x0; + if (RNG==NULL) x0=rand(*mod); + else x0=strong_rand(RNG, *mod); + + while (!w.g.set(x0,x0)) x0+=1; +} + +Big PFC::hash_to_aes_key(const GT& w) +{ + Big m=pow((Big)2,S); + return H2(w.g)%m; +} + +Big PFC::hash_to_group(char *ID) +{ + Big m=H1(ID); + return m%(*ord); +} + +Big PFC::hash_to_group(char *buffer, int len) +{ + Big h,p; + char s[HASH_LEN]; + int i,j; + sha256 sh; + + shs256_init(&sh); + for (i=0; i < len; i++) + { + shs256_process(&sh,buffer[i]); + } + shs256_hash(&sh,s); + + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=(unsigned char)s[j++]; + if (h>=p) break; + } + h%=p; + return h % (*ord); +} + +GT operator*(const GT& x,const GT& y) +{ + GT z=x; + z.g*=y.g; + return z; +} + +GT operator/(const GT& x,const GT& y) +{ + GT z=x; + z.g/=y.g; + return z; +} + +// +// spill precomputation on GT to byte array +// + +int GT::spill(char *& bytes) +{ + int i,j,n=(1<nib-1); + int len=n*12*bytes_per_big+1; + ZZn4 a,b,c; + ZZn2 f,s; + Big x,y; + + if (etable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*12*bytes_per_big; + ZZn4 a,b,c; + ZZn2 f,s; + Big x,y; + if (etable!=NULL) return; + + etable=new ZZn12[1<nib-1); + int len=n*2*bytes_per_big+1; + Big x,y; + + if (mtable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*2*bytes_per_big; + Big x,y; + if (mtable!=NULL) return; + + mtable=new ECn[1<nib-1); + int len=n*4*bytes_per_big+1; + ZZn2 a,b; + Big x,y; + + if (mtable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*4*bytes_per_big; + ZZn2 a,b; + Big x,y; + if (mtable!=NULL) return; + + mtable=new ECn2[1<=p) break; + } + h%=p; + return h; +} + +void PFC::start_hash(void) +{ + shs256_init(&SH); +} + +Big PFC::finish_hash_to_group(void) +{ + Big hash; + char s[HASH_LEN]; + shs256_hash(&SH,s); + hash=from_binary(HASH_LEN,s); + return hash%(*ord); +} + +void PFC::add_to_hash(const GT& x) +{ // compress it and add + ZZn2 u=x.g; + Big a; + int m; + + u.get(a); + + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } +} + +void PFC::add_to_hash(const G1& x) +{ + Big a,X,Y; + int i,m; + x.g.get(X,Y); + a=X; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } + a=Y; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } +} + +void PFC::add_to_hash(const G2& x) +{ + Big a,X,Y; + int i,m; + x.g.get(X,Y); + a=X; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } + a=Y; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } +} + +void PFC::add_to_hash(const Big& x) +{ + int m; + Big a=x; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } +} + + +void PFC::add_to_hash(char *x) +{ + int i=0; + while (x[i]!=0) + { + shs256_process(&SH,x[i]); + i++; + } +} + +Big H2(ZZn2 y) +{ // Hash and compress an Fp2 to a big number + sha256 sh; + Big a,h; + char s[HASH_LEN]; + int m; + + shs256_init(&sh); + y.get(a); + + while (a>0) + { + m=a%256; + shs256_process(&sh,m); + a/=256; + } + shs256_hash(&sh,s); + h=from_binary(HASH_LEN,s); + return h; +} + +#ifndef MR_AFFINE_ONLY + +void force(ZZn& x,ZZn& y,ZZn& z,ECn& A) +{ // A=(x,y,z) + copy(getbig(x),A.get_point()->X); + copy(getbig(y),A.get_point()->Y); + copy(getbig(z),A.get_point()->Z); + A.get_point()->marker=MR_EPOINT_GENERAL; +} + +void extract(ECn &A, ZZn& x,ZZn& y,ZZn& z) +{ // (x,y,z) <- A + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} + +#endif + +void force(ZZn& x,ZZn& y,ECn& A) +{ // A=(x,y) + copy(getbig(x),A.get_point()->X); + copy(getbig(y),A.get_point()->Y); + A.get_point()->marker=MR_EPOINT_NORMALIZED; +} + +void extract(ECn& A,ZZn& x,ZZn& y) +{ // (x,y) <- A + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +void extractZ(ECn& A,ZZn& z) +{ + big t; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn2 line(ECn& A,ECn& C,ECn& B,int type,ZZn& slope,ZZn& ex1,ZZn& ex2,ZZn& Px,ZZn& Py) +{ + ZZn2 w; + ZZn x,y,z3; + + extractZ(C,z3); + if (type==MR_ADD) + { + extract(B,x,y); + w.set(slope*(x+Px)-z3*y,z3*Py); + } + if (type==MR_DOUBLE) + { + extract(A,x,y); + w.set(-(slope*ex2)*Px-slope*x+ex1,-(z3*ex2)*Py); + } + +/* + extract(A,x,y,z); + x*=z; t=z; z*=z; z*=t; // 9 ZZn muls + n*=z; n+=x; n*=slope; + d*=z; w.set(-y,d); + extractZ(C,z3); + + w*=z3; w+=n; +*/ + +// w.set(Px*z*z*z*slope+slope*x*z-y*z3,Py*z*z*z*z3); + return w; +} + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn2 g(ECn& A,ECn& B,ZZn& Px,ZZn& Py) +{ + int type; + ZZn lam,extra1,extra2; + ZZn2 u; + ECn P=A; + big ptr,ex1,ex2; + + type=A.add(B,&ptr,&ex1,&ex2); + if (!type) return (ZZn2)1; + lam=ptr; + extra1=ex1; + extra2=ex2; + + return line(P,A,B,type,lam,extra1,extra2,Px,Py); +} + +// if multiples of G2 can be precalculated, its a lot faster! + +ZZn2 gp(ZZn* ptable,int &j,ZZn& Px,ZZn& Py) +{ + ZZn2 w; + w.set(ptable[j]*Px+ptable[j+1],Py); + j+=2; + return w; +} + +// +// Spill precomputation on pairing to byte array +// + +int PFC::spill(G2& w,char *& bytes) +{ + int i,j,n=2*(bits(*ord-1)-2+ham(*ord)); + int bytes_per_big=(MIRACL/8)*(get_mip()->nib-1); + int len=n*bytes_per_big; + Big x; + if (w.ptable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); + int len=n*bytes_per_big; + Big x; + + if (w.ptable!=NULL) return; + + w.ptable=new ZZn[n]; + for (i=j=0;icoord=MR_AFFINE; + for (i=nb-2;i>=0;i--) + { + Q=A; +// Evaluate line from A to A+B + A.add(A,&ptr); + lam=ptr; + extract(Q,x,y); + w.ptable[j++]=lam; w.ptable[j++]=lam*x-y; + + if (bit(iters,i)==1) + { + Q=A; + A.add(B,&ptr); + lam=ptr; + extract(Q,x,y); + w.ptable[j++]=lam; w.ptable[j++]=lam*x-y; + } + } + get_mip()->coord=MR_PROJECTIVE; + return len; +} + +GT PFC::multi_miller(int n,G2** QQ,G1** PP) +{ + GT z; + ZZn *Px,*Py; + int i,j,*k,nb; + ECn *Q,*A; + ECn P; + ZZn2 res; + Big iters=*ord-1; + + Px=new ZZn[n]; + Py=new ZZn[n]; + Q=new ECn[n]; + A=new ECn[n]; + k=new int[n]; + + nb=bits(iters); + res=1; + + for (j=0;jg; normalise(P); Q[j]=QQ[j]->g; normalise(Q[j]); + extract(P,Px[j],Py[j]); + } + + for (j=0;j=0;i--) + { + res*=res; + for (j=0;jptable==NULL) + res*=g(A[j],A[j],Px[j],Py[j]); + else + res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + if (bit(iters,i)==1) + for (j=0;jptable==NULL) + res*=g(A[j],Q[j],Px[j],Py[j]); + else + res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + if (res.iszero()) return 0; + } + + delete [] k; + delete [] A; + delete [] Q; + delete [] Py; + delete [] Px; + + z.g=res; + return z; +} + +// +// Tate Pairing G1 x G1 -> GT +// +// P and Q are points of order q in G1. +// + +GT PFC::miller_loop(const G2& QQ,const G1& PP) +{ + GT z; + int i,j,n,nb,nbw,nzs; + ECn A,Q; + ECn P; + ZZn Px,Py; + BOOL precomp; + ZZn2 res; + Big iters=*ord-1; // can omit last addition + + P=PP.g; Q=QQ.g; + precomp=FALSE; + if (QQ.ptable!=NULL) precomp=TRUE; + + normalise(P); + normalise(Q); + extract(P,Px,Py); + //Px=-Px; + + res=1; + A=Q; // reset A + nb=bits(iters); + + j=0; + + for (i=nb-2;i>=0;i--) + { + res*=res; + if (precomp) res*=gp(QQ.ptable,j,Px,Py); + else res*=g(A,A,Px,Py); + + if (bit(iters,i)==1) + { + if (precomp) res*=gp(QQ.ptable,j,Px,Py); + else res*=g(A,Q,Px,Py); + } + } + + z.g=res; + return z; +} + +GT PFC::final_exp(const GT& z) +{ + GT y; + ZZn2 res; + + res=z.g; + res=conj(res)/res; + res=pow(res,(*mod+1)/(*ord)); // raise to power of (p^2-1)/q + + y.g=res; + + return y; +} + +PFC::PFC(int s, csprng *rng) +{ + int mod_bits,words; + + if (s!=80) + { + cout << "No suitable curve available" << endl; + exit(0); + } + + mod_bits=512; + + if (mod_bits%MIRACL==0) + words=(mod_bits/MIRACL); + else + words=(mod_bits/MIRACL)+1; + +#ifdef MR_SIMPLE_BASE + miracl *mip=mirsys((MIRACL/4)*words,16); +#else + miracl *mip=mirsys(words,0); + mip->IOBASE=16; +#endif + + B=new Big; + mod=new Big; + ord=new Big; + cof=new Big; + npoints=new Big; + trace=new Big; + + *B=Btext; + + *cof=COFtext; + *ord=pow((Big)2,159)+pow((Big)2,17)+1; + *npoints=*cof*(*ord); + + S=s; + *mod=MODtext; + *trace=*mod+1-*npoints; + + ecurve(-3,*B,*mod,MR_PROJECTIVE); + + RNG=rng; +} + +PFC::~PFC() +{ + delete B; + delete mod; + delete ord; + delete cof; + delete npoints; + delete trace; + mirexit(); +} + +G1 PFC::mult(const G1& w,const Big& k) +{ + G1 z; + if (w.mtable!=NULL) + { // we have precomputed values + + Big e=k; + if (k<0) e=-e; + + int i,j,t=w.mtbits; // MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.mtable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g+=z.g; + if (j>0) z.g+=w.mtable[j]; + } + if (k<0) z.g=-z.g; + } + else + { + z.g=w.g; + z.g*=k; + } + return z; +} + +G2 PFC::mult(const G2& w,const Big& k) +{ + G2 z; + if (w.mtable!=NULL) + { // we have precomputed values + + Big e=k; + if (k<0) e=-e; + + int i,j,t=w.mtbits; // MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.mtable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g+=z.g; + if (j>0) z.g+=w.mtable[j]; + } + if (k<0) z.g=-z.g; + } + else + { + z.g=w.g; + z.g*=k; + } + return z; +} + +GT PFC::power(const GT& w,const Big& k) +{ + GT z; + Big e=k; + if (k<0) e=-e; + if (w.etable!=NULL) + { // precomputation is available + int i,j,t=w.etbits; //MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.etable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g*=z.g; + if (j>0) z.g*=w.etable[j]; + } + } + else + { + z.g=powu(w.g,e); + } + if (k<0) z.g=conj(z.g); + return z; +} + +// random group member + +void PFC::random(Big& w) +{ + if (RNG==NULL) w=rand(*ord); + else w=strong_rand(RNG,*ord); +} + +// random AES key + +void PFC::rankey(Big& k) +{ + if (RNG==NULL) k=rand(S,2); + else k=strong_rand(RNG,S,2); +} + +// Can be done deterministicly + +void PFC::hash_and_map(G1& w,char *ID) +{ + Big x0=H1(ID); + while (!w.g.set(x0,x0)) x0+=1; + w.g*=*cof; +} + +void PFC::hash_and_map(G2& w,char *ID) +{ + Big x0=H1(ID); + *B=-(*B); + ecurve((Big)-3,*B,*mod,MR_PROJECTIVE); // move to twist + while (!w.g.set(x0,x0)) x0+=1; + w.g*=(*mod+1+*trace)/(*ord); + *B=-(*B); + ecurve((Big)-3,*B,*mod,MR_PROJECTIVE); // move back +} + +void PFC::random(G1& w) +{ + Big x0; + if (RNG==NULL) x0=rand(*mod); + else x0=strong_rand(RNG,*mod); + while (!w.g.set(x0,x0)) x0+=1; + w.g*=*cof; +} + +void PFC::random(G2& w) +{ + Big x0; + if (RNG==NULL) x0=rand(*mod); + else x0=strong_rand(RNG,*mod); + + *B=-(*B); + ecurve((Big)-3,*B,*mod,MR_PROJECTIVE); // move to twist + while (!w.g.set(x0,x0)) x0+=1; + w.g*=(*mod+1+*trace)/(*ord); + *B=-(*B); + ecurve((Big)-3,*B,*mod,MR_PROJECTIVE); // move back +} + +Big PFC::hash_to_aes_key(const GT& w) +{ + Big m=pow((Big)2,S); + return H2(w.g)%m; +} + +Big PFC::hash_to_group(char *ID) +{ + Big m=H1(ID); + return m%(*ord); +} + +GT operator*(const GT& x,const GT& y) +{ + GT z=x; + z.g*=y.g; + return z; +} + +GT operator/(const GT& x,const GT& y) +{ + GT z=x; + z.g*=conj(y.g); // elements in GT are unitary + return z; +} + +// +// spill precomputation on GT to byte array +// + +int GT::spill(char *& bytes) +{ + int i,j,n=(1<nib-1); + int len=n*2*bytes_per_big+1; + Big x,y; + + if (etable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*2*bytes_per_big; + Big x,y; + if (etable!=NULL) return; + + etable=new ZZn2[1<nib-1); + int len=n*2*bytes_per_big+1; + Big x,y; + + if (mtable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*2*bytes_per_big; + Big x,y; + if (mtable!=NULL) return; + + mtable=new ECn[1<nib-1); + int len=n*2*bytes_per_big+1; + Big x,y; + + if (mtable==NULL) return 0; + + bytes=new char[len]; + + for (i=j=0;inib-1); +// int len=n*2*bytes_per_big; + Big x,y,B; + if (mtable!=NULL) return; + + mtable=new ECn[1< +#include + +//********* choose just one of these pairs ********** +//#define MR_PAIRING_CP // AES-80 security +//#define AES_SECURITY 80 + +//#define MR_PAIRING_MNT // AES-80 security +//#define AES_SECURITY 80 + +#define MR_PAIRING_BN // AES-128 or AES-192 security +#define AES_SECURITY 128 +//#define AES_SECURITY 192 + +//#define MR_PAIRING_KSS // AES-192 security +//#define AES_SECURITY 192 + +//#define MR_PAIRING_BLS // AES-256 security +//#define AES_SECURITY 256 +//********************************************* + +#include "pairing_3.h" + +// Access structure - crude boolean description of combination of attributes that a recipient must have +// to be able to reconstruct the secret value + +/* Note that Access structure consists of threshold gates - output is TRUE if t out of n inputs are TRUE */ +/* Access tree: Number (n), threshold (t), followed by n Child nodes */ +/* Negative number denotes leaf node */ + +/* +// This is example from Liu and Cao http://eprint.iacr.org/2010/374 +// Negative number denotes leaf node + +int Access[]={ // node - index +2,2,1,2, // node 0 - 0 Here (n,t) = (2,2) so AND gate and the two children are nodes 1 and 2 +2,1,3,4, // node 1 - 4 Here (n,t) = (2,1) so OR gate and the two children are nodes 3 and 4 +4,3,-'E',-'F',-'G',-'H', // node 2 - 8 +2,2,-'B',5, // node 3 - 14 Here (n,t) = (2,2) the first child is a leaf node, the second is node 5 +3,2,-'C',-'D',-'E', // node 4 - 18 Here (n,t) = (3,2) and all 3 children are leaf nodes. +2,1,-'A',-'C', // node 5 - 23 +0}; + +// Note total of 8 attributes A-H + +#define U 8 + +// These are the attributes of a particular recipient + +int auth[]={'D','E','F','G',0}; // attributes of recipient +*/ + +int Access[]={ // node - index +3,3,1,2,6, // node 0 - 0 Here (n,t) = (3,3) so AND gate and the children are nodes 1 and 2 and 6 +2,1,3,4, // node 1 - 4 Here (n,t) = (2,1) so OR gate and the two children are nodes 3 and 4 +4,3,-'E',-'F',-'G',-'H', // node 2 - 8 +2,2,-'B',5, // node 3 - 14 Here (n,t) = (2,2) the first child is a leaf node, the second is node 5 +3,2,-'C',-'D',-'E', // node 4 - 18 Here (n,t) = (3,2) and all 3 children are leaf nodes. +2,1,-'A',-'C', // node 5 - 23 +2,1,-'I',7, // add in n<11 condition +2,2,-'J',8, +2,1,-'K',-'L', +0}; + +// Note total of 12 attributes A-L + +#define U 12 + +// These are the attributes of a particular recipient + +int auth[]={'D','E','F','G','J','K',0}; // attributes of valid recipient - try removing one! + + +/* +int Access[]={ // node - index +20,20,-'A',-'B',-'C',-'D',-'E',-'F',-'G',-'H',-'I',-'J',-'K',-'L',-'M',-'N',-'O',-'P',-'Q',-'R',-'S',-'T',0 +}; + +#define U 20 + +int auth[]={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',0}; +*/ + +// get node index for i-th node + +int find_index(int Access[],int i) +{ + int n,j,k; + j=k=0; + while (kn=Access[ipos]; + + nd->t=Access[ipos+1]; + + nd->child=new node [nd->n]; + for (i=0;in;i++) + { + k=Access[ipos+2+i]; + if (k<0) nd->child[i].n=k; + else + { + j=find_index(Access,k); + fill_node(&nd->child[i],Access,j); + } + } +} + +void delete_node(node *nd) +{ + int i,n=nd->n; + nd->n=0; + nd->t=0; + if (n<=0) return; + for (i=0;ichild[i]); + delete [] nd->child; + nd->child=NULL; +} + +void copy_node(node *f, node *t) +{ + int i; + t->n=f->n; + if (t->n<=0) return; + t->t=f->t; + t->child=new node [t->n]; + for (i=0;in;i++) + copy_node(&f->child[i],&t->child[i]); +} + +// node constructor + +node::node(int *Access) +{ + fill_node(this,Access,0); +} + +// node destructor + +node::~node() +{ + delete_node(this); +} + +node& node::operator=(node& b) +{ + delete_node(this); + copy_node(&b,this); + return *this; +} + +// Find number of leaf attributes - the number of rows in Access matrix + +int find_m(int Access[]) +{ + int i,m; + i=m=0; + while (Access[i]!=0) + { + i++; + if (Access[i]<0) m++; + } + return m; +} + +// find number of columns in Access matrix = 1 + Sum of (thresholds-1) ?? + +int find_d(int Access[]) +{ + int j,d,n; + j=0; d=1; + while (Access[j]>0) + { + n=Access[j]; + if (n==0) break; + d+=Access[j+1]-1; + j+=(n+2); + + } + return d; +} + +// traverse Access tree and pretty-print it + +void print_node(node *nd) +{ + int c,n=nd->n; + if (n<0) + { + cout << "(" << (char)(-n) << ")"; + return; + } + cout << "("; + for (int i=0;ichild[i].n; + if (c<0) + cout << (char)(-c) << ","; + else + print_node(&nd->child[i]); + } + cout << nd->t << "),"; +} + +ostream& operator<<(ostream& s, node& x) +{ + print_node(&x); + return s; +} + +// +// make LSSS matrix of size rowsXcols from Access description +// attr[i] contains attribute of each row. +// algorithm due to Liu and Cao http://eprint.iacr.org/2010/374 +// (but much simplified) +// + +void make_LSSS(int Access[],int rows,int cols,Big **LSSS,int *attr) +{ + int i,j,z,m,d,n,t; + Big k; + node Fz,root(Access); + + node *L=new node[rows]; + + for (i=0;i=z;i--) + L[i+n-1]=L[i]; + + for (i=0;i=z;i--) + { + for (j=0;j=i;k--) matrix[jj][k]-=modmult(s,matrix[ii][k],order); + } + } + if (ok) for (j=n-1;j>=0;j--) + { /* Backward substitution */ + s=0; + for (k=j+1;korder/2) + { + if (w[j]<0) w[j]+=order; + else if (w[j]>0) w[j]-=order; + } + } + delete [] row; + return ok; +} + +// given set of attributes and LSSS matrix, returns reconstruction constant numerators w, and rows +// Note that original LSSS matrix is destroyed. Returns denominator of w. + +BOOL reduce_LSSS(Big &order,int &m,int &d,Big **LSSS,int *attr,int *auth,int *rows,Big *w) +{ + int i,j,k,n,nattr=0; + Big s,det; + while (auth[nattr]!=0) nattr++; + +// find rows in LSSS which are associated with attributes in auth + k=0; + for (i=0;iIOBASE=256; + M=(char *)"test message"; + cout << "Message to be encrypted= " << M << endl; + mip->IOBASE=16; + + Big *v=new Big [d]; + Big *lambda=new Big [m]; + Big *r=new Big [m]; + for (i=0;i +#include + +#include "gf2m.h" +#include "gf2m4x.h" +#include "ec2.h" + +#define M 313 +#define T 121 +#define U 0 +#define V 0 +#define B 1 +#define TYPE 2 + +// #define M 101 +// #define T 35 +// #define U 31 +// #define V 3 +// #define B 0 +// #define TYPE 2 + +// #define M 107 +// #define T 37 +// #define U 33 +// #define V 23 +// #define B 1 +// #define TYPE 1 + +// #define M 271 +// #define T 58 +// #define U 0 +// #define V 0 +// #define B 0 +// #define TYPE 1 + +using namespace std; + +Miracl precision(15,0); + +// +// Extract ECn point in internal GF2m format +// + +void extract(EC2& A,GF2m& x,GF2m& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +// +// Tate Pairing - note miller -> miller variable +// + +GF2m4x tate(EC2& P,EC2& Q) +{ + GF2m xp,yp,xq,yq,t,w; + GF2m4x miller,u0,u1,u,res; + int i,m=M; + + normalise(P); + normalise(Q); + + extract(P,xp,yp); + extract(Q,xq,yq); + + miller=1; + +// loop is unrolled x 2 + + for (i=0;i<(m-1);i+=2) + { + t=xp*xp; + u0.set((t+1)*(xp+xq)+yp+yq+t,t+xq,t+xq+1,0); + xp=t; yp*=yp; xq=sqrt(xq); yq=sqrt(yq); + + t=xp*xp; + u1.set((t+1)*(xp+xq)+yp+yq+t,t+xq,t+xq+1,0); + xp=t; yp*=yp; xq=sqrt(xq); yq=sqrt(yq); + + u=mul(u0,u1); + + miller*=u; + } + +// final step + + t=xp*xp; + u.set((t+1)*(xp+xq)+yp+yq+t,t+xq,t+xq+1,0); + xp=t; yp*=yp; xq=sqrt(xq); yq=sqrt(yq); + miller*=u; + + res=miller; + +// final exponentiation to q^2-1 + + res.powq(); // raise to the power of q=2^m using Frobenius + res.powq(); + + res/=miller; // one inversion + + return res; +} + +int main() +{ + EC2 P,Q; + Big bx,by,s,r; + GF2m4x res; + time_t seed; + + time(&seed); + irand((long)seed); + + if (!ecurve2(-M,T,U,V,(Big)1,(Big)B,TRUE,MR_PROJECTIVE)) + { + cout << "Problem with the curve" << endl; + return 0; + } + +// Curve order = 2^M+2^[(M+1)/2]+1 or 2^M-2^[(M+1)/2]+1 is prime + + forever + { + bx=rand(M,2); + if (P.set(bx,bx)) break; + } + + forever + { + bx=rand(M,2); + if (Q.set(bx,bx)) break; + } + + res=tate(P,Q); + + s=rand(200,2); + r=rand(200,2); + res=pow(res,s*r); + + cout << "e(P,Q)^sr= " << res << endl; + + P*=s; + Q*=r; + + res=tate(P,Q); + + cout << "e(sP,rQ)= " << res << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/dl2.cpp b/miracl/source/curve/pairing/dl2.cpp new file mode 100644 index 0000000..5f00d0a --- /dev/null +++ b/miracl/source/curve/pairing/dl2.cpp @@ -0,0 +1,417 @@ +/* Even Faster Duursma-Lee char 2 Tate pairing based on eta_T pairing */ +/* cl /O2 /GX dl2.cpp ec2.cpp gf2m4x.cpp gf2m.cpp big.cpp miracl.lib */ +/* Half sized loop so nearly twice as fast! */ +/* 14th March 2005 */ + +#include +#include + +#include "gf2m.h" +#include "gf2m4x.h" +#include "ec2.h" + +// set TYPE = 1 if B=0 && (M=1 or 7 mod 8), else TYPE = 2 +// set TYPE = 1 if B=1 && (M=3 or 5 mod 8), else TYPE = 2 + +// some example curves to play with + +//#define M 283 +//#define T 249 +//#define U 219 +//#define V 27 +//#define B 1 +//#define TYPE 1 +//#define CF 1 + +//#define M 367 +//#define T 21 +//#define U 0 +//#define V 0 +//#define B 1 +//#define TYPE 2 +//#define CF 1 + +//#define M 379 +//#define T 317 +//#define U 315 +//#define V 283 +//#define B 1 +//#define TYPE 1 +//#define CF 1 + +#define M 1223 +#define T 255 +#define U 0 +#define V 0 +#define B 0 +#define TYPE 1 +#define CF 5 + +//#define M 271 +//#define T 207 +//#define U 175 +//#define V 111 +//#define B 0 +//#define TYPE 1 +//#define CF 487805 + +//#define M 353 +//#define B 1 +//#define T 215 +//#define U 0 +//#define V 0 +//#define TYPE 2 +//#define CF 1 + +//#define M 271 +//#define U 0 +//#define V 0 +//#define T 201 +//#define B 0 +//#define TYPE 1 +//#define CF 487805 + +#define IMOD4 ((M+1)/2)%4 + +//#define XX (IMOD4%2) +//#define YY (IMOD4/2) +//#define NXX (1-XX) + +using namespace std; + +Miracl precision(40,0); + +// +// Extract ECn point in internal GF2m format +// + +void extract(EC2& A,GF2m& x,GF2m& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +// +// Tate Pairing - note miller -> miller variable +// Loop unrolled x2 for speed +// + +GF2m4x tate(EC2& P,EC2& Q) +{ + GF2m xp,yp,xq,yq,t; + GF2m4x miller,w,u,u0,u1,v,f,res; + int i,m=M; + + normalise(P); normalise(Q); + extract(P,xp,yp); + extract(Q,xq,yq); + +// first calculate the contribution of adding P or -P to 2^[(m+1)/2].P +// +// Note that 2^[(m+1)/2].Point(x,y) = Point(x^2+1,x^2+y^2) or something similar.... +// Line slope is x or x+1 (thanks Steven!) +// +// Then the truncated loop, four flavours... + +#if IMOD4 == 1 + // (X=1) + // (Y=0) + t=xp; // 0 (X+1) + f.set(t*(xp+xq+1)+yq+yp+B,t+xq+1,t+xq,0); // 0 (Y) + + + miller=1; + for (i=0;i<(m-3)/2;i+=2) + { + + t=xp+1; xp=sqrt(xp); yp=sqrt(yp); // 1 (X) + u0.set(t*(xp+xq+1)+yp+yq,t+xq+1,t+xq,0); // 1 0 (X) ((X+1)*(xp+1)+Y) + xq*=xq; yq*=yq; + + t=xp+1; xp=sqrt(xp); yp=sqrt(yp); + u1.set(t*(xp+xq+1)+yp+yq,t+xq+1,t+xq,0); + xq*=xq; yq*=yq; + + u=mul(u0,u1); + miller*=u; + } + +// final step + + t=xp+1; xp=sqrt(xp); yp=sqrt(yp); + u.set(t*(xp+xq+1)+yp+yq,t+xq+1,t+xq,0); + miller*=u; + +#endif + +#if IMOD4 == 0 + // (X=0) + // (Y=0) + t=xp+1; // 1 (X+1) + f.set(t*(xq+xp+1)+yq+yp+B,t+xq+1,t+xq,0); // 0 (Y) + miller=1; + + for (i=0;i<(m-1)/2;i+=2) + { +// loop is unrolled x 2 + t=xp; xp=sqrt(xp); yp=sqrt(yp); // 0 (X) + u0.set(t*(xp+xq)+yp+yq+xp+1,t+xq+1,t+xq,0); // 0 xp+1 (X) ((X+1)*(xp+1)+Y + xq*=xq; yq*=yq; + + t=xp; xp=sqrt(xp); yp=sqrt(yp); + u1.set(t*(xp+xq)+yp+yq+xp+1,t+xq+1,t+xq,0); + xq*=xq; yq*=yq; + + u=mul(u0,u1); + miller*=u; + } + +#endif + +#if IMOD4 == 2 + // (X=0) // (Y=1) + t=xp+1; // 1 (X+1) + f.set(t*(xq+xp+1)+yq+yp+B+1,t+xq+1,t+xq,0); // 1 (Y) + miller=1; + for (i=0;i<(m-1)/2;i+=2) + { + + t=xp; xp=sqrt(xp); yp=sqrt(yp); // 0 (X) + u0.set(t*(xp+xq)+yp+yq+xp,t+xq+1,t+xq,0); // 0 xp+0 (X) ((X+1)*(xp+1)+Y) + xq*=xq; yq*=yq; + + t=xp; xp=sqrt(xp); yp=sqrt(yp); + u1.set(t*(xp+xq)+yp+yq+xp,t+xq+1,t+xq,0); + xq*=xq; yq*=yq; + + u=mul(u0,u1); + miller*=u; + } + +#endif + +#if IMOD4 == 3 + // (X=1) // (Y=1) + t=xp; // 0 (X+1) + f.set(t*(xq+xp+1)+yq+yp+B+1,t+xq+1,t+xq,0); // 1 (Y) + + miller=1; + for (i=0;i<(m-3)/2;i+=2) + { + + t=xp+1; xp=sqrt(xp); yp=sqrt(yp); // 1 (X) + u0.set(t*(xp+xq+1)+yp+yq+1,t+xq+1,t+xq,0); // 1 1 (X) ((X+1)*(xp+1)+Y) + xq*=xq; yq*=yq; + + t=xp+1; xp=sqrt(xp); yp=sqrt(yp); + u1.set(t*(xp+xq+1)+yp+yq+1,t+xq+1,t+xq,0); + xq*=xq; yq*=yq; + + u=mul(u0,u1); + miller*=u; + } + +// final step + + t=xp+1; xp=sqrt(xp); yp=sqrt(yp); + u.set(t*(xp+xq+1)+yp+yq+1,t+xq+1,t+xq,0); + miller*=u; + +#endif + + miller*=f; + +// raising to the power (2^m-2^[m+1)/2]+1)(2^[(m+1)/2]+1)(2^(2m)-1) (TYPE 2) +// or (2^m+2^[(m+1)/2]+1)(2^[(m+1)/2]-1)(2^(2m)-1) (TYPE 1) +// 6 Frobenius, 4 big field muls... + + u=v=w=miller; + for (i=0;i<(m+1)/2;i++) u*=u; + +#if TYPE == 1 + + u.powq(); + w.powq(); + v=w; + w.powq(); + res=w; + w.powq(); + w*=u; + w*=miller; + res*=v; + u.powq(); + u.powq(); + res*=u; + +#else + + u.powq(); + v.powq(); + w=u*v; + v.powq(); + w*=v; + v.powq(); + u.powq(); + u.powq(); + res=v*u; + res*=miller; + +#endif + + res/=w; + return res; +} + +int main() +{ + EC2 P,Q,W; + Big bx,s,r,x,y,order; + GF2m4x res; + time_t seed; + int i; + miracl *mip=&precision; + + time(&seed); + irand((long)seed); + + if (!ecurve2(-M,T,U,V,(Big)1,(Big)B,TRUE,MR_PROJECTIVE)) // -M indicates Super-Singular + { + cout << "Problem with the curve" << endl; + return 0; + } + +// Curve order = 2^M+2^[(M+1)/2]+1 or 2^M-2^[(M+1)/2]+1 is nearly prime + + cout << "IMOD4= " << IMOD4 << endl; + cout << "M%8= " << M%8 << endl; + + forever + { + bx=rand(M,2); + if (P.set(bx,bx)) break; + } + + forever + { + bx=rand(M,2); + if (Q.set(bx,bx)) break; + } + + /* for (int i=0;i<10000;i++) */ + + P*=CF; // cofactor multiplication + Q*=CF; + +// order=pow((Big)2,M)-pow((Big)2,(M+1)/2)+1; +// P*=order; +// cout << "P= " << P << endl; +// exit(0); +/* +mip->IOBASE=16; +cout << "P= " << P << endl; +cout << "Q= " << Q << endl; + +Big ddd=pow((Big)2,32); +Big sx,sy; + + +P.get(x,y); +sx=x; +sy=y; + +while (x>0) +{ + cout << "0x" << hex << x%ddd << ","; + x/=ddd; +} +cout << endl; + +while (y>0) +{ + cout << "0x" << hex << y%ddd << ","; + y/=ddd; +} +cout << endl; + +ddd=256; +x=sx; +y=sy; + +while (x>0) +{ + cout << "0x" << hex << x%ddd << ","; + x/=ddd; +} +cout << endl; + +while (y>0) +{ + cout << "0x" << hex << y%ddd << ","; + y/=ddd; +} +cout << endl; + + +Q.get(x,y); +sx=x; +sy=y; +ddd=pow((Big)2,32); + +while (x>0) +{ + cout << "0x" << hex << x%ddd << ","; + x/=ddd; +} +cout << endl; + +while (y>0) +{ + cout << "0x" << hex << y%ddd << ","; + y/=ddd; +} +cout << endl; + +ddd=256; +x=sx; +y=sy; + +while (x>0) +{ + cout << "0x" << hex << x%ddd << ","; + x/=ddd; +} +cout << endl; + +while (y>0) +{ + cout << "0x" << hex << y%ddd << ","; + y/=ddd; +} +cout << endl; + + + +exit(0); +*/ +//for (i=0;i<1000;i++) + res=tate(P,Q); + + s=rand(256,2); + r=rand(256,2); + res=pow(res,s); res=pow(res,r); +//mip->IOBASE=16; + cout << "e(P,Q)^sr= " << res << endl; + + P*=s; + Q*=r; + + res=tate(Q,P); + + cout << "e(sP,rQ)= " << res << endl; + +//Big q=pow((Big)2,M)-pow((Big)2,(M+1)/2)+1; + +//cout << pow(res,q) << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/ecn2.cpp b/miracl/source/curve/pairing/ecn2.cpp new file mode 100644 index 0000000..aa15bd8 --- /dev/null +++ b/miracl/source/curve/pairing/ecn2.cpp @@ -0,0 +1,219 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file ecn2.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ECn2 (Elliptic curves over n^2) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + */ + +#include "ecn2.h" + +using namespace std; + +#ifndef MR_AFFINE_ONLY +void ECn2::get(ZZn2& x,ZZn2& y,ZZn2& z) const +{ecn2_get(&fn,&(x.fn),&(y.fn),&(z.fn));} +#endif + +void ECn2::get(ZZn2& x,ZZn2& y) const +{norm(); ecn2_getxy(&fn,&(x.fn),&(y.fn)); } + +void ECn2::get(ZZn2& x) const +{norm(); ecn2_getx(&fn,&(x.fn));} + +#ifndef MR_AFFINE_ONLY +void ECn2::getZ(ZZn2& z) const +{ecn2_getz(&fn,&(z.fn));} +#endif + +void ECn2::norm(void) const +{ // normalize a point + ecn2_norm(&(fn)); +} + +BOOL ECn2::iszero(void) const +{if (fn.marker==MR_EPOINT_INFINITY) return TRUE; return FALSE;} + +BOOL ECn2::set(const ZZn2& xx,const ZZn2& yy) +{ + return ecn2_set((zzn2 *)&(xx.fn),(zzn2 *)&(yy.fn),&(fn)); +} + +BOOL ECn2::set(const ZZn2& xx) +{ + return ecn2_setx((zzn2 *)&(xx.fn),&(fn)); +} + +#ifndef MR_AFFINE_ONLY +void ECn2::set(const ZZn2& xx,const ZZn2& yy,const ZZn2& zz) +{ + ecn2_setxyz((zzn2 *)&(xx.fn),(zzn2 *)&(yy.fn),(zzn2 *)&(zz.fn),&(fn)); +} +#endif + +ECn2 operator-(const ECn2& a) +{ + ECn2 w=a; + ecn2_negate(&(w.fn),&(w.fn)); + return w; +} + +ECn2& ECn2::operator*=(const Big& k) +{ + ecn2_mul(k.getbig(),&(this->fn)); + return *this; +} + +ECn2 operator*(const Big& r,const ECn2& P) +{ + ECn2 T=P; + T*=r; + return T; +} + +#ifndef MR_NO_STANDARD_IO + +ostream& operator<<(ostream& s,const ECn2& b) +{ + ZZn2 x,y,z; + if (b.iszero()) + s << "(Infinity)"; + else + { + b.get(x,y); + + s << "(" << x << "," << y << ")"; + } + return s; +} + +#endif + +ECn2 operator+(const ECn2& a,const ECn2& b) +{ECn2 c=a; c+=b; return c;} + +ECn2 operator-(const ECn2& a,const ECn2& b) +{ECn2 c=a; c-=b; return c;} + +ECn2& ECn2::operator-=(const ECn2& z) +{ECn2 t=(-z); *this+=t; return *this; } + +ECn2& ECn2::operator+=(const ECn2& w) +{ + ecn2_add(&(w.fn),&(this->fn)); + return *this; +} + +#ifndef MR_EDWARDS + +BOOL ECn2::add(const ECn2& w,const ZZn2& lam,const ZZn2 &extra1) +{ + return ecn2_add2(&(w.fn),&(this->fn),(zzn2 *)&(lam.fn),(zzn2 *)&(extra1.fn)); +} + +BOOL ECn2::add(const ECn2& w,const ZZn2& lam) +{ + return ecn2_add1(&(w.fn),&(this->fn),(zzn2 *)&(lam.fn)); +} + +BOOL ECn2::add(const ECn2& w,const ZZn2& lam,const ZZn2& extra1,const ZZn2& extra2) +{ + return ecn2_add3(&(w.fn),&(this->fn),(zzn2 *)&(lam.fn),(zzn2 *)&(extra1.fn),(zzn2 *)&(extra2.fn)); +} + +#endif + +#ifndef MR_NO_ECC_MULTIADD + +ECn2 mul(const Big& a,const ECn2& P,const Big& b,const ECn2& Q) +{ + ECn2 R; + ecn2_mul2_jsf(a.getbig(),&(P.fn),b.getbig(),&(Q.fn),&(R.fn)); + R.norm(); + return R; +} + +// standard MIRACL multi-addition + + +ECn2 mul4(ECn2* P,const Big* b) +{ + int i,n=4; + ECn2 R; + big x[4]; + ecn2 p[4]; + + for (i=0;i. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ecn2.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class ECn2 (Arithmetic on an Elliptic Curve, + * mod n^2) + * + * NOTE : Must be used in conjunction with zzn.cpp, big.cpp and + * zzn2.cpp + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#ifndef ECN2_H +#define ECN2_H + +#include "zzn2.h" + +#ifdef ZZNS + +#ifndef MR_AFFINE_ONLY +#define MR_INIT_ECN2 {fn.x.a=&xat; xat.w=xa; xat.len=UZZNS; fn.x.b=&xbt; xbt.w=xb; xbt.len=UZZNS; \ + fn.y.a=&yat; yat.w=ya; yat.len=UZZNS; fn.y.b=&ybt; ybt.w=yb; ybt.len=UZZNS; \ + fn.z.a=&zat; zat.w=za; zat.len=UZZNS; fn.z.b=&zbt; zbt.w=zb; zbt.len=UZZNS; \ + } + +#define MR_CLONE_ECN2(x) {xat.len=x.xat.len; xbt.len=x.xbt.len; yat.len=x.yat.len; ybt.len=x.ybt.len; \ + fn.marker=x.fn.marker; \ + zat.len=x.zat.len; zbt.len=x.zbt.len; \ + for (int i=0;i. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file ecn3.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ECn3 (Elliptic curves over n^3) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#include "ecn3.h" + +using namespace std; + +void ECn3::get(ZZn3& a,ZZn3& b) const +{ +#ifdef MR_ECN3_PROJECTIVE + norm(); +#endif + a=x; b=y; +} + +BOOL ECn3::iszero(void) const +{if (marker==MR_EPOINT_INFINITY) return TRUE; return FALSE;} + +void ECn3::get(ZZn3& a) const +{ +#ifdef MR_ECN3_PROJECTIVE + norm(); +#endif + a=x; +} + +#ifdef MR_ECN3_PROJECTIVE +#ifndef MR_AFFINE_ONLY +void ECn3::getZ(ZZn3& a) const +{a=z;} +void ECn3::get(ZZn3& a,ZZn3& b,ZZn3& c) const +{ + a=x;b=y; + if (marker==MR_EPOINT_GENERAL) c=z; + else c=(ZZn)1; +} + +void ECn3::set(const ZZn3& xx,const ZZn3& yy,const ZZn3& zz) +{ + x=xx; + y=yy; + z=zz; + if (z==(ZZn)1) marker=MR_EPOINT_NORMALIZED; + else marker=MR_EPOINT_GENERAL; +} +#endif +#endif + +BOOL ECn3::set(const ZZn3& xx,const ZZn3& yy) +{ + int qnr; + ZZn3 w; + + w=rhs(xx); + if (yy*yy!=w) return FALSE; + x=xx; + y=yy; + marker=MR_EPOINT_NORMALIZED; + return TRUE; +} + +BOOL ECn3::set(const ZZn3& xx) +{ + ZZn3 w; + + w=rhs(xx); + + if (!w.iszero()) + { + w=sqrt(w); + if (w.iszero()) return FALSE; + } + + x=xx; + y=w; + + marker=MR_EPOINT_NORMALIZED; + return TRUE; +} + +void ECn3::norm(void) const +{ // normalize a point +#ifdef MR_ECN3_PROJECTIVE +#ifndef MR_AFFINE_ONLY + if (marker!=MR_EPOINT_GENERAL) return; + ZZn3 t; + z=inverse(z); + t=z; + z*=z; + x*=z; + z*=t; + y*=z; + z=1; + marker=MR_EPOINT_NORMALIZED; +#endif +#endif +} + + +ECn3 operator-(const ECn3& a) +{ECn3 w; + if (a.marker!=MR_EPOINT_INFINITY) + { + w.x=a.x; + w.y=-a.y; + w.marker=a.marker; +#ifdef MR_ECN3_PROJECTIVE +#ifndef MR_AFFINE_ONLY + if (w.marker==MR_EPOINT_GENERAL) w.z=a.z; +#endif +#endif + } + return w; +} + +ECn3& ECn3::operator*=(const Big& k) +{ + int i,j,n,nb,nbs,nzs; + ECn3 p2,pt,t[11]; + Big h,kk; + + if (k==0) + { + clear(); + return *this; + } + if (k==1) + { + return (*this); + } +#ifdef MR_ECN3_PROJECTIVE + norm(); +#endif + pt=*this; + kk=k; + if (kk<0) + { + pt=-pt; + kk=-kk; + } + h=3*kk; + +// This is not optimal! + + p2=pt+pt; +#ifdef MR_ECN3_PROJECTIVE + p2.norm(); +#endif + t[0]=pt; + for (i=1;i<=10;i++) + { + t[i]=t[i-1]+p2; +#ifdef MR_ECN3_PROJECTIVE + t[i].norm(); +#endif + } + +// Left to Right method + + nb=bits(h); + for (i=nb-2;i>=1;) + { + n=naf_window(kk,h,i,&nbs,&nzs,11); + for (j=0;j0) pt+=t[n/2]; + if (n<0) pt-=t[(-n)/2]; + i-=nbs; + if (nzs) + { + for (j=0;jTWIST; + int qnr=mip->cnr; + + if (marker==MR_EPOINT_INFINITY) + { + *this=W; + return MR_ADD; + } + if (W.marker==MR_EPOINT_INFINITY) + { + return MR_ADD; + } +#ifdef MR_ECN3_PROJECTIVE +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { +#endif +#endif + if (x!=W.x) + { + ZZn3 t=y; t-=W.y; + ZZn3 t2=x; t2-=W.x; + lam=t; lam/=t2; + + x+=W.x; t=lam; t*=t; t-=x; x=t; + y=W.x; y-=x; y*=lam; y-=W.y; + marker=MR_EPOINT_NORMALIZED; + return MR_ADD; + } + else + { + if (y!=W.y || y.iszero()) + { + clear(); + lam=one(); // any non-zero value + return 0; + } + ZZn3 t=x; + ZZn3 t1,t2=x; + + // lam=(3*(x*x)+getA())/(y+y); + lam=x; + lam*=lam; + lam*=3; + + t1=getA(); + if (twist==MR_QUADRATIC) t1=qnr*qnr*t1; + if (twist==MR_QUARTIC_M) t1=tx(t1); + if (twist==MR_QUARTIC_D) t1=txd(t1); + lam+=t1; + + lam/=(y+y); + t2+=x; + x=lam; + x*=x; + x-=t2; + + t-=x; + t*=lam; + t-=y; + y=t; + marker=MR_EPOINT_NORMALIZED; + return MR_DOUBLE; + } +#ifdef MR_ECN3_PROJECTIVE +#ifndef MR_AFFINE_ONLY + } + int iA; + BOOL Doubling; + ZZn3 t1,t2,t3; + ZZn3 Yzzz; + + t3=W.x; + Yzzz=W.y; + + Doubling=FALSE; + if (this==&W) Doubling=TRUE; + + if (!Doubling) + { + if (W.marker!=MR_EPOINT_NORMALIZED) + { + mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + MR_OUT + return 0; + } + if (marker!=MR_EPOINT_NORMALIZED) + { + t1=z; t1*=t1; + t3*=t1; + t1*=z; + Yzzz*=t1; + } + if (t3==x) + { + if (Yzzz!=y || y==0) + { + clear(); + lam=1; + } + else Doubling=TRUE; + } + } + if (!Doubling) + { // Addition + t3-=x; + lam=Yzzz-y; + if (marker==MR_EPOINT_NORMALIZED) z=t3; + else z*=t3; + t1=t3; t1*=t1; + Yzzz=t1*t3; + t1*=x; + t3=t1; + t3+=t3; + x=lam; x*=x; + x-=t3; + x-=Yzzz; + t1-=x; + t1*=lam; + Yzzz*=y; + y=t1-Yzzz; + } + else + { // doubling + t3=y; t3*=t3; + iA=get_mip()->Asize; + if (iA!=0) + { + if (marker==MR_EPOINT_NORMALIZED) t1=1; + else {t1=z; t1*=t1;} + if (ex2!=NULL) *ex2=t1; + if (iA==-3 && twist<=MR_QUADRATIC) + { + if (twist==MR_QUADRATIC) t1*=qnr; + lam=x-t1; + t1+=x; + lam*=t1; + t2=lam; t2+=t2; + lam+=t2; + } + else + { + lam=x; lam*=lam; + t2=lam; t2+=t2; + lam+=t2; + if (twist==MR_QUADRATIC) t1*=qnr; + t1*=t1; + if (twist==MR_QUARTIC_M) t1=tx(t1); + if (twist==MR_QUARTIC_D) t1=txd(t1); + if (iA!=1) + { + if (iAB3) nb=bits(A3)-1; + else nb=bits(B3)-1; + + while (nb>=0) + { + R+=R; + e1=h1=e2=h2=0; + t=0; + if (bit(A,nb)) {e2=1; t+=8;} + if (bit(A3,nb)) {h2=1; t+=4;} + if (bit(B,nb)) {e1=1; t+=2;} + if (bit(B3,nb)) {h1=1; t+=1;} + + if (t==1 || t==13) R+=Y; + if (t==2 || t==14) R-=Y; + if (t==4 || t==7) R+=X; + if (t==8 || t==11) R-=X; + if (t==5) R+=S; + if (t==10) R-=S; + if (t==9) R+=D; + if (t==6) R-=D; + nb-=1; + } +#ifdef MR_ECN3_PROJECTIVE + R.norm(); +#endif + return R; +} + +#ifndef MR_STATIC + +ECn3 mul(int n,ECn3* P,const Big* b) +{ + int k,j,i,m,nb,ea; + ECn3 *G; + ECn3 R; + m=1<nb) nb=k; + + for (i=nb-1;i>=0;i--) + { + ea=0; + k=1; + for (j=0;j. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ecn3.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class ECn3 (Arithmetic on an Elliptic Curve, + * mod n^3) + * + * NOTE : Must be used in conjunction with zzn.cpp, big.cpp and + * zzn3.cpp + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#ifndef ECN3_H +#define ECN3_H + +#include "zzn3.h" + +//#define MR_ECN3_PROJECTIVE + +class ECn3 +{ + mutable ZZn3 x,y; // can change from affine to projective, but maintain same logical value +#ifdef MR_ECN3_PROJECTIVE +#ifndef MR_AFFINE_ONLY + mutable ZZn3 z; +#endif +#endif + mutable int marker; +public: + ECn3() {marker=MR_EPOINT_INFINITY;} + ECn3(const ECn3& b) + { + x=b.x; y=b.y; +#ifdef MR_ECN3_PROJECTIVE +#ifndef MR_AFFINE_ONLY + z=b.z; +#endif +#endif + marker=b.marker; + } + + ECn3& operator=(const ECn3& b) + { + x=b.x; y=b.y; +#ifdef MR_ECN3_PROJECTIVE +#ifndef MR_AFFINE_ONLY + z=b.z; +#endif +#endif + marker=b.marker; + return *this; + } + + int add(const ECn3&,ZZn3&,ZZn3 *ex1=NULL,ZZn3 *ex2=NULL ); + + ECn3& operator+=(const ECn3&); + ECn3& operator-=(const ECn3&); + ECn3& operator*=(const Big&); + + void clear() + { + x=y=0; +#ifdef MR_ECN3_PROJECTIVE +#ifndef MR_AFFINE_ONLY + z=0; +#endif +#endif + marker=MR_EPOINT_INFINITY; + } + + BOOL iszero() const; + + void get(ZZn3&,ZZn3&) const; + void get(ZZn3&) const; +#ifdef MR_ECN3_PROJECTIVE +#ifndef MR_AFFINE_ONLY + void getZ(ZZn3&) const; + void get(ZZn3&,ZZn3&,ZZn3&) const; + + void set(const ZZn3&,const ZZn3&,const ZZn3&); +#endif +#endif + BOOL set(const ZZn3&,const ZZn3&); // set on the curve - returns FALSE if no such point + BOOL set(const ZZn3&); // sets x coordinate on curve, and finds y coordinate + + void norm(void) const; + friend ECn3 operator-(const ECn3&); + friend ECn3 operator+(const ECn3&,const ECn3&); + friend ECn3 operator-(const ECn3&,const ECn3&); + + friend ECn3 mul(int,ECn3*,const Big*); + friend ECn3 mul(const ECn3&,const Big&,const ECn3&,const Big&); + + friend BOOL operator==(const ECn3& a,const ECn3 &b) + { +#ifdef MR_ECN3_PROJECTIVE + a.norm(); b.norm(); +#endif + return (a.x==b.x && a.y==b.y && a.marker==b.marker); + } + friend BOOL operator!=(const ECn3& a,const ECn3 &b) + { +#ifdef MR_ECN3_PROJECTIVE + a.norm(); b.norm(); +#endif + return (a.x!=b.x || a.y!=b.y || a.marker!=b.marker); + } + + friend ECn3 operator*(const Big &,const ECn3&); +#ifndef MR_NO_STANDARD_IO + friend ostream& operator<<(ostream&,const ECn3&); +#endif + + ~ECn3() {} +}; + +#endif + diff --git a/miracl/source/curve/pairing/ecn4.cpp b/miracl/source/curve/pairing/ecn4.cpp new file mode 100644 index 0000000..ce8bbfe --- /dev/null +++ b/miracl/source/curve/pairing/ecn4.cpp @@ -0,0 +1,294 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file ecn4.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ECn4 (Elliptic curves over n^4) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + + +#include "ecn4.h" + +using namespace std; + +void ECn4::get(ZZn4& a,ZZn4& b) const +{a=x;b=y;} + +void ECn4::get(ZZn4& a) const +{a=x;} + +BOOL ECn4::iszero(void) const +{if (marker==MR_EPOINT_INFINITY) return TRUE; return FALSE;} + +BOOL ECn4::set(const ZZn4& xx,const ZZn4& yy) +{ + if (yy*yy!=rhs(xx)) return FALSE; + x=xx; + y=yy; + marker=MR_EPOINT_NORMALIZED; + return TRUE; +} + +BOOL ECn4::set(const ZZn4& xx) +{ + ZZn4 w=rhs(xx); + + if (!w.iszero()) + { + w=sqrt(w); + if (w.iszero()) return FALSE; + } + + x=xx; + y=w; + marker=MR_EPOINT_NORMALIZED; + return TRUE; +} + +ECn4 operator-(const ECn4& a) +{ECn4 w; + if (a.marker!=MR_EPOINT_INFINITY) + {w.x=a.x; w.y=-a.y; w.marker=a.marker;} + return w; +} + +ECn4& ECn4::operator*=(const Big& k) +{ + int i,j,n,nb,nbs,nzs; + ECn4 p2,pt,t[11]; + Big h,kk; + + if (k==0) + { + clear(); + return *this; + } + if (k==1) + { + return (*this); + } + + pt=*this; + kk=k; + if (kk<0) + { + pt=-pt; + kk=-k; + } + h=3*kk; + + p2=pt+pt; + t[0]=pt; + for (i=1;i<=10;i++) + t[i]=t[i-1]+p2; + +// Left to Right method + + nb=bits(h); + for (i=nb-2;i>=1;) + { + n=naf_window(kk,h,i,&nbs,&nzs,11); + for (j=0;j0) pt+=t[n/2]; + if (n<0) pt-=t[(-n)/2]; + i-=nbs; + if (nzs) + { + for (j=0;jTWIST; + + if (marker==MR_EPOINT_INFINITY) + { + *this=z; + return FALSE; + } + if (z.marker==MR_EPOINT_INFINITY) + { + return FALSE; + } + + if (x!=z.x) + { + ZZn4 t=y; t-=z.y; + ZZn4 t2=x; t2-=z.x; + lam=t; lam/=t2; + + x+=z.x; t=lam; t*=t; t-=x; x=t; + y=z.x; y-=x; y*=lam; y-=z.y; + + } + else + { + if (y!=z.y || y.iszero()) + { + clear(); + lam=(ZZn4)1; + return TRUE; // any non-zero value + } + ZZn4 t=x; + ZZn4 t2=x; + + // lam=(3*(x*x)+getA())/(y+y); + + lam=x; + lam*=lam; + lam*=3; + if (twist==MR_QUADRATIC) + { + // ZZn4 a4; + // ZZn2 x((ZZn)0,getA()); + // a4.set(x,(ZZn2)0); // A*i^4 + lam+=txx( (ZZn2)getA() ); + // lam+=a4; + } + else lam+=getA(); + lam/=(y+y); + + t2+=x; + x=lam; + x*=x; + x-=t2; + + t-=x; + t*=lam; + t-=y; + y=t; + } + + marker=MR_EPOINT_GENERAL; + return TRUE; +} + +#ifndef MR_NO_ECC_MULTIADD +#ifndef MR_STATIC + +ECn4 mul(int n,ECn4* P,const Big* b) +{ + int k,j,i,m,nb,ea; + ECn4 *G; + ECn4 R; + m=1<nb) nb=k; + + for (i=nb-1;i>=0;i--) + { + ea=0; + k=1; + for (j=0;j. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ecn4.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class ECn4 (Arithmetic on an Elliptic Curve, + * mod n^4) + * + * NOTE : Must be used in conjunction with zzn.cpp, big.cpp and + * zzn2.cpp and zzn4.cpp + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#ifndef ECN4_H +#define ECN4_H + +#include "zzn4.h" + +// Affine Only + +class ECn4 +{ + ZZn4 x,y; + int marker; +public: + ECn4() {marker=MR_EPOINT_INFINITY;} + ECn4(const ECn4& b) {x=b.x; y=b.y; marker=b.marker; } + + ECn4& operator=(const ECn4& b) + {x=b.x; y=b.y; marker=b.marker; return *this; } + + BOOL add(const ECn4&,ZZn4&); + + ECn4& operator+=(const ECn4&); + ECn4& operator-=(const ECn4&); + ECn4& operator*=(const Big&); + + void clear() {x=y=0; marker=MR_EPOINT_INFINITY;} + BOOL iszero() const; + + void get(ZZn4&,ZZn4&) const; + void get(ZZn4&) const; + + BOOL set(const ZZn4&,const ZZn4&); // set on the curve - returns FALSE if no such point + BOOL set(const ZZn4&); // sets x coordinate on curve, and finds y coordinate + + friend ECn4 operator-(const ECn4&); + friend ECn4 operator+(const ECn4&,const ECn4&); + friend ECn4 operator-(const ECn4&,const ECn4&); + + friend ECn4 mul(int,ECn4*,const Big*); + + friend BOOL operator==(const ECn4& a,const ECn4 &b) + {return (a.x==b.x && a.y==b.y && a.marker==b.marker); } + friend BOOL operator!=(const ECn4& a,const ECn4 &b) + {return (a.x!=b.x || a.y!=b.y || a.marker!=b.marker); } + + friend ECn4 operator*(const Big &,const ECn4&); + +#ifndef MR_NO_STANDARD_IO + friend ostream& operator<<(ostream&,const ECn4&); +#endif + + ~ECn4() {} +}; + +#endif + diff --git a/miracl/source/curve/pairing/ecn6.cpp b/miracl/source/curve/pairing/ecn6.cpp new file mode 100644 index 0000000..b1c6d33 --- /dev/null +++ b/miracl/source/curve/pairing/ecn6.cpp @@ -0,0 +1,240 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file ecn6.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ECn6 (Elliptic curves over n^6) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#include "ecn6.h" + +using namespace std; + +void ECn6::get(ZZn6& a,ZZn6& b) const +{a=x;b=y;} + +void ECn6::get(ZZn6& a) const +{a=x;} + +BOOL ECn6::iszero() const +{if (marker==MR_EPOINT_INFINITY) return TRUE; return FALSE;} + +BOOL ECn6::set(const ZZn6& xx,const ZZn6& yy) +{ + if (yy*yy!=rhs(xx)) return FALSE; + x=xx; + y=yy; + marker=MR_EPOINT_NORMALIZED; + return TRUE; +} + +BOOL ECn6::set(const ZZn6& xx) +{ + ZZn6 w=rhs(xx); + + if (!w.iszero()) + { + w=sqrt(w); + if (w.iszero()) return FALSE; + } + + x=xx; + y=w; + marker=MR_EPOINT_NORMALIZED; + return TRUE; +} + +ECn6 operator-(const ECn6& a) +{ECn6 w; + if (a.marker!=MR_EPOINT_INFINITY) + {w.x=a.x; w.y=-a.y; w.marker=a.marker;} + return w; +} + +ECn6& ECn6::operator*=(const Big& k) +{ + int i,j,n,nb,nbs,nzs; + ECn6 p2,pt,t[11]; + Big h,kk; + + if (k==0) + { + clear(); + return *this; + } + if (k==1) + { + return (*this); + } + + pt=*this; + kk=k; + if (kk<0) + { + pt=-pt; + kk=-k; + } + h=3*kk; + + p2=pt+pt; + t[0]=pt; + for (i=1;i<=10;i++) + t[i]=t[i-1]+p2; + +// Left to Right method + + nb=bits(h); + for (i=nb-2;i>=1;) + { + n=naf_window(kk,h,i,&nbs,&nzs,11); + for (j=0;j0) pt+=t[n/2]; + if (n<0) pt-=t[(-n)/2]; + i-=nbs; + if (nzs) + { + for (j=0;jTWIST; + + if (marker==MR_EPOINT_INFINITY) + { + *this=z; + return FALSE; + } + if (z.marker==MR_EPOINT_INFINITY) + { + return FALSE; + } + + if (x!=z.x) + { + ZZn6 t=y; t-=z.y; + ZZn6 t2=x; t2-=z.x; + lam=t; lam/=t2; + + x+=z.x; t=lam; t*=t; t-=x; x=t; + y=z.x; y-=x; y*=lam; y-=z.y; + + } + else + { + if (y!=z.y || y.iszero()) + { + clear(); + lam=(ZZn6)1; + return TRUE; // any non-zero value + } + ZZn6 t=x; + ZZn6 t2=x; + + // lam=(3*(x*x)+getA())/(y+y); + + lam=x; + lam*=lam; + lam*=3; + lam+=getA(); + lam/=(y+y); + + t2+=x; + x=lam; + x*=x; + x-=t2; + + t-=x; + t*=lam; + t-=y; + y=t; + } + + marker=MR_EPOINT_GENERAL; + return TRUE; +} + diff --git a/miracl/source/curve/pairing/ecn6.h b/miracl/source/curve/pairing/ecn6.h new file mode 100644 index 0000000..8ecc7b5 --- /dev/null +++ b/miracl/source/curve/pairing/ecn6.h @@ -0,0 +1,104 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ecn6.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class ECn6 (Arithmetic on an Elliptic Curve, + * mod n^6) + * + * NOTE : Must be used in conjunction with zzn.cpp, big.cpp and + * zzn2.cpp and zzn6a.cpp + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#ifndef ECN6_H +#define ECN6_H + +#include "zzn6.h" + +// Affine Only + +class ECn6 +{ + ZZn6 x,y; + int marker; +public: + ECn6() {marker=MR_EPOINT_INFINITY;} + ECn6(const ECn6& b) {x=b.x; y=b.y; marker=b.marker; } + + ECn6& operator=(const ECn6& b) + {x=b.x; y=b.y; marker=b.marker; return *this; } + + BOOL add(const ECn6&,ZZn6&); + + ECn6& operator+=(const ECn6&); + ECn6& operator-=(const ECn6&); + ECn6& operator*=(const Big&); + + void clear() {x=y=0; marker=MR_EPOINT_INFINITY;} + BOOL iszero() const; + + void get(ZZn6&,ZZn6&) const; + void get(ZZn6&) const; + + BOOL set(const ZZn6&,const ZZn6&); // set on the curve - returns FALSE if no such point + BOOL set(const ZZn6&); // sets x coordinate on curve, and finds y coordinate + + friend ECn6 operator-(const ECn6&); + friend ECn6 operator+(const ECn6&,const ECn6&); + friend ECn6 operator-(const ECn6&,const ECn6&); + + friend BOOL operator==(const ECn6& a,const ECn6 &b) + {return (a.x==b.x && a.y==b.y && a.marker==b.marker); } + friend BOOL operator!=(const ECn6& a,const ECn6 &b) + {return (a.x!=b.x || a.y!=b.y || a.marker!=b.marker); } + + friend ECn6 operator*(const Big &,const ECn6&); + +#ifndef MR_NO_STANDARD_IO + friend ostream& operator<<(ostream&,const ECn6&); +#endif + + ~ECn6() {} +}; + +#endif + diff --git a/miracl/source/curve/pairing/ecn8.cpp b/miracl/source/curve/pairing/ecn8.cpp new file mode 100644 index 0000000..10e34b0 --- /dev/null +++ b/miracl/source/curve/pairing/ecn8.cpp @@ -0,0 +1,290 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file ECn8.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ECn8 (Elliptic curves over n^4) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + + +#include "ecn8.h" + +using namespace std; + +void ECn8::get(ZZn8& a,ZZn8& b) const +{a=x;b=y;} + +void ECn8::get(ZZn8& a) const +{a=x;} + +BOOL ECn8::iszero(void) const +{if (marker==MR_EPOINT_INFINITY) return TRUE; return FALSE;} + +BOOL ECn8::set(const ZZn8& xx,const ZZn8& yy) +{ + if (yy*yy!=rhs(xx)) return FALSE; + x=xx; + y=yy; + marker=MR_EPOINT_NORMALIZED; + return TRUE; +} + +BOOL ECn8::set(const ZZn8& xx) +{ + ZZn8 w=rhs(xx); + + if (!w.iszero()) + { + w=sqrt(w); + if (w.iszero()) return FALSE; + } + + x=xx; + y=w; + marker=MR_EPOINT_NORMALIZED; + return TRUE; +} + +ECn8 operator-(const ECn8& a) +{ECn8 w; + if (a.marker!=MR_EPOINT_INFINITY) + {w.x=a.x; w.y=-a.y; w.marker=a.marker;} + return w; +} + +ECn8& ECn8::operator*=(const Big& k) +{ + int i,j,n,nb,nbs,nzs; + ECn8 p2,pt,t[11]; + Big h,kk; + + if (k==0) + { + clear(); + return *this; + } + if (k==1) + { + return (*this); + } + + pt=*this; + kk=k; + if (kk<0) + { + pt=-pt; + kk=-k; + } + h=3*kk; + + p2=pt+pt; + t[0]=pt; + for (i=1;i<=10;i++) + t[i]=t[i-1]+p2; + +// Left to Right method + + nb=bits(h); + for (i=nb-2;i>=1;) + { + n=naf_window(kk,h,i,&nbs,&nzs,11); + for (j=0;j0) pt+=t[n/2]; + if (n<0) pt-=t[(-n)/2]; + i-=nbs; + if (nzs) + { + for (j=0;jTWIST; + + if (marker==MR_EPOINT_INFINITY) + { + *this=z; + return FALSE; + } + if (z.marker==MR_EPOINT_INFINITY) + { + return FALSE; + } + + if (x!=z.x) + { + ZZn8 t=y; t-=z.y; + ZZn8 t2=x; t2-=z.x; + lam=t; lam/=t2; + + x+=z.x; t=lam; t*=t; t-=x; x=t; + y=z.x; y-=x; y*=lam; y-=z.y; + + } + else + { + if (y!=z.y || y.iszero()) + { + clear(); + lam=(ZZn8)1; + return TRUE; // any non-zero value + } + ZZn8 t=x; + ZZn8 t2=x; + + // lam=(3*(x*x)+getA())/(y+y); + + lam=x; + lam*=lam; + lam*=3; + if (twist==MR_QUADRATIC) + { + lam+=tx((ZZn4)getA() ); + } + else lam+=getA(); + lam/=(y+y); + + t2+=x; + x=lam; + x*=x; + x-=t2; + + t-=x; + t*=lam; + t-=y; + y=t; + } + + marker=MR_EPOINT_GENERAL; + return TRUE; +} + +#ifndef MR_NO_ECC_MULTIADD +#ifndef MR_STATIC + +ECn8 mul(int n,ECn8* P,const Big* b) +{ + int k,j,i,m,nb,ea; + ECn8 *G; + ECn8 R; + m=1<nb) nb=k; + + for (i=nb-1;i>=0;i--) + { + ea=0; + k=1; + for (j=0;j. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ecn8.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class ECn8 (Arithmetic on an Elliptic Curve, + * mod n^8) + * + * NOTE : Must be used in conjunction with zzn.cpp, big.cpp and + * zzn2.cpp, zzn4.cpp and zzn8.cpp + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#ifndef ECN8_H +#define ECN8_H + +#include "zzn8.h" + +// Affine Only + +class ECn8 +{ + ZZn8 x,y; + int marker; +public: + ECn8() {marker=MR_EPOINT_INFINITY;} + ECn8(const ECn8& b) {x=b.x; y=b.y; marker=b.marker; } + + ECn8& operator=(const ECn8& b) + {x=b.x; y=b.y; marker=b.marker; return *this; } + + BOOL add(const ECn8&,ZZn8&); + + ECn8& operator+=(const ECn8&); + ECn8& operator-=(const ECn8&); + ECn8& operator*=(const Big&); + + void clear() {x=y=0; marker=MR_EPOINT_INFINITY;} + BOOL iszero() const; + + void get(ZZn8&,ZZn8&) const; + void get(ZZn8&) const; + + BOOL set(const ZZn8&,const ZZn8&); // set on the curve - returns FALSE if no such point + BOOL set(const ZZn8&); // sets x coordinate on curve, and finds y coordinate + + friend ECn8 operator-(const ECn8&); + friend ECn8 operator+(const ECn8&,const ECn8&); + friend ECn8 operator-(const ECn8&,const ECn8&); + + friend ECn8 mul(int,ECn8*,const Big*); + + friend BOOL operator==(const ECn8& a,const ECn8 &b) + {return (a.x==b.x && a.y==b.y && a.marker==b.marker); } + friend BOOL operator!=(const ECn8& a,const ECn8 &b) + {return (a.x!=b.x || a.y!=b.y || a.marker!=b.marker); } + + friend ECn8 operator*(const Big &,const ECn8&); + +#ifndef MR_NO_STANDARD_IO + friend ostream& operator<<(ostream&,const ECn8&); +#endif + + ~ECn8() {} +}; + +#endif + diff --git a/miracl/source/curve/pairing/etat271.c b/miracl/source/curve/pairing/etat271.c new file mode 100644 index 0000000..1621dd9 --- /dev/null +++ b/miracl/source/curve/pairing/etat271.c @@ -0,0 +1,1021 @@ +/* Author: Michael Scott */ +/* Date: Dec 2007 */ +/* Even Faster Duursma-Lee char 2 Tate pairing based on eta_T pairing */ +/* See MIRACL dl2.cpp for more readable C++ version */ +/* cl /O2 etat271.c miracl.lib */ +/* 8-bit version */ +/* Half sized loop so nearly twice as fast! */ + +/* MIRACL mirdef.h + * For Atmel AVR (e.g. ATmega128L) set up mirdef.h as follows + +#define MR_LITTLE_ENDIAN +#define MIRACL 8 +#define mr_utype char +#define MR_IBITS 16 +#define MR_LBITS 32 +#define mr_unsign32 unsigned long +#define mr_dltype int +#define MR_STATIC 34 +#define MR_ALWAYS_BINARY +#define MR_NOASM +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_NOKOBLITZ +#define MR_NO_STANDARD_IO +#define MR_NO_FILE_IO +#define MR_SIMPLE_BASE +#define MR_SIMPLE_IO +#define MR_AVR +#define SP271 + +*/ + +/* use this mirdef.h to mimic 8-bit implementation on a PC +#define MR_LITTLE_ENDIAN +#define MIRACL 8 +#define mr_utype char +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype short +#define MR_STATIC 34 +#define MR_ALWAYS_BINARY +#define MR_NOASM +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_NOKOBLITZ + +*/ + +/* rem build using this batch file for PC +rem Compile MIRACL modules +cl /c /O2 /W3 mrcore.c +cl /c /O2 /W3 mrarth0.c +cl /c /O2 /W3 mrarth1.c +cl /c /O2 /W3 mrio1.c +cl /c /O2 /W3 mrbits.c +cl /c /O2 /W3 mrgf2m.c +cl /c /O2 /W3 mrec2m.c + +rem +rem Create library 'miracl.lib' +del miracl.lib + +lib /OUT:miracl.lib mrio1.obj +lib /OUT:miracl.lib miracl.lib mrbits.obj +lib /OUT:miracl.lib miracl.lib mrarth0.obj mrarth1.obj mrcore.obj +lib /OUT:miracl.lib miracl.lib mrec2m.obj mrgf2m.obj +del mr*.obj + +cl /O2 etat271.c miracl.lib + +On the ARM use a header like + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype long long +#define MR_STATIC 9 +#define MR_ALWAYS_BINARY +#define MR_NOASM +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_NOKOBLITZ + + +/* define one curve or the other.. */ + +#include +#include +#include "miracl.h" + +#define M 271 +#define T 207 +#define U 175 +#define V 111 + +#define B 0 +#define TYPE 1 + +/* points P and Q from ROM */ + +/* WORDS = number of words needs to store GF(2^m) = size of bigs */ + +/* elements of GF(2^m) are stored in bigs */ +/* elements of the quartic extension field GF(2^{4m}) are stored as an array of 4 bigs */ +/* = {a,b,c,d} = d.X^3+c.X^2+b.X+a */ + +/* fast inlined addition code */ + +#if MIRACL==64 + +#define WORDS 5 +#define NPW 16 /* nibbles per word */ +#define ROMSZ 20 + +static const mr_small rom[]={ +0x591B401498D66271,0xA16F0C4E5357F2F6,0xD76AEF912696E510,0x75C041258C778D1D,0x10B1, +0x80DC7F385B9C26BF,0x2B65C2A7BAF3B9FD,0x6A84C19620F8D8B9,0x6D0DB856E16E7097,0x7C02, +0x4EDF428FD0EE2151,0x8A4509E6D6013138,0xBB5FBE66F7C468E7,0xA2740AF91652325E,0x2C67, +0x329B869A3E833026,0xB3716EC7D5F80608,0x3EE35C892B03AE59,0x5AF93E7449ABB134,0x48FB +}; + +void fincr2(big a,big c) +{ + mr_small *aa,*cc; + aa=a->w; cc=c->w; + + cc[0]^=aa[0]; + cc[1]^=aa[1]; + cc[2]^=aa[2]; + cc[3]^=aa[3]; + cc[4]^=aa[4]; + + c->len=WORDS; + if (cc[4]==0) mr_lzero(c); +} + +void fadd2(big a,big b,big c) +{ + mr_small *aa,*bb,*cc; + aa=a->w; bb=b->w; cc=c->w; + + cc[0]=aa[0]^bb[0]; + cc[1]=aa[1]^bb[1]; + cc[2]=aa[2]^bb[2]; + cc[3]=aa[3]^bb[3]; + cc[4]=aa[4]^bb[4]; + + c->len=WORDS; + if (cc[4]==0) mr_lzero(c); +} + +/* fast inlined copy code - replaces copy(.) */ + +void fcopy2(big a,big b) +{ + mr_small *aa,*bb; + aa=a->w; bb=b->w; + + bb[0]=aa[0]; + bb[1]=aa[1]; + bb[2]=aa[2]; + bb[3]=aa[3]; + bb[4]=aa[4]; + + b->len=a->len; +} + + +#endif + +#if MIRACL==32 + +#define WORDS 9 +#define NPW 8 /* nibbles per word */ +#define ROMSZ 36 + +static const mr_small rom[]={ +0x98D66271,0x591B4014,0x5357F2F6,0xA16F0C4E,0x2696E510,0xD76AEF91,0x8C778D1D,0x75C04125,0x10B1, +0x5B9C26BF,0x80DC7F38,0xBAF3B9FD,0x2B65C2A7,0x20F8D8B9,0x6A84C196,0xE16E7097,0x6D0DB856,0x7C02, +0xD0EE2151,0x4EDF428F,0xD6013138,0x8A4509E6,0xF7C468E7,0xBB5FBE66,0x1652325E,0xA2740AF9,0x2C67, +0x3E833026,0x329B869A,0xD5F80608,0xB3716EC7,0x2B03AE59,0x3EE35C89,0x49ABB134,0x5AF93E74,0x48FB +}; + +void fincr2(big a,big c) +{ + mr_small *aa,*cc; + aa=a->w; cc=c->w; + + cc[0]^=aa[0]; + cc[1]^=aa[1]; + cc[2]^=aa[2]; + cc[3]^=aa[3]; + cc[4]^=aa[4]; + cc[5]^=aa[5]; + cc[6]^=aa[6]; + cc[7]^=aa[7]; + cc[8]^=aa[8]; + + + c->len=WORDS; + if (cc[8]==0) mr_lzero(c); +} + +void fadd2(big a,big b,big c) +{ + mr_small *aa,*bb,*cc; + aa=a->w; bb=b->w; cc=c->w; + + cc[0]=aa[0]^bb[0]; + cc[1]=aa[1]^bb[1]; + cc[2]=aa[2]^bb[2]; + cc[3]=aa[3]^bb[3]; + cc[4]=aa[4]^bb[4]; + cc[5]=aa[5]^bb[5]; + cc[6]=aa[6]^bb[6]; + cc[7]=aa[7]^bb[7]; + cc[8]=aa[8]^bb[8]; + + c->len=WORDS; + if (cc[8]==0) mr_lzero(c); +} + +/* fast inlined copy code - replaces copy(.) */ + +void fcopy2(big a,big b) +{ + mr_small *aa,*bb; + aa=a->w; bb=b->w; + + bb[0]=aa[0]; + bb[1]=aa[1]; + bb[2]=aa[2]; + bb[3]=aa[3]; + bb[4]=aa[4]; + bb[5]=aa[5]; + bb[6]=aa[6]; + bb[7]=aa[7]; + bb[8]=aa[8]; + + b->len=a->len; +} + +#endif + +#if MIRACL==8 + +#define WORDS 34 +#define NPW 2 +#define ROMSZ 136 + +/* For Pentanomial x^271+x^207+x^175+x^111+1 */ + +#ifdef MR_AVR +__attribute__((__progmem__)) +#endif +static const mr_small rom[]={ +0x71,0x62,0xD6,0x98,0x14,0x40,0x1B,0x59,0xF6,0xF2,0x57,0x53,0x4E,0xC,0x6F,0xA1,0x10,0xE5,0x96,0x26,0x91,0xEF,0x6A,0xD7,0x1D,0x8D,0x77,0x8C,0x25,0x41,0xC0,0x75,0xB1,0x10, +0xBF,0x26,0x9C,0x5B,0x38,0x7F,0xDC,0x80,0xFD,0xB9,0xF3,0xBA,0xA7,0xC2,0x65,0x2B,0xB9,0xD8,0xF8,0x20,0x96,0xC1,0x84,0x6A,0x97,0x70,0x6E,0xE1,0x56,0xB8,0xD,0x6D,0x2,0x7C, +0x51,0x21,0xEE,0xD0,0x8F,0x42,0xDF,0x4E,0x38,0x31,0x1,0xD6,0xE6,0x9,0x45,0x8A,0xE7,0x68,0xC4,0xF7,0x66,0xBE,0x5F,0xBB,0x5E,0x32,0x52,0x16,0xF9,0xA,0x74,0xA2,0x67,0x2C, +0x26,0x30,0x83,0x3E,0x9A,0x86,0x9B,0x32,0x8,0x6,0xF8,0xD5,0xC7,0x6E,0x71,0xB3,0x59,0xAE,0x3,0x2B,0x89,0x5C,0xE3,0x3E,0x34,0xB1,0xAB,0x49,0x74,0x3E,0xF9,0x5A,0xFB,0x48 +}; + +void fincr2(big a,big c) +{ + mr_small *aa,*cc; + aa=a->w; cc=c->w; + + cc[0]^=aa[0]; + cc[1]^=aa[1]; + cc[2]^=aa[2]; + cc[3]^=aa[3]; + cc[4]^=aa[4]; + cc[5]^=aa[5]; + cc[6]^=aa[6]; + cc[7]^=aa[7]; + cc[8]^=aa[8]; + cc[9]^=aa[9]; + cc[10]^=aa[10]; + cc[11]^=aa[11]; + cc[12]^=aa[12]; + cc[13]^=aa[13]; + cc[14]^=aa[14]; + cc[15]^=aa[15]; + cc[16]^=aa[16]; + cc[17]^=aa[17]; + cc[18]^=aa[18]; + cc[19]^=aa[19]; + cc[20]^=aa[20]; + cc[21]^=aa[21]; + cc[22]^=aa[22]; + cc[23]^=aa[23]; + cc[24]^=aa[24]; + cc[25]^=aa[25]; + cc[26]^=aa[26]; + cc[27]^=aa[27]; + cc[28]^=aa[28]; + cc[29]^=aa[29]; + cc[30]^=aa[30]; + cc[31]^=aa[31]; + cc[32]^=aa[32]; + cc[33]^=aa[33]; + + c->len=WORDS; + if (cc[33]==0) mr_lzero(c); +} + +void fadd2(big a,big b,big c) +{ + mr_small *aa,*bb,*cc; + aa=a->w; bb=b->w; cc=c->w; + + cc[0]=aa[0]^bb[0]; + cc[1]=aa[1]^bb[1]; + cc[2]=aa[2]^bb[2]; + cc[3]=aa[3]^bb[3]; + cc[4]=aa[4]^bb[4]; + cc[5]=aa[5]^bb[5]; + cc[6]=aa[6]^bb[6]; + cc[7]=aa[7]^bb[7]; + cc[8]=aa[8]^bb[8]; + cc[9]=aa[9]^bb[9]; + cc[10]=aa[10]^bb[10]; + cc[11]=aa[11]^bb[11]; + cc[12]=aa[12]^bb[12]; + cc[13]=aa[13]^bb[13]; + cc[14]=aa[14]^bb[14]; + cc[15]=aa[15]^bb[15]; + cc[16]=aa[16]^bb[16]; + cc[17]=aa[17]^bb[17]; + cc[18]=aa[18]^bb[18]; + cc[19]=aa[19]^bb[19]; + cc[20]=aa[20]^bb[20]; + cc[21]=aa[21]^bb[21]; + cc[22]=aa[22]^bb[22]; + cc[23]=aa[23]^bb[23]; + cc[24]=aa[24]^bb[24]; + cc[25]=aa[25]^bb[25]; + cc[26]=aa[26]^bb[26]; + cc[27]=aa[27]^bb[27]; + cc[28]=aa[28]^bb[28]; + cc[29]=aa[29]^bb[29]; + cc[30]=aa[30]^bb[30]; + cc[31]=aa[31]^bb[31]; + cc[32]=aa[32]^bb[32]; + cc[33]=aa[33]^bb[33]; + + c->len=WORDS; + if (cc[33]==0) mr_lzero(c); +} + +/* fast inlined copy code - replaces copy(.) */ + +void fcopy2(big a,big b) +{ + mr_small *aa,*bb; + aa=a->w; bb=b->w; + + bb[0]=aa[0]; + bb[1]=aa[1]; + bb[2]=aa[2]; + bb[3]=aa[3]; + bb[4]=aa[4]; + bb[5]=aa[5]; + bb[6]=aa[6]; + bb[7]=aa[7]; + bb[8]=aa[8]; + bb[9]=aa[9]; + bb[10]=aa[10]; + bb[11]=aa[11]; + bb[12]=aa[12]; + bb[13]=aa[13]; + bb[14]=aa[14]; + bb[15]=aa[15]; + bb[16]=aa[16]; + bb[17]=aa[17]; + bb[18]=aa[18]; + bb[19]=aa[19]; + bb[20]=aa[20]; + bb[21]=aa[21]; + bb[22]=aa[22]; + bb[23]=aa[23]; + bb[24]=aa[24]; + bb[25]=aa[25]; + bb[26]=aa[26]; + bb[27]=aa[27]; + bb[28]=aa[28]; + bb[29]=aa[29]; + bb[30]=aa[30]; + bb[31]=aa[31]; + bb[32]=aa[32]; + bb[33]=aa[33]; + + b->len=a->len; +} + +#endif + +/* Use internal workspace variables w1-w13 - must be careful doing this! - see comment below */ + +void mul(_MIPD_ big *a,big *b,big *r) +{ + /* Special multiplier for GF(2^{4m}) values of the form (x,y,y+1,0) */ + + fcopy2(a[1],mr_mip->w2); + fcopy2(b[1],mr_mip->w3); + fadd2(a[1],a[0],mr_mip->w8); /* e=w+p */ + fadd2(b[1],b[0],mr_mip->w9); /* s=t+q */ + + /* only 3 modmults.. */ + + modmult2(_MIPP_ mr_mip->w9,mr_mip->w8,mr_mip->w9); /* z=(w+p)*(t+q) */ + modmult2(_MIPP_ mr_mip->w3,mr_mip->w2,mr_mip->w4); /* tw=t*w */ + modmult2(_MIPP_ a[0],b[0],mr_mip->w8); /* pq=p*q */ + fincr2(mr_mip->w4,mr_mip->w9); /* z+=tw */ + fincr2(mr_mip->w8,mr_mip->w9); /* z+=pq */ + fincr2(mr_mip->w3,mr_mip->w2); /* w+=t */ + fadd2(mr_mip->w2,mr_mip->w4,mr_mip->w3); /* t=w+tw */ + incr2(mr_mip->w3,1,mr_mip->w3); /* t=w+tw+1 */ + + fadd2(mr_mip->w9,a[0],mr_mip->w12); /* x=z+p */ + fincr2(b[0],mr_mip->w12); /* x=z+p+q */ + + fadd2(mr_mip->w8,mr_mip->w3,r[0]); /* r[0]=pq+t */ + fadd2(mr_mip->w9,mr_mip->w3,r[1]); /* r[1]=z+t */ + fadd2(mr_mip->w12,mr_mip->w4,r[2]); /* r[2]=z+p+q+tw */ + fcopy2(mr_mip->w2,r[3]); /* r[3]=w */ +} + +/* squaring GF(2^{4m}) values */ + +void square4(_MIPD_ big *a,big *c) +{ + if (a!=c) + { + fcopy2(a[0],c[0]); + fcopy2(a[1],c[1]); + fcopy2(a[2],c[2]); + fcopy2(a[3],c[3]); + } + + modsquare2(_MIPP_ c[3],c[3]); + fcopy2(c[2],mr_mip->w1); + modsquare2(_MIPP_ mr_mip->w1,mr_mip->w1); + fcopy2(c[1],c[2]); + modsquare2(_MIPP_ c[2],c[2]); + modsquare2(_MIPP_ c[0],c[0]); + fincr2(c[3],c[2]); + fincr2(mr_mip->w1,c[0]); + fcopy2(mr_mip->w1,c[1]); + + return; +} + +/* multiplying general GF(2^{4m}) values */ +/* Uses karatsuba - 9 modmults - very time critical */ +/* Use internal workspace variables w1-w13 - must be careful doing this! */ +/* The thing is to ensure that none of the invoked miracl internal routines are using the same variables */ +/* So first check the miracl source code.... I did... Its OK ... */ + +void mult4(_MIPD_ big *a,big *b,big *c) +{ + fadd2(a[1],a[3],mr_mip->w3); + fadd2(a[0],a[2],mr_mip->w4); + fadd2(b[1],b[3],mr_mip->w8); + fadd2(b[0],b[2],mr_mip->w9); + + modmult2(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w10); + modmult2(_MIPP_ mr_mip->w9,mr_mip->w4,mr_mip->w11); + modmult2(_MIPP_ a[1],b[1],mr_mip->w2); + modmult2(_MIPP_ a[2],b[2],mr_mip->w1); + + fadd2(mr_mip->w2,mr_mip->w1,mr_mip->w13); + + fadd2(a[1],a[0],c[1]); + fadd2(b[0],b[1],mr_mip->w12); + modmult2(_MIPP_ c[1],mr_mip->w12,c[1]); + modmult2(_MIPP_ a[0],b[0],c[0]); + fincr2(c[0],c[1]); + fincr2(mr_mip->w2,c[1]); + + fcopy2(a[2],c[2]); + fadd2(a[2],a[3],mr_mip->w12); + fadd2(b[2],b[3],mr_mip->w2); + modmult2(_MIPP_ mr_mip->w12,mr_mip->w2,mr_mip->w12); + + fincr2(mr_mip->w12,mr_mip->w1); + modmult2(_MIPP_ a[3],b[3],mr_mip->w2); + fincr2(mr_mip->w2,mr_mip->w1); + + fadd2(mr_mip->w9,mr_mip->w8,mr_mip->w12); + fcopy2(mr_mip->w12,c[3]); + fadd2(mr_mip->w4,mr_mip->w3,mr_mip->w12); + modmult2(_MIPP_ c[3],mr_mip->w12,c[3]); + + fincr2(mr_mip->w2,mr_mip->w1); + + fincr2(mr_mip->w10,c[3]); + fincr2(mr_mip->w11,c[3]); + fincr2(mr_mip->w1,c[3]); + fincr2(c[1],c[3]); + + fadd2(mr_mip->w13,c[0],c[2]); + fincr2(mr_mip->w11,c[2]); + fincr2(mr_mip->w1,c[2]); + + fincr2(mr_mip->w1,c[1]); + fincr2(mr_mip->w10,mr_mip->w13); + fincr2(mr_mip->w13,c[1]); + + fincr2(mr_mip->w2,mr_mip->w13); + fincr2(mr_mip->w13,c[0]); + + return; +} + +/* Frobenius action - GF(2^{4m}) ^ 2^m */ + +void powq(_MIPD_ big *x) +{ + fcopy2(x[1],mr_mip->w1); + fincr2(x[1],x[0]); + fcopy2(x[2],x[1]); + fincr2(x[3],x[1]); + fcopy2(mr_mip->w1,x[2]); +} + +/* return degree of GF(2^{4m}) polynomial */ + +int degree(big *c) +{ + if (size(c[3])!=0) return 3; + if (size(c[2])!=0) return 2; + if (size(c[1])!=0) return 1; + return 0; +} + +/* Raise a GF(2^{4m}) to a power */ + +void power4(_MIPD_ big *a,big k,big *u) +{ + int i,j,m,nb,n,nbw,nzs; + big u2[4],t[4][4]; +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 20); +#else + char mem[MR_BIG_RESERVE(20)]; + memset(mem,0,MR_BIG_RESERVE(20)); +#endif + m=0; + for (i=0;i<4;i++) + for (j=0;j<4;j++) t[i][j]=mirvar_mem(_MIPP_ mem,m++); + + u2[0]=mirvar_mem(_MIPP_ mem,16); + u2[1]=mirvar_mem(_MIPP_ mem,17); + u2[2]=mirvar_mem(_MIPP_ mem,18); + u2[3]=mirvar_mem(_MIPP_ mem,19); + + if(size(k)==0) + { + convert(_MIPP_ 1,u[0]); + zero(u[1]); + zero(u[2]); + zero(u[3]); +#ifndef MR_STATIC + memkill(_MIPP_ mem,20); +#else + memset(mem,0,MR_BIG_RESERVE(20)); +#endif + return; + } + + for (i=0;i<4;i++) + fcopy2(a[i],u[i]); + + if (size(k)==1) + { +#ifndef MR_STATIC + memkill(_MIPP_ mem,20); +#else + memset(mem,0,MR_BIG_RESERVE(20)); +#endif + return; + } + + square4(_MIPP_ u,u2); + for (i=0;i<4;i++) + fcopy2(u[i],t[0][i]); + + for(i=1;i<4;i++) + mult4(_MIPP_ u2,t[i-1],t[i]); + + nb=logb2(_MIPP_ k); + if(nb>1) for(i=nb-2;i>=0;) + { + n=mr_window(_MIPP_ k,i,&nbw,&nzs,3); /* small 3 bit window to save RAM */ + for(j=0;j0) mult4(_MIPP_ u,t[n/2],u); + i-=nbw; + if(nzs!=0) + { + for (j=0;j=j-1) + { + modmult2(_MIPP_ gamma,GP[i-j+1],t); + fincr2(t,FP[i]); + } + if (i>=j) + { + modmult2(_MIPP_ beta,GP[i-j],t); + fincr2(t,FP[i]); + } + } + for (i=0;i<=degB || i<=(degC+j);i++) + { + modmult2(_MIPP_ BP[i],alpha,BP[i]); + if (i>=j-1) + { + modmult2(_MIPP_ gamma,CP[i-j+1],t); + fincr2(t,BP[i]); + } + if (i>=j) + { + modmult2(_MIPP_ beta,CP[i-j],t); + fincr2(t,BP[i]); + } + } + + while (degF>=0 && size(FP[degF])==0) degF--; + if (degF==degG) + { + fcopy2(FP[degF],alpha); + for (i=0;i<=degF;i++) + { + modmult2(_MIPP_ FP[i],GP[degF],FP[i]); + modmult2(_MIPP_ alpha,GP[i],t); + fincr2(t,FP[i]); + } + for (i=0;i<=4-degF;i++) + { + modmult2(_MIPP_ BP[i],GP[degF],BP[i]); + modmult2(_MIPP_ CP[i],alpha,t); + fincr2(t,BP[i]); + + } + while (degF>=0 && size(FP[degF])==0) degF--; + } + degB=3; + while (degB>=0 && size(BP[degB])==0) degB--; + } + + inverse2(_MIPP_ FP[0],alpha); + + for (i=0;i<=degB;i++) + modmult2(_MIPP_ alpha,BP[i],x[i]); +#ifndef MR_STATIC + memkill(_MIPP_ mem,22); +#else + memset(mem,0,MR_BIG_RESERVE(22)); +#endif +} + +/* Tate Pairing - calculated from eta_T pairing */ + +void eta_T(_MIPD_ epoint *P,epoint *Q,big *f,big *res) +{ + big xp,yp,xq,yq,t,d; + big miller[4],v[4],u[4]; + int i,m=M; + int promptr; +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 18); +#else + char mem[MR_BIG_RESERVE(18)]; /* 972 bytes from stack */ + memset(mem,0,MR_BIG_RESERVE(18)); +#endif + + xp=mirvar_mem(_MIPP_ mem,0); + yp=mirvar_mem(_MIPP_ mem,1); + xq=mirvar_mem(_MIPP_ mem,2); + yq=mirvar_mem(_MIPP_ mem,3); + t=mirvar_mem(_MIPP_ mem,4); + d=mirvar_mem(_MIPP_ mem,5); + for (i=0;i<4;i++) miller[i]=mirvar_mem(_MIPP_ mem,6+i); + for (i=0;i<4;i++) v[i]=mirvar_mem(_MIPP_ mem,10+i); + for (i=0;i<4;i++) u[i]=mirvar_mem(_MIPP_ mem,14+i); + + fcopy2(P->X,xp); + fcopy2(P->Y,yp); + fcopy2(Q->X,xq); + fcopy2(Q->Y,yq); + + incr2(xp,1,t); /* t=xp+1 */ + + fadd2(xp,xq,d); + incr2(d,1,d); /* xp+xq+1 */ + modmult2(_MIPP_ d,t,d); /* t*(xp+xq+1) */ + fincr2(yp,d); + fincr2(yq,d); + incr2(d,B,d); + incr2(d,1,f[0]); /* f[0]=t*(xp+xq+1)+yp+yq+B+1 */ + + convert(_MIPP_ 1,miller[0]); + + fadd2(t,xq,f[2]); /* f[2]=t+xq */ + incr2(f[2],1,f[1]); /* f[1]=t+xq+1 */ + zero(f[3]); + promptr=0; + + for (i=0;i<(m-1)/2;i+=2) + { + fcopy2(xp,t); + sqroot2(_MIPP_ xp,xp); + sqroot2(_MIPP_ yp,yp); + fadd2(xp,xq,d); + modmult2(_MIPP_ d,t,d); + fincr2(yp,d); + fincr2(yq,d); + fadd2(d,xp,v[0]); /* v[0]=t*(xp+xq)+yp+yq+xp */ + fadd2(t,xq,v[2]); /* v[2]=t+xq */ + incr2(v[2],1,v[1]); /* v[1]=t+xq+1 */ + modsquare2(_MIPP_ xq,xq); /* xq*=xq */ + modsquare2(_MIPP_ yq,yq); /* yp*=yp */ + + fcopy2(xp,t); /* same again - unlooped times 2 */ + + sqroot2(_MIPP_ xp,xp); + sqroot2(_MIPP_ yp,yp); + + fadd2(xp,xq,d); + modmult2(_MIPP_ d,t,d); + fincr2(yp,d); + fincr2(yq,d); + fadd2(d,xp,u[0]); + fadd2(t,xq,u[2]); + incr2(u[2],1,u[1]); + modsquare2(_MIPP_ xq,xq); + modsquare2(_MIPP_ yq,yq); + + mul(_MIPP_ u,v,u); /* fast mul */ + mult4(_MIPP_ miller,u,miller); + } + + mult4(_MIPP_ miller,f,miller); + + for (i=0;i<4;i++) + { + fcopy2(miller[i],u[i]); + fcopy2(miller[i],v[i]); + fcopy2(miller[i],f[i]); + } + + /* final exponentiation */ + + for (i=0;i<(m+1)/2;i++) square4(_MIPP_ u,u); /* u*=u */ + powq(_MIPP_ u); + powq(_MIPP_ f); + for(i=0;i<4;i++) fcopy2(f[i],v[i]); + powq(_MIPP_ f); + for(i=0;i<4;i++) fcopy2(f[i],res[i]); + powq(_MIPP_ f); + mult4(_MIPP_ f,u,f); + mult4(_MIPP_ f,miller,f); + mult4(_MIPP_ res,v,res); + powq(_MIPP_ u); + powq(_MIPP_ u); + mult4(_MIPP_ res,u,res); + + /* doing inversion here could kill the stack... */ + +#ifndef MR_STATIC + memkill(_MIPP_ mem,18); +#else + memset(mem,0,MR_BIG_RESERVE(18)); +#endif +} + +/* ... so do inversion here to avoid stack overflow */ + +void tate(_MIPD_ epoint *P,epoint *Q,big *res) +{ + int i; + big f[4]; +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 4); +#else + char mem[MR_BIG_RESERVE(4)]; /* 160 bytes from stack */ + memset(mem,0,MR_BIG_RESERVE(4)); +#endif + for (i=0;i<4;i++) f[i]=mirvar_mem(_MIPP_ mem,i); + + eta_T(_MIPP_ P,Q,f,res); + + invert(_MIPP_ f); + mult4(_MIPP_ res,f,res); + +#ifndef MR_STATIC + memkill(_MIPP_ mem,4); +#else + memset(mem,0,MR_BIG_RESERVE(4)); +#endif +} + +/* Max stack requirement < 4K */ + +int main() +{ + big a2,a6,bx,r; + big res[4]; + epoint *P,*Q; + + int i,romptr; + miracl instance; /* sizeof(miracl)= 2000 bytes from the stack */ +#ifndef MR_STATIC +#ifdef MR_GENERIC_MT + miracl *mr_mip=mirsys(WORDS*NPW,16); +#else + miracl *mr_mip=mirsys(WORDS*NPW,16); +#endif + char *mem=(char *)memalloc(_MIPP_ 8); + char *mem1=(char *)ecp_memalloc(_MIPP_ 2); +#else +#ifdef MR_GENERIC_MT + miracl *mr_mip=mirsys(&instance,MR_STATIC*NPW,16); /* size of bigs is fixed */ +#else + miracl *mr_mip=mirsys(&instance,MR_STATIC*NPW,16); +#endif + char mem[MR_BIG_RESERVE(8)]; /* reserve space on the stack for 8 bigs */ + char mem1[MR_ECP_RESERVE(2)]; /* reserve space on stack for 2 curve points */ + memset(mem,0,MR_BIG_RESERVE(8)); /* clear this memory */ + memset(mem1,0,MR_ECP_RESERVE(2)); /* ~668 bytes in all */ +#endif + + /* Initialise bigs */ + + a2=mirvar_mem(_MIPP_ mem,0); + a6=mirvar_mem(_MIPP_ mem,1); + bx=mirvar_mem(_MIPP_ mem,2); + for (i=0;i<4;i++) + res[i]=mirvar_mem(_MIPP_ mem,3+i); + r=mirvar_mem(_MIPP_ mem,7); + + /* printf("ROM size= %d\n",sizeof(rom)+sizeof(prom)); */ +#ifndef MR_NO_STANDARD_IO +#ifdef MR_STATIC + printf("n Bigs require n*%d+%d bytes\n",MR_SIZE,MR_SL); + printf("n Points require n*%d+%d bytes\n",MR_ESIZE,MR_SL); + printf("sizeof(miracl)= %d\n",sizeof(miracl)); +#endif +#endif + /* Initialise Elliptic curve points */ + + P=epoint_init_mem(_MIPP_ mem1,0); + Q=epoint_init_mem(_MIPP_ mem1,1); + + /* Initialise supersingular curve */ + + convert(_MIPP_ 1,a2); + convert(_MIPP_ B,a6); + + /* The -M tells MIRACL that this is a supersingular curve */ + + if (!ecurve2_init(_MIPP_ -M,T,U,V,a2,a6,FALSE,MR_PROJECTIVE)) + { +#ifndef MR_NO_STANDARD_IO + printf("Problem with the curve\n"); +#endif + return 0; + } + + /* Get P and Q from ROM */ + /* These should have been multiplied by the cofactor 487805 = 5*97561 */ + /* 487805 is a cofactor of the group order 2^271+2^136+1 */ + + romptr=0; + init_point_from_rom(P,WORDS,rom,ROMSZ,&romptr); + init_point_from_rom(Q,WORDS,rom,ROMSZ,&romptr); + +#ifndef MR_NO_STANDARD_IO + printf( "P= \n"); + otnum(_MIPP_ P->X,stdout); + otnum(_MIPP_ P->Y,stdout); + printf( "Q= \n"); + otnum(_MIPP_ Q->X,stdout); + otnum(_MIPP_ Q->Y,stdout); +#endif + + bigbits(_MIPP_ 160,r); + + /* Simple bilinearity test */ + + tate(_MIPP_ P,Q,res); + + /* this could break the 4k stack, 2060+668+2996 >4K */ + /* so we cannot afford much precomputation in power4 */ + + power4(_MIPP_ res,r,res); /* res=res^{sr} */ + +#ifndef MR_NO_STANDARD_IO + printf( "\ne(P,Q)^r= \n"); + for (i=0;i<4;i++) + { + otnum(_MIPP_ res[i],stdout); + zero(res[i]); + } +#endif + + ecurve2_mult(_MIPP_ r,Q,Q); /* Q=rQ */ + + epoint2_norm(_MIPP_ Q); + + tate(_MIPP_ P,Q,res); /* Now invert is taken out of Tate, and the stack should be OK */ + +#ifndef MR_NO_STANDARD_IO + printf( "\ne(P,rQ)= \n"); + for (i=0;i<4;i++) + otnum(_MIPP_ res[i],stdout); +#endif + + /* all done */ + +#ifndef MR_STATIC + memkill(_MIPP_ mem,8); + ecp_memkill(_MIPP_ mem1,2); +#else + memset(mem,0,MR_BIG_RESERVE(8)); /* clear this stack memory */ + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + + mirexit(_MIPPO_ ); /* clears workspace memory */ + return 0; +} + + diff --git a/miracl/source/curve/pairing/folklore.cpp b/miracl/source/curve/pairing/folklore.cpp new file mode 100644 index 0000000..5b021cb --- /dev/null +++ b/miracl/source/curve/pairing/folklore.cpp @@ -0,0 +1,225 @@ +// +// Generate random non-supersingular curves suitable for pairings... +// Security Multiplier 2,4 or 8 +// Uses "folklore method" - actually due to Cocks & Pinch +// +// See Chapter 9 (by Steve Galbraith) in Advances in Elliptic Curve +// Cryptography, edited by Blake, Seroussi and Smart, Cambridge University +// Press (published January 2005) +// +// cl /O2 /GX folklore.cpp big.cpp miracl.lib +// +// if k=2 prime p = 3 mod 4 +// +// Creates batch file c.bat to generate curve using CM +// You MUST make sure that the CM utility builds the curve with the right +// number of points (normally you get two choices for the given D). +// +// NOTE: The CM utility creates a file kn.ecs (where n=2,4 or 8) +// Then you must delete the last line from kn.ecs and manually insert the file +// extra.ecs at the bottom. +// The file extra.ecs is created by this program. +// + +#include +#include +#include "big.h" +#include + +using namespace std; + +Miracl precision(100,0); + +BOOL sqr_free(Big m) +{ + Big r; + for (r=2;;r+=1) + { + if (m%(r*r)==0) return FALSE; + if (r*r > m) break; + } + return TRUE; +} + +int main(int argc,char **argv) +{ + Big D; + time_t seed; + int i,e,k,nbits; + Big s,j,p,r,g,b0,a,c,n,v,w,t; + ofstream batch("c.bat"); + ofstream extra("extra.ecs"); + miracl *mip=&precision; + BOOL correct; + + time(&seed); + irand((long)seed); + + argc--; argv++; + + if (argc!=1) + { + cout << "Missing parameter" << endl; + return 0; + } + e=atoi(argv[0]); + + if (e<1 || e>3) + { + cout << "Bad parameters" << endl; + cout << "folklore N " << endl; + cout << "where N is 1,2 or 3. Security multiplier k=2^N" << endl; + return 0; + } + +// important parameters calculated here... + + k=1<IOBASE=16; + extra << n/r << endl; + extra << r << endl; + + + if (k==4) + { +// extra << pow(p-2,(p-1)/4,p) << endl; + w=(pow(p,2)+1)/r; + extra << w/p << endl; + extra << w%p << endl; + + } + if (k==8) + { +// extra << pow(p-2,(p-5)/8,p) << endl; + w=(pow(p,4)+1)/r; + extra << w/(p*p*p) << endl; + w%=(p*p*p); + extra << w/(p*p) << endl; + w%=(p*p); + extra << w/p << endl; + extra << w%p << endl; + } + + return 0; +} + diff --git a/miracl/source/curve/pairing/freeman.cpp b/miracl/source/curve/pairing/freeman.cpp new file mode 100644 index 0000000..44228d9 --- /dev/null +++ b/miracl/source/curve/pairing/freeman.cpp @@ -0,0 +1,263 @@ +/* + * Program to find Freeman pairing-friendly elliptic curves with embedding degree k=10 + * + * See http://www.hpl.hp.com/techreports/2005/HPL-2005-155.html + * + * Compile as (for example) + * cl /O2 /GX freeman.cpp big.cpp miracl.lib + * + * Outputs curves to a file freeman.dat + * + * Mike Scott 6/10/2005 + * + */ + +#include +#include +#include +#include +#include "big.h" + +using namespace std; + +// Solve the Pell equation + +int pell(int max,Big D,Big F,Big& X,Big& Y,Big *SX,Big *SY,BOOL& complete) +{ + int i,j,ns; + BOOL SMALLD; + Big A,P,Q,SD,G,B,OG,OB,NG,NB,T; + + complete=FALSE; + SMALLD=FALSE; + if (Dmax) return ns; + // abort - these are only solutions + T=G*G-D*B*B; + if (T == F/4) + { + SX[ns]=2*G; SY[ns]=2*B; + ns++; + } + + if (T == F) + { + SX[ns]=G; SY[ns]=B; + ns++; + } + if (i>0 && Q==1) break; + } + + if (i%2==1) + for (j=0;jmax) return ns; + + T=G*G-D*B*B; + if (T == F/4) + { + SX[ns]=2*G; SY[ns]=2*B; + ns++; + } + if (T == F) + { + SX[ns]=G; SY[ns]=B; + ns++; + } + } + + complete=TRUE; // we got to the end.... + X=G; Y=B; // minimal solution of x^2-dy^2=1 + // can be used to find more solutions.... + + if (SMALLD) + { // too small - do it the hard way + Big ylim1,ylim2,R; + ns=0; + if (F<0) + { + ylim1=sqrt(-F/D); + ylim2=sqrt(-F*(X+1)/(2*D)); + } + else + { + ylim1=0; + ylim2=sqrt(F*(X-1)/(2*D)); + } + +// This might take too long... +// Should really implement LMM method here + + if (ylim2-ylim1>300) + { + cout << "." << flush; + ylim2=ylim1+300; + } + for (B=ylim1;BPRIMES[i]; + if ((d%(s*s))==0) return FALSE; + if ((s*s)>d) break; + } + + return TRUE; +} + +void results(BOOL fout,ofstream& ofile,int d,Big p,Big cf,Big ord) +{ + cout << "*** Found one - p=" << bits(p) << "-bits ord=" << bits(ord) << "-bits" << endl; + cout << "D= " << d << endl; + cout << "p= " << p << endl; + cout << "ord= " << ord << endl; + cout << "cf= " << cf << endl << endl; + + if (fout) + { + ofile << "*** Found one: p=" << bits(p) << "-bits ord=" << bits(ord) << "-bits p%8= " << p%8 << endl; + ofile << "D= " << d << endl; + ofile << "p= " << p << endl; + ofile << "ord= " << ord << endl; + ofile << "cf= " << cf << endl; + ofile << "cm " << p << " -D" << d << " -K" << cf << endl << endl; + } +} + +int main(int argc,char **argv) +{ + ofstream ofile; + int MIN_SECURITY,MAX_SECURITY,MIN_D,MAX_D,MIN_P; + int ip,j,d,d15,m,mm,solutions,mnt,start,N,precision,max; + BOOL fout,complete; + +// Defaults + + fout=TRUE; + precision=100; + ofile.open("freeman.dat"); + + miracl *mip=mirsys(precision,0); + Big F,T,M,D,W,K,C,mmax,td,X,Y,x,y,w,xn,yn,t0,u0,p,k,nrp,ord,R; + Big SX[20],SY[20]; + + start=1; + max=276; // 10+5120/20 + gprime(100000); + MAX_D=2000000000; // as far as I can reasonably go.... + + for (d=start;d<=MAX_D;d++) + { +// D must be square-free + if (d%120!=43 && d%120!=67) continue; + + if (!squfree(d)) continue; + + td=(Big)d*15; + F=-20; + + solutions=pell(max,td,F,t0,u0,SX,SY,complete); + if (!solutions) continue; + + for (j=0;j512) break; + if ((X-5)%15==0) + { + x=(X-5)/15; + p=25*x*x*x*x+25*x*x*x+25*x*x+10*x+3; + if (bits(p)>148) + { + if (prime(p)) + { + nrp=25*x*x*x*x+25*x*x*x+15*x*x+5*x+1; + ord=trial_divide(nrp); + if (prime(ord) && bits(ord)>148) + results(fout,ofile,d,p,nrp/ord,ord); + } + } + } + + if ((-X-5)%15==0) + { + x=(-X-5)/15; + p=25*x*x*x*x+25*x*x*x+25*x*x+10*x+3; + if (bits(p)>148) + { + if (prime(p)) + { + nrp=25*x*x*x*x+25*x*x*x+15*x*x+5*x+1; + ord=trial_divide(nrp); + if (prime(ord) && bits(ord)>148) + results(fout,ofile,d,p,nrp/ord,ord); + } + } + } + if (!complete) break; // no more solutions + multiply(td,t0,u0,X,Y); + } + } + } + return 0; +} + diff --git a/miracl/source/curve/pairing/fuzzy.cpp b/miracl/source/curve/pairing/fuzzy.cpp new file mode 100644 index 0000000..5320850 --- /dev/null +++ b/miracl/source/curve/pairing/fuzzy.cpp @@ -0,0 +1,212 @@ +/* + Fuzzy IBE - Sahai-Waters + See http://eprint.iacr.org/2004/086.pdf + Section 4.1 + + Compile with modules as specified below + + For MR_PAIRING_CP curve + cl /O2 /GX fuzzy.cpp cp_pair.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_MNT curve + cl /O2 /GX fuzzy.cpp mnt_pair.cpp zzn6a.cpp ecn3.cpp zzn3.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_BN curve + cl /O2 /GX fuzzy.cpp bn_pair.cpp zzn12a.cpp ecn2.cpp zzn4.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_KSS curve + cl /O2 /GX fuzzy.cpp kss_pair.cpp zzn18.cpp zzn6.cpp ecn3.cpp zzn3.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_BLS curve + cl /O2 /GX fuzzy.cpp bls_pair.cpp zzn24.cpp zzn8.cpp zzn4.cpp zzn2.cpp ecn4.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + Test program +*/ + +#include +#include + +//********* choose just one of these pairs ********** +//#define MR_PAIRING_CP // AES-80 security +//#define AES_SECURITY 80 + +//#define MR_PAIRING_MNT // AES-80 security +//#define AES_SECURITY 80 + +#define MR_PAIRING_BN // AES-128 or AES-192 security +#define AES_SECURITY 128 +//#define AES_SECURITY 192 + +//#define MR_PAIRING_KSS // AES-192 security +//#define AES_SECURITY 192 + +//#define MR_PAIRING_BLS // AES-256 security +//#define AES_SECURITY 256 +//********************************************* + +#include "pairing_3.h" + +// +// Note that in this case Bobs attributes are "close enough" to Alices +// so that he can decrypt +// + +#define NATTR 20 // Universe of attributes +#define NALICE 7 // number of Alice's attributes +#define NBOB 7 // number of Bob's attributes +#define Nd 5 // number required in common + +int Alice[NALICE]={7,6,3,4,12,1,9}; // Alice's attributes +int Bob[NBOB]= {6,3,4,12,5,10,7}; // Bob's attributes + +// Check if person has attribute a +int has_attribute(int num,int *attr,int a) +{ + for (int i=0;iIOBASE=256; + M=(char *)"test message"; + cout << "Message to be encrypted= " << M << endl; + mip->IOBASE=16; + pfc.random(s); + ED=lxor(M,pfc.hash_to_aes_key(pfc.power(Y,s))); + for (j=0;jIOBASE=256; + cout << "Decrypted message= " << M << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/gf2m12x.cpp b/miracl/source/curve/pairing/gf2m12x.cpp new file mode 100644 index 0000000..0e2732e --- /dev/null +++ b/miracl/source/curve/pairing/gf2m12x.cpp @@ -0,0 +1,339 @@ +/* + * MIRACL C++ Implementation file GF2m12x.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class GF2m12x (12-th extension over 2^m) + * uses irreducible polynomial x^12+x^FA+x^FB+x^FC+1 + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#include "gf2m12x.h" + +using namespace std; + +void GF2m12x::get(GF2m* a) +{for (int i=0;i=1;i--) + { + if (!x[i].iszero()) return i; + } + + return 0; +} + +GF2m12x& GF2m12x::powq() +{ + GF2m t[2*FM],m; + int i,j,r=(get_mip()->M)%FM; + if (r==0) return *this; + + for (j=0;j=FM;i--) + { // reduce mod x^FM+x^FA+x^FB+x^FC+1 + m=t[i]; if (m.iszero()) continue; + t[i]=0; + t[i-FM]+=m; + t[i-(FM-FA)]+=m; +#ifdef FB + t[i-(FM-FB)]+=m; + t[i-(FM-FC)]+=m; +#endif + } + for (i=0;i=FM;i--) + { // reduce mod x^FM+x^FA+x^FB+x^FC+1 + m=t[i]; if (m.iszero()) continue; + t[i]=0; + t[i-FM]+=m; + t[i-(FM-FA)]+=m; +#ifdef FB + t[i-(FM-FB)]+=m; + t[i-(FM-FC)]+=m; +#endif + + } + for (i=0;i=FM;i--) + { + m=t[i]; t[i]=0; + t[i-FM]+=m; + t[i-(FM-FA)]+=m; +#ifdef FB + t[i-(FM-FB)]+=m; + t[i-(FM-FC)]+=m; +#endif + } + + for (i=0;i=j-1) F[i]+=gamma*G[i-j+1]; + if (i>=j) F[i]+=beta*G[i-j]; + } + for (i=0;i<=degB || i<=degC+j;i++) + { + B[i]*=alpha; + if (i>=j-1) B[i]+=gamma*C[i-j+1]; + if (i>=j) B[i]+=beta*C[i-j]; + } + while (degF>=0 && F[degF]==0) degF--; + + if (degF==degG) + { + alpha=F[degF]; + for (i=0;i<=degF;i++) + { + F[i]*=G[degF]; + F[i]+=alpha*G[i]; + } + + for (i=0;i<=FM-degF;i++) + { + B[i]*=G[degF]; + B[i]+=alpha*C[i]; + } + while (degF>=0 && F[degF]==0) degF--; + } + degB=FM-1; while (degB>=0 && B[degB]==0) degB--; + } + alpha=(GF2m)1/F[0]; + for (i=0;i<=degB;i++) + x[i]=alpha*B[i]; + return; +} + +GF2m12x& GF2m12x::operator/=(const GF2m12x& a) +{ + GF2m12x b=a; + b.invert(); + *this *= b; + return *this; +} + +GF2m12x operator+(const GF2m12x& a,const GF2m12x& b) +{ GF2m12x r=a; r+=b; return r;} + +GF2m12x operator+(const GF2m12x& a,const GF2m& b) +{ GF2m12x r=a; r+=b; return r;} + +GF2m12x operator+(const GF2m& a,const GF2m12x& b) +{ GF2m12x r=b; r+=a; return r;} + +GF2m12x operator*(const GF2m12x& a,const GF2m12x& b) +{ + GF2m12x r=a; + if (&a!=&b) r*=b; + else r*=r; + return r; +} + +GF2m12x operator/(const GF2m12x& a,const GF2m12x& b) +{ + GF2m12x r=a; + r/=b; + return r; +} + +GF2m12x operator*(const GF2m12x& a,const GF2m& b) +{ GF2m12x r=a; r*=b; return r;} +GF2m12x operator*(const GF2m& a,const GF2m12x& b) +{ GF2m12x r=b; r*=a; return r;} + +GF2m12x randx12(void) +{ + int m=get_mip()->M; + GF2m12x r; + for (int i=0;i1) for (i=nb-2;i>=0;) + { + n=window(k,i,&nbw,&nzs,5); + for (j=0;j0) u*=t[n/2]; + i-=nbw; + if (nzs) + { + for (j=0;j +#include "gf2m.h" + +// set field and irreducible polynomial, undefine FB and FC for trinomials + +#define FM 12 +#define FA 5 +//#define FB 5 +//#define FC 1 + +class GF2m12x +{ + GF2m x[FM]; +public: + GF2m12x() {for (int i=0;i. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file gf2m4x.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class GF2m4x (Quartic extension over 2^m) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#include "gf2m4x.h" + +using namespace std; + +void GF2m4x::get(GF2m& a,GF2m& b,GF2m& c,GF2m &d) +{a=x[0]; b=x[1]; c=x[2]; d=x[3];} + +void GF2m4x::get(GF2m& a,GF2m& b) +{a=x[0]; b=x[1];} + +void GF2m4x::get(GF2m& a) +{a=x[0];} + +int GF2m4x::degree() +{ + if (!x[3].iszero()) return 3; + if (!x[2].iszero()) return 2; + if (!x[1].iszero()) return 1; + return 0; +} + +GF2m4x& GF2m4x::powq() +{ + GF2m t=x[1]; // t=c + int r=(get_mip()->M)%4; + + if (r==0) return *this; + if (r==1) + { + x[0]+=x[2]; // d=b+d + x[1]=x[2]; // c=b + x[2]=x[3]; + x[2]+=t; // b=a+c + } + if (r==2) + { + x[0]+=(x[1]+x[2]+x[3]); + x[1]+=x[3]; + x[2]+=x[3]; + } + if (r==3) + { + x[0]+=t; // d=c+d + x[1]=x[2]; + x[1]+=x[3]; // c=a+b + x[2]=t; // b=c + } + + return *this; +} + +GF2m4x& GF2m4x::operator*=(const GF2m4x& b) +{ + GF2m x4; + if (this==&b) + { // squaring + x[3]*=x[3]; + x4=x[2]; x4*=x4; + x[2]=x[1]; x[2]*=x[2]; + x[0]*=x[0]; + + x[2]+=x[3]; + x[0]+=x4; + x[1]=x4; + + return *this; + } + else + { // Use Karatsuba +/* + int i; + big A[4],B[4],C[8],T[8]; + GF2m x4,x5,x6; + GF2m4x bb=b; + + char *memc=(char *)memalloc(16); + + for (i=0;i<8;i++) + { + C[i]=mirvar_mem(memc,i); + T[i]=mirvar_mem(memc,i+8); + } + + for (i=0;i<4;i++) + { + A[i]=getbig(x[i]); + B[i]=getbig(bb.x[i]); + } + + karmul2_poly(4,T,A,B,C); + + for (i=0;i<4;i++) x[i]=C[i]; + + x4=C[4]; + x5=C[5]; + x6=C[6]; + + memkill(memc,16); +*/ + +// fastest + + GF2m x5,x6,w1,w0,z1,z0,z1w1,z0w0,t; + + w1=x[1]; w1+=x[3]; w0=x[0]; w0+=x[2]; + z1=b.x[1]; z1+=b.x[3]; z0=b.x[0]; z0+=b.x[2]; + z1w1=z1; z1w1*=w1; z0w0=z0; z0w0*=w0; + + x6=x[1]; x6*=b.x[1]; + x5=x[2]; x5*=b.x[2]; + x4=x6; x4+=x5; + + x[1]+=x[0]; t=b.x[0]; t+=b.x[1]; x[1]*=t; + x[0]*=b.x[0]; x[1]+=x[0]; x[1]+=x6; + + t=x[2]; t+=x[3]; x6=b.x[2]; x6+=b.x[3]; t*=x6; + x5+=t; + x6=x[3]; x6*=b.x[3]; + x5+=x6; + + t=z0; t+=z1; x[3]=t; t=w0; t+=w1; x[3]*=t; + + x[3]+=z1w1; x[3]+=z0w0; x[3]+=x5; x[3]+=x[1]; + + x[2]=x4; x[2]+=x[0]; x[2]+=z0w0; + x4+=x6; x4+=z1w1; + +/* + GF2m x4,x5,x6; + x6=x[3]*b.x[3]; + x5=x[3]*b.x[2]+x[2]*b.x[3]; + x4=x[3]*b.x[1]+x[2]*b.x[2]+x[1]*b.x[3]; + x[3]=x[3]*b.x[0]+x[2]*b.x[1]+x[1]*b.x[2]+x[0]*b.x[3]; + x[2]=x[2]*b.x[0]+x[1]*b.x[1]+x[0]*b.x[2]; + x[1]=x[1]*b.x[0]+x[0]*b.x[1]; + x[0]=x[0]*b.x[0]; +*/ + +// reduction mod x^4+x+1 + + x[2]+=x6; + x[3]+=x6; + x[1]+=x5; + x[2]+=x5; + x[0]+=x4; + x[1]+=x4; + + return *this; + } +} + +GF2m4x& GF2m4x::operator*=(const GF2m& b) +{ // specialised for our circumstances + x[0]*=b; + if (x[1].isone()) x[1]=b; + else x[1]*=b; + if (x[2].isone()) x[2]=b; + else x[2]*=b; + if (!x[3].iszero()) x[3]*=b; + return *this; +} + +GF2m4x& GF2m4x::operator/=(const GF2m& b) +{ + GF2m ib=(GF2m)1/b; + x[0]*=ib; + x[1]*=ib; + x[2]*=ib; + x[3]*=ib; + return *this; +} + +// +// Lim & Hwang - just one field inversion +// + +void GF2m4x::invert() +{ + int degF,degG,degB,degC,d,i,j; + GF2m alpha,beta,gamma,BB[5],FF[5],CC[5],GG[5]; + + GF2m *B=BB,*C=CC,*F=FF,*G=GG,*T; + + C[0]=1; + F[4]=F[1]=F[0]=1; // f(x) + + degF=4; degG=degree(); degC=0; degB=-1; + + if (degG==0) + { + x[0]=(GF2m)1/x[0]; + return; + } + + for (i=0;i<4;i++) + { + G[i]=x[i]; + x[i]=0; + } + while (degF!=0) + { + if (degF=j-1) F[i]+=gamma*G[i-j+1]; + if (i>=j) F[i]+=beta*G[i-j]; + } + for (i=0;i<=degB || i<=degC+j;i++) + { + B[i]*=alpha; + if (i>=j-1) B[i]+=gamma*C[i-j+1]; + if (i>=j) B[i]+=beta*C[i-j]; + } + while (degF>=0 && F[degF]==0) degF--; + + if (degF==degG) + { + alpha=F[degF]; + for (i=0;i<=degF;i++) + { + F[i]*=G[degF]; + F[i]+=alpha*G[i]; + } + + for (i=0;i<=4-degF;i++) + { + B[i]*=G[degF]; + B[i]+=alpha*C[i]; + } + while (degF>=0 && F[degF]==0) degF--; + } + degB=3; while (degB>=0 && B[degB]==0) degB--; + } + + alpha=(GF2m)1/F[0]; + for (i=0;i<=degB;i++) + x[i]=alpha*B[i]; + return; +} + +// An inversion for unitary elements + +GF2m4x conj(const GF2m4x& x) +{ + GF2m4x r=x; + r.powq(); + r.powq(); + return r; +} + +GF2m4x& GF2m4x::operator/=(const GF2m4x& a) +{ + GF2m4x b=a; + b.invert(); + *this *= b; + return *this; +} + +GF2m4x operator+(const GF2m4x& a,const GF2m4x& b) +{ GF2m4x r=a; r+=b; return r;} + +GF2m4x operator+(const GF2m4x& a,const GF2m& b) +{ GF2m4x r=a; r+=b; return r;} + +GF2m4x operator+(const GF2m& a,const GF2m4x& b) +{ GF2m4x r=b; r+=a; return r;} + +GF2m4x operator/(const GF2m4x& a,const GF2m& b) +{ GF2m4x r=a; r/=b; return r; } + + +// special purpose mul, a and b are of the form (x,y,y+1,0) +// only 3 muls... + +GF2m4x mul(const GF2m4x& a,const GF2m4x& b) +{ + GF2m p,w,t,q,tw,pq,z; + GF2m4x r; + + p=a.x[0]; w=a.x[1]; + q=b.x[0]; t=b.x[1]; + + z=(w+p)*(t+q); + + tw=t*w; pq=p*q; // 2x2 Karatsuba + + z+=tw; z+=pq; // z=wq+tp + + w+=t; + t=w+tw+1; + + r.set(pq+t,z+t,z+p+q+tw,w); + return r; + +} + +GF2m4x operator*(const GF2m4x& a,const GF2m4x& b) +{ + GF2m4x r=a; + if (&a!=&b) r*=b; + else r*=r; + return r; +} + +GF2m4x operator/(const GF2m4x& a,const GF2m4x& b) +{ + GF2m4x r=a; + r/=b; + return r; +} + +GF2m4x operator*(const GF2m4x& a,const GF2m& b) +{ GF2m4x r=a; r*=b; return r;} +GF2m4x operator*(const GF2m& a,const GF2m4x& b) +{ GF2m4x r=b; r*=a; return r;} + +#ifndef MR_NO_RAND +GF2m4x randx4(void) +{ + int m=get_mip()->M; + GF2m4x r; + r.x[0]=rand(m,2); + r.x[1]=rand(m,2); + r.x[2]=rand(m,2); + r.x[3]=rand(m,2); + return r; +} +#endif + +GF2m4x pow(const GF2m4x& a,const Big& k) +{ + int i,j,nb,n,nbw,nzs; + GF2m4x u,u2,t[16]; + + if (k.iszero()) return (GF2m4x)1; + Big e=k; + + if (k<0) e=-e; + + u=a; + if (e.isone()) + { + if (k<0) u.invert(); + return u; + } + +// +// Prepare table for windowing +// + u2=(u*u); + t[0]=u; + + for (i=1;i<16;i++) + t[i]=u2*t[i-1]; + +// Left to right method - with windows + + nb=bits(e); + if (nb>1) for (i=nb-2;i>=0;) + { + n=window(e,i,&nbw,&nzs,5); + for (j=0;j0) u*=t[n/2]; + i-=nbw; + if (nzs) + { + for (j=0;j=1;) + { + n=naf_window(k,k3,i,&nbw,&nzs,11); + + for (j=0;j0) u*=t[n/2]; + if (n<0) u*=conj(t[(-n)/2]); + i-=nbw; + if (nzs) + { + for (j=0;j. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Headerfile gf2m4x.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class GF2m4x - Arithmetic over the extension + * field GF(2^4m) + * + * NOTE : The underlying field basis must be set by the modulo() routine + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#ifndef GF2M4X_H +#define GF2M4X_H + +#include +#include "gf2m.h" + +class GF2m4x +{ + GF2m x[4]; +public: + GF2m4x() { } + GF2m4x(const GF2m4x & b) + { x[0]=b.x[0]; x[1]=b.x[1]; x[2]=b.x[2]; x[3]=b.x[3]; } + GF2m4x(int i) { x[0]=i; } + GF2m4x(const GF2m& a,const GF2m& b,const GF2m& c=0,const GF2m& d=0) + { x[0]=a; x[1]=b; x[2]=c; x[3]=d; } + + GF2m4x(const Big& a) {x[0]=(GF2m)a;} + + void set(const GF2m& a,const GF2m& b,const GF2m& c,const GF2m& d) + {x[0]=a; x[1]=b; x[2]=c; x[3]=d; } + void set(const GF2m& a) {x[0]=a; x[1]=x[2]=x[3]=0; } + void invert(); + + void get(GF2m&,GF2m&,GF2m&,GF2m&); + void get(GF2m&,GF2m&); + void get(GF2m&); + + + void clear() {x[0]=x[1]=x[2]=x[3]=0; } + int degree(); + + BOOL iszero() const + {if (x[0].iszero() && x[1].iszero() && x[2].iszero() && x[3].iszero()) return TRUE; else return FALSE; } + BOOL isunity() const + {if (x[0].isone() && x[1].iszero() && x[2].iszero() && x[3].iszero()) return TRUE; else return FALSE; } + + GF2m4x& powq(); + + GF2m4x& operator=(const GF2m4x& b) + { x[0]=b.x[0]; x[1]=b.x[1]; x[2]=b.x[2]; x[3]=b.x[3]; return *this; } + GF2m4x& operator=(const GF2m& b) + { x[0]=b; x[1]=x[2]=x[3]=0; return *this; } + GF2m4x& operator=(int b) + { x[0]=b; x[1]=x[2]=x[3]=0; return *this; } + GF2m4x& operator+=(const GF2m4x& b) + {x[0]+=b.x[0]; x[1]+=b.x[1]; x[2]+=b.x[2]; x[3]+=b.x[3]; return *this; } + GF2m4x& operator+=(const GF2m& b) + {x[0]+=b; return *this; } + GF2m4x& operator*=(const GF2m4x&); + GF2m4x& operator*=(const GF2m&); + GF2m4x& operator/=(const GF2m4x&); + GF2m4x& operator/=(const GF2m&); + + friend GF2m4x operator+(const GF2m4x&,const GF2m4x&); + friend GF2m4x operator+(const GF2m4x&,const GF2m&); + friend GF2m4x operator+(const GF2m&,const GF2m4x&); + + friend GF2m4x operator*(const GF2m4x&,const GF2m4x&); + friend GF2m4x operator*(const GF2m4x&,const GF2m&); + friend GF2m4x operator*(const GF2m&,const GF2m4x&); + friend GF2m4x operator/(const GF2m4x&,const GF2m4x&); + friend GF2m4x operator/(const GF2m4x&,const GF2m&); + + friend GF2m4x mul(const GF2m4x&,const GF2m4x&); + friend GF2m4x conj(const GF2m4x&); + + friend BOOL operator==(const GF2m4x& a,const GF2m4x& b) + {if (a.x[0]==b.x[0] && a.x[1]==b.x[1] && a.x[2]==b.x[2] && a.x[3]==b.x[3]) + return TRUE; else return FALSE; } + + friend BOOL operator!=(const GF2m4x& a,const GF2m4x& b) + {if (a.x[0]!=b.x[0] || a.x[1]!=b.x[1] || a.x[2]!=b.x[2] || a.x[3]!=b.x[3]) + return TRUE; else return FALSE; } + + friend GF2m4x pow(const GF2m4x&,const Big&); + friend GF2m4x powu(const GF2m4x&,const Big&); +#ifndef MR_NO_RAND + friend GF2m4x randx4(void); +#endif + friend ostream& operator<<(ostream&,const GF2m4x&); + + ~GF2m4x() {} ; +}; +#ifndef MR_NO_RAND +extern GF2m4x randx4(void); +#endif +#endif + diff --git a/miracl/source/curve/pairing/gf2m6x.cpp b/miracl/source/curve/pairing/gf2m6x.cpp new file mode 100644 index 0000000..103c7c7 --- /dev/null +++ b/miracl/source/curve/pairing/gf2m6x.cpp @@ -0,0 +1,379 @@ +/* + * MIRACL C++ Implementation file GF2m6x.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class GF2m6x (6-th extension over 2^m) + * uses irreducible polynomial x^6+x^FA+x^FB+x^FC+1 + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#include "gf2m6x.h" + +using namespace std; + +void GF2m6x::get(GF2m* a) +{for (int i=0;i=1;i--) if (!x[i].iszero()) return i; + return 0; +} + +GF2m6x& GF2m6x::powq() +{ + GF2m t[2*FM],m; + int r=(get_mip()->M)%FM; + int i,j; + if (r==0) return *this; + + for (j=0;j=FM;i--) + { // reduce mod x^FM+x^FA+x^FB+x^FC+1 + m=t[i]; if (m.iszero()) continue; + t[i]=0; + t[i-FM]+=m; + t[i-(FM-FA)]+=m; +#ifdef FB + t[i-(FM-FB)]+=m; + t[i-(FM-FC)]+=m; +#endif + } + for (i=0;i=FM;i--) + { + m=t[i]; if (m.iszero()) continue; + t[i]=0; + t[i-FM]+=m; + t[i-(FM-FA)]+=m; +#ifdef FB + t[i-(FM-FB)]+=m; + t[i-(FM-FC)]+=m; +#endif + } + for (i=0;i=FM;i--) + { // reduce mod x^FM+x^FA+x^FB+x^FC+1 + m=t[i]; if (m.iszero()) continue; + t[i]=0; + t[i-FM]+=m; + t[i-(FM-FA)]+=m; +#ifdef FB + t[i-(FM-FB)]+=m; + t[i-(FM-FC)]+=m; +#endif + + } + for (i=0;i=FM;i--) + { + m=t[i]; t[i]=0; + t[i-FM]+=m; + t[i-(FM-FA)]+=m; +#ifdef FB + t[i-(FM-FB)]+=m; + t[i-(FM-FC)]+=m; +#endif + } + + for (i=0;i=FM;i--) + { + m=t[i]; t[i]=0; + t[i-FM]+=m; + t[i-(FM-FA)]+=m; +#ifdef FB + t[i-(FM-FB)]+=m; + t[i-(FM-FC)]+=m; +#endif + } + + for (i=0;i=j-1) F[i]+=gamma*G[i-j+1]; + if (i>=j) F[i]+=beta*G[i-j]; + } + for (i=0;i<=degB || i<=degC+j;i++) + { + B[i]*=alpha; + if (i>=j-1) B[i]+=gamma*C[i-j+1]; + if (i>=j) B[i]+=beta*C[i-j]; + } + while (degF>=0 && F[degF]==0) degF--; + + if (degF==degG) + { + alpha=F[degF]; + for (i=0;i<=degF;i++) + { + F[i]*=G[degF]; + F[i]+=alpha*G[i]; + } + + for (i=0;i<=FM-degF;i++) + { + B[i]*=G[degF]; + B[i]+=alpha*C[i]; + } + while (degF>=0 && F[degF]==0) degF--; + } + degB=FM-1; while (degB>=0 && B[degB]==0) degB--; + } + alpha=(GF2m)1/F[0]; + for (i=0;i<=degB;i++) x[i]=alpha*B[i]; + return; +} + +GF2m6x& GF2m6x::operator/=(const GF2m6x& a) +{ + GF2m6x b=a; + b.invert(); + *this *= b; + return *this; +} + +GF2m6x operator+(const GF2m6x& a,const GF2m6x& b) +{ GF2m6x r=a; r+=b; return r;} + +GF2m6x operator+(const GF2m6x& a,const GF2m& b) +{ GF2m6x r=a; r+=b; return r;} + +GF2m6x operator+(const GF2m& a,const GF2m6x& b) +{ GF2m6x r=b; r+=a; return r;} + +GF2m6x operator*(const GF2m6x& a,const GF2m6x& b) +{ + GF2m6x r=a; + if (&a!=&b) r*=b; + else r*=r; + return r; +} + +GF2m6x operator/(const GF2m6x& a,const GF2m6x& b) +{ + GF2m6x r=a; + r/=b; + return r; +} + +GF2m6x operator*(const GF2m6x& a,const GF2m& b) +{ GF2m6x r=a; r*=b; return r;} +GF2m6x operator*(const GF2m& a,const GF2m6x& b) +{ GF2m6x r=b; r*=a; return r;} + +GF2m6x randx6(void) +{ + int m=get_mip()->M; + GF2m6x r; + for (int i=0;i1) for (i=nb-2;i>=0;) + { + n=window(k,i,&nbw,&nzs,5); + for (j=0;j0) u*=t[n/2]; + i-=nbw; + if (nzs) + { + for (j=0;j +#include "gf2m.h" + +// set field and irreducible polynomial, undefine FB and FC for trinomials + +#define FM 6 +#define FA 5 +#define FB 3 +#define FC 2 + +class GF2m6x +{ + GF2m x[FM]; +public: + GF2m6x() { } + GF2m6x(const GF2m6x & b) {for (int i=0;i +#include + +//********* choose just one of these pairs ********** +//#define MR_PAIRING_CP // AES-80 security +//#define AES_SECURITY 80 + +//#define MR_PAIRING_MNT // AES-80 security +//#define AES_SECURITY 80 + +#define MR_PAIRING_BN // AES-128 or AES-192 security +#define AES_SECURITY 128 +//#define AES_SECURITY 192 + +//#define MR_PAIRING_KSS // AES-192 security +//#define AES_SECURITY 192 + +//#define MR_PAIRING_BLS // AES-256 security +//#define AES_SECURITY 256 +//********************************************* + +#include "pairing_3.h" + +int main() +{ + PFC pfc(AES_SECURITY); // initialise pairing-friendly curve + miracl* mip=get_mip(); + Big order=pfc.order(); + + Big tau,a,alpha,s,c0,M,ID,y,c1,c2,t; + int i; + G1 g1,u1,h1,t1; + G1 g1a,u1a,h1a,g1t,u1t,h1t; + G1 c[6]; + G2 k[6]; + G2 g2,u2,h2,v2,v2d,f2; + GT w; + time_t seed; + + time(&seed); + irand((long)seed); + +// setup + cout << "Setup" << endl; + pfc.random(g1); + pfc.random(g2); + pfc.random(tau); + u1=pfc.mult(g1,tau); + u2=pfc.mult(g2,tau); + pfc.random(tau); + h1=pfc.mult(g1,tau); + h2=pfc.mult(g2,tau); + pfc.random(a); + pfc.random(alpha); + pfc.random(v2d); + pfc.random(f2); + pfc.random(tau); + v2=pfc.mult(f2,tau)+(-pfc.mult(v2d,a)); + w=pfc.power(pfc.pairing(g2,g1),alpha); + g1a=pfc.mult(g1,a); + u1a=pfc.mult(u1,a); + h1a=pfc.mult(h1,a); + g1t=pfc.mult(g1,tau); + u1t=pfc.mult(u1,tau); + h1t=pfc.mult(h1,tau); + + pfc.precomp_for_mult(g1); + pfc.precomp_for_mult(g1a); + pfc.precomp_for_mult(g1t); + pfc.precomp_for_mult(u1); + pfc.precomp_for_mult(u1a); + pfc.precomp_for_mult(u1t); + pfc.precomp_for_mult(h1); + pfc.precomp_for_mult(h1a); + pfc.precomp_for_mult(h1t); + + pfc.precomp_for_mult(g2); + pfc.precomp_for_mult(u2); + pfc.precomp_for_mult(h2); + pfc.precomp_for_mult(v2); + pfc.precomp_for_mult(v2d); + pfc.precomp_for_mult(f2); + +// public parameters {g1,u1,h1,g1a,u1a,h1a,g1t,u1t,h1t,w} +// master secret {g2,alpha,v2,v2d,u2,h2,f2} + +// encrypt + cout << "Encryption" << endl; + mip->IOBASE=256; + M=(char *)"a message"; // to be encrypted to Alice + cout << "Message to be encrypted= " << M << endl; + mip->IOBASE=16; + + ID=pfc.hash_to_group((char *)"Alice"); + pfc.random(s); + c0=lxor(M,pfc.hash_to_aes_key(pfc.power(w,s))); + t=modmult(s,ID,order); + c[0]=pfc.mult(h1,s)+pfc.mult(u1,t); + c[1]=pfc.mult(h1a,s)+pfc.mult(u1a,t); // typo in paper + c[2]=-(pfc.mult(h1t,s)+pfc.mult(u1t,t)); + c[3]=pfc.mult(g1,s); + c[4]=pfc.mult(g1a,s); + c[5]=-pfc.mult(g1t,s); // typo in paper + +// keygen + cout << "Keygen" << endl; + pfc.random(y); + pfc.random(c1); + pfc.random(c2); + + t=modmult(y,ID,order); + + k[0]=-(pfc.mult(g2,y)+pfc.mult(v2,c1)); + k[1]=-pfc.mult(v2d,c1); + k[2]=-pfc.mult(f2,c1); + k[3]=pfc.mult(g2,alpha)+pfc.mult(h2,y)+pfc.mult(u2,t)+pfc.mult(v2,c2); + k[4]=pfc.mult(v2d,c2); + k[5]=pfc.mult(f2,c2); + + for (i=0;i<6;i++) + pfc.precomp_for_pairing(k[i]); + +// decrypt + cout << "Decryption" << endl; + G1 *r[6]; + G2 *l[6]; + + for (i=0;i<6;i++) + { + r[i]=&c[i]; + l[i]=&k[i]; + } + + M=lxor(c0,pfc.hash_to_aes_key(pfc.multi_pairing(6,l,r))); // Use private key + + mip->IOBASE=256; + cout << "Decrypted message= " << M << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/ipe.cpp b/miracl/source/curve/pairing/ipe.cpp new file mode 100644 index 0000000..527e1f1 --- /dev/null +++ b/miracl/source/curve/pairing/ipe.cpp @@ -0,0 +1,245 @@ +/* + J.H. Park + Inner-product encryption under standard assumptions - Des. Codes Cryptogr. (2011) 58:235257 + Implemented on Type-3 pairing + + Compile with modules as specified below + + For MR_PAIRING_CP curve + cl /O2 /GX ipe.cpp cp_pair.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_MNT curve + cl /O2 /GX ipe.cpp mnt_pair.cpp zzn6a.cpp ecn3.cpp zzn3.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_BN curve + cl /O2 /GX ipe.cpp bn_pair.cpp zzn12a.cpp ecn2.cpp zzn4.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_KSS curve + cl /O2 /GX ipe.cpp kss_pair.cpp zzn18.cpp zzn6.cpp ecn3.cpp zzn3.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_BLS curve + cl /O2 /GX ipe.cpp bls_pair.cpp zzn24.cpp zzn8.cpp zzn4.cpp zzn2.cpp ecn4.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + +*/ + +#include +#include + +//********* choose just one of these pairs ********** +//#define MR_PAIRING_CP // AES-80 security +//#define AES_SECURITY 80 + +//#define MR_PAIRING_MNT // AES-80 security +//#define AES_SECURITY 80 + +#define MR_PAIRING_BN // AES-128 or AES-192 security +#define AES_SECURITY 128 +//#define AES_SECURITY 192 + +//#define MR_PAIRING_KSS // AES-192 security +//#define AES_SECURITY 192 + +//#define MR_PAIRING_BLS // AES-256 security +//#define AES_SECURITY 256 +//********************************************* + +#include "pairing_3.h" + +#define n 10 // number of attributes + +// generate v[i] such that x.v=0 (dot product) + +void inner_product(Big *x,Big *v,Big& order) +{ + Big prod=0; + for (int i=0;iIOBASE=256; + M=(char *)"message"; // to be encrypted + cout << "Message to be encrypted= " << M << endl; + mip->IOBASE=16; + + pfc.random(s1); + pfc.random(s2); + pfc.random(s3); + pfc.random(s4); + for (i=0;iIOBASE=256; + cout << "Decrypted message= " << M << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/ipk.txt b/miracl/source/curve/pairing/ipk.txt new file mode 100644 index 0000000..216a6fb --- /dev/null +++ b/miracl/source/curve/pairing/ipk.txt @@ -0,0 +1,72 @@ + +ID-PKC + +This Identity Based Encryption method was invented by Cliff Cocks +See http://www.cesg.gov.uk/technology/id-pkc/index.htm for more details. + +This demonstration implementation consists of four programs that implement +each of the four steps in the algorithm. The source code is intended to be +read in conjunction with the academic paper which describes the method. The +clarity of C++ makes the code very readable, and easy to associate with the +mathematical description. + +NOTE: This method is patented! Do not deploy before checking with the patent +holders. This is just a demonstration of the method, and lacks some +functionality in its current state. + +Tested with MS C++, Borland C++ and the DJGPP port of gcc + + +Function: SETUP + +Source File: ipk_set.cpp + +This program generates suitable random global domain parameters, and stores +them in the file common.ipk. The Master key is stored in master.ipk + +Compile as (for example with MS C++) + +cl /O2 ipk_set.cpp big.cpp miracl.lib + + + +Function: EXTRACT + +Source File: ipk_ext.cpp + +This program extracts a private (secret) key from the proffered identity +string, and stores it in the file private.ipk + +Compile as + +cl /O2 ipk_ext.cpp big.cpp crt.cpp miracl.lib + + + +Function: ENCRYPT + +Source File: ipk_enc.cpp + +This program accepts the identity of the recipient (which is his public key), +and encrypts a file. + +Compile as + +cl /O2 ipk_enc.cpp big.cpp miracl.lib + + + +Function: DECRYPT + +Source File: ipk_dec.cpp + +This program decrypts a file using the private key from private.ipk + +Compile as (for example with MS C++) + +cl /O2 ipk_dec.cpp big.cpp miracl.lib + + +Run the four programs in the order above, and encrypt a file to yourself! + + diff --git a/miracl/source/curve/pairing/ipk_dec.cpp b/miracl/source/curve/pairing/ipk_dec.cpp new file mode 100644 index 0000000..8438fef --- /dev/null +++ b/miracl/source/curve/pairing/ipk_dec.cpp @@ -0,0 +1,123 @@ +/* + Cock's Identity Based Encryption + + Decryption phase + + Decrypts a file .ipk + Finds the session key by ID-PKC decrypting the file .key + Uses this session key to AES decrypt the file. + + Outputs to the screen + + Requires : big.cpp + + */ + +#include +#include +#include +#include "big.h" + +using namespace std; + +void strip(char *name) +{ /* strip extension off filename */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +int main() +{ + miracl *mip=mirsys(36,0); // thread-safe ready. + ifstream common("common.ipk"); + ifstream private_key("private.ipk"); + ifstream key_file,ciphertext; + char ifname[100],ch,iv[16],key[16]; + Big s,b,r,x,n; + int i,j,bit; + int sign; + aes a; + +// DECRYPT + + mip->IOBASE=16; + common >> n; + private_key >> b; + private_key >> sign; + b+=b; // 2*b + +// figure out where input is coming from + + cout << "file to be decoded = "; + cin >> ifname; + + strip(ifname); // open key file + strcat(ifname,".key"); + key_file.open(ifname,ios::in); + if (!key_file) + { + cout << "Key file " << ifname << " not found\n"; + return 0; + } + + for (i=0;i<16;i++) + { + ch=0; + for (j=0;j<8;j++) + { + if (sign==0) + { + key_file >> s; + s+=b; if (s>=n) s-=n; + bit=jacobi(s,n); + key_file >> s; + } + else + { + key_file >> s; + key_file >> s; + s-=b; if (s<0) s+=n; + bit=jacobi(s,n); + } + ch<<=1; + if (bit==1) ch|=1; + } + key[i]=ch; + } + + strip(ifname); // open ciphertext + strcat(ifname,".ipk"); + ciphertext.open(ifname,ios::binary|ios::in); + if (!ciphertext) + { + cout << "Unable to open file " << ifname << "\n"; + return 0; + } + + cout << "Decrypting message" << endl; + +// +// Use session key to decrypt file +// + + for (i=0;i<16;i++) iv[i]=i; // Set CFB IV + aes_init(&a,MR_CFB1,16,key,iv); + + forever + { // decrypt input .. + ciphertext.get(ch); + if (ciphertext.eof()) break; + aes_decrypt(&a,&ch); + cout << ch; + } + aes_end(&a); + + return 0; +} + + diff --git a/miracl/source/curve/pairing/ipk_enc.cpp b/miracl/source/curve/pairing/ipk_enc.cpp new file mode 100644 index 0000000..d76da90 --- /dev/null +++ b/miracl/source/curve/pairing/ipk_enc.cpp @@ -0,0 +1,184 @@ +/* + Cock's Identity Based Encryption + + Encryption phase + + Generates a random AES session key, and uses it to encrypt a file. + Outputs ciphertext .ipk + + The session key is ID_PKC encrypted, and written to .key + + Requires : big.cpp + + */ + +#include +#include +#include +#include "big.h" + +using namespace std; + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +// Using SHA-1 as basic hash algorithm + +#define HASH_LEN 20 + +// +// Public Hash Function +// + +Big H(char *string,Big n) +{ // Hash a zero-terminated string to a number h < modulus n + // Then increment this number until (h/n)=+1 + Big h; + char s[HASH_LEN]; + int i,j; + sha sh; + + shs_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs_process(&sh,string[i]); + } + shs_hash(&sh,s); + + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=n) break; + } + while (jacobi(h,n)!=1) h+=1; + h%=n; + return h; +} + +int main() +{ + miracl *mip=mirsys(36,0); // thread-safe ready. + ifstream common("common.ipk"); + ifstream plaintext; + ofstream key_file,ciphertext; + char ifname[100],ofname[100],ch,iv[16],key[16]; + Big t,s,n,x; + Big tp[128],tm[128],wp[128],wm[128]; + int i,j,bit; + long seed; + aes a; + + mip->IOBASE=16; + common >> n; + + cout << "Enter 9 digit random number seed = "; + + cin >> seed; + irand(seed); + +// +// Generate random numbers (off-line) +// and generate a random key +// + + ch=0; + for (i=0;i<128;i++) + { + tp[i]=rand(n); // random t + bit=jacobi(tp[i],n); + + ch<<=1; + if (bit==1) ch|=1; + do { + tm[i]=rand(n); // different t, same (t/n) + } while (jacobi(tm[i],n)!=bit); + + if (i%8==7) + { + key[i/8]=ch; + ch=0; + } + } + multi_inverse(128,tp,n,wp); // generate 1/t + multi_inverse(128,tm,n,wm); + +// ENCRYPT + + char id[1000]; + cout << "Enter your correspondents email address (lower case)" << endl; + cin.get(); + cin.getline(id,1000); + + x=H(id,n); + +// figure out where input is coming from + + cout << "Text file to be encrypted = " ; + cin >> ifname; + + /* set up input file */ + strcpy(ofname,ifname); + +// +// Now ID-PKC encrypt a random session key +// + + strip(ofname); + strcat(ofname,".key"); + mip->IOBASE=16; + key_file.open(ofname); + + for (i=0;i<128;i++) + { // ID-PKC encrypt + s=tp[i]+modmult(x,wp[i],n); if (s>=n) s-=n; + key_file << s << endl; + s=tm[i]-modmult(x,wm[i],n); if (s<0) s+=n; + key_file << s << endl; + } + +// +// prepare to encrypt file with random session key +// + for (i=0;i<16;i++) iv[i]=i; // set CFB IV + aes_init(&a,MR_CFB1,16,key,iv); + + /* set up input file */ + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".ipk"); + plaintext.open(ifname,ios::in); + if (!plaintext) + { + cout << "Unable to open file " << ifname << "\n"; + return 0; + } + cout << "encrypting message\n"; + ciphertext.open(ofname,ios::binary|ios::out); + +// now encrypt the plaintext file + + forever + { // encrypt input .. + plaintext.get(ch); + if (plaintext.eof()) break; + aes_encrypt(&a,&ch); + ciphertext << ch; + } + + aes_end(&a); + return 0; +} + diff --git a/miracl/source/curve/pairing/ipk_ext.cpp b/miracl/source/curve/pairing/ipk_ext.cpp new file mode 100644 index 0000000..3077475 --- /dev/null +++ b/miracl/source/curve/pairing/ipk_ext.cpp @@ -0,0 +1,104 @@ +/* + Cocks ID-PKC Scheme + + Extract Phase + + After this program has run the file private.ipk contains + + + OR + + + Requires : big.cpp crt.cpp + +*/ + + +#include +#include +#include "big.h" +#include "crt.h" + +using namespace std; + +Miracl precision(100,0); + +// Using SHA-1 as basic hash algorithm + +#define HASH_LEN 20 + +// +// Public Hash Function +// + +Big H(char *string,Big n) +{ // Hash a zero-terminated string to a number h < modulus n + // Then increment this number until (h/n)=+1 + Big h; + char s[HASH_LEN]; + int i,j; + sha sh; + + shs_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs_process(&sh,string[i]); + } + shs_hash(&sh,s); + + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=n) break; + } + while (jacobi(h,n)!=1) h+=1; + h%=n; + return h; +} + +int main() +{ + ifstream master_key("master.ipk"); + ofstream private_key("private.ipk"); + Big b,x,r[2],n,p[2]; + miracl *mip=&precision; + int sign; + + mip->IOBASE=16; + master_key >> p[0] >> p[1]; + n=p[0]*p[1]; + +// EXTRACT + + char id[1000]; + + cout << "Enter your email address (lower case)" << endl; + cin.getline(id,1000); + + x=H(id,n); + sign=0; + if (jacobi(x,p[0])==-1) + { + x=n-x; // Modify if its not QR + sign=1; + } + + Crt chinese(2,p); + r[0]=sqrt(x,p[0]); + if (jacobi(r[0],p[0])==-1) r[0]=p[0]-r[0]; + + r[1]=sqrt(x,p[1]); + if (jacobi(r[1],p[1])==-1) r[1]=p[1]-r[1]; + + b=chinese.eval(r); + + private_key << b << endl; + private_key << sign << endl; + return 0; +} + diff --git a/miracl/source/curve/pairing/ipk_set.cpp b/miracl/source/curve/pairing/ipk_set.cpp new file mode 100644 index 0000000..ac84a7e --- /dev/null +++ b/miracl/source/curve/pairing/ipk_set.cpp @@ -0,0 +1,100 @@ +/* + Cocks ID-PKC scheme + + Program to generate ID-PKC global and master keys + + Set-up phase + + After this program has run the file common.ipk contains + + + + The file master.ibe contains + + + + + Requires : big.cpp + +*/ + +#include +#include +#include +#include "big.h" /* include MIRACL system */ + +using namespace std; + +#define PBITS 512 + +Miracl precision(100,0); + +static Big pd,pl,ph; + +long randise() +{ /* get a random number */ + long seed; + cout << "Enter 9 digit random number seed = "; + cin >> seed; + return seed; +} + +Big strongp(int n,long seed1,long seed2) +{ /* generate strong prime number = 11 mod 12 */ + Big p; + int r,r1,r2; + irand(seed1); + pd=rand(2*n/3,2); + pd=nextprime(pd); + ph=pow((Big)2,n-1)/pd; + pl=pow((Big)2,n-2)/pd; + ph-=pl; + irand(seed2); + ph=rand(ph); + ph+=pl; + r1=pd%12; + r2=ph%12; + r=0; + while ((r1*(r2+r))%12!=5) r++; + ph+=r; + do + { /* find p=2*r*pd+1 = 11 mod 12 */ + p=2*ph*pd+1; + ph+=12; + } while (!prime(p)); + return p; +} + +int main() +{ /* calculate common and master keys * + * for ID-PKC scheme encryption */ + int k,i; + long seed[4]; + Big p[2],n; + ofstream common("common.ipk"); + ofstream master("master.ipk"); + miracl *mip=&precision; + + gprime(15000); /* speeds up large prime generation */ + + for (i=0;i<4;i++) + seed[i]=randise(); + + cout << "generating keys - please wait\n"; + + p[0]=strongp(PBITS,seed[0],seed[1]); + p[1]=strongp(PBITS,seed[2],seed[3]); + n=p[0]*p[1]; + + cout << "Global modulus\n"; + cout << n << endl; + cout << "Master key\n"; + cout << p[0] << endl; + cout << p[1] << endl; + mip->IOBASE=16; + common << n << endl; + master << p[0] << endl; + master << p[1] << endl; + return 0; +} + diff --git a/miracl/source/curve/pairing/irred.cpp b/miracl/source/curve/pairing/irred.cpp new file mode 100644 index 0000000..f3ebc69 --- /dev/null +++ b/miracl/source/curve/pairing/irred.cpp @@ -0,0 +1,458 @@ +/* program to find smallest irreducible polynomial */ +/* cl /O2 /GX irred.cpp polymod.cpp poly.cpp big.cpp zzn.cpp miracl.lib + */ + +#include +#include +#include +#include "polymod.h" + +using namespace std; + +Miracl precision=200; + +// Code to parse formula in command line +// This code isn't mine, but its public domain +// Shamefully I forget the source +// +// NOTE: It may be necessary on some platforms to change the operators * and # +// + +#if defined(unix) +#define TIMES '.' +#define RAISE '^' +#else +#define TIMES '*' +#define RAISE '#' +#endif + +Big tt; +static char *ss; + +void eval_power (Big& oldn,Big& n,char op) +{ + if (op) n=pow(oldn,toint(n)); // power(oldn,size(n),n,n); +} + +void eval_product (Big& oldn,Big& n,char op) +{ + switch (op) + { + case TIMES: + n*=oldn; + break; + case '/': + n=oldn/n; + break; + case '%': + n=oldn%n; + } +} + +void eval_sum (Big& oldn,Big& n,char op) +{ + switch (op) + { + case '+': + n+=oldn; + break; + case '-': + n=oldn-n; + } +} + +void eval (void) +{ + Big oldn[3]; + Big n; + int i; + char oldop[3]; + char op; + char minus; + for (i=0;i<3;i++) + { + oldop[i]=0; + } +LOOP: + while (*ss==' ') + ss++; + if (*ss=='-') /* Unary minus */ + { + ss++; + minus=1; + } + else + minus=0; + while (*ss==' ') + ss++; + if (*ss=='(' || *ss=='[' || *ss=='{') /* Number is subexpression */ + { + ss++; + eval (); + n=tt; + } + else /* Number is decimal value */ + { + for (i=0;ss[i]>='0' && ss[i]<='9';i++) + ; + if (!i) /* No digits found */ + { + cout << "Error - invalid number" << endl; + exit (20); + } + op=ss[i]; + ss[i]=0; + n=atoi(ss); + ss+=i; + *ss=op; + } + if (minus) n=-n; + do + op=*ss++; + while (op==' '); + if (op==0 || op==')' || op==']' || op=='}') + { + eval_power (oldn[2],n,oldop[2]); + eval_product (oldn[1],n,oldop[1]); + eval_sum (oldn[0],n,oldop[0]); + tt=n; + return; + } + else + { + if (op==RAISE) + { + eval_power (oldn[2],n,oldop[2]); + oldn[2]=n; + oldop[2]=RAISE; + } + else + { + if (op==TIMES || op=='/' || op=='%') + { + eval_power (oldn[2],n,oldop[2]); + oldop[2]=0; + eval_product (oldn[1],n,oldop[1]); + oldn[1]=n; + oldop[1]=op; + } + else + { + if (op=='+' || op=='-') + { + eval_power (oldn[2],n,oldop[2]); + oldop[2]=0; + eval_product (oldn[1],n,oldop[1]); + oldop[1]=0; + eval_sum (oldn[0],n,oldop[0]); + oldn[0]=n; + oldop[0]=op; + } + else /* Error - invalid operator */ + { + cout << "Error - invalid operator" << endl; + exit (20); + } + } + } + } + goto LOOP; +} + +int main(int argc,char ** argv) +{ + ofstream ofile; + int ip,i,j,k,m,s,M,Base; + BOOL gotP,ir,fout,first,binomial; + Big w,p,t,xx[16]; + miracl *mip=&precision; + argc--; argv++; + + if (argc<1) + { + cout << "incorrect usage" << endl; + cout << "Program finds simplest irreducible polynomial with respect" << endl; + cout << "to a given prime modulus, of the form x^k+x^2+n" << endl; + cout << "irred " << endl; + cout << "OR" << endl; + cout << "irred " << endl; + cout << "To insist on a binomial, use -b" << endl; + cout << "To input P in Hex, precede with -h" << endl; + cout << "To output to a file, use flag -o " << endl; +#if defined(unix) + cout << "e.g. irred -f 2^192-2^64-1 6 -o zzn6.dat" << endl; +#else + cout << "e.g. irred -f 2#192-2#64-1 6 -o zzn6.dat" << endl; +#endif + return 0; + } + + fout=FALSE; + Base=10; + ip=0; + M=0; + gotP=FALSE; + binomial=FALSE; + while (ipIOBASE=Base; + p=argv[ip++]; + mip->IOBASE=10; + gotP=TRUE; + continue; + } + if (gotP) + { + M=atoi(argv[ip++]); + continue; + } + cout << "Error in command line" << endl; + return 0; + } + if (!gotP || M<2) + { + cout << "Error in command line" << endl; + return 0; + } + + if (!prime(p)) + { + cout << "This number is not prime!" << endl; + exit(0); + } + if (M>36) + { + cout << "M is too big!" << endl; + exit(0); + } + +//forever +//{ + modulo(p); + cout << "p%24= " << p%24 << endl; + if (M==2) binomial=TRUE; + + PolyMod h,g,x; + Poly f; + int ns=0; + + x.addterm(1,1); + + i=1; + j=2; m=1; first=FALSE; + if (M==12) j=4; + + //j=2; m=-1; + + forever + { + g=x; + + f.clear(); + f.addterm(i,0); + if (!binomial) f.addterm(m,j); + + f.addterm(1,M); + +// cout << f << endl; + + setmod(f); + +/* + ir=TRUE; + for (k=1;k<=M;k++) + { + g=pow(g,p); + if (k==M) break; + if (k>1 && prime((Big)k) && M%k==0) + { + h=gcd(g-x); + if (!isone(h)) + { +cout << "k= " << k << endl; +cout << "h= " << h << endl; + ir=FALSE; + break; + } + } + } + + if (ir) + { + if (!iszero(g-x)) ir=FALSE; + break; + } + + if (ir) break; +*/ + + ir=TRUE; + +// Ben-Or irreducibility test + + for (k=1;k<=M/2;k++) + { + g=pow(g,p); + h=gcd(g-x); + if (!isone(h)) + { + ir=FALSE; + break; + } + } + if (ir) + { + cout << "\nirreducible polynomial P(x) = " << f ; + ns++; + if (ns==10) break; + + // break; + } + if (first) + { + if (!binomial) + { + if (m==1) + { + m=-1; + continue; + } + m=1; + } + j=j+1; + if (j==M) + { + j=1; + if (i<0) first=FALSE; + else i=-1; + } + continue; + } + +//cout << "\ni= " << i << endl; + + if (i>0) i=(-i); + else { i=(-i); i++; } + } + +//cout << "p= " << p; +//cout << " irreducible polynomial P(x) = " << f << endl; + +// cout << "\nirreducible polynomial P(x) = " << f << endl << endl; + + if (fout) + { + ofile << i << endl; + if (binomial) ofile << 0 << endl; + else ofile << j << endl; + } + g=x; + g=pow(g,p); + if (fout) + for (i=0;i +#include "ecn3.h" +#include "ecn.h" + +Miracl precision(50,0); + +int main() +{ + miracl *mip=&precision; + Big s,x,q,p,t,A,B,cf,X,Y,sru,n,best_s,f; + Big T,P,F,m1,m2; + ECn W; + ECn3 Q; + ZZn3 r; + mip->IOBASE=16; + int i,ns,sign,best_ham=1000; + + sign=1; // 1= positive, 2=negative for +/- s solutions + //s="808000000000000"; + s=(char *)"800000000000000"; + + ns=1; + for (i=0;i<100;i++) + { + forever + { + forever + { + sign=3-sign; + if (sign==1) s+=1; + if (sign==1) x=14+42*s; + else x=14-42*s; + + t=(pow(x,4) + 16*x + 7)/7; +// p=(pow(x,8) + 5*pow(x,7) + 7*pow(x,6) + 37*pow(x,5) + 188*pow(x,4) + 259*pow(x,3) + 343*pow(x,2) + 1763*x + 2401)/21; + q=(pow(x,6) + 37*pow(x,3) + 343)/343; + if (!prime(q)) continue; + cf=(49*x*x+245*x+343)/3; + n=cf*q; + p=cf*q+t-1; // avoids overflow.. + + if (p%8!=5) continue; + + + if (!prime(p)) continue; + modulo(p); + if (pow((ZZn)-2,(p-1)/3)==1) continue; + + break; + } + + T=t*t*t-3*p*t; + P=p*p*p; + F=(4*P-T*T)/3; + + F=sqrt(F); + + m1=P+1-(-3*F+T)/2; // Wrong Curve + + m2=P+1-(3*F+T)/2; + + B=1; + + forever + { + B+=1; + if (B==2) + { + X=-1; Y=1; + } + else if (B==3) + { + X=1; Y=2; + } + else if (B==8) + { + X=1; Y=3; + } + else if (B==15) + { + X=1; Y=4; + } + else + { + do + { + X=rand(p); + Y=sqrt(X*X*X+B,p); + } while (Y==0); + } + + ecurve(0,B,p,MR_AFFINE); + + + W.set(X,Y); + W*=cf; + if ((q*W).iszero()) break; + } + +/* This always works! + B=2; + ecurve(0,B,p,MR_AFFINE); + W.set(-1,1); + W*=cf; +*/ + sru=pow((ZZn)-2,(p-1)/6); // x^6+2 is irreducible + set_zzn3(-2,sru); + + mip->TWIST=MR_SEXTIC_M; + do + { + r=randn3(); + } while (!Q.set(r)); + + Q*=(m2/q); + + if ((q*Q).iszero()) break; + +// cout << "m1*Q= " << m1*Q << endl; +// cout << "m1%q= " << m1%q << endl; + + mip->TWIST=MR_SEXTIC_D; + do + { + r=randn3(); + } while (!Q.set(r)); + + Q*=(m2/q); + + if ((q*Q).iszero()) break; + + cout << "Something wrong" << endl; + exit(0); + } + cout << "solution " << ns << endl; + cout << "X^18+2 is irreducible" << endl; + + if (sign==1) + { + cout << "s= +" << s << endl; + cout << "s%12= " << s%12 << endl; + } + else + { + cout << "s= -" << s << endl; + cout << "s%12= " << 12-(s%12) << endl; + } + cout << "x= " << x << " ham(x)= " << ham(x) << endl; + cout << "p= " << p << " bits(p)= " << bits(p) << endl; + cout << "q= " << q << " bits(q)= " << bits(q) << endl; + cout << "n= " << n << endl; + cout << "t= " << t << endl; + cout << "cf= " << cf << endl; + + cout << "W= " << W << endl; + cout << "q*W= " << q*W << endl; + mip->IOBASE=10; + cout << "E(Fp): y^2=x^3+" << B << endl; + cout << "(p-1)%18= " << (p-1)%18 << endl; + mip->IOBASE=16; + if (mip->TWIST==MR_SEXTIC_M) cout << "Twist type M" << endl; + if (mip->TWIST==MR_SEXTIC_D) cout << "Twist type D" << endl; + + m2/=q; + // cout << "cf0= " << p-m2%p << endl; m2/=p; + // cout << "cf1= " << m2%p << endl; m2/=p; + // cout << "cf2= " << m2 << endl; + + cout << "Q= " << Q << endl; + Q*=q; + cout << "check - if right twist should be O - q*Q= " << Q << endl; + if (ham(x)IOBASE=16; + int i,j,ns,sign,best_ham=1000; + + s="2000000000"; + + ns=1; + //for (i=0;i<100;i++) + //{ + forever + { + forever + { + s+=1; + + for (j=0;j<6;j++) + { + for (sign=1;sign<=2;sign++) + { + + if (sign==1) x=rc[j]+777*s; + else x=rc[j]-777*s; + + + t=(2*pow(x,7) + 757*x + 259)/259; + p=(pow(x,14)-4*pow(x,13)+7*pow(x,12)+683*pow(x,8)-2510*pow(x,7)+4781*pow(x,6)+117649*pow(x,2)-386569*x + 823543)/28749; + q=(pow(x,12) + 683*pow(x,6) + 117649)/161061481; + + if (x<0) continue; + if (p%8!=5) continue; + + if (!prime(q)) continue; + if (!prime(p)) continue; + modulo(p); + if (pow((ZZn)-2,(p-1)/3)==1) continue; + + + n=p+1-t; + cf=n/q; + +// find number of points on sextic twist E(p^6) + + T=t*t*t*t*t*t-6*p*t*t*t*t+9*p*p*t*t-2*p*p*p; // t^6-6p*t^4+9p^2.t^2-2p^3 + + P=p*p*p*p*p*p; + F=(4*P-T*T)/3; + + F=sqrt(F); + + m2=P+1-(3*F+T)/2; + + B=1; + + forever + { + B+=1; + if (B==2) + { + X=-1; Y=1; + } + else if (B==3) + { + X=1; Y=2; + } + else if (B==8) + { + X=1; Y=3; + } + else if (B==15) + { + X=1; Y=4; + } + else + { + do + { + X=rand(p); + Y=sqrt(X*X*X+B,p); + } while (Y==0); + } + + ecurve(0,B,p,MR_AFFINE); + W.set(X,Y); + W*=cf; + if ((q*W).iszero()) break; + } + + sru=pow((ZZn)-2,(p-1)/6); // x^6+2 is irreducible + set_zzn3(-2,sru); + + mip->TWIST=MR_SEXTIC_M; + do + { + r=randn6(); + } while (!Q.set(r)); + got_one=FALSE; + + Q*=(m2/q); + + if ((q*Q).iszero()) got_one=TRUE; + +// cout << "m1*Q= " << m1*Q << endl; +// cout << "m1%q= " << m1%q << endl; + else + { + mip->TWIST=MR_SEXTIC_D; + do + { + r=randn6(); + } while (!Q.set(r)); + + Q*=(m2/q); + + if ((q*Q).iszero()) got_one=TRUE; + } + if (!got_one) + { + cout << "Something wrong" << endl; + exit(0); + } + if (mip->TWIST==MR_SEXTIC_M) continue; + + cout << "solution " << ns << endl; + cout << "X^36+2 is irreducible" << endl; + + if (sign==1) + { + cout << "s= +" << s << endl; + cout << "s%12= " << s%12 << endl; + } + else + { + cout << "s= -" << s << endl; + cout << "s%12= " << 12-(s%12) << endl; + } + cout << "x= " << x << " ham(x)= " << ham(x) << endl; + cout << "p= " << p << " bits(p)= " << bits(p) << endl; + cout << "q= " << q << " bits(q)= " << bits(q) << endl; + cout << "n= " << n << endl; + cout << "t= " << t << endl; + cout << "cf= " << cf << endl; + cout << "residue class= 777x+" << rc[j] << endl; + + cout << "W= " << W << endl; + cout << "q*W= " << q*W << endl; + mip->IOBASE=10; + cout << "E(Fp): y^2=x^3+" << B << endl; + cout << "(p-1)%36= " << (p-1)%36 << endl; + mip->IOBASE=16; + if (mip->TWIST==MR_SEXTIC_M) cout << "Twist type M" << endl; + if (mip->TWIST==MR_SEXTIC_D) cout << "Twist type D" << endl; + + m2/=q; + // cout << "cf0= " << p-m2%p << endl; m2/=p; + // cout << "cf1= " << m2%p << endl; m2/=p; + // cout << "cf2= " << m2 << endl; + + // cout << "Q= " << Q << endl; + Q*=q; + cout << "check - if right twist should be O - q*Q= " << Q << endl; + + if (ham(x)IOBASE=16; + int i,ns,sign,best_ham=1000; + sign=1; // 1= positive, 2=negative for +/- x solutions + s="1400000000000000"; + ns=1; + for (i=0;i<100;i++) + { + forever + { + forever + { + sign=3-sign; // always looking for +ve x solutions. + if (sign==1) s+=1; + if (sign==1) x=5+30*s; + else x=5-30*s; + + t=(2*pow(x,3) - 11*x + 15)/15; + q=(pow(x,4) - 8*pow(x,2) + 25)/450; + cf=(5*x*x+10*x+25)/2; + n=cf*q; + p=cf*q+t-1; // avoids overflow.. + + if (p%8!=5) continue; // p will be 1 mod 4 + if (!prime(q)) continue; + if (!prime(p)) continue; + + break; + } + + T=t*t-2*p; + P=p*p; + F=(4*P-T*T); + + F=sqrt(F); + m1=P+1-F; // Wrong Curve + + m2=P+1+F; + + A=0; B=0; + forever + { + A+=1; + do + { + X=rand(p); + Y=sqrt(X*X*X+A*X,p); + } while (Y==0); + + ecurve(A,B,p,MR_AFFINE); + + W.set(X,Y); + W*=cf; + if ((q*W).iszero()) break; + } + + mip->TWIST=MR_QUARTIC_M; + do + { + r=randn2(); + } while (!Q.set(r)); + + Q*=(m2/q); + + if ((q*Q).iszero()) break; + + mip->TWIST=MR_QUARTIC_D; + do + { + r=randn2(); + } while (!Q.set(r)); + + Q*=(m2/q); + + if ((q*Q).iszero()) break; + + cout << "Something wrong!" << endl; + exit(0); + } + cout << "solution " << ns << endl; + cout << "irreducible polynomial = X^4 - [0,1]" << endl; + + if (sign==1) + { + cout << "s= +" << s << endl; + cout << "s%12= " << s%12 << endl; + } + else + { + cout << "s= -" << s << endl; + cout << "s%12= " << 12-(s%12) << endl; + } + cout << "x= " << x << " ham(x)= " << ham(x) << endl; + cout << "p= " << p << " bits(p)= " << bits(p) << endl; + cout << "q= " << q << " bits(q)= " << bits(q) << endl; + cout << "n= " << n << endl; + cout << "t= " << t << endl; + cout << "cf= " << cf << endl; + + //cout << "W= " << W << endl; + cout << "q*W= " << q*W << endl; + mip->IOBASE=10; + cout << "E(Fp): y^2=x^3+" << A << "x" << endl; + mip->IOBASE=16; + if (mip->TWIST==MR_QUARTIC_M) cout << "Twist type M" << endl; + if (mip->TWIST==MR_QUARTIC_D) cout << "Twist type D" << endl; + + //cout << "Q= " << Q << endl; + Q*=q; + cout << "check - if right twist should be O - q*Q= " << Q << endl; + if (ham(x)=p) break; + } + h%=p; + return h; +} + +void PFC::start_hash(void) +{ + shs256_init(&SH); +} + +Big PFC::finish_hash_to_group(void) +{ + Big hash; + char s[HASH_LEN]; + shs256_hash(&SH,s); + hash=from_binary(HASH_LEN,s); + return hash%(*ord); +} + +void PFC::add_to_hash(const GT& x) +{ + ZZn6 u; + ZZn18 v=x.g; + ZZn3 h,l; + Big a; + ZZn xx[6]; + + int i,j,m; + v.get(u); + u.get(l,h); + l.get(xx[0],xx[1],xx[2]); + h.get(xx[3],xx[4],xx[5]); + + for (i=0;i<6;i++) + { + a=(Big)xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } + } +} + +void PFC::add_to_hash(const G2& x) +{ + ZZn3 X,Y; + ECn3 v=x.g; + Big a; + ZZn xx[6]; + + int i,m; + + v.get(X,Y); + X.get(xx[0],xx[1],xx[2]); + Y.get(xx[3],xx[4],xx[5]); + for (i=0;i<6;i++) + { + a=(Big)xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } + } +} + +void PFC::add_to_hash(const G1& x) +{ + Big a,X,Y; + int i,m; + x.g.get(X,Y); + a=X; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } + a=Y; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } +} + +void PFC::add_to_hash(const Big& x) +{ + int m; + Big a=x; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } +} + + +void PFC::add_to_hash(char *x) +{ + int i=0; + while (x[i]!=0) + { + shs256_process(&SH,x[i]); + i++; + } +} + +Big H2(ZZn18 x) +{ // Compress and hash an Fp18 to a big number + sha256 sh; + ZZn6 u; + ZZn3 h,l; + Big a,hash; + ZZn xx[6]; + char s[HASH_LEN]; + int i,j,m; + + shs256_init(&sh); + x.get(u); // compress to single ZZn6 + u.get(l,h); + l.get(xx[0],xx[1],xx[2]); + h.get(xx[3],xx[4],xx[5]); + + for (i=0;i<6;i++) + { + a=(Big)xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&sh,m); + a/=256; + } + } + shs256_hash(&sh,s); + hash=from_binary(HASH_LEN,s); + return hash; +} + +#ifndef MR_AFFINE_ONLY + +void force(ZZn& x,ZZn& y,ZZn& z,ECn& A) +{ // A=(x,y,z) + copy(getbig(x),A.get_point()->X); + copy(getbig(y),A.get_point()->Y); + copy(getbig(z),A.get_point()->Z); + A.get_point()->marker=MR_EPOINT_GENERAL; +} + +void extract(ECn &A, ZZn& x,ZZn& y,ZZn& z) +{ // (x,y,z) <- A + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} + +#endif + +void force(ZZn& x,ZZn& y,ECn& A) +{ // A=(x,y) + copy(getbig(x),A.get_point()->X); + copy(getbig(y),A.get_point()->Y); + A.get_point()->marker=MR_EPOINT_NORMALIZED; +} + +void extract(ECn& A,ZZn& x,ZZn& y) +{ // (x,y) <- A + if (A.iszero()) + { + x=0; y=0; + return; + } + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + + +// +// This calculates p.A quickly using Frobenius +// 1. Extract A(x,y) from twisted curve to point on curve over full extension, as X=i^2.x and Y=i^3.y +// where i=NR^(1/k) +// 2. Using Frobenius calculate (X^p,Y^p) +// 3. map back to twisted curve +// Here we simplify things by doing whole calculation on the twisted curve +// +// Note we have to be careful as in detail it depends on w where p=w mod k +// In this case w=13 +// + +ECn3 psi(ECn3 &A,ZZn &W,int n) +{ + int i; + ECn3 R; + ZZn3 X,Y; + ZZn FF; +// Fast multiplication of A by q^n + A.get(X,Y); + + FF=NR*W*W; + for (i=0;isru; + } + R.set(X,Y); + return R; +} + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn18 line(ECn3& A,ECn3& C,ZZn3& slope,ZZn& Qx,ZZn& Qy) +{ + ZZn18 w; + ZZn6 nn,dd; + ZZn3 X,Y; + + A.get(X,Y); + + nn.set(Qy,Y-slope*X); + dd.set(slope*Qx); + w.set(nn,dd); +//cout << "1. w= " << w << endl; + return w; +} + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn18 g(ECn3& A,ECn3& B,ZZn& Qx,ZZn& Qy) +{ + ZZn3 lam; + ZZn18 r; + ECn3 P=A; + +// Evaluate line from A + A.add(B,lam); + if (A.iszero()) return (ZZn18)1; + r=line(P,A,lam,Qx,Qy); + + return r; +} + +// if multiples of G2 can be precalculated, its a lot faster! + +ZZn18 gp(ZZn3* ptable,int &j,ZZn& Px,ZZn& Py) +{ + ZZn18 w; + ZZn6 nn,dd; + + nn.set(Py,ptable[j+1]); + dd.set(ptable[j]*Px); + j+=2; + w.set(nn,dd); +//cout << "2. w= " << w << endl; + return w; +} + +// +// Spill precomputation on pairing to byte array +// + +int PFC::spill(G2& w,char *& bytes) +{ + int i,j,len,m; + int bytes_per_big=(MIRACL/8)*(get_mip()->nib-1); + + Big n; + Big X=*x; + ZZn a,b,c; + if (w.ptable==NULL) return 0; + + n=X/7; + + m=2*(bits(n)+ham(n)+1); + len=m*3*bytes_per_big; + + bytes=new char[len]; + for (i=j=0;inib-1); + + Big n; + Big X=*x; + ZZn a,b,c; + if (w.ptable!=NULL) return; + + n=X/7; + + m=2*(bits(n)+ham(n)+1); + len=m*3*bytes_per_big; + + w.ptable=new ZZn3[m]; + for (i=j=0;i=0;i--) + { + Q=A; +// Evaluate line from A to A+B + A.add(A,lam); + Q.get(x1,y1); + w.ptable[j++]=lam; w.ptable[j++]=y1-lam*x1; + + if (bit(n,i)==1) + { + Q=A; + A.add(B,lam); + Q.get(x1,y1); + w.ptable[j++]=lam; w.ptable[j++]=y1-lam*x1; + } + } + dA=A; + Q=A; + A.add(A,lam); + Q.get(x1,y1); + w.ptable[j++]=lam; w.ptable[j++]=y1-lam*x1; + + m2A=A; + + Q=A; + A.add(dA,lam); + Q.get(x1,y1); + w.ptable[j++]=lam; w.ptable[j++]=y1-lam*x1; + + A=psi(A,*frob,6); + + Q=A; + A.add(m2A,lam); + Q.get(x1,y1); + w.ptable[j++]=lam; w.ptable[j++]=y1-lam*x1; + + return len; +} + +GT PFC::multi_miller(int n,G2** QQ,G1** PP) +{ + GT z; + ZZn *Px,*Py; + int i,j,*k,nb; + ECn3 *Q,*A,*A2; + ECn P; + ZZn18 res,rd; + Big m; + Big X=*x; + + Px=new ZZn[n]; + Py=new ZZn[n]; + Q=new ECn3[n]; + A=new ECn3[n]; + A2=new ECn3[n]; + k=new int[n]; + + m=X/7; + + nb=bits(m); + res=1; + + for (j=0;jg; normalise(P); Q[j]=QQ[j]->g; + extract(P,Px[j],Py[j]); + } + + for (j=0;j=0;i--) + { + res*=res; + for (j=0;jptable==NULL) + res*=g(A[j],A[j],Px[j],Py[j]); + else + res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + if (bit(m,i)==1) + for (j=0;jptable==NULL) + res*=g(A[j],Q[j],Px[j],Py[j]); + else + res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + if (res.iszero()) return 0; + } + + rd=res; + res*=res; + + for (j=0;jptable==NULL) + { + Q[j]=A[j]; + res*=g(A[j],A[j],Px[j],Py[j]); + } + else res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + + rd*=res; + + for (j=0;jptable==NULL) + { + A2[j]=A[j]; + rd*=g(A[j],Q[j],Px[j],Py[j]); + } + else rd*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + + res*=Frobenius(rd,*frob,6); + + for (j=0;jptable==NULL) + { + A[j]=psi(A[j],*frob,6); + res*=g(A[j],A2[j],Px[j],Py[j]); + } + else + res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + + delete [] k; + delete [] A2; + delete [] A; + delete [] Q; + delete [] Py; + delete [] Px; + + z.g=res; + return z; +} + +// +// R-ate Pairing G2 x G1 -> GT +// +// P is a point of order q in G1. Q(x,y) is a point of order q in G2. +// Note that Q is a point on the sextic twist of the curve over Fp^3, P(x,y) is a point on the +// curve over the base field Fp +// + +GT PFC::miller_loop(const G2& QQ,const G1& PP) +{ + GT z; + Big n; + int i,j,nb,nbw,nzs; + ECn3 A,m2A,Q; + ECn P; + ZZn Px,Py; + BOOL precomp; + ZZn18 r,rd; + Big X=*x; + + Q=QQ.g; P=PP.g; + + precomp=FALSE; + if (QQ.ptable!=NULL) precomp=TRUE; + + normalise(P); + extract(P,Px,Py); + + A=Q; + n=(X/7); + + nb=bits(n); + r=1; j=0; + r.mark_as_miller(); + for (i=nb-2;i>=0;i--) + { + r*=r; + if (precomp) r*=gp(QQ.ptable,j,Px,Py); + else r*=g(A,A,Px,Py); + if (bit(n,i)) + { + if (precomp) r*=gp(QQ.ptable,j,Px,Py); + else r*=g(A,Q,Px,Py); + } + } + + rd=r; + r*=r; + + Q=A; + if (precomp) r*=gp(QQ.ptable,j,Px,Py); + else r*=g(A,A,Px,Py); + + rd*=r; + + m2A=A; + if (precomp) rd*=gp(QQ.ptable,j,Px,Py); + else rd*=g(A,Q,Px,Py); + + r*=Frobenius(rd,*frob,6); + if (precomp) r*=gp(QQ.ptable,j,Px,Py); + else + { + A=psi(A,*frob,6); + r*=g(A,m2A,Px,Py); + } + + z.g=r; + return z; +} + +// Automatically generated by Luis Dominquez + +ZZn18 HardExpo(ZZn18 &f3x0, ZZn &X, Big &x){ +//vector=[ 3, 5, 7, 14, 15, 21, 25, 35, 49, 54, 62, 70, 87, 98, 112, 245, 273, 319, 343, 434, 450, 581, 609, 784, 931, 1407, 1911, 4802, 6517 ] + ZZn18 xA; + ZZn18 xB; + ZZn18 t0; + ZZn18 t1; + ZZn18 t2; + ZZn18 t3; + ZZn18 t4; + ZZn18 t5; + ZZn18 t6; + ZZn18 t7; + ZZn18 f3x1; + ZZn18 f3x2; + ZZn18 f3x3; + ZZn18 f3x4; + ZZn18 f3x5; + ZZn18 f3x6; + ZZn18 f3x7; + + f3x1=pow(f3x0,x); + f3x2=pow(f3x1,x); + f3x3=pow(f3x2,x); + f3x4=pow(f3x3,x); + f3x5=pow(f3x4,x); + f3x6=pow(f3x5,x); + f3x7=pow(f3x6,x); + + xA=Frobenius(inverse(f3x1),X,2); + xB=Frobenius(inverse(f3x0),X,2); + t0=xA*xB; + xB=Frobenius(inverse(f3x2),X,2); + t1=t0*xB; + t0=t0*t0; + xB=Frobenius(inverse(f3x0),X,2); + t0=t0*xB; + xB=Frobenius(f3x1,X,1); + t0=t0*xB; + xA=Frobenius(inverse(f3x5),X,2)*Frobenius(f3x4,X,4)*Frobenius(f3x2,X,5); + //xB=Frobenius(f3x1,X,1); + t5=xA*xB; + t0=t0*t0; + t3=t0*t1; + xA=Frobenius(inverse(f3x4),X,2)*Frobenius(f3x1,X,5); + xB=Frobenius(f3x2,X,1); + t1=xA*xB; + xA=xB;//Frobenius(f3x2,X,1); + xB=xA; //xB=Frobenius(f3x2,X,1); + t0=xA*xB; + xB=Frobenius(f3x2,X,4); + t0=t0*xB; + xB=Frobenius(f3x1,X,4); + t2=t3*xB; + xB=Frobenius(inverse(f3x1),X,2); + t4=t3*xB; + t2=t2*t2; + xB=Frobenius(inverse(f3x2),X,3); + t3=t0*xB; + xB=inverse(f3x2); + t0=t3*xB; + t4=t3*t4; + xB=Frobenius(inverse(f3x3),X,3); + t0=t0*xB; + t3=t0*t2; + xB=Frobenius(inverse(f3x3),X,2)*Frobenius(f3x0,X,5); + t2=t3*xB; + t3=t3*t5; + t5=t3*t2; + xB=inverse(f3x3); + t2=t2*xB; + xA=Frobenius(inverse(f3x6),X,3); + //xB=inverse(f3x3); + t3=xA*xB; + t2=t2*t2; + t4=t2*t4; + xB=Frobenius(f3x3,X,1); + t2=t1*xB; + xA=xB; //xA=Frobenius(f3x3,X,1); + xB=Frobenius(inverse(f3x2),X,3); + t1=xA*xB; + t6=t2*t4; + xB=Frobenius(f3x4,X,1); + t4=t2*xB; + xB=Frobenius(f3x3,X,4); + t2=t6*xB; + xB=Frobenius(inverse(f3x5),X,3)*Frobenius(f3x5,X,4); + t7=t6*xB; + t4=t2*t4; + xB=Frobenius(f3x6,X,1); + t2=t2*xB; + t4=t4*t4; + t4=t4*t5; + xA=inverse(f3x4); + xB=Frobenius(inverse(f3x4),X,3); + t5=xA*xB; +// xB=Frobenius(inverse(f3x4),X,3); + t3=t3*xB; + xA=Frobenius(f3x5,X,1); + xB=xA; //xB=Frobenius(f3x5,X,1); + t6=xA*xB; + t7=t6*t7; + xB=Frobenius(f3x0,X,3); + t6=t5*xB; + t4=t6*t4; + xB=Frobenius(inverse(f3x7),X,3); + t6=t6*xB; + t0=t4*t0; + xB=Frobenius(f3x6,X,4); + t4=t4*xB; + t0=t0*t0; + xB=inverse(f3x5); + t0=t0*xB; + t1=t7*t1; + t4=t4*t7; + t1=t1*t1; + t2=t1*t2; + t1=t0*t3; + xB=Frobenius(inverse(f3x3),X,3); + t0=t1*xB; + t1=t1*t6; + t0=t0*t0; + t0=t0*t5; + xB=inverse(f3x6); + t2=t2*xB; + t2=t2*t2; + t2=t2*t4; + t0=t0*t0; + t0=t0*t3; + t1=t2*t1; + t0=t1*t0; +// xB=inverse(f3x6); + t1=t1*xB; + t0=t0*t0; + t0=t0*t2; + xB=f3x0*inverse(f3x7); + t0=t0*xB; +// xB=f3x0*inverse(f3x7); + t1=t1*xB; + t0=t0*t0; + t0=t0*t1; + + return t0; +} + +GT PFC::final_exp(const GT& z) +{ + GT y; + ZZn18 rd,r=z.g; + rd=r; + Big X=*x; + + // final exponentiation + r.conj(); + r/=rd; // r^(p^9-1) + r.mark_as_regular(); // no longer "miller" + rd=r; + r.powq(*frob); r.powq(*frob); r.powq(*frob); r*=rd; //r^(p^3+1) + + r.mark_as_unitary(); + r=HardExpo(r,*frob,X); + + y.g=r; + return y; + +} + +PFC::PFC(int s, csprng *rng) +{ + int i,j,mod_bits,words; + if (s!=192) + { + cout << "No suitable curve available" << endl; + exit(0); + } + + mod_bits=(8*s)/3; + + if (mod_bits%MIRACL==0) + words=(mod_bits/MIRACL); + else + words=(mod_bits/MIRACL)+1; + +#ifdef MR_SIMPLE_BASE + miracl *mip=mirsys((MIRACL/4)*words,16); +#else + miracl *mip=mirsys(words,0); + mip->IOBASE=16; +#endif + + + B=new Big; + x=new Big; + mod=new Big; + ord=new Big; + cof=new Big; + npoints=new Big; + trace=new Big; + + for (i=0;i<6;i++) + { + WB[i]=new Big; + for (j=0;j<6;j++) + { + BB[i][j]=new Big; + } + } + for (i=0;i<2;i++) + { + W[i]=new Big; + for (j=0;j<2;j++) + { + SB[i][j]=new Big; + } + } + + S=s; + + Beta=new ZZn; + frob=new ZZn; + + *B=curveB; + *x=param; + + Big X=*x; + + *trace=(pow(X,4) + 16*X + 7)/7; + *ord=(pow(X,6) + 37*pow(X,3) + 343)/343; + + *cof=(49*X*X+245*X+343)/3; + *npoints=*cof*(*ord); + *mod=*cof*(*ord)+*trace-1; + ecurve(0,*B,*mod,MR_PROJECTIVE); + + Big BBeta=(3*pow(X,7)-7*pow(X,6)+46*pow(X,5)+68*pow(X,4)-308*pow(X,3)+189*X*X+145*X-3192)/56; + BBeta+=X*(pow(X,7)/28); + BBeta/=3; + + Big sru=*mod-BBeta; // sixth root of unity = -Beta + set_zzn3(NR,sru); + *Beta=BBeta; + set_frobenius_constant(*frob); + +// Use standard Gallant-Lambert-Vanstone endomorphism method for G1 + + *W[0]=(X*X*X)/343; // This is first column of inverse of SB (without division by determinant) + *W[1]=(18*X*X*X+343)/343; + + *SB[0][0]=(X*X*X)/343; + *SB[0][1]=-(18*X*X*X+343)/343; + *SB[1][0]=(19*X*X*X+343)/343; + *SB[1][1]=(X*X*X)/343; + +// Use Galbraith & Scott Homomorphism idea for G2 & GT ... (http://eprint.iacr.org/2008/117.pdf) + + *WB[0]=5*pow(X,3)/49+2; // This is first column of inverse of BB (without division by determinant) + *WB[1]=-(X*X)/49; + *WB[2]=pow(X,4)/49+3*X/7; + *WB[3]=-(17*pow(X,3)/343+1); + *WB[4]=-(pow(X,5)/343+2*(X*X)/49); + *WB[5]=5*pow(X,4)/343+2*X/7; + + *BB[0][0]=1; *BB[0][1]=0; *BB[0][2]=5*X/7; *BB[0][3]=1; *BB[0][4]=0; *BB[0][5]=-X/7; + *BB[1][0]=-5*X/7; *BB[1][1]=-2; *BB[1][2]=0; *BB[1][3]=X/7; *BB[1][4]=1; *BB[1][5]=0; + *BB[2][0]=0; *BB[2][1]=2*X/7; *BB[2][2]=1; *BB[2][3]=0; *BB[2][4]=X/7; *BB[2][5]=0; + *BB[3][0]=1; *BB[3][1]=0; *BB[3][2]=X; *BB[3][3]=2; *BB[3][4]=0; *BB[3][5]=0; + *BB[4][0]=-X; *BB[4][1]=-3; *BB[4][2]=0; *BB[4][3]=0; *BB[4][4]=1; *BB[4][5]=0; + *BB[5][0]=0; *BB[5][1]=-X; *BB[5][2]=-3; *BB[5][3]=0; *BB[5][4]=0; *BB[5][5]=1; + + mip->TWIST=MR_SEXTIC_D; // map Server to point on twisted curve E(Fp3) + + RNG=rng; +} + +PFC::~PFC() +{ + int i,j; + delete B; + delete x; + delete mod; + delete ord; + delete cof; + delete npoints; + delete trace; + + for (i=0;i<6;i++) + { + delete WB[i]; + for (j=0;j<6;j++) + delete BB[i][j]; + } + for (i=0;i<2;i++) + { + delete W[i]; + for (j=0;j<2;j++) + delete SB[i][j]; + } + + delete Beta; + delete frob; + mirexit(); +} + +// GLV method + +void glv(const Big &e,Big &r,Big *W[2],Big *B[2][2],Big u[2]) +{ + int i,j; + Big v[2],w; + for (i=0;i<2;i++) + { + v[i]=mad(*W[i],e,(Big)0,r,w); + u[i]=0; + } + u[0]=e; + for (i=0;i<2;i++) + for (j=0;j<2;j++) + u[i]-=v[j]*(*B[j][i]); + return; +} + +// Use Galbraith & Scott Homomorphism idea ... + +void galscott(const Big &e,Big &r,Big *WB[6],Big *B[6][6],Big u[6]) +{ + int i,j; + Big v[6],w; + + for (i=0;i<6;i++) + { + v[i]=mad(*WB[i],e,(Big)0,r,w); + u[i]=0; + } + + u[0]=e; + for (i=0;i<6;i++) + { + for (j=0;j<6;j++) + u[i]-=v[j]*(*B[j][i]); + } + return; +} + +void endomorph(ECn &A,ZZn &Beta) +{ // apply endomorphism (x,y) = (Beta*x,y) where Beta is cube root of unity + ZZn x; + x=(A.get_point())->X; + x*=Beta; + copy(getbig(x),(A.get_point())->X); +} + +G1 PFC::mult(const G1& w,const Big& k) +{ + G1 z; + ECn Q; + if (w.mtable!=NULL) + { // we have precomputed values + Big e=k; + if (k<0) e=-e; + + int i,j,t=w.mtbits; //MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.mtable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g+=z.g; + if (j>0) z.g+=w.mtable[j]; + + } + if (k<0) z.g=-z.g; + } + else + { + Big u[2]; + Q=w.g; + glv(k,*ord,W,SB,u); + endomorph(Q,*Beta); + Q=mul(u[0],w.g,u[1],Q); + z.g=Q; + } + return z; +} + +// GLV + Galbraith-Scott + +G2 PFC::mult(const G2& w,const Big& k) +{ + G2 z; + int i; + if (w.mtable!=NULL) + { // we have precomputed values + Big e=k; + if (k<0) e=-e; + + int i,j,t=w.mtbits; //MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.mtable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g+=z.g; + if (j>0) z.g+=w.mtable[j]; + } + if (k<0) z.g=-z.g; + } + else + { + ECn3 Q[6]; + Big u[6]; + BOOL small=TRUE; + galscott(k,*ord,WB,BB,u); + + Q[0]=w.g; + + for (i=1;i<6;i++) + { + if (u[i]!=0) + { + small=FALSE; + break; + } + } + + if (small) + { + if (u[0]<0) + { + u[0]=-u[0]; + Q[0]=-Q[0]; + } + z.g=Q[0]; + z.g*=u[0]; + return z; + } + + for (i=1;i<6;i++) + Q[i]=psi(Q[i-1],*frob,1); + +// deal with -ve multipliers + for (i=0;i<6;i++) + { + if (u[i]<0) + {u[i]=-u[i];Q[i]=-Q[i];} + } + +// simple multi-addition + z.g= mul(6,Q,u); + } + return z; +} + +// GLV method + Galbraith-Scott idea + +GT PFC::power(const GT& w,const Big& k) +{ + GT z; + int i; + if (w.etable!=NULL) + { // precomputation is available + Big e=k; + if (k<0) e=-e; + + int i,j,t=w.etbits; // MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.etable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g*=z.g; + if (j>0) z.g*=w.etable[j]; + } + if (k<0) z.g=inverse(z.g); + } + else + { + ZZn18 Y[6]; + Big u[6]; + + galscott(k,*ord,WB,BB,u); + + Y[0]=w.g; + for (i=1;i<6;i++) + {Y[i]=Y[i-1]; Y[i].powq(*frob);} + +// deal with -ve exponents + for (i=0;i<6;i++) + { + if (u[i]<0) + {u[i]=-u[i];Y[i].conj();} + } + +// simple multi-exponentiation + z.g= pow(6,Y,u); + } + return z; +} + +// Faster Hashing to G2 - Fuentes-Castaneda, Knapp and Rodriguez-Henriquez + +ECn3 HashG2(ECn3& Qx0,Big &x,ZZn&F) +{ + ECn3 Qx0_; + ECn3 Qx1; + ECn3 Qx1_; + ECn3 Qx2; + ECn3 Qx2_; + ECn3 Qx3; + ECn3 t1; + ECn3 t2; + ECn3 t3; + ECn3 t4; + ECn3 t5; + ECn3 t6; + + Qx0_=-Qx0; + Qx1=x*Qx0; + Qx1_=-Qx1; + Qx2=x*Qx1; + Qx2_=-Qx2; + Qx3=x*Qx2; + + t1=Qx0; + t2=psi(Qx1_,F,2); + t3=Qx1+psi(Qx1,F,5); + t4=psi(Qx1,F,3)+psi(Qx2,F,1)+psi(Qx2_,F,2); + t5=psi(Qx0_,F,4); + t6=psi(Qx0,F,1)+psi(Qx0,F,3)+psi(Qx2_,F,4)+psi(Qx2,F,5)+psi(Qx3,F,1); + + t2+=t1; // Olivos addition sequence + t1+=t1; + t1+=t3; + t1+=t2; + t4+=t2; + t5+=t1; + t4+=t1; + t5+=t4; + t4+=t6; + t5+=t5; + t5+=t4; + + return t5; +} + +// random group element + +void PFC::random(Big& w) +{ + if (RNG==NULL) w=rand(*ord); + else w=strong_rand(RNG,*ord); +} + +// random AES key + +void PFC::rankey(Big& k) +{ + if (RNG==NULL) k=rand(S,2); + else k=strong_rand(RNG,S,2); +} + +void PFC::hash_and_map(G2& w,char *ID) +{ + int i; + ZZn3 XX; + Big X=*x; + + Big x0=H1(ID); + forever + { + x0+=1; + XX.set((ZZn)0,(ZZn)x0,(ZZn)0); + if (!w.g.set(XX)) continue; + break; + } + w.g=HashG2(w.g,X,*frob); +} + +void PFC::random(G2 &w) +{ + int i; + ZZn3 XX; + Big X=*x; + + Big x0; + if (RNG==NULL) x0=rand(*mod); + else x0=strong_rand(RNG,*mod); + + forever + { + x0+=1; + XX.set((ZZn)0,(ZZn)x0,(ZZn)0); + if (!w.g.set(X)) continue; + break; + } + + w.g=HashG2(w.g,X,*frob); +} + +void PFC::hash_and_map(G1& w,char *ID) +{ + Big x0=H1(ID); + while (!w.g.set(x0,x0)) x0+=1; + w.g*=*cof; +} + +void PFC::random(G1& w) +{ + Big x0; + if (RNG==NULL) x0=rand(*mod); + else x0=strong_rand(RNG,*mod); + + while (!w.g.set(x0,x0)) x0+=1; + + w.g*=*cof; + +} + +Big PFC::hash_to_aes_key(const GT& w) +{ + Big m=pow((Big)2,S); + return H2(w.g)%m; +} + +Big PFC::hash_to_group(char *ID) +{ + Big m=H1(ID); + return m%(*ord); +} + +GT operator*(const GT& x,const GT& y) +{ + GT z=x; + z.g*=y.g; + return z; +} + +GT operator/(const GT& x,const GT& y) +{ + GT z=x; + z.g/=y.g; + return z; +} + +// +// spill precomputation on GT to byte array +// + +int GT::spill(char *& bytes) +{ + int i,j,n=(1<nib-1); + int len=n*18*bytes_per_big+1; + ZZn6 a,b,c; + ZZn3 f,s; + ZZn x,y,z; + + if (etable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*18*bytes_per_big; + ZZn6 a,b,c; + ZZn3 f,s; + ZZn x,y,z; + if (etable!=NULL) return; + + etable=new ZZn18[1<nib-1); + int len=n*2*bytes_per_big+1; + Big x,y; + + if (mtable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*2*bytes_per_big; + Big x,y; + if (mtable!=NULL) return; + + mtable=new ECn[1<nib-1); + int len=n*6*bytes_per_big+1; + ZZn3 x,y; + ZZn a,b,c; + + if (mtable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*6*bytes_per_big; + ZZn3 x,y; + ZZn a,b,c; + if (mtable!=NULL) return; + + mtable=new ECn3[1< +#include +#include "ecn.h" +#include "zzn.h" + +using namespace std; + +Miracl precision(36,0); + +int main() +{ + ofstream params("xk1.ecs"); + miracl *mip=&precision; + Big q,p,c,lambda; + + lambda=pow((Big)2,80)+pow((Big)2,16); + q=lambda*lambda+lambda+1; +/* + forever + { + q+=1; + if (!prime(q)) continue; + if (jacobi((Big)-3,q)!=1) continue; + break; + } +*/ + c=pow((Big)2,351); + if (c%2==1) c+=1; + + for (; ;c+=2) + { + p=3*q*q*c*c+1; + if (p%8==1) continue; + if (prime(p)) break; + } + + cout << "bits(p)= " << bits(p) << endl; + cout << "p%8= " << p%8 << endl; + cout << "p%3= " << p%3 << endl; + cout << "jacobi(-3,q)= " << jacobi((Big)-3,q) << endl; + + cout << "cm " << p << " -D3" << endl; + + mip->IOBASE=16; + cout << "p= " << p << endl; + cout << "c= " << c << endl; + cout << "q= " << q << endl; + + params << "1024" << endl; + params << p << endl; + params << "0" << endl; + params << "1" << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/mnt.cpp b/miracl/source/curve/pairing/mnt.cpp new file mode 100644 index 0000000..52c885e --- /dev/null +++ b/miracl/source/curve/pairing/mnt.cpp @@ -0,0 +1,509 @@ +/* + * program to generate MNT Elliptic curves + * + * Compile as (for example) + * cl /O2 /GX mnt.cpp big.cpp miracl.lib + * + * See Miyaji, Nakabayashi & Takano "New explicit conditions of elliptic curve + * traces for FR-reduction", IEICE Trans. Fundementals., Vol. E84A, No. 5,May + * 2001 + * + * Invoke as mnt N where k= 3,4 or 6 + * + * Security level is preportional to the difficulty of the associated + * discrete log problem in bits. e.g. if p is 160 bits and k=6, then + * discrete log problem is 160*6=960 bits. + * + * To find actual elliptic curve use CM utility + * For example from output:- + * + * *** Found one - 165 bits + * D= 998 + * p= 28795013727143986241793993458326894706197949151527 + * NP= 28795013727143986241793989663922216291941998151802 + * = 78*369166842655692131305051149537464311435153822459 + * (a 159-bit prime) + * + * Execute + * cm 28795013727143986241793993458326894706197949151527 -D998 -K78 + * + * New! Now also finds "extended" MNT curves. By allowing a co-factor > 1 + * many more curves will be found. + * + * However this can cause a problem for our Pell code. A "." indicates that + * only a partial search was possible. + * + * Mike Scott 4/07/2002 + * + */ + +#include +#include +#include +#include +#include "big.h" + +using namespace std; + +// Solve the Pell equation + +int pell(int max,Big D,Big F,Big& X,Big& Y,Big *SX,Big *SY,BOOL& complete) +{ + int i,j,ns; + BOOL SMALLD; + Big A,P,Q,SD,G,B,OG,OB,NG,NB,T; + + complete=FALSE; + SMALLD=FALSE; + if (Dmax) return ns; + // abort - these are only solutions + T=G*G-D*B*B; + if (T == F/4) + { + SX[ns]=2*G; SY[ns]=2*B; + ns++; + } + + if (T == F) + { + SX[ns]=G; SY[ns]=B; + ns++; + } + if (i>0 && Q==1) break; + } + + if (i%2==1) + for (j=0;jmax) return ns; + + T=G*G-D*B*B; + if (T == F/4) + { + SX[ns]=2*G; SY[ns]=2*B; + ns++; + } + if (T == F) + { + SX[ns]=G; SY[ns]=B; + ns++; + } + } + + complete=TRUE; // we got to the end.... + X=G; Y=B; // minimal solution of x^2-dy^2=1 + // can be used to find more solutions.... + + if (SMALLD) + { // too small - do it the hard way + Big ylim1,ylim2,R; + ns=0; + if (F<0) + { + ylim1=sqrt(-F/D); + ylim2=sqrt(-F*(X+1)/(2*D)); + } + else + { + ylim1=0; + ylim2=sqrt(F*(X-1)/(2*D)); + } + +// This might take too long... +// Should really implement LMM method here + + if (ylim2-ylim1>300) + { + cout << "." << flush; + ylim2=ylim1+300; + } + for (B=ylim1;BPRIMES[i]; + if ((d%(s*s))==0) return FALSE; + if ((s*s)>d) break; + } + + return TRUE; +} + +void results(BOOL fout,ofstream& ofile,int d,Big p,Big nrp,Big ord,BOOL prime_ord) +{ + Big cf=nrp/ord; + + cout << "*** Found one - " << bits(p) << " bits" << endl; + cout << " D= " << d << endl; + cout << " p= " << p << " p%24= " << p%24 << endl; + cout << "NP= " << nrp << endl; + if (cf>1) cout << " = " << cf << "*" << ord << endl; + if (prime_ord) + { + if (cf==1) + cout << " (a " << bits(ord) << "-bit prime) !\n" << endl; + else + cout << " (a " << bits(ord) << "-bit prime)\n" << endl; + + } + else cout << endl; + + if (fout) + { + ofile << "*** Found one - " << bits(p) << " bits" << endl; + ofile << " D= " << d << endl; + ofile << " p= " << p << " p%24= " << p%24 << endl; + ofile << "NP= " << nrp << endl; + if (cf>1) ofile << " = " << cf << "*" << ord << endl; + if (prime_ord) + { + if (cf==1) + ofile << " (a " << bits(ord) << "-bit prime) !" << endl; + else + ofile << " (a " << bits(ord) << "-bit prime)" << endl; + ofile << " cm " << p << " -D" << d << " -K" << cf << endl << endl; + } + else ofile << endl; + } +} + +int main(int argc,char **argv) +{ + ofstream ofile; + int MIN_SECURITY,MAX_SECURITY,MIN_D,MAX_D,MIN_P; + int ip,j,d,m,mm,solutions,mnt,start,N,precision,max; + BOOL fout,complete; + +// Defaults + MIN_SECURITY=768; + MAX_SECURITY=1536; + MIN_D=1; + MAX_D=10000; + MIN_P=128; + fout=FALSE; + precision=100; + m=1; + + argc--; argv++; + if (argc<1) + { + cout << "Wrong number of parameters" << endl; + cout << "Utility to find MNT elliptic curves" << endl; + cout << "The output from this program must be processed by the" << endl; + cout << "CM (Complex Multiplication) utility to find the actual" << endl; + cout << "curve parameters" << endl; + cout << "See comments at start of source file mnt.cpp for more details" << endl; + cout << "mnt k, where k=3,4 or 6 is the security multiplier" << endl; + cout << "Flags allowed, e.g. mnt 6 -c2 -d100 -D1000 -m1000 -M2000" << endl; + cout << "-c: cofactor (number of points on curve will be multiple of cofactor)" << endl; + cout << "-d: min value of D, -D: max value of D" << endl; + cout << "-m: min security level, -M: max security level (RSA equivalent bits)" << endl; + cout << "-p: min prime size/field size in bits" << endl; + cout << "Increase co-factor for more curves" << endl; + cout << "Defaults -c1 -d0 -D10000 -m768 -M1536 -p128" << endl; + cout << "To output to a file, use flag -o " << endl; + exit(0); + } + + N=atoi(argv[0]); + if (N!=3 && N!=4 && N!=6) + { + cout << "Wrong parameter - should be 3,4 or 6" << endl; + exit(0); + } + + ip=1; + while (ip8) + { + cout << "Co-factor must be > 0 and <= 8" << endl; + exit(0); + } + + miracl *mip=mirsys(precision,0); + Big F,T,M,D,W,K,C,mmax,td,X,Y,x,y,w,xn,yn,t0,u0,p,k,nrp,ord,R; + Big SX[20],SY[20]; + + start=1; + if (1=4*M) break; // Hasse limit + if (gcd(R,M)!=1) continue; + T=R*R-4*M*M; + } + else + { // R=1,3,7,9,13,... 1 or 3 mod 6 + if (R%6!=1 && R%6!=3) continue; + if (R%5==0 || R%2==0) continue; + if (R>=4*M) break; // Hasse limit + if (gcd(R,M)!=1) continue; + if (N==3) T=(R+M)*(R+M)-4*M*M; + else T=(R-M)*(R-M)-4*M*M; + } + +// Check that quadratic polynomial for p does not factor +// i.e. b^2-4ac is not a square +// The prime p will be of the form M*Phi_N(x)/R + x + + if (T>=0) + { + W=sqrt(T); + if (W*W==T) continue; // p cannot be prime - has factors + } + +// There are probably more conditions like these ..... + + if (N==6) + { + if (M==4 && R==3) continue; // p cannot be prime - multiple of 3 + if (R>3 && (R/3)%3==0) continue; + } + + cout << "\nM= " << M << " R= " << R << endl << endl; + if (fout) ofile << "\nM= " << M << " R= " << R << endl << endl; + + K=(4*M-R); + + if (N==3) C=2*M+R; + if (N==4) C=R; + if (N==6) C=-(2*M-R); + + F=C*C-K*K; + +// CM equation is R.D.V^2 = 4*M*Phi_N(x)-R*(x-1)^2 +// Substitute x=(X-C)/K (to get rid of x term) +// Pell equation is then X^2-R*K*D.V^2 = F + +// Our Pell code runs into problems if F is too big + +// This hack makes F a bit smaller - better for Pell +// If M is even x must be odd... + + mm=1; + if (M%2==0 && F%4==0) + { + mm=2; F/=4; + } + + max=10+MAX_SECURITY/(2*N); + gprime(100000); // > 2^16 + + + for (d=start;d<=MAX_D;d++) + { +// D must be square-free + if (!squfree(d)) continue; + td=R*K*d; + solutions=pell(max,td,F,t0,u0,SX,SY,complete); + + if (!solutions) continue; + for (j=0;j max) break; // primes are too big + + if ((mm*X-C)%K == 0) + { + x=(mm*X-C)/K; + if (N==3) p=x*x+x+1; + if (N==4) p=x*x+1; + if (N==6) p=x*x-x+1; + if (R==1 || p%R==0) + { + p=(M*p)/R+x; + if (N*bits(p) > MAX_SECURITY) break; + if (bits(p)>=MIN_P && N*bits(p)>= MIN_SECURITY && prime(p)) + { + nrp=p+1-(x+1); + ord=trial_divide(nrp); + if (prime(ord)) + { + if (bits(ord)>=MIN_P) + { + mnt++; + results(fout,ofile,d,p,nrp,ord,TRUE); + } + } + // else + // { // ord has at least a 16-bit factor... + // if (bits(ord)>=MIN_P+16) + // { + // mnt++; + // results(fout,ofile,d,p,nrp,ord,FALSE); + // } + // } + } + } + } + if ((-mm*X-C)%K == 0) + { + x=(-mm*X-C)/K; + if (N==3) p=x*x+x+1; + if (N==4) p=x*x+1; + if (N==6) p=x*x-x+1; + if (R==1 || p%R==0) + { + p=(M*p)/R+x; + if (N*bits(p) > MAX_SECURITY) break; + if (bits(p)>=MIN_P && N*bits(p)>= MIN_SECURITY && prime(p)) + { + nrp=p+1-(x+1); + ord=trial_divide(nrp); + if (prime(ord)) + { + if (bits(ord)>=MIN_P) + { + results(fout,ofile,d,p,nrp,ord,TRUE); + mnt++; + } + } + // else + // { + // if (bits(ord)>=MIN_P+16) + // { + // results(fout,ofile,d,p,nrp,ord,FALSE); + // mnt++; + // } + // } + } + } + } + if (!complete) break; // no more solutions + multiply(td,t0,u0,X,Y); + } + } + } + } + } + if (fout) ofile << mnt << " MNT elliptic curves found in this range" << endl; + cout << mnt << " MNT elliptic curves found in this range" << endl; + return 0; +} + diff --git a/miracl/source/curve/pairing/mnt.ecs b/miracl/source/curve/pairing/mnt.ecs new file mode 100644 index 0000000..160a130 --- /dev/null +++ b/miracl/source/curve/pairing/mnt.ecs @@ -0,0 +1,7 @@ +159 +7DDCA613A2E3DDB1749D0195BB9F14CF44626303 +-3 +21C3F3AC7864D1F1F99273D0F828D3657D8CFD4E +3EEE5309D171EED8BA4E12DEF44414FD17D369B7 +FBB94C2745C7BB62E93BBADB1D6BFF48B23BE531 +3AA6D7A29EA2B8F45913FCF124C6F8B9A92DB540 diff --git a/miracl/source/curve/pairing/mnt_pair.cpp b/miracl/source/curve/pairing/mnt_pair.cpp new file mode 100644 index 0000000..dd8af3d --- /dev/null +++ b/miracl/source/curve/pairing/mnt_pair.cpp @@ -0,0 +1,1349 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * + * mnt_pair.cpp + * + * MNT curve, ate pairing embedding degree 6, ideal for security level AES-80 + * + * + * Irreducible binomial MUST be of the form x^6+2. This excludes many of the curves + * found using the mnt utility! + * NOTE: This version uses a "compositum". That is the ZZn6 class is a cubic tower over ZZn2, but can + * also be considered as a quadratic tower over ZZn3. The routine shuffle converts from one form to the other. + * The former is fastest for ZZn6 arithmetic, the latter form is required for handling the second parameter + * to the pairing, which is on the quadratic twist E(Fp3) + * + * Provides high level interface to pairing functions + * + * GT=pairing(G2,G1) + * + * This is calculated on a Pairing Friendly Curve (PFC), which must first be defined. + * + * G1 is a point over the base field, and G2 is a point over an extension field of degree 3 + * GT is a finite field point over the 6-th extension, where 6 is the embedding degree. + * + */ + +#define MR_PAIRING_MNT +#include "pairing_3.h" + +// AES_SECURITY=80 bit curve +// MNT curve parameters, x,A,B +// Thanks to Drew Sutherland for providing the MNT curve +// irreducible poly is x^6+2 +static char param[]="-D285DA0CFEF02F06F812"; +static char curveB[]="77479D33943B5B1F590B54258B72F316B3261D45"; + +void read_only_error(void) +{ + cout << "Attempt to write to read-only object" << endl; + exit(0); +} + +void set_frobenius_constant(ZZn2 &X) +{ + Big p=get_modulus(); + switch (get_mip()->pmod8) + { + case 5: + X.set((Big)0,(Big)1); // = (sqrt(-2)^(p-1)/2 + break; + case 3: // = (1+sqrt(-1))^(p-1)/2 + X.set((Big)1,(Big)1); + break; + case 7: + X.set((Big)2,(Big)1); // = (2+sqrt(-1))^(p-1)/2 + default: break; + } + X=pow(X,(p-1)/3); +} + +// Using SHA as basic hash algorithm +// +// Hash function +// + +#define HASH_LEN 20 + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha sh; + + shs_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs_process(&sh,string[i]); + } + shs_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +void PFC::start_hash(void) +{ + shs_init(&SH); +} + +Big PFC::finish_hash_to_group(void) +{ + Big hash; + char s[HASH_LEN]; + shs_hash(&SH,s); + hash=from_binary(HASH_LEN,s); + return hash%(*ord); +} + +void PFC::add_to_hash(const GT& x) +{ + ZZn6 u=x.g; + ZZn2 v; + ZZn l,h; + Big a,xx[2]; + int i,j,m; + + u.get(v); + v.get(l,h); + xx[0]=l; xx[1]=h; + + for (i=0;i<2;i++) + { + a=xx[i]; + while (a>0) + { + m=a%256; + shs_process(&SH,m); + a/=256; + } + } + +} + +void PFC::add_to_hash(const G2& x) +{ + ZZn3 X,Y; + ECn3 v=x.g; + Big a; + ZZn xx[6]; + + int i,m; + + v.get(X,Y); + X.get(xx[0],xx[1],xx[2]); + Y.get(xx[3],xx[4],xx[5]); + for (i=0;i<6;i++) + { + a=(Big)xx[i]; + while (a>0) + { + m=a%256; + shs_process(&SH,m); + a/=256; + } + } +} + +void PFC::add_to_hash(const G1& x) +{ + Big a,X,Y; + int i,m; + x.g.get(X,Y); + a=X; + while (a>0) + { + m=a%256; + shs_process(&SH,m); + a/=256; + } + a=Y; + while (a>0) + { + m=a%256; + shs_process(&SH,m); + a/=256; + } +} + +void PFC::add_to_hash(const Big& x) +{ + int m; + Big a=x; + while (a>0) + { + m=a%256; + shs_process(&SH,m); + a/=256; + } +} + + +void PFC::add_to_hash(char *x) +{ + int i=0; + while (x[i]!=0) + { + shs_process(&SH,x[i]); + i++; + } +} + +Big H2(ZZn6 y) +{ // Hash and compress an Fp6 to a big number + sha sh; + ZZn u,v,w; + ZZn2 x; + Big a,h,xx[2]; + char s[HASH_LEN]; + int i,j,m; + + shs_init(&sh); + y.get(x); + x.get(u,v); + xx[0]=u; xx[1]=v; + + for (i=0;i<2;i++) + { + a=xx[i]; + while (a>0) + { + m=a%256; + shs_process(&sh,m); + a/=256; + } + } + shs_hash(&sh,s); + h=from_binary(HASH_LEN,s); + return h; +} + +#ifndef MR_AFFINE_ONLY + +void force(ZZn& x,ZZn& y,ZZn& z,ECn& A) +{ // A=(x,y,z) + copy(getbig(x),A.get_point()->X); + copy(getbig(y),A.get_point()->Y); + copy(getbig(z),A.get_point()->Z); + A.get_point()->marker=MR_EPOINT_GENERAL; +} + +void extract(ECn &A, ZZn& x,ZZn& y,ZZn& z) +{ // (x,y,z) <- A + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} + +#endif + +void force(ZZn& x,ZZn& y,ECn& A) +{ // A=(x,y) + copy(getbig(x),A.get_point()->X); + copy(getbig(y),A.get_point()->Y); + A.get_point()->marker=MR_EPOINT_NORMALIZED; +} + +void extract(ECn& A,ZZn& x,ZZn& y) +{ // (x,y) <- A + if (A.iszero()) + { + x=0; y=0; + return; + } + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + + +ZZn6 shuffle(const ZZn3 &first, const ZZn3 &second) +{ // shuffle from a pair ZZn3's to three ZZn2's, as required by ZZn6 + ZZn6 w; + ZZn x0,x1,x2,x3,x4,x5; + ZZn2 t0,t1,t2; + first.get(x0,x2,x4); + second.get(x1,x3,x5); + t0.set(x0,x3); + t1.set(x1,x4); + t2.set(x2,x5); + w.set(t0,t1,t2); + return w; +} + +void unshuffle(ZZn6 &S,ZZn3 &first,ZZn3 &second) +{ // unshuffle a ZZn6 into two ZZn3's + ZZn x0,x1,x2,x3,x4,x5; + ZZn2 t0,t1,t2; + S.get(t0,t1,t2); + t0.get(x0,x3); + t1.get(x1,x4); + t2.get(x2,x5); + first.set(x0,x2,x4); + second.set(x1,x3,x5); +} + +// Calculate q*P. P(X,Y) -> P(X^p,Y^p)) + +void q_power_frobenius(ECn3 &S,ZZn2& X) +{ + ZZn6 X1,X2,Y1,Y2; + ZZn3 Sx,Sy,T; + + int qnr=get_mip()->cnr; + + S.get(Sx,Sy); + + // untwist + Sx=Sx/qnr; + Sy=tx(Sy); + Sy=Sy/(qnr*qnr); + + X1=shuffle(Sx,(ZZn3)0); Y1=shuffle((ZZn3)0,Sy); + X1.powq(X); Y1.powq(X); + unshuffle(X1,Sx,T); unshuffle(Y1,T,Sy); + + // twist + Sx=qnr*Sx; + Sy=txd(Sy*qnr*qnr); + S.set(Sx,Sy); +} + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn6 line(ECn3& A,ECn3& C,ECn3& B,int type,ZZn3& slope,ZZn3& ex1,ZZn3& ex2,ZZn& Px,ZZn& Py) +{ + ZZn6 w; + ZZn3 d; + ZZn3 x,y; +#ifdef MR_ECN3_PROJECTIVE + ZZn3 z,z3,t; + C.getZ(z3); + d.set1(Py); + + if (type==MR_ADD) + { // exploit that B is in affine + ZZn3 x2,y2; + B.get(x2,y2); + y2*=z3; d*=z3; + w=shuffle(y2-slope*(Px+x2),d); + } + if (type==MR_DOUBLE) + { // use extra information from point doubling + A.get(x,y,z); + w=shuffle(ex1-slope*(Px*ex2+x),d*z3*ex2); + } +#else + A.get(x,y); + d.set1(Py); + w=shuffle(y-slope*(Px+x),d); +#endif + return w; +} + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn6 g(ECn3& A,ECn3& B,ZZn& Px,ZZn& Py) +{ + BOOL type; + ZZn3 lam,ex1,ex2; + ECn3 Q=A; + +// Evaluate line from A to A+B + type=A.add(B,lam,&ex1,&ex2); + + return line(Q,A,B,type,lam,ex1,ex2,Px,Py); +} + +// if multiples of G2 can be precalculated, its a lot faster! + +ZZn6 gp(ZZn3* ptable,int &j,ZZn& Px,ZZn& Py) +{ + ZZn6 w; + ZZn3 d; + d.set1(Py); + w=shuffle(ptable[j]*Px+ptable[j+1],d); + j+=2; + return w; +} + +// +// Spill precomputation on pairing to byte array +// + +int PFC::spill(G2& w,char *& bytes) +{ + int i,j,len,m; + int bytes_per_big=(MIRACL/8)*(get_mip()->nib-1); + + ZZn a,b,c; + Big X=*x; + if (w.ptable==NULL) return 0; + + m=2*(bits(X)-2+ham(X)); + len=m*3*bytes_per_big; + + bytes=new char[len]; + for (i=j=0;inib-1); + + ZZn a,b,c; + Big X=*x; + if (w.ptable!=NULL) return; + + m=2*(bits(X)-2+ham(X)); + len=m*3*bytes_per_big; + + w.ptable=new ZZn3[m]; + for (i=j=0;icoord=MR_AFFINE; // switch to affine + for (i=nb-2;i>=0;i--) + { + Q=A; +// Evaluate line from A to A+B + A.add(A,lam,NULL,NULL); + Q.get(x1,y1); + w.ptable[j++]=-lam; w.ptable[j++]=y1-lam*x1; + + if (bit(X,i)==1) + { + Q=A; + type=A.add(B,lam,NULL,NULL); + Q.get(x1,y1); + w.ptable[j++]=-lam; w.ptable[j++]=y1-lam*x1; + } + } + get_mip()->coord=MR_PROJECTIVE; + return len; +} + +GT PFC::multi_miller(int n,G2** QQ,G1** PP) +{ + GT z; + ZZn *Px,*Py; + int i,j,*k,nb; + ECn3 *Q,*A; + ECn P; + ZZn6 res; + Big X=*x; + + Px=new ZZn[n]; + Py=new ZZn[n]; + Q=new ECn3[n]; + A=new ECn3[n]; + k=new int[n]; + + nb=bits(X); + res=1; + + for (j=0;jg; normalise(P); Q[j]=QQ[j]->g; + extract(P,Px[j],Py[j]); + Px[j]+=Px[j]; + Py[j]+=Py[j]; + } + + for (j=0;j=0;i--) + { + res*=res; + for (j=0;jptable==NULL) + res*=g(A[j],A[j],Px[j],Py[j]); + else + res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + if (bit(X,i)==1) + for (j=0;jptable==NULL) + res*=g(A[j],Q[j],Px[j],Py[j]); + else + res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + if (res.iszero()) return 0; + } + + delete [] k; + delete [] A; + delete [] Q; + delete [] Py; + delete [] Px; + + z.g=res; + return z; +} + +// +// R-ate Pairing G2 x G1 -> GT +// +// P is a point of order q in G1. Q(x,y) is a point of order q in G2. +// Note that Q is a point on the sextic twist of the curve over Fp^2, P(x,y) is a point on the +// curve over the base field Fp +// + +GT PFC::miller_loop(const G2& QQ,const G1& PP) +{ + GT z; + int i,j,n,nb,nbw,nzs; + ECn3 A,Q; + ECn P; + ZZn Px,Py; + BOOL precomp; + ZZn6 res; + Big X=*x; + + P=PP.g; Q=QQ.g; +#ifdef MR_ECN3_PROJECTIVE + Q.norm(); +#endif + precomp=FALSE; + if (QQ.ptable!=NULL) precomp=TRUE; + + normalise(P); + extract(P,Px,Py); + + Px+=Px; // because x^6+2 is irreducible.. simplifies line function calculation + Py+=Py; + + res=1; + A=Q; // reset A + nb=bits(X); + res.mark_as_miller(); + j=0; + + for (i=nb-2;i>=0;i--) + { + res*=res; + if (precomp) res*=gp(QQ.ptable,j,Px,Py); + else res*=g(A,A,Px,Py); + + if (bit(X,i)==1) + { + if (precomp) res*=gp(QQ.ptable,j,Px,Py); + else res*=g(A,Q,Px,Py); + } + } + + z.g=res; + return z; +} + +GT PFC::final_exp(const GT& z) +{ + GT y; + ZZn6 w,res; + Big X=*x; + + res=z.g; + + w=res; + w.powq(*frob); + res*=w; // ^(p+1) + + w=res; + w.powq(*frob); w.powq(*frob); w.powq(*frob); + res=w/res; // ^(p^3-1) + +// exploit the clever "trick" for a half-length exponentiation! + + res.mark_as_unitary(); + + w=res; + res.powq(*frob); // res*=res; // res=pow(res,CF); + + if (X<0) res/=powu(w,-X); + else res*=powu(w,X); + + y.g=res; + + return y; +} + +PFC::PFC(int s, csprng *rng) +{ + int mod_bits,words; + if (s!=80) + { + cout << "No suitable curve available" << endl; + exit(0); + } + mod_bits=2*s; + + if (mod_bits%MIRACL==0) + words=(mod_bits/MIRACL); + else + words=(mod_bits/MIRACL)+1; + +#ifdef MR_SIMPLE_BASE + miracl *mip=mirsys((MIRACL/4)*words,16); +#else + miracl *mip=mirsys(words,0); + mip->IOBASE=16; +#endif + + B=new Big; + x=new Big; + mod=new Big; + ord=new Big; + cof=new Big; + npoints=new Big; + trace=new Big; + frob=new ZZn2; + + *B=curveB; + S=s; + *x=param; + Big X=*x; + + *mod=X*X+1; + *npoints=X*X-X+1; + *trace=X+1; + *cof=X*X+X+1; + *ord=*npoints; + ecurve(-3,*B,*mod,MR_PROJECTIVE); + set_frobenius_constant(*frob); + Big sru=pow((ZZn)-2,(*mod-1)/6); // x^6+2 is irreducible + set_zzn3(-2,sru); + mip->TWIST=MR_QUADRATIC; // twisted curve E'(ZZn3) + + RNG = rng; +} + +PFC::~PFC() +{ + delete B; + delete x; + delete mod; + delete ord; + delete cof; + delete npoints; + delete trace; + delete frob; + mirexit(); +} + +G1 PFC::mult(const G1& w,const Big& k) +{ + G1 z; + if (w.mtable!=NULL) + { // we have precomputed values + Big e=k; + if (k<0) e=-e; + + int i,j,t=w.mtbits; //MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.mtable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g+=z.g; + if (j>0) z.g+=w.mtable[j]; + } + if (k<0) z.g=-z.g; + } + else + { + z.g=w.g; + z.g*=k; + } + return z; +} + +// GLV + Galbraith-Scott + +G2 PFC::mult(const G2& w,const Big& k) +{ + G2 z; + Big X=*x; + if (w.mtable!=NULL) + { // we have precomputed values + Big e=k; + if (k<0) e=-e; + + int i,j,t=w.mtbits; //MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.mtable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g+=z.g; + if (j>0) z.g+=w.mtable[j]; + } + if (k<0) z.g=-z.g; + } + else + { + ECn3 v=w.g; + q_power_frobenius(v,*frob); + z.g=mul(v,k/X,w.g,k%X); + } + return z; +} + +// GLV method + Galbraith-Scott idea + +GT PFC::power(const GT& w,const Big& k) +{ + GT z; + Big X=*x; + if (w.etable!=NULL) + { // precomputation is available + Big e=k; + if (k<0) e=-e; + + int i,j,t=w.etbits; //MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.etable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g*=z.g; + if (j>0) z.g*=w.etable[j]; + } + if (k<0) z.g=inverse(z.g); + } + else + { + ZZn6 y=w.g; + y.powq(*frob); + z.g=powu(y,k/X,w.g,k%X); + } + return z; +} + +// Use Scott et al. idea - http://eprint.iacr.org/2008/530.pdf +// Map to point of correct order + +void map(ECn3 &S,Big x, ZZn2& X) +{ // S=Phi(2xP)+phi^2(2xP) + ZZn6 X1,X2,Y1,Y2; + ZZn3 Sx,Sy,T; + ECn3 S2; + int qnr=get_mip()->cnr; + + S*=x; S+=S; // hard work done here + + S.get(Sx,Sy); + + // untwist + Sx=Sx/qnr; + Sy=tx(Sy); + Sy=Sy/(qnr*qnr); + + X1=shuffle(Sx,(ZZn3)0); Y1=shuffle((ZZn3)0,Sy); + X1.powq(X); Y1.powq(X); + X2=X1; Y2=Y1; + X2.powq(X); Y2.powq(X); + unshuffle(X1,Sx,T); unshuffle(Y1,T,Sy); + + // twist + Sx=qnr*Sx; + Sy=txd(Sy*qnr*qnr); + S.set(Sx,Sy); + unshuffle(X2,Sx,T); unshuffle(Y2,T,Sy); + + //twist (again, like we did last summer...) + Sx=qnr*Sx; + Sy=txd(Sy*qnr*qnr); + S2.set(Sx,Sy); + S+=S2; +} + +// random group element + +void PFC::random(Big& w) +{ + if (RNG==NULL) w=rand(*ord); + else w=strong_rand(RNG,*ord); +} + +// random AES key + +void PFC::rankey(Big& k) +{ + if (RNG==NULL) k=rand(S,2); + else k=strong_rand(RNG,S,2); +} + +void PFC::hash_and_map(G2& w,char *ID) +{ + int i; + ZZn3 XX; + Big X=*x; + + Big x0=H1(ID); + forever + { + x0+=1; + XX.set2((ZZn)x0); + if (!w.g.set(XX)) continue; + + break; + } + map(w.g,X,*frob); +} + +void PFC::random(G2& w) +{ + int i; + ZZn3 XX; + Big X=*x; + Big x0; + + if (RNG==NULL) x0=rand(*mod); + else x0=strong_rand(RNG,*mod); + forever + { + x0+=1; + XX.set2((ZZn)x0); + if (!w.g.set(XX)) continue; + + break; + } + map(w.g,X,*frob); +} + +void PFC::hash_and_map(G1& w,char *ID) +{ + Big x0=H1(ID); + while (!w.g.set(x0,x0)) x0+=1; +} + +void PFC::random(G1& w) +{ + Big x0; + if (RNG==NULL) x0=rand(*mod); + else x0=strong_rand(RNG,*mod); + + while (!w.g.set(x0,x0)) x0+=1; +} + +Big PFC::hash_to_aes_key(const GT& w) +{ + Big m=pow((Big)2,S); + return H2(w.g)%m; +} + +Big PFC::hash_to_group(char *ID) +{ + Big m=H1(ID); + return m%(*ord); +} + +GT operator*(const GT& x,const GT& y) +{ + GT z=x; + z.g*=y.g; + return z; +} + +GT operator/(const GT& x,const GT& y) +{ + GT z=x; + z.g/=y.g; + return z; +} + +// +// spill precomputation on GT to byte array +// + +int GT::spill(char *& bytes) +{ + int i,j,n=(1<nib-1); + int len=n*6*bytes_per_big+1; + ZZn2 a,b,c; + Big x,y; + + if (etable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*6*bytes_per_big; + ZZn2 a,b,c; + Big x,y; + if (etable!=NULL) return; + + etable=new ZZn6[1<nib-1); + int len=n*2*bytes_per_big+1; + Big x,y; + + if (mtable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*2*bytes_per_big; + Big x,y; + if (mtable!=NULL) return; + + mtable=new ECn[1<nib-1); + int len=n*6*bytes_per_big+1; + ZZn3 x,y; + ZZn a,b,c; + + if (mtable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*6*bytes_per_big; + ZZn3 x,y; + ZZn a,b,c; + if (mtable!=NULL) return; + + mtable=new ECn3[1<. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * pairing_1.h + * + * High level interface to pairing functions - Type 1 pairings + * + * GT=pairing(G1,G1) + * + * This is calculated on a Pairing Friendly Curve (PFC), which must first be defined. + * + * G1 is a point over the base field + * GT is a finite field point over the k-th extension, where k is the embedding degree. + */ + +#ifndef PAIRING_1_H +#define PAIRING_1_H + +// k=2 Super-Singular curve over GF(P) +#ifdef MR_PAIRING_SSP +#include "zzn2.h" // GT +#include "ecn.h" // G1 +#define G1_TYPE ECn +#define G1_SUBTYPE ZZn +#define GT_TYPE ZZn2 +#define WINDOW_SIZE 8 // window size for precomputation +extern void read_only_error(void); +#endif + +// k=4 Super-Singular curve over GF(2^M) +#ifdef MR_PAIRING_SS2 +#include "gf2m4x.h" // GT +#include "ec2.h" // G1 +#define G1_TYPE EC2 +#define GT_TYPE GF2m4x +#endif + +class PFC; + +class G1 +{ +public: + G1_TYPE g; + +#ifdef MR_PAIRING_SSP + G1_SUBTYPE *ptable; + G1_TYPE *mtable; + int mtbits; + + G1() {mtable=NULL; mtbits=0; ptable=NULL;} + G1(const G1& w) {mtable=NULL; mtbits=0; ptable=NULL; g=w.g;} + + G1& operator=(const G1& w) + { + if (mtable==NULL && ptable==NULL) g=w.g; + else read_only_error(); + return *this; + } + +#else + G1() {} + G1(const G1& w) {g=w.g;} + + G1& operator=(const G1& w) + { + g=w.g; + return *this; + } +#endif + int spill(char *&); // spill precomputation to byte array, and return length + void restore(char *); // restore precomputation from byte array + + friend G1 operator-(const G1&); + friend G1 operator+(const G1&,const G1&); + friend BOOL operator==(const G1& x,const G1& y) + {if (x.g==y.g) return TRUE; else return FALSE;} + friend BOOL operator!=(const G1& x,const G1& y) + {if (x.g!=y.g) return TRUE; else return FALSE;} + +#ifdef MR_PAIRING_SSP + ~G1() {if (ptable!=NULL) {delete [] ptable; ptable=NULL;} + if (mtable!=NULL) {delete [] mtable; mtable=NULL;}} +#else + ~G1() {} +#endif +}; + +class GT +{ +public: + GT_TYPE g; + +#ifdef MR_PAIRING_SSP + GT_TYPE *etable; + int etbits; + GT() {etable=NULL; etbits=0;} + GT(const GT& w) {etable=NULL; etbits=0; g=w.g;} + GT(int d) {etable=NULL; g=d;} + + GT& operator=(const GT& w) + { + if (etable==NULL) g=w.g; + else read_only_error(); + return *this; + } +#else + GT() {} + GT(const GT& w) {g=w.g;} + GT(int d) {g=d;} + + GT& operator=(const GT& w) + { + g=w.g; + return *this; + } +#endif + int spill(char *&); // spill precomputation to byte array, and return length + void restore(char *); // restore precomputation from byte array + friend GT operator*(const GT&,const GT&); + friend GT operator/(const GT&,const GT&); + friend BOOL operator==(const GT& x,const GT& y) + {if (x.g==y.g) return TRUE; else return FALSE;} + friend BOOL operator!=(const GT& x,const GT& y) + {if (x.g!=y.g) return TRUE; else return FALSE;} +#ifdef MR_PAIRING_SSP + ~GT() {if (etable!=NULL) {delete [] etable; etable=NULL;}} +#else + ~GT() {} +#endif +}; + +// pairing friendly curve class + +class PFC +{ +#ifdef MR_PAIRING_SSP +public: + Big *mod; + Big *cof; +#else + int B; +public: + int M; + int CF; +#endif + int S; + Big *ord; + sha256 SH; +#ifndef MR_NO_RAND + csprng *RNG; +#endif + + PFC(int, csprng *rng=NULL); + Big order(void) {return *ord;} + + GT power(const GT&,const Big&); + G1 mult(const G1&,const Big&); + void hash_and_map(G1&,char *); + void random(Big&); + void rankey(Big&); + void random(G1&); + BOOL member(const GT&); // test if element is member of pairing friendly group + + int precomp_for_pairing(G1&); // precompute multiples of G1 that occur in Miller loop + int precomp_for_mult(G1&,BOOL small=FALSE); // (precomputation may not be implemented!) + int precomp_for_power(GT&,BOOL small=FALSE); // returns number of precomputed values +// small=TRUE if exponent is always less than full group size and equal to 2*Security level +// creates a smaller table + + int spill(G1&,char *&); + void restore(char *,G1&); + + Big hash_to_aes_key(const GT&); + Big hash_to_group(char *); + GT miller_loop(const G1&,const G1&); + GT final_exp(const GT&); + GT pairing(const G1&,const G1&); +// parameters: number of pairings n, pointers to pair of G1 elements + GT multi_pairing(int n,G1 **,G1 **); //product of pairings + GT multi_miller(int n,G1 **,G1 **); + void start_hash(void); + void add_to_hash(const G1&); + void add_to_hash(const GT&); + void add_to_hash(const Big&); + Big finish_hash_to_group(void); + ~PFC() { +#ifdef MR_PAIRING_SSP + delete mod; delete cof; +#endif + delete ord; mirexit(); } +}; + +#ifdef MR_PAIRING_SSP + +#ifndef MR_AFFINE_ONLY + +extern void force(ZZn&,ZZn&,ZZn&,ECn&); +extern void extract(ECn&,ZZn&,ZZn&,ZZn&); + +#endif + +extern void force(ZZn&,ZZn&,ECn&); +extern void extract(ECn&,ZZn&,ZZn&); +#endif + +#endif diff --git a/miracl/source/curve/pairing/pairing_3.h b/miracl/source/curve/pairing/pairing_3.h new file mode 100644 index 0000000..3b4048b --- /dev/null +++ b/miracl/source/curve/pairing/pairing_3.h @@ -0,0 +1,301 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * pairing.h + * + * High level interface to pairing functions - Type 3 pairings + * + * GT=pairing(G2,G1) + * + * This is calculated on a Pairing Friendly Curve (PFC), which must first be defined. + * + * G1 is a point over the base field, and G2 is a point over an extension field. + * GT is a finite field point over the k-th extension, where k is the embedding degree. + */ + +#ifndef PAIRING_3_H +#define PAIRING_3_H + +#include "ecn.h" // G1 + +// K=2 Cocks-Pinch curve +#ifdef MR_PAIRING_CP +#include "zzn2.h" +#define WINDOW_SIZE 8 // window size for precomputation +#define G2_TYPE ECn +#define G2_SUBTYPE ZZn +#define GT_TYPE ZZn2 +#endif + +// k=6 MNT curve +#ifdef MR_PAIRING_MNT +#include "zzn2.h" +#include "ecn3.h" // G2 +#include "zzn6a.h" // GT +#define WINDOW_SIZE 8 // window size for precomputation +#define G2_TYPE ECn3 +#define G2_SUBTYPE ZZn3 +#define GT_TYPE ZZn6 +#define FROB_TYPE ZZn2 +#endif + +//k=12 BN curve +#ifdef MR_PAIRING_BN +#include "zzn2.h" +#include "ecn2.h" // G2 +#include "zzn12a.h" // GT +#define WINDOW_SIZE 8 // window size for precomputation +#define G2_TYPE ECn2 +#define G2_SUBTYPE ZZn2 +#define GT_TYPE ZZn12 +#define FROB_TYPE ZZn2 +#endif + +// k=18 KSS curve +#ifdef MR_PAIRING_KSS +#include "ecn3.h" // G2 +#include "zzn18.h" // GT +#define WINDOW_SIZE 8 // window size for precomputation +#define G2_TYPE ECn3 +#define G2_SUBTYPE ZZn3 +#define GT_TYPE ZZn18 +#define FROB_TYPE ZZn +#endif + +// k=24 BLS curve +#ifdef MR_PAIRING_BLS +#include "ecn4.h" // G2 +#include "zzn24.h" // GT +#define WINDOW_SIZE 8 // window size for precomputation +#define G2_TYPE ECn4 +#define G2_SUBTYPE ZZn4 +#define GT_TYPE ZZn24 +#define FROB_TYPE ZZn2 +#endif + +class PFC; +extern void read_only_error(void); + +// Multiples of G1 may be precomputed. If it is, the instance becomes read-only. +// Read-only instances cannot be written to - causes an error and exits +// Precomputation for pairing calculation only possible for G2 for ate pairing + +class G1 +{ +public: + ECn g; + + ECn *mtable; // pointer to values precomputed for multiplication + + int mtbits; + G1() {mtable=NULL; mtbits=0;} + G1(const G1& w) {mtable=NULL; mtbits=0; g=w.g;} + + G1& operator=(const G1& w) + { + if (mtable==NULL) g=w.g; + else read_only_error(); + return *this; + } + int spill(char *&); + void restore(char *); + friend G1 operator-(const G1&); + friend G1 operator+(const G1&,const G1&); + friend BOOL operator==(const G1& x,const G1& y) + {if (x.g==y.g) return TRUE; else return FALSE; } + friend BOOL operator!=(const G1& x,const G1& y) + {if (x.g!=y.g) return TRUE; else return FALSE; } + ~G1() {if (mtable!=NULL) {delete [] mtable; mtable=NULL;}} +}; + +// +// This is just a G2_TYPE. But we want to restrict the ways in which it can be used. +// We want the instances to always be of an order compatible with the PFC +// + +class G2 +{ +public: + G2_TYPE g; + + G2_SUBTYPE *ptable; // pointer to values precomputed for pairing + G2_TYPE *mtable; // pointer to values precomputed for multiplication + int mtbits; + + G2() {ptable=NULL; mtable=NULL; mtbits=0;} + G2(const G2& w) {ptable=NULL; mtable=NULL; mtbits=0; g=w.g;} + G2& operator=(const G2& w) + { + if (ptable==NULL && mtable==NULL) g=w.g; + else read_only_error(); + return *this; + } + int spill(char *&); + void restore(char *); + + friend G2 operator-(const G2&); + friend G2 operator+(const G2&,const G2&); + friend BOOL operator==(G2& x,G2& y) + {if (x.g==y.g) return TRUE; else return FALSE; } + friend BOOL operator!=(G2& x,G2& y) + {if (x.g!=y.g) return TRUE; else return FALSE; } + + ~G2() {if (ptable!=NULL) {delete [] ptable; ptable=NULL;} + if (mtable!=NULL) {delete [] mtable; mtable=NULL;}} +}; + +class GT +{ +public: + GT_TYPE g; + + GT_TYPE *etable; + int etbits; + + GT() {etable=NULL; etbits=0;} + GT(const GT& w) {etable=NULL; etbits=0; g=w.g;} + GT(int d) {etable=NULL; etbits=0; g=d;} + + GT& operator=(const GT& w) + { + if (etable==NULL) g=w.g; + else read_only_error(); + return *this; + } + int spill(char *&); + void restore(char *); + friend GT operator*(const GT&,const GT&); + friend GT operator/(const GT&,const GT&); + friend BOOL operator==(const GT& x,const GT& y) + {if (x.g==y.g) return TRUE; else return FALSE; } + friend BOOL operator!=(const GT& x,const GT& y) + {if (x.g!=y.g) return TRUE; else return FALSE; } + ~GT() {if (etable!=NULL) {delete [] etable; etable=NULL;}} +}; + +// pairing friendly curve class + +class PFC +{ +public: + Big *B; // y^2=x^3+Ax+B. This is B + Big *x; // curve parameter + Big *mod; + Big *ord; + Big *cof; + Big *npoints; + Big *trace; + +#ifdef MR_PAIRING_BN + Big *BB[4][4],*WB[4],*SB[2][2],*W[2]; + ZZn *Beta; +#endif +#ifdef MR_PAIRING_KSS + Big *BB[6][6],*WB[6],*SB[2][2],*W[2]; + ZZn *Beta; +#endif +#ifdef MR_PAIRING_BLS + ZZn *Beta; +#endif +#ifdef FROB_TYPE + FROB_TYPE *frob; // Frobenius constant +#endif + + int S; +#ifdef MR_PAIRING_MNT + sha SH; +#else + sha256 SH; +#endif + +#ifndef MR_NO_RAND + csprng *RNG; +#endif + + PFC(int, csprng *rng=NULL); + Big order(void) {return *ord;} + GT power(const GT&,const Big&); + G1 mult(const G1&,const Big&); + G2 mult(const G2&,const Big&); + void hash_and_map(G1&,char *); + void hash_and_map(G2&,char *); + void random(Big&); + void rankey(Big&); + void random(G1&); + void random(G2&); + BOOL member(const GT&); // test if element is member of pairing friendly group + + int precomp_for_pairing(G2&); // precompute multiples of G2 that occur in Miller loop + int precomp_for_mult(G1&,BOOL small=FALSE); // precompute multiples of G1 for precomputation + int precomp_for_mult(G2&,BOOL small=FALSE); + int precomp_for_power(GT&,BOOL small=FALSE); // returns number of precomputed values +// small=TRUE if exponent is always less than full group size and equal to 2*Security level +// creates a smaller table + + int spill(G2&,char *&); + void restore(char *,G2&); + + Big hash_to_aes_key(const GT&); + Big hash_to_group(char *); + Big hash_to_group(char *, int); + GT miller_loop(const G2&,const G1&); + GT final_exp(const GT&); + GT pairing(const G2&,const G1&); +// parameters: number of pairings n, pointers to G1 and G2 elements + GT multi_miller(int n,G2 **,G1 **); + GT multi_pairing(int n,G2 **,G1 **); //product of pairings + void start_hash(void); + void add_to_hash(const G1&); + void add_to_hash(const G2&); + void add_to_hash(const GT&); + void add_to_hash(const Big&); + void add_to_hash(char *); + Big finish_hash_to_group(void); + Big finish_hash_to_aes_key(void); + void seed_rng(int s); + ~PFC() ; +}; + +#ifndef MR_AFFINE_ONLY + +extern void force(ZZn&,ZZn&,ZZn&,ECn&); +extern void extract(ECn&,ZZn&,ZZn&,ZZn&); + +#endif + +extern void force(ZZn&,ZZn&,ECn&); +extern void extract(ECn&,ZZn&,ZZn&); + +#endif diff --git a/miracl/source/curve/pairing/pairings.txt b/miracl/source/curve/pairing/pairings.txt new file mode 100644 index 0000000..036cdee --- /dev/null +++ b/miracl/source/curve/pairing/pairings.txt @@ -0,0 +1,296 @@ + +A new High level interface for pairings has now been implemented. +It works with type-1 and type-3 pairings. In the former case it +uses the eta_T pairing (for GF(2^m) and the Tate pairing (for GF(p)), +and in the latter it always uses the optimal ate pairing. It can be +used to implement a pairing-based protocol in almost the same amount +of space it takes to describe it. + +*** NOTE: Pairings over GF(2^m) are effectively broken and should +no longer be used **** + +This is particularly useful for the protocol developer who wants +to test their protocol in a few lines of code, while exploiting +all of the latest optimizations. The timings achieved are realistic +and close to what can be expected from a real implementation. + +Sixteen example programs are supplied, which implement many of the schemes +proposed in the P1363.3 standard. These are all written to use type-3 +pairings + +ake.cpp - Scott's key exchange +bls.cpp - Boneh-Lynn-Shacham short signature +bmc.cpp - Barreto & McCullagh signcryption +blmq.cpp - BLMQ signcryption +daa.cpp - Direct Anonymous Attestation (Brickell & Li) +fuzzy.cpp - Sahai-Waters Fuzzy IBE +peks.cpp - Public Key Encryption with keyword search +sk_3.cpp - Sakai-Kasahara IBE +cpabe.cpp - Waters Attribute Based Cryptography +hibe.cpp - Hierarchical IBE (Lewko-Waters) +ipe.cpp - Inner-product Predicate Encryption + +These last four instead use a type-1 pairing + +sok.cpp - Sakai-Ohgishi-Kasahara non-interactive key exchange +bgw.cpp - Boneh-Gentry-Waters broadcast encryption +sk_1.cpp - Sakai-Kasahara IBE +wang.cpp - Wang interactive key exchange + +The details of the pairing implementation are now hidden away. +The implementor decides on one of 4 levels of security, corresponding +to AES-80, AES-128, AES-192 and AES-256. However currently only the +first two are supported for type-1 pairings. These choices do not affect +the application code, which is written using an intuitive and very +high level interface. + + +Type-1 pairings are implemented on a super-singular curve defined over +GF(2^m) (implementation in ss2_pair.cpp) or a super-singular curve +over GF(p) (implementation is ssp_pair.cpp). The former implements +the eta_T pairing, and the latter the Tate pairing. + +** Note that super-singular curves over GF(2^m) are now considered weak, +and do not provide the expected levels of security. Do not use them. + +Here the pairing is GT=e(G1,G1), where G1 and GT classes are defined in +pairing_1.h + +Note that for type-1 pairings it is almost impossible to get a perfect match +between parameter sizes and security levels. Indeed there is no known +efficient way to get AES-256 security from type-1 pairings on elliptic curves. + +For Type-3 pairings, the ate pairing is always used. Curves are chosen +for optimal match to the required security level. + +AES-80 security uses an MNT k=6 curve +(implementation in mnt_pair.cpp) + +AES-128 security uses a BN k=12 curve +(implementation in bn_pair.cpp) + +AES-192 security uses a KSS k=18 curve +(implementation in kss_pair.cpp) + +AES-256 security uses a BLS k=24 curve +(implementation in bls_pair.cpp) + +For the ate pairing GT=e(G2,G1), where G1, G2 and GT classes are defined +in pairing_3.h + +All known optimizations are used for the pairing itself and +manipulation of instances of G1, G2 and GT. + +Precomputation optimizations are fully supported for type-3 pairings. +Precomputation is of much less benefit for type-1 pairings over GF(2^m) +When a point instance is precomputed on, it becomes read-only. + +If an element of G1, G2 or GT is fixed, then it can be +precomputed on, using pfc.precomp_for_mult() for G1 and G2 +and pfc.precomp_for_power() for GT + +If an element of G2 is fixed, and it appears in the context +of e(G2,.), then precomputation can greatly speed up the +calculation of the pairing. For this use pfc.precomp_for_pairing(). +In general the first parameter to the pairing can be pre-computed +on. This also applies to type-1 pairings over GF(p). + +Fast techniques for products of pairings are also supported - see +pfc.multi_pairing() + +For arithmetic in Zr, the pairing friendly group of order r, use +the Big functions modmult(x,y,r) (returns x*y mod r), moddiv(x,y,r) +and inverse(x,r) to avoid overflow. + +To print out an instance of G1, G2 or GT, then simply print the instance's +member g. So if W is an instance of GT, cout << W.g << endl; Note that +the g member is public (C++ purists will kill me!) and all available +MIRACL methods can be applied to it. + +Please examine the example programs to see how it works, and +to fully appreciate how easy it is to use. + +NEW FEATURE + +It is now possible to spill and restore precomputed values to a +byte array. See members spill() and restore() in G1, G2 and GT +definitions. Also G2 precomputation for the pairing can be spilled +and restored via member functions of class PFC. + +For example:- + +pfc.precomp_for_mult(Q); // precomputation based on fixed point Q +char *bytes; +int len=Q.spill(bytes); // allocates byte array of length len +.. // ..and spills precomputation into it +Q.restore(bytes); // restores Q from byte array (and deletes array) + + +Note that all MIRACL library optimizations can be used for further +speed-up. In particular COMBA builds of the library will be much faster. +Also compilation with the flag /DZZNS=n, where n is the value of +the variable words calculated in the PFC() constructor will also be faster. +Use /DGF2MS=n for supersingular curves over GF(2^m) + +Which is best, type-1 or type-3? + +This is a bit complicated. Most protocol designers specify their protocols +on a type-1 pairing, because its less complicated, because they are lazy, +and because the security reduction is to a "more natural" security assumption. +However type-3 pairings are much more efficient in practise. + +Some protocols require a type-1 or a type-3 pairing to work properly as +originally described, but many can work equally well on both. +Some protocols like BLMQ signcryption work easily on a type-1 pairing, +but need to be changed significantly to work correctly on a type-3 pairing. +In some cases its quite hard to tell if a protocol will work on a type-3 +pairing. Often the security proof would have to be changed. + +For more discussion, see http://eprint.iacr.org/2010/388 and the papers +referenced there. + + +-------------------------------------------------------- + +MIRACL contains several optimized implementations of pairings over various +fields. + +*** Legacy pairings stuff here + +The fastest pairing code over F_p can be found in the files ake2cpt.cpp and +ake2sst.cpp, which implements a simple key exchange protocol, using non- +supersingular and supersingular curves respectively. +This uses an embedding degree of k=2, so the pairing e(P,Q) evaluates +naturally as an element in F_p^2. P is a point on the elliptic curve E(Fp) and +Q is a point on E'(F_p^{k/2}), or in this case E'(F_p) where E' is the twisted +curve. Using compression the pairing evaluates as an element in F_p^{k/2}, or +just Fp in this case. + +For higher levels of security it is recommended to increase the embedding +degree and use non-supersingular curves - see ake4cpt.cpp and ake8cpt.cpp for +examples. We use a "tower of extensions" to build an Fp^4 class on top of an +Fp^2 class - see zzn2.h and zzn4.h + +Recommendations: + +For AES-80 security see ake6mntx.cpp +For AES-128 security see ake12bnx.cpp +For AES-192 security see ake18kssx.cpp +For AES-256 security see ake24blsa.cpp + +The pairing-relevant files.. + +DL.CPP - This implements the eta pairing on supersingular curves over +F_{2^m} + +DL2.CPP - This implements the eta_T pairing over F_{2^m}. This is possibly +the fastest known pairing. See Barreto, Galbraith, O'hEigeartaigh and Scott +- http://eprint.iacr.org/2004/375 + +etat271.c - A C version of the above - particularly useful for constrained + environments. A good example program for embedded implementations + +BANDW.CPP - This is actually an NTL program (!) which finds Brezing & Weng +pairing friendly curves. + +MNT.CPP - Finds MNT non-supersingular pairing-friendly curves for k=3,4 or 6 + +FREEMAN.CPP - Finds k=10 ideal pairing-friendly curves + +FOLKLORE.CPP - Finds pairing friendly curves using Cocks-Pinch method. + +FINDBASE.CPP - Finds suitable basis for F_{2^m} fields + +IRRED.CPP - Finds a suitable irreducible polynomial for Fp^n + +WEIL.CPP - Finds the number of points on E(F_p^k) + +CM.CPP - Finds elliptic curve parameters using the method of Complex +Multiplication + +Note the name AKE2CPT means AKE protocol, on a K=2 curve. The curve is found +by the Cocks-Pinch Method, and it implements the Tate pairing. + +AKE1KMT.CPP - Implements Authenticated Key Exchange using k=1 non-supersingular curve, using an efficient endomorphism + +AKE2CPT.CPP - Implements Authenticated Key Exchange using k=2 non-supersingular curve + +AKE2SST.CPP - Implements Authenticated Key Exchange using k=2 supersingular curve + +AKE2CPT2.CPP - Implements Authenticated Key Exchange using Trace map homomorphism + +AKE4CPT.CPP - Implements AKE using Cocks-Pinch k=4 curve + +AKE6MNTT.CPP - Implements AKE using MNT k=6 curve, DL 1024-bit security, 1-3-6 tower + +AKE6MNTX.CPP - Implements AKE using MNT k=6 curve, DL 1024-bit security, and a "compositum" tower (1-3-6 and 1-2-6) + +AKE6MNTA.CPP - Implements AKE using MNT k=6 curve, DL 1024-bit security, and a "compositum" tower (1-3-6 and 1-2-6) + +AKE6MNTT.C - A partial C implementation of ake6mntt.cpp - particularly useful for constrained + environments. A good example program for embedded implementations + +AKE4MNTT.CPP - Implements AKE using MNT k=4 curve, Tate pairing, DL 640-bit security. + +AKE4MNTT.C - A partial C implementation of the above + +AKE4MNTA.CPP - Implements AKE using MNT k=4 curve, Ate pairing, DL 640-bit security. + +AKE4MNTA.C - A partial C implementation of the above + +AKE6FSTA.CPP - Implements AKE using sextic twist on a D=3, k=6 curve, using Ate pairing. + +AKE2NSST.CPP - Faster pairings on a curve with an efficient endomorphism - see + Scott Indocrypt 2005 + +AKE2CPW.CPP - Uses a modified and optimized version of the Weil pairing + +BN.CPP - Program to find suitable BN curves - see below + +AKE12BNE.CPP - Implements AKE using Eta pairing on BN curves (k=12) 1-2-6-12 tower of extensions + +AKE12BNA.CPP - Implements AKE using Ate pairing on BN curves (k=12) 1-2-6-12 tower of extensions + +AKE12BNR.CPP - Implements AKE using R-ate pairing on BN curves (k=12) 1-2-6-12 tower of extensions + +AKE12BNX.CPP - Implements AKE using R-ate pairing on BN curves (k=12) 1-2-4-12 tower of extensions (NEW - fastest!) + +AKE12BLSA.CPP - Implements AKE using Ate pairing on a k=12, rho=1.5 Barreto-Lynn-Scott curve + +KSS18.CPP - Program to find suitable KSS k=18 curves - see below + +AKE18KSSX.CPP - Implements AKE using R-ate pairing on a k=18, rho=4/3 Kachisa-Schaefer-Scott curve + +BLS24.CPP - Program to find suitable BLS k=12 curves - see below + +AKE24BLSA.CPP - Implements AKE using ate pairing on a k=24, rho=5/4 Barreto-Lynn-Scott curve + +The Boneh-Lynn-Shachem short signature scheme + +BLS_GEN.CPP - Generate the public and private parameters from an MNT curve + +BLS_SIGN.CPP - create a BLS short signature + +BLS_VER.CPP - verify a BLS short signature + +These example programs use the power-pairing idea, which calculates +E(P,Q,e) = e(P,Q)^e at no (significant) extra cost. See comments in programs. + +AKE8BWT.CPP - Implements the AKE using a low-rho Brezing & Weng k=8 curve. + +AKE4SBT.CPP - Implements AKE using a low-rho k=4 curve. + +AKE8CPT.CPP - Implements AKE using a Cocks-Pinch k=8 curve + +AKE4FSTA.CPP - Implements AKE using ATE pairing - see The Eta Pairing Revisited by Hess, Smart, Vercauteren + + +For more details on the evolution and implementation of these pairing algorithms, see +ftp://ftp.computing.dcu.ie/pub/crypto/pairings.pdf + +See also + +ftp://ftp.computing.dcu.ie/pub/crypto/twists.pdf + +---------------------------------------------------------- + diff --git a/miracl/source/curve/pairing/peks.cpp b/miracl/source/curve/pairing/peks.cpp new file mode 100644 index 0000000..b825525 --- /dev/null +++ b/miracl/source/curve/pairing/peks.cpp @@ -0,0 +1,93 @@ +/* + Boneh, Di Crescenzo, Ostrovsky & Persiano + Public Key Encryption with keyword Search + + See http://eprint.iacr.org/2003/195.pdf + Section 3.1 + + (From reading the protocol to a working implementation - 10 minutes!) + + Compile with modules as specified below + + For MR_PAIRING_CP curve + cl /O2 /GX peks.cpp cp_pair.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_MNT curve + cl /O2 /GX peks.cpp mnt_pair.cpp zzn6a.cpp ecn3.cpp zzn3.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_BN curve + cl /O2 /GX peks.cpp bn_pair.cpp zzn12a.cpp ecn2.cpp zzn4.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_KSS curve + cl /O2 /GX peks.cpp kss_pair.cpp zzn18.cpp zzn6.cpp ecn3.cpp zzn3.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_BLS curve + cl /O2 /GX peks.cpp bls_pair.cpp zzn24.cpp zzn8.cpp zzn4.cpp zzn2.cpp ecn4.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + Test program +*/ + +#include +#include + +//********* choose just one of these pairs ********** +//#define MR_PAIRING_CP // AES-80 security +//#define AES_SECURITY 80 + +//#define MR_PAIRING_MNT // AES-80 security +//#define AES_SECURITY 80 + +#define MR_PAIRING_BN // AES-128 or AES-192 security +#define AES_SECURITY 128 +//#define AES_SECURITY 192 + +//#define MR_PAIRING_KSS // AES-192 security +//#define AES_SECURITY 192 + +//#define MR_PAIRING_BLS // AES-256 security +//#define AES_SECURITY 256 +//********************************************* + +#include "pairing_3.h" + +int main() +{ + PFC pfc(AES_SECURITY); // initialise pairing-friendly curve + + time_t seed; + time(&seed); + irand((long)seed); + + G1 g,h,PA; + Big alpha,r,PB; + GT t; + G2 HW,TW; + +// keygen + + pfc.random(g); + pfc.precomp_for_mult(g); // precompute on fixed g + pfc.random(alpha); // private key + h=pfc.mult(g,alpha); // public key + pfc.precomp_for_mult(h); + +// PEKS + pfc.random(r); + pfc.hash_and_map(HW,(char *)"test"); + t=pfc.pairing(HW,pfc.mult(h,r)); + PA=pfc.mult(g,r); + PB=pfc.hash_to_aes_key(t); // [PA,PB] added to ciphertext + +// Trapdoor + + pfc.hash_and_map(HW,(char *)"test"); // key word we are looking for + TW=pfc.mult(HW,alpha); + pfc.precomp_for_pairing(TW); + +// Test + if (pfc.hash_to_aes_key(pfc.pairing(TW,PA))==PB) + cout << "yes" << endl; + else cout << "no" << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/sf2m12x.cpp b/miracl/source/curve/pairing/sf2m12x.cpp new file mode 100644 index 0000000..927ecbe --- /dev/null +++ b/miracl/source/curve/pairing/sf2m12x.cpp @@ -0,0 +1,238 @@ +/* + * MIRACL C++ Implementation file SF2m12x.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class SF2m12x (special 12-th extension over 2^m) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#include "sf2m12x.h" + +using namespace std; + +void SF2m12x::get(GF2m6x& a,GF2m6x& b) +{a=U; b=V;} + +SF2m12x& SF2m12x::powq() +{ + int r=(get_mip())->M%12; + U.powq(); + V.powq(); + if (r==0) return *this; + + GF2m6x S(0,0,0,1,0,1),T=0; + // x^3 + x^5 + if (r==7) + { // which it is for M=103! + T.set(1,0,0,1,0,1); + U+=(T*V); + return *this; + } + + for (int i=0;i=FM;i--) + { // reduce mod x^FM+x^FA+x^FB+x^FC+1 + m=t[i]; t[i]=0; + t[i-FM]+=m; + t[i-(FM-FA)]+=m; +#ifdef FB + t[i-(FM-FB)]+=m; + t[i-(FM-FC)]+=m; +#endif + } + for (i=0;i1) for (i=nb-2;i>=0;) + { + n=window(k,i,&nbw,&nzs,5); + for (j=0;j0) u*=t[n/2]; + i-=nbw; + if (nzs) + { + for (j=0;j +#include "gf2m6x.h" + +class SF2m12x +{ + GF2m6x U,V; +public: + SF2m12x() {} + SF2m12x(const SF2m12x & b) {U=b.U; V=b.V; } + SF2m12x(const GF2m6x& b) {U=b;} + SF2m12x(int i) {U=i;} + SF2m12x(const GF2m& a,const GF2m& b, const GF2m& c=0, const GF2m& d=0, const GF2m& e=0, const GF2m& f=0, + const GF2m& g=0, const GF2m& h=0, const GF2m& i=0, const GF2m& j=0, const GF2m& k=0, const GF2m& l=0) + {U.set(a,b,c,d,e,f); V.set(g,h,i,j,k,l);} + SF2m12x(const Big& a) {U=(GF2m)a;} + + void set(const GF2m& a) {U=a; V=0;} + void set(const GF2m6x& a,const GF2m6x& b=(GF2m6x)0) {U=a; V=b;} + void set(const GF2m& a,const GF2m& b=0, const GF2m& c=0, const GF2m& d=0, const GF2m& e=0, const GF2m& f=0, + const GF2m& g=0, const GF2m& h=0, const GF2m& i=0, const GF2m& j=0, const GF2m& k=0, const GF2m& l=0) + {U.set(a,b,c,d,e,f); V.set(g,h,i,j,k,l);} + + void invert(); + + void get(GF2m6x&,GF2m6x&); + void clear() {U=V=0;} + + BOOL iszero() const + {if (U.iszero() && V.iszero()) return TRUE; return FALSE; } + + BOOL isunity() const + {if (U.isunity() && V.iszero()) return TRUE; return FALSE; } + + SF2m12x& powq(); + SF2m12x& conj(); + + SF2m12x& operator=(const SF2m12x& b) + { U=b.U; V=b.V; return *this; } + SF2m12x& operator=(const GF2m& b) + { U=b; V=0; return *this; } + SF2m12x& operator=(int b) + { U=b; V=0; return *this; } + SF2m12x& operator+=(const SF2m12x& b) + { U+=b.U; V+=b.V; return *this; } + SF2m12x& operator+=(const GF2m& b) + {U+=b; return *this; } + SF2m12x& operator*=(const SF2m12x&); + SF2m12x& operator*=(const GF2m&); + SF2m12x& operator/=(const SF2m12x&); + SF2m12x& operator/=(const GF2m&); + + friend SF2m12x operator+(const SF2m12x&,const SF2m12x&); + friend SF2m12x operator+(const SF2m12x&,const GF2m&); + friend SF2m12x operator+(const GF2m&,const SF2m12x&); + + friend SF2m12x operator*(const SF2m12x&,const SF2m12x&); + friend SF2m12x operator*(const SF2m12x&,const GF2m&); + friend SF2m12x operator*(const GF2m&,const SF2m12x&); + friend SF2m12x operator/(const SF2m12x&,const SF2m12x&); + friend SF2m12x mul(const SF2m12x&,const SF2m12x&); + friend SF2m12x mull(const SF2m12x&,const SF2m12x&); + + friend BOOL operator==(const SF2m12x& a,const SF2m12x& b) + {if (a.U==b.U && a.V==b.V) return TRUE; return FALSE;} + + friend BOOL operator!=(const SF2m12x& a,const SF2m12x& b) + {if (a.U!=b.U || a.V==b.V) return TRUE; return FALSE; } + + friend SF2m12x pow(const SF2m12x&,const Big&); + + friend SF2m12x randx12(void); + + friend ostream& operator<<(ostream&,const SF2m12x&); + + ~SF2m12x() {} ; +}; + +extern SF2m12x randx12(void); + +#endif + diff --git a/miracl/source/curve/pairing/sk_1.cpp b/miracl/source/curve/pairing/sk_1.cpp new file mode 100644 index 0000000..439c8b4 --- /dev/null +++ b/miracl/source/curve/pairing/sk_1.cpp @@ -0,0 +1,97 @@ +/* + Sakai & Kasahara IBE key establishment + using type 1 pairing. See P1363.3 + + Compile with modules as specified below + + For MR_PAIRING_SS2 curves + cl /O2 /GX sk_1.cpp ss2_pair.cpp ec2.cpp gf2m4x.cpp gf2m.cpp big.cpp miracl.lib + + For MR_PAIRING_SSP curves + cl /O2 /GX sk_1.cpp ssp_pair.cpp ecn.cpp zzn2.cpp zzn.cpp big.cpp miracl.lib + + Very Simple Test program +*/ + +#include +#include + +//********* CHOOSE JUST ONE OF THESE ********** +#define MR_PAIRING_SS2 // AES-80 or AES-128 security GF(2^m) curve +//#define AES_SECURITY 80 // OR +#define AES_SECURITY 128 + +//#define MR_PAIRING_SSP // AES-80 or AES-128 security GF(p) curve +//#define AES_SECURITY 80 // OR +//#define AES_SECURITY 128 +//********************************************* + +#include "pairing_1.h" + +int main() +{ + PFC pfc(AES_SECURITY); // initialise pairing-friendly curve + Big q=pfc.order(); + + Big z,b,SSV,r,H,t; + G1 P,Z,KB,R; + GT g; + time_t seed; + + time(&seed); + irand((long)seed); + +// setup + pfc.random(P); + g=pfc.pairing(P,P); + pfc.precomp_for_power(g); + pfc.random(z); + pfc.precomp_for_mult(P); + Z=pfc.mult(P,z); + +// extract private key for Robert + b=pfc.hash_to_group((char *)"Robert"); + KB=pfc.mult(P,inverse(b+z,q)); + +// verify private key + + pfc.precomp_for_pairing(KB); // Bob can precompute on his own private key + if (pfc.pairing(KB,pfc.mult(P,b)+Z)!=g) + { + cout << "Bad private key" << endl; + exit(0); + } + + char *bytes; + int len=pfc.spill(KB,bytes); // demo - spill precomputation to byte array + +// Send session key to Bob + cout << "All set to go.." << endl; + pfc.rankey(SSV); // random AES key + pfc.start_hash(); + pfc.add_to_hash(SSV); + pfc.add_to_hash(b); + r=pfc.finish_hash_to_group(); + + R=pfc.mult(pfc.mult(P,b)+Z,r); + t=pfc.hash_to_aes_key(pfc.power(g,r)); + H=lxor(SSV,t); + cout << "Encryption key= " << SSV << endl; + +// Receiver + pfc.restore(bytes,KB); // restore precomputation for KB from byte array + + t=pfc.hash_to_aes_key(pfc.pairing(KB,R)); + SSV=lxor(H,t); + pfc.start_hash(); + pfc.add_to_hash(SSV); + pfc.add_to_hash(b); + r=pfc.finish_hash_to_group(); + + if (pfc.mult(pfc.mult(P,b)+Z,r)==R) + cout << "Decryption key= " << SSV << endl; + else + cout << "The key is BAD - do not use!" << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/sk_3.cpp b/miracl/source/curve/pairing/sk_3.cpp new file mode 100644 index 0000000..9673991 --- /dev/null +++ b/miracl/source/curve/pairing/sk_3.cpp @@ -0,0 +1,116 @@ +/* + Sakai & Kasahara IBE key establishment + using type 3 pairing. See P1363.3 + + Compile with modules as specified below + + For MR_PAIRING_CP curve + cl /O2 /GX sk_3.cpp cp_pair.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_MNT curve + cl /O2 /GX sk_3.cpp mnt_pair.cpp zzn6a.cpp ecn3.cpp zzn3.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_BN curve + cl /O2 /GX sk_3.cpp bn_pair.cpp zzn12a.cpp ecn2.cpp zzn4.cpp zzn2.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_KSS curve + cl /O2 /GX sk_3.cpp kss_pair.cpp zzn18.cpp zzn6.cpp ecn3.cpp zzn3.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + For MR_PAIRING_BLS curve + cl /O2 /GX sk_3.cpp bls_pair.cpp zzn24.cpp zzn8.cpp zzn4.cpp zzn2.cpp ecn4.cpp big.cpp zzn.cpp ecn.cpp miracl.lib + + Very Simple Test program +*/ + +#include +#include + +//********* choose just one of these pairs ********** +//#define MR_PAIRING_CP // AES-80 security +//#define AES_SECURITY 80 + +//#define MR_PAIRING_MNT // AES-80 security +//#define AES_SECURITY 80 + +#define MR_PAIRING_BN // AES-128 or AES-192 security +#define AES_SECURITY 128 +//#define AES_SECURITY 192 + +//#define MR_PAIRING_KSS // AES-192 security +//#define AES_SECURITY 192 + +//#define MR_PAIRING_BLS // AES-256 security +//#define AES_SECURITY 256 +//********************************************* + +#include "pairing_3.h" + +int main() +{ + PFC pfc(AES_SECURITY); // initialise pairing-friendly curve + + Big q=pfc.order(); + + Big z,b,SSV,r,H,t; + G1 P,Z,R; + G2 Q,KB; + GT g,w; + time_t seed; + + time(&seed); + irand((long)seed); + +// setup + pfc.random(P); + pfc.random(Q); + g=pfc.pairing(Q,P); + pfc.precomp_for_power(g); + + pfc.random(z); + pfc.precomp_for_mult(P); + + Z=pfc.mult(P,z); + pfc.precomp_for_mult(Q); + +// extract private key for Robert + b=pfc.hash_to_group((char *)"Robert"); + KB=pfc.mult(Q,inverse(b+z,q)); + +// verify private key + + pfc.precomp_for_pairing(KB); // Bob can precompute on his own private key + if (pfc.pairing(KB,pfc.mult(P,b)+Z)!=g) + { + cout << "Bad private key" << endl; + exit(0); + } + +// Send session key to Bob + cout << "All set to go.." << endl; + + pfc.rankey(SSV); // random AES key + pfc.start_hash(); + pfc.add_to_hash(SSV); + pfc.add_to_hash(b); + r=pfc.finish_hash_to_group(); + + R=pfc.mult(pfc.mult(P,b)+Z,r); + t=pfc.hash_to_aes_key(pfc.power(g,r)); + H=lxor(SSV,t); + cout << "Encryption key= " << SSV << endl; + +// Receiver + + t=pfc.hash_to_aes_key(pfc.pairing(KB,R)); + SSV=lxor(H,t); + pfc.start_hash(); + pfc.add_to_hash(SSV); + pfc.add_to_hash(b); + r=pfc.finish_hash_to_group(); + if (pfc.mult(pfc.mult(P,b)+Z,r)==R) + cout << "Decryption key= " << SSV << endl; + else + cout << "The key is BAD - do not use!" << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/ss2_pair.cpp b/miracl/source/curve/pairing/ss2_pair.cpp new file mode 100644 index 0000000..e7be76e --- /dev/null +++ b/miracl/source/curve/pairing/ss2_pair.cpp @@ -0,0 +1,615 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * ss.cpp + * + * Super-Singular curve, eta_T pairing embedding degree 4 + * + * Provides high level interface to pairing functions + * + * GT=pairing(G1,G1) + * + * This is calculated on a Pairing Friendly Curve (PFC), which must first be defined. + * + * G1 is a point over the base field + * GT is a finite field point over the 4-th extension, where 4 is the embedding degree. + */ + + +#define MR_PAIRING_SS2 +#include "pairing_1.h" + +// Using SHA256 as basic hash algorithm +// +// Hash function +// + +#define HASH_LEN 32 + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h; + char s[HASH_LEN]; + int i,j,M; + sha256 sh; + + shs256_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs256_process(&sh,string[i]); + } + shs256_hash(&sh,s); + M=get_mip()->M; + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (bits(h)>=M) break; + } + while (bits(h)>=M) h/=2; + return h; +} + +// general hash + +void PFC::start_hash(void) +{ + shs256_init(&SH); +} + +Big PFC::finish_hash_to_group(void) +{ + Big hash; + Big o=pow((Big)2,2*S); + char s[HASH_LEN]; + shs256_hash(&SH,s); + hash=from_binary(HASH_LEN,s); + return hash%o; +} + +void PFC::add_to_hash(const GT& x) +{ + int i,m; + GF2m xx[4]; + Big a; + GF2m4x w=x.g; + + w.get(xx[0],xx[1],xx[2],xx[3]); + + for (i=0;i<4;i++) + { + a=(Big)xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } + } +} + +void PFC::add_to_hash(const G1& x) +{ + Big a,X,Y; + int i,m; + x.g.get(X,Y); + a=X; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } + a=Y; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } +} + +void PFC::add_to_hash(const Big& x) +{ + int m; + Big a=x; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } +} + +// random multiplier + +void PFC::random(Big& w) +{ + if (RNG==NULL) w=rand(2*S,2); + else w=strong_rand(RNG,2*S,2); +} + +// random AES key + +void PFC::rankey(Big& k) +{ + if (RNG==NULL) k=rand(S,2); + else k=strong_rand(RNG,S,2); +} + +// Compress and hash a GF2m4x to a big number + +Big H2(GF2m4x x) +{ + sha256 sh; + Big a,hash; + GF2m xx[4]; + char s[HASH_LEN]; + int i,j,m; + + shs256_init(&sh); + x.get(xx[0],xx[1],xx[2],xx[3]); + + for (i=0;i<4;i++) + { + a=xx[i]; + while (a>0) + { + m=a%256; + shs256_process(&sh,m); + a/=256; + } + } + shs256_hash(&sh,s); + hash=from_binary(HASH_LEN,s); + return hash; +} + +// +// Extract ECn point in internal GF2m format +// + +void extract(EC2& A,GF2m& x,GF2m& y) +{ + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +// Does nothing... + +int PFC::precomp_for_pairing(G1& w) +{ + return 0; +} + +// +// eta_T Pairing G1 x G1 -> GT +// +// P is a point of order q in G1. Q is also a point of order q in G1. +// +// Note miller -> miller variable +// Loop unrolled x2 for speed +// + +GT PFC::miller_loop(const G1& PP,const G1& QQ) +{ + GF2m xp,yp,xq,yq,t; + GF2m4x miller,w,u,u0,u1,v,f,res; + EC2 P,Q; + GT mill; + int i,imod4,m=get_mip()->M; + + P=PP.g; Q=QQ.g; + normalise(P); normalise(Q); + extract(P,xp,yp); + extract(Q,xq,yq); + + imod4=((m+1)/2)%4; + if (imod4==1) + { // (X=1) // (Y=0) + t=xp; // 0 (X+1) + f.set(t*(xp+xq+1)+yq+yp+B,t+xq+1,t+xq,0); // 0 (Y) + miller=1; + for (i=0;i<(m-3)/2;i+=2) + { + t=xp+1; xp=sqrt(xp); yp=sqrt(yp); // 1 (X) + u0.set(t*(xp+xq+1)+yp+yq,t+xq+1,t+xq,0); // 1 0 (X) ((X+1)*(xp+1)+Y) + xq*=xq; yq*=yq; + + t=xp+1; xp=sqrt(xp); yp=sqrt(yp); + u1.set(t*(xp+xq+1)+yp+yq,t+xq+1,t+xq,0); + xq*=xq; yq*=yq; + + u=mul(u0,u1); + miller*=u; + } + +// final step + + t=xp+1; xp=sqrt(xp); yp=sqrt(yp); + u.set(t*(xp+xq+1)+yp+yq,t+xq+1,t+xq,0); + miller*=u; + } + + if (imod4==0) + { // (X=0) // (Y=0) + t=xp+1; // 1 (X+1) + f.set(t*(xq+xp+1)+yq+yp+B,t+xq+1,t+xq,0); // 0 (Y) + miller=1; + + for (i=0;i<(m-1)/2;i+=2) + { +// loop is unrolled x 2 + t=xp; xp=sqrt(xp); yp=sqrt(yp); // 0 (X) + u0.set(t*(xp+xq)+yp+yq+xp+1,t+xq+1,t+xq,0); // 0 xp+1 (X) ((X+1)*(xp+1)+Y + xq*=xq; yq*=yq; + + t=xp; xp=sqrt(xp); yp=sqrt(yp); + u1.set(t*(xp+xq)+yp+yq+xp+1,t+xq+1,t+xq,0); + xq*=xq; yq*=yq; + + u=mul(u0,u1); + miller*=u; + } + } + + if (imod4==2) + { // (X=0) // (Y=1) + t=xp+1; // 1 (X+1) + f.set(t*(xq+xp+1)+yq+yp+B+1,t+xq+1,t+xq,0); // 1 (Y) + miller=1; + for (i=0;i<(m-1)/2;i+=2) + { + t=xp; xp=sqrt(xp); yp=sqrt(yp); // 0 (X) + u0.set(t*(xp+xq)+yp+yq+xp,t+xq+1,t+xq,0); // 0 xp+0 (X) ((X+1)*(xp+1)+Y) + xq*=xq; yq*=yq; + t=xp; xp=sqrt(xp); yp=sqrt(yp); + u1.set(t*(xp+xq)+yp+yq+xp,t+xq+1,t+xq,0); + xq*=xq; yq*=yq; + u=mul(u0,u1); + miller*=u; + } + } + + if (imod4==3) + { // (X=1) // (Y=1) + t=xp; // 0 (X+1) + f.set(t*(xq+xp+1)+yq+yp+B+1,t+xq+1,t+xq,0); // 1 (Y) + + miller=1; + for (i=0;i<(m-3)/2;i+=2) + { + t=xp+1; xp=sqrt(xp); yp=sqrt(yp); // 1 (X) + u0.set(t*(xp+xq+1)+yp+yq+1,t+xq+1,t+xq,0); // 1 1 (X) ((X+1)*(xp+1)+Y) + xq*=xq; yq*=yq; + + t=xp+1; xp=sqrt(xp); yp=sqrt(yp); + u1.set(t*(xp+xq+1)+yp+yq+1,t+xq+1,t+xq,0); + xq*=xq; yq*=yq; + + u=mul(u0,u1); + miller*=u; + } +// final step + + t=xp+1; xp=sqrt(xp); yp=sqrt(yp); + u.set(t*(xp+xq+1)+yp+yq+1,t+xq+1,t+xq,0); + miller*=u; + } + + miller*=f; + mill.g=miller; + return mill; +} + +GT PFC::final_exp(const GT& z) +{ + int i,m,TYPE; + GT res; + GF2m4x r,u,v,w,y; +// raising to the power (2^m-2^[m+1)/2]+1)(2^[(m+1)/2]+1)(2^(2m)-1) or (2^m+2^[(m+1)/2]+1)(2^[(m+1)/2]-1)(2^(2m)-1) +// 6 Frobenius, 4 big field muls... + y=z.g; + + if (B==0) + { + if (M%8==1 || M%8==7) TYPE=1; + else TYPE=2; + } + if (B==1) + { + if (M%8==3 || M%8==5) TYPE=1; + else TYPE=2; + } + + u=v=w=y; + for (i=0;i<(M+1)/2;i++) u*=u; + + if (TYPE==1) + { + u.powq(); + w.powq(); + v=w; + w.powq(); + r=w; + w.powq(); + w*=u; + w*=y; + r*=v; + u.powq(); + u.powq(); + r*=u; + } + else + { + u.powq(); + v.powq(); + w=u*v; + v.powq(); + w*=v; + v.powq(); + u.powq(); + u.powq(); + r=v*u; + r*=y; + } + + r/=w; + res.g=r; + return res; +} + +// initialise Pairing Friendly Curve + +PFC::PFC(int s, csprng *rng) +{ + int t,u,v,b,words,mod_bits; + + if (s!=80 && s!=128) + { + cout << "No suitable curve available" << endl; + exit(0); + } + + if (s==80) mod_bits=379; + if (s==128) mod_bits=1223; + + words=(mod_bits/MIRACL)+1; + +#ifdef MR_SIMPLE_BASE + miracl *mip=mirsys((MIRACL/4)*words,16); +#else + miracl *mip=mirsys(words,0); + mip->IOBASE=16; +#endif + + ord=new Big; + + S=s; + M=mod_bits; + if (s==80) + { + t=253; u=251; v=59; B=1; CF=1; + *ord=pow((Big)2,M)+pow((Big)2,(M+1)/2)+1; //TYPE=1 + } + if (s==128) + { + t=255; u=0; v=0; B=0; CF=5; + *ord=pow((Big)2,M)+pow((Big)2,(M+1)/2)+1; //TYPE=1 + } + *ord/=CF; + +#ifdef MR_AFFINE_ONLY + ecurve2(-M,t,u,v,(Big)1,(Big)B,TRUE,MR_AFFINE); +#else + ecurve2(-M,t,u,v,(Big)1,(Big)B,TRUE,MR_PROJECTIVE); +#endif + + RNG=rng; +} + +G1 PFC::mult(const G1& w,const Big& k) +{ + G1 z=w; + z.g*=k; + return z; +} + +GT PFC::power(const GT& w,const Big& k) +{ + GT z; + z.g=powu(w.g,k); + return z; +} + +// Precomputation not used here + +// +// Spill precomputation on pairing to byte array +// + +int PFC::spill(G1& w,char *& bytes) +{ + return 0; +} + +// +// Restore precomputation on pairing to byte array +// + +void PFC::restore(char * bytes,G1& w) +{ +} + +// +// spill precomputation on GT to byte array +// + +int GT::spill(char *& bytes) +{ + return 0; +} + +// +// restore precomputation for GT from byte array +// + +void GT::restore(char *bytes) +{ +} + +// +// spill precomputation on G1 to byte array +// + +int G1::spill(char *& bytes) +{ + return 0; +} + +// +// restore precomputation for G1 from byte array +// + +void G1::restore(char *bytes) +{ +} + +void PFC::hash_and_map(G1& w,char *ID) +{ + Big x0=H1(ID); + while (!w.g.set(x0,x0)) x0+=1; + w.g*=CF; +} + +void PFC::random(G1& w) +{ + Big x0; + if (RNG==NULL) x0=rand(M,2); + else x0=strong_rand(RNG,M,2); + + while (!w.g.set(x0,x0)) x0+=1; + w.g*=CF; +} + +Big PFC::hash_to_aes_key(const GT& w) +{ + Big m=pow((Big)2,S); + return H2(w.g)%m; +} + +// hash to group multiplier + +Big PFC::hash_to_group(char *ID) +{ + Big m=H1(ID); + Big o=pow((Big)2,2*S); + return m%o; +} + +GT operator*(const GT& x,const GT& y) +{ + GT z=x; + z.g*=y.g; + return z; +} + +// elements in GT are unitary + +GT operator/(const GT& x,const GT& y) +{ + GT z=x; + z.g*=conj(y.g); + return z; +} + +G1 operator+(const G1& x,const G1& y) +{ + G1 z=x; + z.g+=y.g; + return z; +} + +G1 operator-(const G1& x) +{ + G1 z=x; + z.g=-z.g; + return z; +} + +// Fast PFC group membership check + +BOOL PFC::member(const GT &z) +{ + GF2m4x w=z.g; + GF2m4x r=z.g; + if (pow(r,CF)==1) return FALSE; + w.powq(); + if (r*w==pow(r,pow((Big)2,(M+1)/2))) return TRUE; + return FALSE; +} + +GT PFC::pairing(const G1& x,const G1& y) +{ + GT z; + z=miller_loop(x,y); + z=final_exp(z); + return z; +} + +GT PFC::multi_pairing(int n,G1 **y,G1 **x) +{ + int i; + GT z=1; + for (i=0;i. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * ssp_pair.cpp + * + * Supersingular curve, Tate pairing embedding degree 2, ideal for security level AES-80 + * + * Provides high level interface to pairing functions + * + * GT=pairing(G1,G1) + * + * This is calculated on a Pairing Friendly Curve (PFC), which must first be defined. + * + * G1 is a point over the base field + * GT is a finite field point over the 2nd extension, where 2 is the embedding degree. + */ + +#define MR_PAIRING_SSP +#include "pairing_1.h" + +// Supersingular curve parameters, A,B and n, where p=2nq-1 +// AES_SECURITY=80 bit curve +static char param_80[]="B83DFB800C851836F9B95087F2642EF80B01601D46BA7CC14978EB4F6225BA7558E3D487FA3639FFE4C36332"; +// AES_SECURITY=128 bit curve +static char param_128[]="83093742908D4D529CEF06C72191A05D5E6073FE861E637D7747C3E52FBB92DAA5DDF3EF1C61F5F70B256802481A36CAFE995FE33CD54014B846751364C0D3B8327D9E45366EA08F1B3446AC23C9D4B656886731A8D05618CFA1A3B202A2445ABA0E77C5F4F00CA1239975A05377084F256DEAA07D21C4CF2A4279BC117603ACB7B10228C3AB8F8C1742D674395701BB02071A88683041D9C4231E8EE982B8DA"; + +void read_only_error(void) +{ + cout << "Attempt to write to read-only object" << endl; + exit(0); +} + +// Using SHA256 as basic hash algorithm +// +// Hash function +// + +#define HASH_LEN 32 + +Big H1(char *string) +{ // Hash a zero-terminated string to a number < modulus + Big h,p; + char s[HASH_LEN]; + int i,j; + sha256 sh; + + shs256_init(&sh); + + for (i=0;;i++) + { + if (string[i]==0) break; + shs256_process(&sh,string[i]); + } + shs256_hash(&sh,s); + p=get_modulus(); + h=1; j=0; i=1; + forever + { + h*=256; + if (j==HASH_LEN) {h+=i++; j=0;} + else h+=s[j++]; + if (h>=p) break; + } + h%=p; + return h; +} + +void PFC::start_hash(void) +{ + shs256_init(&SH); +} + +Big PFC::finish_hash_to_group(void) +{ + Big hash; + char s[HASH_LEN]; + shs256_hash(&SH,s); + hash=from_binary(HASH_LEN,s); + return hash%(*ord); +} + +void PFC::add_to_hash(const GT& x) +{ // compress it and add + ZZn2 u=x.g; + Big a; + int m; + + u.get(a); + + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } +} + +void PFC::add_to_hash(const G1& x) +{ + Big a,X,Y; + int i,m; + x.g.get(X,Y); + a=X; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } + a=Y; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } +} + +void PFC::add_to_hash(const Big& x) +{ + int m; + Big a=x; + while (a>0) + { + m=a%256; + shs256_process(&SH,m); + a/=256; + } +} + +Big H2(ZZn2 y) +{ // Hash and compress an Fp2 to a big number + sha256 sh; + Big a,h; + char s[HASH_LEN]; + int m; + + shs256_init(&sh); + y.get(a); + + while (a>0) + { + m=a%256; + shs256_process(&sh,m); + a/=256; + } + shs256_hash(&sh,s); + h=from_binary(HASH_LEN,s); + return h; +} + +#ifndef MR_AFFINE_ONLY + +void force(ZZn& x,ZZn& y,ZZn& z,ECn& A) +{ // A=(x,y,z) + copy(getbig(x),A.get_point()->X); + copy(getbig(y),A.get_point()->Y); + copy(getbig(z),A.get_point()->Z); + A.get_point()->marker=MR_EPOINT_GENERAL; +} + +void extract(ECn &A, ZZn& x,ZZn& y,ZZn& z) +{ // (x,y,z) <- A + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} + +#endif + +void force(ZZn& x,ZZn& y,ECn& A) +{ // A=(x,y) + copy(getbig(x),A.get_point()->X); + copy(getbig(y),A.get_point()->Y); + A.get_point()->marker=MR_EPOINT_NORMALIZED; +} + +void extract(ECn& A,ZZn& x,ZZn& y) +{ // (x,y) <- A + if (A.iszero()) + { + x=0; y=0; + return; + } + x=(A.get_point())->X; + y=(A.get_point())->Y; +} + +void extractZ(ECn& A,ZZn& z) +{ + big t; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} + +// +// Line from A to destination C. Let A=(x,y) +// Line Y-slope.X-c=0, through A, so intercept c=y-slope.x +// Line Y-slope.X-y+slope.x = (Y-y)-slope.(X-x) = 0 +// Now evaluate at Q -> return (Qy-y)-slope.(Qx-x) +// + +ZZn2 line(ECn& A,ECn& C,ECn& B,int type,ZZn& slope,ZZn& ex1,ZZn& ex2,ZZn& Px,ZZn& Py) +{ + ZZn2 w; + ZZn x,y,z3; + + extractZ(C,z3); + if (type==MR_ADD) + { + extract(B,x,y); + w.set(slope*(x+Px)-z3*y,z3*Py); + } + if (type==MR_DOUBLE) + { + extract(A,x,y); + w.set(-(slope*ex2)*Px-slope*x+ex1,-(z3*ex2)*Py); + } + +/* + extract(A,x,y,z); + x*=z; t=z; z*=z; z*=t; // 9 ZZn muls + n*=z; n+=x; n*=slope; + d*=z; w.set(-y,d); + extractZ(C,z3); + + w*=z3; w+=n; +*/ + +// w.set(Px*z*z*z*slope+slope*x*z-y*z3,Py*z*z*z*z3); + return w; +} + +// +// Add A=A+B (or A=A+A) +// Return line function value +// + +ZZn2 g(ECn& A,ECn& B,ZZn& Px,ZZn& Py) +{ + int type; + ZZn lam,extra1,extra2; + ZZn2 u; + ECn P=A; + big ptr,ex1,ex2; + + type=A.add(B,&ptr,&ex1,&ex2); + if (!type) return (ZZn2)1; + lam=ptr; + extra1=ex1; + extra2=ex2; + + return line(P,A,B,type,lam,extra1,extra2,Px,Py); +} + +// if multiples of G1 can be precalculated, its a lot faster! + +ZZn2 gp(ZZn* ptable,int &j,ZZn& Px,ZZn& Py) +{ + ZZn2 w; + w.set(ptable[j]*Px+ptable[j+1],Py); + j+=2; + return w; +} + +// +// Spill precomputation on pairing to byte array +// + +int PFC::spill(G1& w,char *& bytes) +{ + int i,j,n=2*(bits(*ord-1)-2+ham(*ord)); + int bytes_per_big=(MIRACL/8)*(get_mip()->nib-1); + int len=n*bytes_per_big; + Big x; + if (w.ptable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); + int len=n*bytes_per_big; + Big x; + + if (w.ptable!=NULL) return; + + w.ptable=new ZZn[n]; + for (i=j=0;icoord=MR_AFFINE; + for (i=nb-2;i>=0;i--) + { + Q=A; +// Evaluate line from A to A+B + A.add(A,&ptr); + lam=ptr; + extract(Q,x,y); + w.ptable[j++]=lam; w.ptable[j++]=lam*x-y; + + if (bit(iters,i)==1) + { + Q=A; + A.add(B,&ptr); + lam=ptr; + extract(Q,x,y); + w.ptable[j++]=lam; w.ptable[j++]=lam*x-y; + } + } + get_mip()->coord=MR_PROJECTIVE; + return len; +} + +GT PFC::multi_miller(int n,G1** QQ,G1** PP) +{ + GT z; + ZZn *Px,*Py; + int i,j,*k,nb; + ECn *Q,*A; + ECn P; + ZZn2 res; + Big iters=*ord-1; + + Px=new ZZn[n]; + Py=new ZZn[n]; + Q=new ECn[n]; + A=new ECn[n]; + k=new int[n]; + + nb=bits(iters); + res=1; + + for (j=0;jg; normalise(P); Q[j]=QQ[j]->g; normalise(Q[j]); + extract(P,Px[j],Py[j]); + } + + for (j=0;j=0;i--) + { + res*=res; + for (j=0;jptable==NULL) + res*=g(A[j],A[j],Px[j],Py[j]); + else + res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + if (bit(iters,i)==1) + for (j=0;jptable==NULL) + res*=g(A[j],Q[j],Px[j],Py[j]); + else + res*=gp(QQ[j]->ptable,k[j],Px[j],Py[j]); + } + if (res.iszero()) return 0; + } + + delete [] k; + delete [] A; + delete [] Q; + delete [] Py; + delete [] Px; + + z.g=res; + return z; +} + +// +// Tate Pairing G1 x G1 -> GT +// +// P and Q are points of order q in G1. +// + +GT PFC::miller_loop(const G1& QQ,const G1& PP) +{ + GT z; + int i,j,n,nb,nbw,nzs; + ECn A,Q; + ECn P; + ZZn Px,Py; + BOOL precomp; + ZZn2 res; + Big iters=*ord-1; // can omit last addition + + P=PP.g; Q=QQ.g; + precomp=FALSE; + if (QQ.ptable!=NULL) precomp=TRUE; + + normalise(P); + normalise(Q); + extract(P,Px,Py); + //Px=-Px; + + res=1; + A=Q; // reset A + nb=bits(iters); + + j=0; + + for (i=nb-2;i>=0;i--) + { + res*=res; + if (precomp) res*=gp(QQ.ptable,j,Px,Py); + else res*=g(A,A,Px,Py); + + if (bit(iters,i)==1) + { + if (precomp) res*=gp(QQ.ptable,j,Px,Py); + else res*=g(A,Q,Px,Py); + } + } + + z.g=res; + return z; +} + +GT PFC::final_exp(const GT& z) +{ + GT y; + Big p; + ZZn2 res; + + res=z.g; + p=get_modulus(); // get p + res=conj(res)/res; + res=pow(res,(p+1)/(*ord)); // raise to power of (p^2-1)/q + + y.g=res; + + return y; +} + +PFC::PFC(int s, csprng *rng) +{ + int mod_bits,words; + if (s!=80 && s!=128) + { + cout << "No suitable curve available" << endl; + exit(0); + } + if (s==80) mod_bits=512; + if (s==128) mod_bits=1536; + + if (mod_bits%MIRACL==0) + words=(mod_bits/MIRACL); + else + words=(mod_bits/MIRACL)+1; + +#ifdef MR_SIMPLE_BASE + miracl *mip=mirsys((MIRACL/4)*words,16); +#else + miracl *mip=mirsys(words,0); + mip->IOBASE=16; +#endif + mod=new Big; + cof=new Big; + ord=new Big; + + Big A=-3; + Big B=0; + if (s==80) + { + *cof=param_80; + *ord=pow((Big)2,159)+pow((Big)2,17)+1; + } + if (s==128) + { + *cof=param_128; + *ord=pow((Big)2,255)+pow((Big)2,41)+1; + } + + S=s; + *mod=2*(*cof)*(*ord)-1; + ecurve(A,B,*mod,MR_PROJECTIVE); + + RNG=rng; +} + +G1 PFC::mult(const G1& w,const Big& k) +{ + G1 z; + if (w.mtable!=NULL) + { // we have precomputed values + Big e=k; + if (k<0) e=-e; + + int i,j,t=w.mtbits; //MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.mtable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g+=z.g; + if (j>0) z.g+=w.mtable[j]; + } + if (k<0) z.g=-z.g; + } + else + { + z.g=w.g; + z.g*=k; + } + return z; +} + +GT PFC::power(const GT& w,const Big& k) +{ + GT z; + Big e=k; + if (k<0) e=-e; + if (w.etable!=NULL) + { // precomputation is available + int i,j,t=w.etbits; //MR_ROUNDUP(2*S,WINDOW_SIZE); + j=recode(e,t,WINDOW_SIZE,t-1); + z.g=w.etable[j]; + for (i=t-2;i>=0;i--) + { + j=recode(e,t,WINDOW_SIZE,i); + z.g*=z.g; + if (j>0) z.g*=w.etable[j]; + } + } + else + { + z.g=powu(w.g,e); + } + if (k<0) z.g=conj(z.g); + return z; +} + +// random group member + +void PFC::random(Big& w) +{ + if (RNG==NULL) w=rand(*ord); + else w=strong_rand(RNG,*ord); +} + +// random AES key + +void PFC::rankey(Big& k) +{ + if (RNG==NULL) k=rand(S,2); + else k=strong_rand(RNG,S,2); +} + +// Can be done deterministicly + +void PFC::hash_and_map(G1& w,char *ID) +{ + Big x0=H1(ID); + if (is_on_curve(x0)) w.g.set(x0); + else w.g.set(-x0); + w.g*=(*cof); +} + +void PFC::random(G1& w) +{ + Big x0; + if (RNG==NULL) x0=rand(get_modulus()); + else x0=strong_rand(RNG,get_modulus()); + + while (!w.g.set(x0,x0)) x0+=1; + w.g*=(*cof); +} + +Big PFC::hash_to_aes_key(const GT& w) +{ + Big m=pow((Big)2,S); + return H2(w.g)%m; +} + +Big PFC::hash_to_group(char *ID) +{ + Big m=H1(ID); + return m%(*ord); +} + +GT operator*(const GT& x,const GT& y) +{ + GT z=x; + z.g*=y.g; + return z; +} + +GT operator/(const GT& x,const GT& y) +{ + GT z=x; + z.g*=conj(y.g); // elements in GT are unitary + return z; +} + +// +// spill precomputation on GT to byte array +// + +int GT::spill(char *& bytes) +{ + int i,j,n=(1<nib-1); + int len=n*2*bytes_per_big+1; + Big x,y; + + if (etable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*2*bytes_per_big; + Big x,y; + if (etable!=NULL) return; + + etable=new ZZn2[1<nib-1); + int len=n*2*bytes_per_big+1; + Big x,y; + + if (mtable==NULL) return 0; + + bytes=new char[len]; + for (i=j=0;inib-1); +// int len=n*2*bytes_per_big; + Big x,y; + if (mtable!=NULL) return; + + mtable=new ECn[1< +#include + +//********* choose just one of these ********** +///#define MR_PAIRING_SS2 // AES-80 or AES-128 security GF(2^m) curve +//#define AES_SECURITY 80 // OR +//#define AES_SECURITY 128 + +#define MR_PAIRING_SSP // AES-80 or AES-128 security GF(p) curve +#define AES_SECURITY 80 // OR +//#define AES_SECURITY 128 +//********************************************* + +#include "pairing_1.h" + +// Here we ignore the mysterious h co-factor which appears in the paper.. + +int main() +{ + PFC pfc(AES_SECURITY); // initialise pairing-friendly curve + + Big alpha,x,y,key,sA,sB; + G1 gIDA,gIDB,dIDA,dIDB,RA,RB; + GT K; + time_t seed; + + time(&seed); + irand((long)seed); + +// setup + pfc.random(alpha); + +// extract private key for Alice + pfc.hash_and_map(gIDA,(char *)"Alice"); + dIDA=pfc.mult(gIDA,alpha); + pfc.precomp_for_mult(dIDA); + +// extract private key for Bob + pfc.hash_and_map(gIDB,(char *)"Robert"); + dIDB=pfc.mult(gIDB,alpha); + pfc.precomp_for_mult(dIDB); + +// Alice to Bob + + pfc.random(x); + RA=pfc.mult(gIDA,x); + +// Bob to Alice + + pfc.random(y); + RB=pfc.mult(gIDB,y); + +// Hash values + + pfc.start_hash(); + pfc.add_to_hash(RA); + pfc.add_to_hash(RB); + sA=pfc.finish_hash_to_group(); + + pfc.start_hash(); + pfc.add_to_hash(RB); + pfc.add_to_hash(RA); + sB=pfc.finish_hash_to_group(); + +// Alice calculates mutual key + K=pfc.pairing(pfc.mult(gIDB,sB)+RB,pfc.mult(dIDA,x+sA)); + key=pfc.hash_to_aes_key(K); + cout << "Alice's key= " << key << endl; + +// Bob calculates mutual key + K=pfc.pairing(pfc.mult(gIDA,sA)+RA,pfc.mult(dIDB,y+sB)); + key=pfc.hash_to_aes_key(K); + cout << "Bob's key= " << key << endl; + + return 0; +} diff --git a/miracl/source/curve/pairing/weng.ecs b/miracl/source/curve/pairing/weng.ecs new file mode 100644 index 0000000..5c035d1 --- /dev/null +++ b/miracl/source/curve/pairing/weng.ecs @@ -0,0 +1,10 @@ +256 +CC485D26177A1A5FCC9D53BA93DA298FD7F2F23D8FC02A8123BF24F9548A5F15 +0 +2 +14D13FF7298021445 +9D0261DD89CF83D5D20198162C22C942EF68622A6DF25621 +14D13FF7298021444 +CC485D26177A1A5DC943A809989E96D1A5C48429D7E2AFE07B11DF7FDDD9DEED +CC485D2610D1594784F97D4CBECF33E43D9EC24868E09195F52A9FEFEBFF171A +CC485D26177A1A5FCC9D53BA93D9FA7744ED3EB0E97A8284849E65054CCAA617 diff --git a/miracl/source/curve/pairing/xk1.ecs b/miracl/source/curve/pairing/xk1.ecs new file mode 100644 index 0000000..27f4f73 --- /dev/null +++ b/miracl/source/curve/pairing/xk1.ecs @@ -0,0 +1,4 @@ +1024 +C000000000000003000180000000000480048002400000030004800480018000C001800240018000C000027600000000000009D804EC000000000EC40EC40762000009D80EC40EC404EC027604EC076204EC0276000204CC000000000008133409980000000C1CD41CCE0E640008133C1CD41CCC099A04D0099E0E68099A04CD +0 +1 diff --git a/miracl/source/curve/pairing/zzn12.cpp b/miracl/source/curve/pairing/zzn12.cpp new file mode 100644 index 0000000..f752afd --- /dev/null +++ b/miracl/source/curve/pairing/zzn12.cpp @@ -0,0 +1,336 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file zzn12.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ZZn12 (Arithmetic over n^12) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * NOTE: - The irreducible polynomial is assumed to be of the form + * x^6-i, where i is + * 1+sqrt(-1) if p=3 mod 8 + * or sqrt(-2) if p=5 mod 8 + * or sqrt(2+sqrt(-1)), for p=7 mod 8 and p=2,3 mod 5 + * + */ + +#include "zzn12.h" + +using namespace std; + +// Frobenius... + +ZZn12& ZZn12::powq(const ZZn2& X) +{ + ZZn2 W=X*X; + BOOL ku=unitary; + a.powq(W); b.powq(W); + b*=X; + unitary=ku; + return *this; +} + +void ZZn12::get(ZZn6 &x,ZZn6 &y) const +{x=a; y=b; } + +void ZZn12::get(ZZn6& x) const +{x=a; } + +ZZn12& ZZn12::operator*=(const ZZn12& x) +{ + if (&x==this) + { +/* See Stam & Lenstra, "Efficient subgroup exponentiation in Quadratic .. Extensions", CHES 2002 */ + if (unitary) + { + ZZn6 t=b; t*=t; + b+=a; b*=b; + b-=t; + a=tx(t); + b-=a; + a+=a; a+=one(); + b-=one(); + // cout << "in here" << endl; + } + else + { + ZZn6 t=a; t+=b; + ZZn6 t2=a; t2+=tx(b); + t*=t2; + b*=a; + t-=b; + t-=tx(b); + b+=b; + a=t; + } + } + else + { // Karatsuba multiplication + ZZn6 ac=a; ac*=x.a; + ZZn6 bd=b; bd*=x.b; + ZZn6 t=x.a; t+=x.b; + b+=a; b*=t; b-=ac; b-=bd; + a=ac; a+=tx(bd); + + if (!x.unitary) unitary=FALSE; + } + + return *this; +} + +ZZn12 conj(const ZZn12& x) +{ + ZZn12 u=x; + u.conj(); + return u; +} + +ZZn12 inverse(const ZZn12 &w) +{ + ZZn12 y=conj(w); + if (w.unitary) return y; + ZZn6 u=w.a; + ZZn6 v=w.b; + u*=u; + v*=v; + u-=tx(v); + u=inverse(u); + y*=u; + return y; +} + +ZZn12& ZZn12::operator/=(const ZZn12& x) +{ // inversion + *this *= inverse(x); + if (!x.unitary) unitary=FALSE; + return *this; +} + +ZZn12& ZZn12::operator/=(const ZZn6& x) +{ // inversion + *this *= inverse(x); + unitary=FALSE; + return *this; +} + +ZZn12 operator+(const ZZn12& x,const ZZn12& y) +{ZZn12 w=x; w+=y; return w;} + +ZZn12 operator+(const ZZn12& x,const ZZn6& y) +{ZZn12 w=x; w+=y; return w; } // + +ZZn12 operator-(const ZZn12& x,const ZZn12& y) +{ZZn12 w=x; w-=y; return w; } + +ZZn12 operator-(const ZZn12& x,const ZZn6& y) +{ZZn12 w=x; w-=y; return w; } // + +ZZn12 operator-(const ZZn12& x) +{ZZn12 w; w.a=-x.a; w.b=-x.b; w.unitary=FALSE; return w; } + +ZZn12 operator*(const ZZn12& x,const ZZn12& y) +{ + ZZn12 w=x; + if (&x==&y) w*=w; + else w*=y; + return w; +} + +ZZn12 operator*(const ZZn12& x,const ZZn6& y) +{ZZn12 w=x; w*=y; return w;} // + +ZZn12 operator*(const ZZn6& y,const ZZn12& x) +{ZZn12 w=x; w*=y; return w;} // + +ZZn12 operator*(const ZZn12& x,int y) +{ZZn12 w=x; w*=y; return w;} + +ZZn12 operator*(int y,const ZZn12& x) +{ZZn12 w=x; w*=y; return w;} + +ZZn12 operator/(const ZZn12& x,const ZZn12& y) +{ZZn12 w=x; w/=y; return w;} + +ZZn12 operator/(const ZZn12& x,const ZZn6& y) +{ZZn12 w=x; ZZn6 j=inverse(y); w.a*=j; w.b*=j; w.unitary=FALSE; return w;} // + +#ifndef MR_NO_RAND +ZZn12 randn12(void) +{ZZn12 w; w.a=randn6(); w.b=randn6(); w.unitary=FALSE; return w;} +#endif +#ifndef MR_NO_STANDARD_IO + +ostream& operator<<(ostream& s,ZZn12& b) +{ + int i; + ZZn6 x,y; + b.get(x,y); + s << "[" << x << "," << y << "]"; + return s; +} + +#endif + +// Left to right method - with windows + +ZZn12 pow(const ZZn12* t,const ZZn12& x,const Big& k) +{ + int i,j,nb,n,nbw,nzs; + ZZn12 u=x; + + if (k==0) return (ZZn12)one(); + if (k==1) return u; + + nb=bits(k); + if (nb>1) for (i=nb-2;i>=0;) + { + n=window(k,i,&nbw,&nzs,5); + for (j=0;j0) u*=t[n/2]; + i-=nbw; + if (nzs) + { + for (j=0;j1) for (i=nb-2;i>=0;i--) + { + u*=u; + if (bit(e,i)) u*=x; + } + + if (invert_it) u=inverse(u); + + return u; +} + + +// standard MIRACL multi-exponentiation + +ZZn12 pow(int n,const ZZn12* x,const Big* b) +{ + int k,j,i,m,nb,ea; + ZZn12 *G; + ZZn12 r; + m=1<nb) nb=k; + + r=1; + for (i=nb-1;i>=0;i--) + { + ea=0; + k=1; + for (j=0;j. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ZZn12.h + * + * AUTHOR : M. Scott + * + * NOTE: : Must be used in conjunction with big.cpp, zzn.cpp and zzn2.cpp and zzn6.cpp, + * + * PURPOSE : Definition of class ZZn12 (Arithmetic over n^12) + * Implemented as a quadratic entension over Fp^6 + * + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#ifndef ZZN12_H +#define ZZN12_H + +#include "zzn6a.h" + +class ZZn12 +{ + + ZZn6 a,b; + BOOL unitary; +public: + ZZn12() {unitary=FALSE;} + ZZn12(int w) {a=(ZZn6)w; b.clear(); if (w==1) unitary=TRUE; else unitary=FALSE;} + ZZn12(const ZZn12& w) {a=w.a; b=w.b; unitary=w.unitary;} + + ZZn12(const Big &x) {a=(ZZn6)x; b.clear(); unitary=FALSE;} + ZZn12(const ZZn &x) {a=(ZZn6)x; b.clear(); unitary=FALSE;} + ZZn12(const ZZn6& x) {a=x; b.clear(); unitary=FALSE;} + + void set(const ZZn6 &x,const ZZn6 &y) {a=x; b=y; unitary=FALSE;} + + void set(const Big &x) {a=(ZZn6)x; b.clear(); unitary=FALSE;} + void set(const ZZn6 &x) {a=x; b.clear(); unitary=FALSE;} + void seti(const ZZn6 &x) {a.clear(); b=x; unitary=FALSE;} + + void get(ZZn6 &,ZZn6 &) const; + void get(ZZn6 &) const; + + void clear() {a.clear(); b.clear(); unitary=FALSE;} + void mark_as_unitary() {unitary=TRUE;} + BOOL is_unitary() {return unitary;} + + ZZn12& conj() {b=-b; return *this;} + + BOOL iszero() const {if (a.iszero() && b.iszero()) return TRUE; return FALSE; } + BOOL isunity() const {if (a.isunity() && b.iszero()) return TRUE; return FALSE; } + + ZZn12& powq(const ZZn2 &); + ZZn12& operator=(int i) {a=(ZZn6)i; b.clear(); if (i==1) unitary=TRUE; else unitary=FALSE; return *this;} + ZZn12& operator=(const ZZn6& x) {a=x; b.clear(); unitary=FALSE; return *this; } + ZZn12& operator=(const ZZn12& x) {a=x.a; b=x.b; unitary=x.unitary; return *this; } + ZZn12& operator+=(const ZZn6& x) {a+=x; unitary=FALSE; return *this; } + ZZn12& operator+=(const ZZn12& x) {a+=x.a; b+=x.b; unitary=FALSE; return *this; } + ZZn12& operator-=(const ZZn6& x) {a-=x; unitary=FALSE; return *this; } + ZZn12& operator-=(const ZZn12& x) {a-=x.a; b-=x.b; unitary=FALSE; return *this; } + ZZn12& operator*=(const ZZn12&); + ZZn12& operator*=(const ZZn6& x) { a*=x; b*=x; unitary=FALSE; return *this;} + ZZn12& operator*=(int x) { a*=x; b*=x; unitary=FALSE; return *this;} + ZZn12& operator/=(const ZZn12&); + ZZn12& operator/=(const ZZn6&); + + friend ZZn12 operator+(const ZZn12&,const ZZn12&); + friend ZZn12 operator+(const ZZn12&,const ZZn6&); + friend ZZn12 operator-(const ZZn12&,const ZZn12&); + friend ZZn12 operator-(const ZZn12&,const ZZn6&); + friend ZZn12 operator-(const ZZn12&); + + friend ZZn12 operator*(const ZZn12&,const ZZn12&); + friend ZZn12 operator*(const ZZn12&,const ZZn6&); + friend ZZn12 operator*(const ZZn6&,const ZZn12&); + + friend ZZn12 operator*(int,const ZZn12&); + friend ZZn12 operator*(const ZZn12&,int); + + friend ZZn12 operator/(const ZZn12&,const ZZn12&); + friend ZZn12 operator/(const ZZn12&,const ZZn6&); + + friend ZZn12 pow(const ZZn12&,const Big&); + friend ZZn12 pow(const ZZn12&,const Big*); + friend ZZn12 pow(const ZZn12*,const ZZn12&,const Big&); + friend ZZn12 pow(int,const ZZn12*,const Big*); + friend void precompute(const ZZn12&,ZZn12 *); + friend ZZn12 inverse(const ZZn12&); + friend ZZn12 conj(const ZZn12&); + friend ZZn6 real(const ZZn12& x) {return x.a;} + friend ZZn6 imaginary(const ZZn12& x) {return x.b;} +#ifndef MR_NO_RAND + friend ZZn12 randn12(void); // random ZZn12 +#endif + friend BOOL operator==(const ZZn12& x,const ZZn12& y) + {if (x.a==y.a && x.b==y.b) return TRUE; else return FALSE; } + + friend BOOL operator!=(const ZZn12& x,const ZZn12& y) + {if (x.a!=y.a || x.b!=y.b) return TRUE; else return FALSE; } +#ifndef MR_NO_STANDARD_IO + friend ostream& operator<<(ostream&,ZZn12&); +#endif + ~ZZn12() {} +}; +#ifndef MR_NO_RAND +extern ZZn12 randn12(void); +#endif +#endif + diff --git a/miracl/source/curve/pairing/zzn12a.cpp b/miracl/source/curve/pairing/zzn12a.cpp new file mode 100644 index 0000000..dc26e48 --- /dev/null +++ b/miracl/source/curve/pairing/zzn12a.cpp @@ -0,0 +1,381 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file ZZn12a.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ZZn12 (Arithmetic over n^12) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#include "zzn12a.h" + +using namespace std; + +// Frobenius X=x^p. Assumes p=1 mod 6 + +ZZn12& ZZn12::powq(const ZZn2& X) +{ + ZZn2 XX=X*X; + ZZn2 XXX=XX*X; + BOOL ku=unitary; + BOOL km=miller; + a.powq(XXX); b.powq(XXX); c.powq(XXX); + b*=X; + c*=XX; + unitary=ku; + miller=km; + return *this; +} + +void ZZn12::get(ZZn4& x,ZZn4& y,ZZn4& z) const +{x=a; y=b; z=c;} + +void ZZn12::get(ZZn4& x) const +{x=a; } + +void ZZn12::get1(ZZn4& x) const +{x=b; } + +void ZZn12::get2(ZZn4& x) const +{x=c; } + +ZZn12& ZZn12::operator*=(const ZZn12& x) +{ // optimized to reduce constructor/destructor calls + if (&x==this) + { + ZZn4 A,B,C,D; + if (unitary) + { // Granger & Scott PKC 2010 - only 3 squarings! + + A=a; a*=a; D=a; a+=a; a+=D; A.conj(); A+=A; a-=A; + B=c; B*=B; B=tx(B); D=B; B+=B; B+=D; + C=b; C*=C; D=C; C+=C; C+=D; + + b.conj(); b+=b; c.conj(); c+=c; c=-c; + b+=B; c+=C; + // cout << "unitary" << endl; + } + else + { + if (!miller) + { // Chung-Hasan SQR2 + A=a; A*=A; + B=b*c; B+=B; + C=c; C*=C; + D=a*b; D+=D; + c+=(a+b); c*=c; + + a=A+tx(B); + b=D+tx(C); + c-=(A+B+C+D); + } + else + { +// Chung-Hasan SQR3 - actually calculate 2x^2 ! +// Slightly dangerous - but works as will be raised to p^{k/2}-1 +// which wipes out the 2. + + A=a; A*=A; // a0^2 = S0 + C=c; C*=b; C+=C; // 2a1.a2 = S3 + D=c; D*=D; // a2^2 = S4 + c+=a; // a0+a2 + + B=b; B+=c; B*=B; // (a0+a1+a2)^2 =S1 + + c-=b; c*=c; // (a0-a1+a2)^2 =S2 + + C+=C; A+=A; D+=D; + + a=A+tx(C); + b=B-c-C+tx(D); + c+=B-A-D; // is this code telling me something...? + +/* if you want to play safe! + c+=B; c/=2; + B-=c; B-=C; + c-=A; c-=D; + a=A+tx(C); + b=B+tx(D); +*/ + } + } + } + else + { // Karatsuba + ZZn4 Z0,Z1,Z2,Z3,T0,T1; + BOOL zero_c,zero_b; + zero_c=(x.c).iszero(); + zero_b=(x.b).iszero(); + + Z0=a*x.a; //9 + if (!zero_b) Z2=b*x.b; //+6 + + T0=a+b; + T1=x.a+x.b; + Z1=T0*T1; //+9 + Z1-=Z0; + if (!zero_b) Z1-=Z2; + T0=b+c; + T1=x.b+x.c; + Z3=T0*T1; //+6 + + if (!zero_b) Z3-=Z2; + + T0=a+c; + T1=x.a+x.c; + T0*=T1; //+9=39 for "special case" + if (!zero_b) Z2+=T0; + else Z2=T0; + Z2-=Z0; + + b=Z1; + if (!zero_c) + { // exploit special form of BN curve line function + T0=c*x.c; + Z2-=T0; + Z3-=T0; + b+=tx(T0); + } + + a=Z0+tx(Z3); + c=Z2; + + if (!x.unitary) unitary=FALSE; + } + return *this; +} + +ZZn12& ZZn12::operator/=(const ZZn4& x) +{ + *this*=inverse(x); + unitary=FALSE; + return *this; +} + + +ZZn12& ZZn12::operator/=(const ZZn12& x) +{ + *this*=inverse(x); + if (!x.unitary) unitary=FALSE; + return *this; +} + +ZZn12 conj(const ZZn12& x) +{ + ZZn12 u=x; + u.conj(); + return u; +} + +ZZn12 inverse(const ZZn12& w) +{ + ZZn12 y; + + if (w.unitary) + { + y=conj(w); + return y; + } + + ZZn4 f0; + + y.a=w.a*w.a-tx(w.b*w.c); + y.b=tx(w.c*w.c)-w.a*w.b; + y.c=w.b*w.b-w.a*w.c; + + f0=tx(w.b*y.c)+w.a*y.a+tx(w.c*y.b); + + f0=inverse(f0); + y.c*=f0; + y.b*=f0; + y.a*=f0; + + return y; +} + +ZZn12 operator+(const ZZn12& x,const ZZn12& y) +{ZZn12 w=x; w.a+=y.a; w.b+=y.b; w.c+=y.c; return w; } + +ZZn12 operator+(const ZZn12& x,const ZZn4& y) +{ZZn12 w=x; w.a+=y; return w; } + +ZZn12 operator-(const ZZn12& x,const ZZn12& y) +{ZZn12 w=x; w.a-=y.a; w.b-=y.b; w.c-=y.c; return w; } + +ZZn12 operator-(const ZZn12& x,const ZZn4& y) +{ZZn12 w=x; w.a-=y; return w; } + +ZZn12 operator-(const ZZn12& x) +{ZZn12 w; w.a=-x.a; w.b=-x.b; w.c-=x.c; w.unitary=FALSE; return w; } + +ZZn12 operator*(const ZZn12& x,const ZZn12& y) +{ + ZZn12 w=x; + if (&x==&y) w*=w; + else w*=y; + return w; +} + +ZZn12 operator*(const ZZn12& x,const ZZn4& y) +{ZZn12 w=x; w*=y; return w;} + +ZZn12 operator*(const ZZn4& y,const ZZn12& x) +{ZZn12 w=x; w*=y; return w;} + +ZZn12 operator*(const ZZn12& x,int y) +{ZZn12 w=x; w*=y; return w;} + +ZZn12 operator*(int y,const ZZn12& x) +{ZZn12 w=x; w*=y; return w;} + +ZZn12 operator/(const ZZn12& x,const ZZn12& y) +{ZZn12 w=x; w/=y; return w;} + +ZZn12 operator/(const ZZn12& x,const ZZn4& y) +{ZZn12 w=x; w/=y; return w;} + +#ifndef MR_NO_RAND +ZZn12 randn12(void) +{ZZn12 w; w.a=randn4(); w.b=randn4(); w.c=randn4(); w.unitary=FALSE; return w;} +#endif +ZZn12 tx(const ZZn12& w) +{ + ZZn12 u=w; + + ZZn4 t=u.a; + u.a=tx(u.c); + u.c=u.b; + u.b=t; + + return u; +} + +// regular ZZn12 powering + +// If k is low Hamming weight this will be just as good.. + +ZZn12 pow(const ZZn12& x,const Big& k) +{ + int i,nb; + ZZn12 u=x; + Big e=k; + BOOL invert_it=FALSE; + + if (e==0) return (ZZn12)one(); + + if (e<0) + { + e=-e; + invert_it=TRUE; + } + + nb=bits(e); + if (nb>1) for (i=nb-2;i>=0;i--) + { + u*=u; + if (bit(e,i)) u*=x; + } + + if (invert_it) u=inverse(u); + + return u; +} + +// standard MIRACL multi-exponentiation + +#ifndef MR_STATIC + +ZZn12 pow(int n,const ZZn12* x,const Big* b) +{ + int k,j,i,m,nb,ea; + ZZn12 *G; + ZZn12 r; + m=1<nb) nb=k; + + r=1; + for (i=nb-1;i>=0;i--) + { + ea=0; + k=1; + for (j=0;j. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ZZn12a.h + * + * AUTHOR : M. Scott + * + * NOTE: : Must be used in conjunction with zzn4.cpp zzn2.cpp big.cpp and zzn.cpp + * : This is designed as a "towering extension", so a ZZn12 consists + * : of three ZZn4. + * + * PURPOSE : Definition of class zzn12 (Arithmetic over n^12) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * Note: This code assumes that + * p=5 mod 8 + * OR p=3 mod 8 + * OR p=7 mod 8, p=2,3 mod 5 + * + * Irreducible poly is X^3+n, where n=sqrt(w+sqrt(m)), m= {-1,-2} and w= {0,1,2} + * if p=5 mod 8, n=sqrt(-2) + * if p=3 mod 8, n=1+sqrt(-1) + * if p=7 mod 8, p=2,3 mod 5, n=2+sqrt(-1) + * + */ + +#ifndef ZZN12A_H +#define ZZN12A_H + +#include "zzn4.h" + +class ZZn12 +{ + ZZn4 a,b,c; + BOOL unitary; // "unitary property means that fast squaring can be used, and inversions are just conjugates + BOOL miller; // "miller" property means that arithmetic on this instance can ignore multiplications + // or divisions by constants - as instance will eventually be raised to (p-1). +public: + ZZn12() {miller=unitary=FALSE;} + ZZn12(int w) {a=(ZZn4)w; b.clear(); c.clear(); miller=FALSE; if (w==1) unitary=TRUE; else unitary=FALSE;} + ZZn12(const ZZn12& w) {a=w.a; b=w.b; c=w.c; miller=w.miller; unitary=w.unitary;} + ZZn12(const ZZn4 &x) {a=x; b.clear(); c.clear(); miller=unitary=FALSE;} + ZZn12(const ZZn4 &x,const ZZn4& y,const ZZn4& z) {a=x; b=y; c=z; miller=unitary=FALSE;} + ZZn12(const ZZn &x) {a=(ZZn4)x; b.clear(); c.clear(); miller=unitary=FALSE;} + ZZn12(const Big &x) {a=(ZZn4)x; b.clear(); c.clear(); miller=unitary=FALSE;} + + void set(const ZZn4 &x,const ZZn4 &y,const ZZn4 &z) {a=x; b=y; c=z; unitary=FALSE;} + void set(const ZZn4 &x) {a=x; b.clear(); c.clear();unitary=FALSE;} + void set(const ZZn4 &x,const ZZn4 &y) {a=x; b=y; c.clear();unitary=FALSE; } + void set1(const ZZn4 &x) {a.clear(); b=x; c.clear();unitary=FALSE;} + void set2(const ZZn4 &x) {a.clear(); b.clear(); c=x; unitary=FALSE;} + void set(const Big &x) {a=(ZZn4)x; b.clear(); c.clear();unitary=FALSE;} + + void get(ZZn4 &,ZZn4 &,ZZn4 &) const; + void get(ZZn4 &) const; + void get1(ZZn4 &) const; + void get2(ZZn4 &) const; + + void clear() {a.clear(); b.clear(); c.clear();} + void mark_as_unitary() {miller=FALSE; unitary=TRUE;} + void mark_as_miller() {miller=TRUE;} + void mark_as_regular() {miller=unitary=FALSE;} + BOOL is_unitary() {return unitary;} + + + ZZn12& conj() {a.conj(); b.conj(); b=-b; c.conj(); return *this;} + + BOOL iszero() const {if (a.iszero() && b.iszero() && c.iszero()) return TRUE; return FALSE; } + BOOL isunity() const {if (a.isunity() && b.iszero() && c.iszero()) return TRUE; return FALSE; } + // BOOL isminusone() const {if (a.isminusone() && b.iszero()) return TRUE; return FALSE; } + + ZZn12& powq(const ZZn2&); + ZZn12& operator=(int i) {a=i; b.clear(); c.clear(); if (i==1) unitary=TRUE; else unitary=FALSE; return *this;} + ZZn12& operator=(const ZZn4& x) {a=x; b.clear(); c.clear(); unitary=FALSE; return *this; } + ZZn12& operator=(const ZZn12& x) {a=x.a; b=x.b; c=x.c; miller=x.miller; unitary=x.unitary; return *this; } + ZZn12& operator+=(const ZZn4& x) {a+=x; unitary=FALSE; return *this; } + ZZn12& operator+=(const ZZn12& x) {a+=x.a; b+=x.b; c+=x.c; unitary=FALSE; return *this; } + ZZn12& operator-=(const ZZn4& x) {a-=x; unitary=FALSE; return *this; } + ZZn12& operator-=(const ZZn12& x) {a-=x.a; b-=x.b; c-=x.c; unitary=FALSE; return *this; } + ZZn12& operator*=(const ZZn12&); + ZZn12& operator*=(const ZZn4& x) {a*=x; b*=x; c*=x; unitary=FALSE; return *this; } + ZZn12& operator*=(int x) {a*=x; b*=x; c*=x; unitary=FALSE; return *this;} + ZZn12& operator/=(const ZZn12&); + ZZn12& operator/=(const ZZn4&); + + friend ZZn12 operator+(const ZZn12&,const ZZn12&); + friend ZZn12 operator+(const ZZn12&,const ZZn4&); + friend ZZn12 operator-(const ZZn12&,const ZZn12&); + friend ZZn12 operator-(const ZZn12&,const ZZn4&); + friend ZZn12 operator-(const ZZn12&); + + friend ZZn12 operator*(const ZZn12&,const ZZn12&); + friend ZZn12 operator*(const ZZn12&,const ZZn4&); + friend ZZn12 operator*(const ZZn4&,const ZZn12&); + + friend ZZn12 operator*(int,const ZZn12&); + friend ZZn12 operator*(const ZZn12&,int); + + friend ZZn12 operator/(const ZZn12&,const ZZn12&); + friend ZZn12 operator/(const ZZn12&,const ZZn4&); + + friend ZZn12 tx(const ZZn12&); + friend ZZn12 pow(const ZZn12&,const Big&); + friend ZZn12 pow(int,const ZZn12*,const Big*); +// friend ZZn6 pow(int,const ZZn6*,const Big*); + + friend ZZn12 inverse(const ZZn12&); + friend ZZn12 conj(const ZZn12&); +#ifndef MR_NO_RAND + friend ZZn12 randn12(void); // random ZZn12 +#endif + friend BOOL operator==(const ZZn12& x,const ZZn12& y) + {if (x.a==y.a && x.b==y.b && x.c==y.c) return TRUE; else return FALSE; } + + friend BOOL operator!=(const ZZn12& x,const ZZn12& y) + {if (x.a!=y.a || x.b!=y.b || x.c!=y.c) return TRUE; else return FALSE; } + +#ifndef MR_NO_STANDARD_IO + friend ostream& operator<<(ostream&,const ZZn12&); +#endif + + ~ZZn12() {} +}; +#ifndef MR_NO_RAND +extern ZZn12 randn12(void); +#endif +#endif + diff --git a/miracl/source/curve/pairing/zzn12b.cpp b/miracl/source/curve/pairing/zzn12b.cpp new file mode 100644 index 0000000..88b4f71 --- /dev/null +++ b/miracl/source/curve/pairing/zzn12b.cpp @@ -0,0 +1,359 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file zzn12b.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ZZn12 (Arithmetic over n^12) + * : Using 1-3-6-12 towering + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * NOTE: - The irreducible polynomial is assumed to be of the form + * x^6-i, where i is sqrt(-2) and p=5 mod 8 + */ + +#include "zzn12b.h" + +using namespace std; + +// Frobenius... + +ZZn12& ZZn12::powq(const ZZn& X) +{ + BOOL ku=unitary; + a.powq(); b.powq(); + b*=X; + unitary=ku; + return *this; +} + +void ZZn12::get(ZZn6 &x,ZZn6 &y) const +{x=a; y=b; } + +void ZZn12::get(ZZn6& x) const +{x=a; } + +void ZZn12::geti(ZZn6& x) const +{x=b; } + +ZZn12& ZZn12::operator*=(const ZZn12& x) +{ + if (&x==this) + { +/* See Stam & Lenstra, "Efficient subgroup exponentiation in Quadratic .. Extensions", CHES 2002 */ + if (unitary) + { + ZZn6 t=b; t*=t; + b+=a; b*=b; + b-=t; + a=tx(t); + b-=a; + a+=a; a+=one(); + b-=one(); + // cout << "in here" << endl; + } + else + { + ZZn6 t=a; t+=b; + ZZn6 t2=a; t2+=tx(b); + t*=t2; + b*=a; + t-=b; + t-=tx(b); + b+=b; + a=t; + } + } + else + { // Karatsuba multiplication + ZZn6 ac=a; ac*=x.a; + ZZn6 bd=b; bd*=x.b; + ZZn6 t=x.a; t+=x.b; + b+=a; b*=t; b-=ac; b-=bd; + a=ac; a+=tx(bd); + + if (!x.unitary) unitary=FALSE; + } + + return *this; +} + +ZZn12 conj(const ZZn12& x) +{ + ZZn12 u=x; + u.conj(); + return u; +} + +ZZn12 inverse(const ZZn12 &w) +{ + ZZn12 y=conj(w); + if (w.unitary) return y; + ZZn6 u=w.a; + ZZn6 v=w.b; + u*=u; + v*=v; + u-=tx(v); + u=inverse(u); + y*=u; + return y; +} + +ZZn12& ZZn12::operator/=(const ZZn12& x) +{ // inversion + *this *= inverse(x); + if (!x.unitary) unitary=FALSE; + return *this; +} + +ZZn12& ZZn12::operator/=(const ZZn6& x) +{ // inversion + *this *= inverse(x); + unitary=FALSE; + return *this; +} + +ZZn12 operator+(const ZZn12& x,const ZZn12& y) +{ZZn12 w=x; w+=y; return w;} + +ZZn12 operator+(const ZZn12& x,const ZZn6& y) +{ZZn12 w=x; w+=y; return w; } // + +ZZn12 operator-(const ZZn12& x,const ZZn12& y) +{ZZn12 w=x; w-=y; return w; } + +ZZn12 operator-(const ZZn12& x,const ZZn6& y) +{ZZn12 w=x; w-=y; return w; } // + +ZZn12 operator-(const ZZn12& x) +{ZZn12 w; w.a=-x.a; w.b=-x.b; w.unitary=FALSE; return w; } + +ZZn12 operator*(const ZZn12& x,const ZZn12& y) +{ + ZZn12 w=x; + if (&x==&y) w*=w; + else w*=y; + return w; +} + +ZZn12 operator*(const ZZn12& x,const ZZn6& y) +{ZZn12 w=x; w*=y; return w;} // + +ZZn12 operator*(const ZZn6& y,const ZZn12& x) +{ZZn12 w=x; w*=y; return w;} // + +ZZn12 operator*(const ZZn12& x,int y) +{ZZn12 w=x; w*=y; return w;} + +ZZn12 operator*(int y,const ZZn12& x) +{ZZn12 w=x; w*=y; return w;} + +ZZn12 operator/(const ZZn12& x,const ZZn12& y) +{ZZn12 w=x; w/=y; return w;} + +ZZn12 operator/(const ZZn12& x,const ZZn6& y) +{ZZn12 w=x; ZZn6 j=inverse(y); w.a*=j; w.b*=j; w.unitary=FALSE; return w;} // + +ZZn12 tx(const ZZn12& x) +{ + ZZn6 t=tx(x.b); + ZZn12 u(t,x.a); + return u; +} + +ZZn12 tx2(const ZZn12& x) +{ + ZZn12 u(tx(x.a),tx(x.b)); + return u; +} + +ZZn12 tx4(const ZZn12& x) +{ + ZZn12 u(tx2(x.a),tx2(x.b)); + return u; +} + +ZZn12 tx8(const ZZn12& x) +{ + ZZn12 u(tx4(x.a),tx4(x.b)); + return u; +} + +#ifndef MR_NO_RAND +ZZn12 randn12(void) +{ZZn12 w; w.a=randn6(); w.b=randn6(); w.unitary=FALSE; return w;} +#endif +#ifndef MR_NO_STANDARD_IO + +ostream& operator<<(ostream& s,ZZn12& b) +{ + ZZn6 x,y; + b.get(x,y); + s << "[" << x << "," << y << "]"; + return s; +} + +#endif + +// Left to right method - with windows + +ZZn12 pow(const ZZn12* t,const ZZn12& x,const Big& k) +{ + int i,j,nb,n,nbw,nzs; + ZZn12 u=x; + + if (k==0) return (ZZn12)one(); + if (k==1) return u; + + nb=bits(k); + if (nb>1) for (i=nb-2;i>=0;) + { + n=window(k,i,&nbw,&nzs,5); + for (j=0;j0) u*=t[n/2]; + i-=nbw; + if (nzs) + { + for (j=0;j1) for (i=nb-2;i>=0;i--) + { + u*=u; + if (bit(e,i)) u*=x; + } + + if (invert_it) u=inverse(u); + + return u; +} + + +// standard MIRACL multi-exponentiation + +ZZn12 pow(int n,const ZZn12* x,const Big* b) +{ + int k,j,i,m,nb,ea; + ZZn12 *G; + ZZn12 r; + m=1<nb) nb=k; + + r=1; + for (i=nb-1;i>=0;i--) + { + ea=0; + k=1; + for (j=0;j. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ZZn12b.h + * + * AUTHOR : M. Scott + * + * NOTE: : Must be used in conjunction with big.cpp, zzn.cpp and zzn3.cpp and zzn6.cpp, + * uses 1-3-6-12 towering, and assumes 12|p-1 + * PURPOSE : Definition of class ZZn12 (Arithmetic over n^12) + * Implemented as a quadratic entension over Fp^6 + * + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#ifndef ZZN12_H +#define ZZN12_H + +#include "zzn6.h" + +class ZZn12 +{ + + ZZn6 a,b; + BOOL unitary; +public: + ZZn12() {unitary=FALSE;} + ZZn12(int w) {a=(ZZn6)w; b.clear(); if (w==1) unitary=TRUE; else unitary=FALSE;} + ZZn12(const ZZn12& w) {a=w.a; b=w.b; unitary=w.unitary;} + + ZZn12(const Big &x) {a=(ZZn6)x; b.clear(); unitary=FALSE;} + ZZn12(const ZZn &x) {a=(ZZn6)x; b.clear(); unitary=FALSE;} + ZZn12(const ZZn6& x) {a=x; b.clear(); unitary=FALSE;} + ZZn12(const ZZn6& x,const ZZn6& y) {a=x; b=y; unitary=FALSE;} + + void set(const ZZn6 &x,const ZZn6 &y) {a=x; b=y; unitary=FALSE;} + + void set(const Big &x) {a=(ZZn6)x; b.clear(); unitary=FALSE;} + void set(const ZZn6 &x) {a=x; b.clear(); unitary=FALSE;} + void seti(const ZZn6 &x) {a.clear(); b=x; unitary=FALSE;} + + void get(ZZn6 &,ZZn6 &) const; + void get(ZZn6 &) const; + void geti(ZZn6 &) const; + + void clear() {a.clear(); b.clear(); unitary=FALSE;} + void mark_as_unitary() {unitary=TRUE;} + BOOL is_unitary() {return unitary;} + + ZZn12& conj() {b=-b; return *this;} + + BOOL iszero() const {if (a.iszero() && b.iszero()) return TRUE; return FALSE; } + BOOL isunity() const {if (a.isunity() && b.iszero()) return TRUE; return FALSE; } + + ZZn12& powq(const ZZn &); + ZZn12& operator=(int i) {a=(ZZn6)i; b.clear(); if (i==1) unitary=TRUE; else unitary=FALSE; return *this;} + ZZn12& operator=(const ZZn6& x) {a=x; b.clear(); unitary=FALSE; return *this; } + ZZn12& operator=(const ZZn12& x) {a=x.a; b=x.b; unitary=x.unitary; return *this; } + ZZn12& operator+=(const ZZn6& x) {a+=x; unitary=FALSE; return *this; } + ZZn12& operator+=(const ZZn12& x) {a+=x.a; b+=x.b; unitary=FALSE; return *this; } + ZZn12& operator-=(const ZZn6& x) {a-=x; unitary=FALSE; return *this; } + ZZn12& operator-=(const ZZn12& x) {a-=x.a; b-=x.b; unitary=FALSE; return *this; } + ZZn12& operator*=(const ZZn12&); + ZZn12& operator*=(const ZZn6& x) { a*=x; b*=x; unitary=FALSE; return *this;} + ZZn12& operator*=(const ZZn& x) { a*=x; b*=x; unitary=FALSE; return *this;} + ZZn12& operator*=(int x) { a*=x; b*=x; unitary=FALSE; return *this;} + ZZn12& operator/=(const ZZn12&); + ZZn12& operator/=(const ZZn6&); + + friend ZZn12 tx(const ZZn12&); + friend ZZn12 tx2(const ZZn12&); + friend ZZn12 tx4(const ZZn12&); + friend ZZn12 tx8(const ZZn12&); + friend ZZn12 operator+(const ZZn12&,const ZZn12&); + friend ZZn12 operator+(const ZZn12&,const ZZn6&); + friend ZZn12 operator-(const ZZn12&,const ZZn12&); + friend ZZn12 operator-(const ZZn12&,const ZZn6&); + friend ZZn12 operator-(const ZZn12&); + + friend ZZn12 operator*(const ZZn12&,const ZZn12&); + friend ZZn12 operator*(const ZZn12&,const ZZn6&); + friend ZZn12 operator*(const ZZn6&,const ZZn12&); + + friend ZZn12 operator*(int,const ZZn12&); + friend ZZn12 operator*(const ZZn12&,int); + + friend ZZn12 operator/(const ZZn12&,const ZZn12&); + friend ZZn12 operator/(const ZZn12&,const ZZn6&); + + friend ZZn12 pow(const ZZn12&,const Big&); + friend ZZn12 pow(const ZZn12&,const Big*); + friend ZZn12 pow(const ZZn12*,const ZZn12&,const Big&); + friend ZZn12 pow(int,const ZZn12*,const Big*); + friend void precompute(const ZZn12&,ZZn12 *); + friend ZZn12 inverse(const ZZn12&); + friend ZZn12 conj(const ZZn12&); + friend ZZn6 real(const ZZn12& x) {return x.a;} + friend ZZn6 imaginary(const ZZn12& x) {return x.b;} +#ifndef MR_NO_RAND + friend ZZn12 randn12(void); // random ZZn12 +#endif + friend BOOL operator==(const ZZn12& x,const ZZn12& y) + {if (x.a==y.a && x.b==y.b) return TRUE; else return FALSE; } + + friend BOOL operator!=(const ZZn12& x,const ZZn12& y) + {if (x.a!=y.a || x.b!=y.b) return TRUE; else return FALSE; } +#ifndef MR_NO_STANDARD_IO + friend ostream& operator<<(ostream&,ZZn12&); +#endif + ~ZZn12() {} +}; +#ifndef MR_NO_RAND +extern ZZn12 randn12(void); +#endif +#endif + diff --git a/miracl/source/curve/pairing/zzn18.cpp b/miracl/source/curve/pairing/zzn18.cpp new file mode 100644 index 0000000..0bb6826 --- /dev/null +++ b/miracl/source/curve/pairing/zzn18.cpp @@ -0,0 +1,375 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file ZZn18.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ZZn18 (Arithmetic over n^12) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#include "zzn18.h" + +using namespace std; + +// Frobenius X=x^p. Assumes p=13 mod 18. Ideally should be generalised depending on mip->pmod9. + +ZZn18& ZZn18::powq(ZZn& W) +{ + BOOL ku=unitary; + BOOL km=miller; + a.powq(); b.powq(); c.powq(); + b=tx4(W*b); + c=get_mip()->cnr*(tx2((W*W)*c)); + unitary=ku; + miller=km; + return *this; +} + +void ZZn18::get(ZZn6& x,ZZn6& y,ZZn6& z) const +{x=a; y=b; z=c;} + +void ZZn18::get(ZZn6& x) const +{x=a; } + +void ZZn18::get1(ZZn6& x) const +{x=b; } + +void ZZn18::get2(ZZn6& x) const +{x=c; } + +ZZn18& ZZn18::operator*=(const ZZn18& x) +{ // optimized to reduce constructor/destructor calls + if (&x==this) + { + ZZn6 A,B,C,D; + if (unitary) + { // Granger & Scott PKC 2010 - only 3 squarings! + + A=a; a*=a; D=a; a+=a; a+=D; A.conj(); A+=A; a-=A; + B=c; B*=B; + B=tx(B); + D=B; B+=B; B+=D; + C=b; C*=C; D=C; C+=C; C+=D; + + b.conj(); b+=b; c.conj(); c+=c; c=-c; + b+=B; c+=C; + // cout << "unitary" << endl; + } + else + { + if (!miller) + { // Chung-Hasan SQR2 + A=a; A*=A; + B=b*c; B+=B; + C=c; C*=C; + D=a*b; D+=D; + c+=(a+b); c*=c; + + a=A+tx(B); + b=D+tx(C); + c-=(A+B+C+D); + } + else + { +// Chung-Hasan SQR3 - actually calculate 2x^2 ! +// Slightly dangerous - but works as will be raised to p^{k/2}-1 +// which wipes out the 2. + A=a; A*=A; // a0^2 = S0 + C=c; C*=b; C+=C; // 2a1.a2 = S3 + D=c; D*=D; // a2^2 = S4 + c+=a; // a0+a2 + + B=b; B+=c; B*=B; // (a0+a1+a2)^2 =S1 + + c-=b; c*=c; // (a0-a1+a2)^2 =S2 + + C+=C; A+=A; D+=D; + + a=A+tx(C); + b=B-c-C+tx(D); + c+=B-A-D; // is this code telling me something...? + } +/* if you want to play safe! + c+=B; c/=2; + B-=c; B-=C; + c-=A; c-=D; + a=A+tx(C); + b=B+tx(D); +*/ + + } + } + else + { // Karatsuba + ZZn6 Z0,Z1,Z2,Z3,Z4,T0,T1; + + Z0=a*x.a; //9 + Z2=b*x.b; //+6 + + T0=a+b; + T1=x.a+x.b; + Z1=T0*T1; //+9 + Z1-=Z0; + Z1-=Z2; + T0=b+c; + T1=x.b+x.c; + Z3=T0*T1; //+6 + + Z3-=Z2; + + T0=a+c; + T1=x.a+x.c; + T0*=T1; //+9=39 for "special case" + Z2+=T0; + Z2-=Z0; + + b=Z1; + if (!(x.c).iszero()) + { // exploit special form of BN curve line function + Z4=c*x.c; + Z2-=Z4; + Z3-=Z4; + b+=tx(Z4); + } + a=Z0+tx(Z3); + c=Z2; + + if (!x.unitary) unitary=FALSE; + } + return *this; +} + +ZZn18& ZZn18::operator/=(const ZZn6& x) +{ + *this*=inverse(x); + unitary=FALSE; + return *this; +} + + +ZZn18& ZZn18::operator/=(const ZZn18& x) +{ + *this*=inverse(x); + if (!x.unitary) unitary=FALSE; + return *this; +} + +ZZn18 conj(const ZZn18& x) +{ + ZZn18 u=x; + u.conj(); + return u; +} + +ZZn18 inverse(const ZZn18& w) +{ + ZZn18 y; + + if (w.unitary) + { + y=conj(w); + return y; + } + + ZZn6 f0; + + y.a=w.a*w.a-tx(w.b*w.c); + y.b=tx(w.c*w.c)-w.a*w.b; + y.c=w.b*w.b-w.a*w.c; + + f0=tx(w.b*y.c)+w.a*y.a+tx(w.c*y.b); + f0=inverse(f0); + + y.c*=f0; + y.b*=f0; + y.a*=f0; + + return y; +} + +ZZn18 operator+(const ZZn18& x,const ZZn18& y) +{ZZn18 w=x; w.a+=y.a; w.b+=y.b; w.c+=y.c; return w; } + +ZZn18 operator+(const ZZn18& x,const ZZn6& y) +{ZZn18 w=x; w.a+=y; return w; } + +ZZn18 operator-(const ZZn18& x,const ZZn18& y) +{ZZn18 w=x; w.a-=y.a; w.b-=y.b; w.c-=y.c; return w; } + +ZZn18 operator-(const ZZn18& x,const ZZn6& y) +{ZZn18 w=x; w.a-=y; return w; } + +ZZn18 operator-(const ZZn18& x) +{ZZn18 w; w.a=-x.a; w.b=-x.b; w.c-=x.c; w.unitary=FALSE; return w; } + +ZZn18 operator*(const ZZn18& x,const ZZn18& y) +{ + ZZn18 w=x; + if (&x==&y) w*=w; + else w*=y; + return w; +} + +ZZn18 operator*(const ZZn18& x,const ZZn6& y) +{ZZn18 w=x; w*=y; return w;} + +ZZn18 operator*(const ZZn6& y,const ZZn18& x) +{ZZn18 w=x; w*=y; return w;} + +ZZn18 operator*(const ZZn18& x,int y) +{ZZn18 w=x; w*=y; return w;} + +ZZn18 operator*(int y,const ZZn18& x) +{ZZn18 w=x; w*=y; return w;} + +ZZn18 operator/(const ZZn18& x,const ZZn18& y) +{ZZn18 w=x; w/=y; return w;} + +ZZn18 operator/(const ZZn18& x,const ZZn6& y) +{ZZn18 w=x; w/=y; return w;} + +#ifndef MR_NO_RAND +ZZn18 randn18(void) +{ZZn18 w; w.a=randn6(); w.b=randn6(); w.c=randn6(); w.unitary=FALSE; return w;} +#endif +ZZn18 tx(const ZZn18& w) +{ + ZZn18 u=w; + + ZZn6 t=u.a; + u.a=tx(u.c); + u.c=u.b; + u.b=t; + + return u; +} + +// regular ZZn18 powering + +// If k is low Hamming weight this will be just as good.. + +ZZn18 pow(const ZZn18& x,const Big& k) +{ + int i,j,nb,n,nbw,nzs; + ZZn18 u=x; + Big e=k; + BOOL invert_it=FALSE; + + if (e==0) return (ZZn18)one(); + + if (e<0) + { + e=-e; + invert_it=TRUE; + } + + nb=bits(e); + if (nb>1) for (i=nb-2;i>=0;i--) + { + u*=u; + if (bit(e,i)) u*=x; + } + + if (invert_it) u=inverse(u); + + return u; +} + +// standard MIRACL multi-exponentiation + +#ifndef MR_STATIC + +ZZn18 pow(int n,const ZZn18* x,const Big* b) +{ + int k,j,i,m,nb,ea; + ZZn18 *G; + ZZn18 r; + m=1<nb) nb=k; + + r=1; + for (i=nb-1;i>=0;i--) + { + ea=0; + k=1; + for (j=0;j. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ZZn18.h + * + * AUTHOR : M. Scott + * + * NOTE: : Must be used in conjunction with ZZn6.cpp zzn3.cpp big.cpp and zzn.cpp + * : This is designed as a "towering extension", so a ZZn18 consists + * : of three ZZn6. + * + * PURPOSE : Definition of class ZZn18 (Arithmetic over n^18) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * Note: This code assumes that + * p=5 mod 8 + * Irreducible poly is X^3+n, where n=(-2)^(1/6) + */ + +#ifndef ZZn18A_H +#define ZZn18A_H + +#include "zzn6.h" + +class ZZn18 +{ + ZZn6 a,b,c; + BOOL unitary; // "unitary" property means that fast squaring can be used, and inversions are just conjugates + BOOL miller; // "miller" property means that arithmetic on this instance can ignore multiplications + // or divisions by constants - as instance will eventually be raised to (p-1). +public: + ZZn18() {miller=unitary=FALSE;} + ZZn18(int w) {a=(ZZn6)w; b.clear(); c.clear(); miller=FALSE; if (w==1) unitary=TRUE; else unitary=FALSE;} + ZZn18(const ZZn18& w) {a=w.a; b=w.b; c=w.c; miller=w.miller; unitary=w.unitary;} + ZZn18(const ZZn6 &x) {a=x; b.clear(); c.clear(); miller=unitary=FALSE;} + ZZn18(const ZZn6 &x,const ZZn6& y,const ZZn6& z) {a=x; b=y; c=z; miller=unitary=FALSE;} + ZZn18(const ZZn &x) {a=(ZZn6)x; b.clear(); c.clear(); miller=unitary=FALSE;} + ZZn18(const Big &x) {a=(ZZn6)x; b.clear(); c.clear(); miller=unitary=FALSE;} + + void set(const ZZn6 &x,const ZZn6 &y,const ZZn6 &z) {a=x; b=y; c=z; unitary=FALSE;} + void set(const ZZn6 &x) {a=x; b.clear(); c.clear();unitary=FALSE;} + void set(const ZZn6 &x,const ZZn6 &y) {a=x; b=y; c.clear();unitary=FALSE; } + void set1(const ZZn6 &x) {a.clear(); b=x; c.clear();unitary=FALSE;} + void set2(const ZZn6 &x) {a.clear(); b.clear(); c=x; unitary=FALSE;} + void set(const Big &x) {a=(ZZn6)x; b.clear(); c.clear();unitary=FALSE;} + + void get(ZZn6 &,ZZn6 &,ZZn6 &) const; + void get(ZZn6 &) const; + void get1(ZZn6 &) const; + void get2(ZZn6 &) const; + + void clear() {a.clear(); b.clear(); c.clear();} + void mark_as_unitary() {miller=FALSE; unitary=TRUE;} + void mark_as_miller() {miller=TRUE;} + void mark_as_regular() {miller=unitary=FALSE;} + BOOL is_unitary() {return unitary;} + + ZZn18& conj() {a.conj(); b.conj(); b=-b; c.conj(); return *this;} + + BOOL iszero() const {if (a.iszero() && b.iszero() && c.iszero()) return TRUE; return FALSE; } + BOOL isunity() const {if (a.isunity() && b.iszero() && c.iszero()) return TRUE; return FALSE; } + // BOOL isminusone() const {if (a.isminusone() && b.iszero()) return TRUE; return FALSE; } + + ZZn18& powq(ZZn&); + ZZn18& operator=(int i) {a=i; b.clear(); c.clear(); if (i==1) unitary=TRUE; else unitary=FALSE; return *this;} + ZZn18& operator=(const ZZn6& x) {a=x; b.clear(); c.clear(); unitary=FALSE; return *this; } + ZZn18& operator=(const ZZn18& x) {a=x.a; b=x.b; c=x.c; miller=x.miller; unitary=x.unitary; return *this; } + ZZn18& operator+=(const ZZn6& x) {a+=x; unitary=FALSE; return *this; } + ZZn18& operator+=(const ZZn18& x) {a+=x.a; b+=x.b; c+=x.c; unitary=FALSE; return *this; } + ZZn18& operator-=(const ZZn6& x) {a-=x; unitary=FALSE; return *this; } + ZZn18& operator-=(const ZZn18& x) {a-=x.a; b-=x.b; c-=x.c; unitary=FALSE; return *this; } + ZZn18& operator*=(const ZZn18&); + ZZn18& operator*=(const ZZn6& x) {a*=x; b*=x; c*=x; unitary=FALSE; return *this; } + ZZn18& operator*=(int x) {a*=x; b*=x; c*=x; unitary=FALSE; return *this;} + ZZn18& operator/=(const ZZn18&); + ZZn18& operator/=(const ZZn6&); + + friend ZZn18 operator+(const ZZn18&,const ZZn18&); + friend ZZn18 operator+(const ZZn18&,const ZZn6&); + friend ZZn18 operator-(const ZZn18&,const ZZn18&); + friend ZZn18 operator-(const ZZn18&,const ZZn6&); + friend ZZn18 operator-(const ZZn18&); + + friend ZZn18 operator*(const ZZn18&,const ZZn18&); + friend ZZn18 operator*(const ZZn18&,const ZZn6&); + friend ZZn18 operator*(const ZZn6&,const ZZn18&); + + friend ZZn18 operator*(int,const ZZn18&); + friend ZZn18 operator*(const ZZn18&,int); + + friend ZZn18 operator/(const ZZn18&,const ZZn18&); + friend ZZn18 operator/(const ZZn18&,const ZZn6&); + + friend ZZn18 tx(const ZZn18&); + friend ZZn18 pow(const ZZn18&,const Big&); + friend ZZn18 pow(int,const ZZn18*,const Big*); +// friend ZZn6 pow(int,const ZZn6*,const Big*); + + friend ZZn18 inverse(const ZZn18&); + friend ZZn18 conj(const ZZn18&); +#ifndef MR_NO_RAND + friend ZZn18 randn18(void); // random ZZn18 +#endif + friend BOOL operator==(const ZZn18& x,const ZZn18& y) + {if (x.a==y.a && x.b==y.b && x.c==y.c) return TRUE; else return FALSE; } + + friend BOOL operator!=(const ZZn18& x,const ZZn18& y) + {if (x.a!=y.a || x.b!=y.b || x.c!=y.c) return TRUE; else return FALSE; } + +#ifndef MR_NO_STANDARD_IO + friend ostream& operator<<(ostream&,const ZZn18&); +#endif + + ~ZZn18() {} +}; +#ifndef MR_NO_RAND +extern ZZn18 randn18(void); +#endif +#endif + diff --git a/miracl/source/curve/pairing/zzn2.cpp b/miracl/source/curve/pairing/zzn2.cpp new file mode 100644 index 0000000..83fa843 --- /dev/null +++ b/miracl/source/curve/pairing/zzn2.cpp @@ -0,0 +1,439 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file zzn2.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ZZn2 (Arithmetic over n^2) + * + * Note: This code assumes that + * p=5 mod 8 + * OR p=3 mod 4 + */ + +#include "zzn2.h" + +using namespace std; + +zzn2* ZZn2::getzzn2(void) const + { return (zzn2 *)&fn;} + +void ZZn2::get(Big& x,Big& y) const +{{redc(fn.a,x.getbig()); redc(fn.b,y.getbig()); }} + +void ZZn2::get(Big& x) const +{{redc(fn.a,x.getbig());} } + +void ZZn2::get(ZZn& x,ZZn& y) const +{{copy(fn.a,x.getzzn()); copy(fn.b,y.getzzn()); }} + +void ZZn2::get(ZZn& x) const +{{copy(fn.a,x.getzzn());} } + + +ZZn2& ZZn2::operator/=(const ZZn2& x) +{ + ZZn2 inv=x; + zzn2_inv(&inv.fn); + zzn2_mul(&fn,&inv.fn,&fn); + return *this; +} + +ZZn2& ZZn2::operator/=(const ZZn& x) +{ + ZZn t=one()/x; + zzn2_smul(&fn,t.getzzn(),&fn); + return *this; +} + +ZZn2& ZZn2::operator/=(int i) +{ + if (i==2) {zzn2_div2(&fn); return *this;} + + ZZn t=one()/i; + zzn2_smul(&fn,t.getzzn(),&fn); + return *this; +} + +ZZn2 operator+(const ZZn2& x,const ZZn2& y) +{ZZn2 w=x; w+=y; return w; } + +ZZn2 operator+(const ZZn2& x,const ZZn& y) +{ZZn2 w=x; w+=y; return w; } + +ZZn2 operator-(const ZZn2& x,const ZZn2& y) +{ZZn2 w=x; w-=y; return w; } + +ZZn2 operator-(const ZZn2& x,const ZZn& y) +{ZZn2 w=x; w-=y; return w; } + +ZZn2 operator-(const ZZn2& x) +{ZZn2 w; zzn2_negate((zzn2 *)&x.fn,&w.fn); return w; } + +ZZn2 operator*(const ZZn2& x,const ZZn2& y) +{ + ZZn2 w=x; + if (&x==&y) w*=w; + else w*=y; + return w; +} + +ZZn2 operator*(const ZZn2& x,const ZZn& y) +{ZZn2 w=x; w*=y; return w;} + +ZZn2 operator*(const ZZn& y,const ZZn2& x) +{ZZn2 w=x; w*=y; return w;} + +ZZn2 operator*(const ZZn2& x,int y) +{ZZn2 w=x; w*=y; return w;} + +ZZn2 operator*(int y,const ZZn2& x) +{ZZn2 w=x; w*=y;return w;} + +ZZn2 operator/(const ZZn2& x,const ZZn2& y) +{ZZn2 w=x; w/=y; return w;} + +ZZn2 operator/(const ZZn2& x,const ZZn& y) +{ZZn2 w=x; w/=y; return w;} + +ZZn2 operator/(const ZZn2& x,int i) +{ZZn2 w=x; w/=i; return w;} + +ZZn2 inverse(const ZZn2 &x) +{ZZn2 i=x; zzn2_inv(&i.fn); return i;} + +#ifndef MR_NO_RAND +ZZn2 randn2(void) +{ZZn2 w; zzn2_from_zzns(randn().getzzn(),randn().getzzn(),&w.fn); return w;} +#endif + +BOOL is_on_curve(const ZZn2& x) +{ + ZZn2 w; + int qnr=get_mip()->qnr; + int twist=get_mip()->TWIST; + + if (twist==MR_QUADRATIC) + { + // w=x*x*x+qnr*getA()*x+qnr*tx((ZZn2)getB()); + w=x*x*x+txx(txx((ZZn2)getA()))*x+txx(txx(txx((ZZn2)getB()))); + } + else + { + w=x*x*x+getA()*x+getB(); + } + + if (qr(w)) return TRUE; + return FALSE; +} + +BOOL qr(const ZZn2& x) +{ + ZZn2 y=x; + return (zzn2_qr(&(y.fn))); +/* + ZZn s,xa,xb; + int qnr=get_mip()->qnr; +cout << "in qr(Zn2)" << endl; + if (x.iszero()) return TRUE; + x.get(xa,xb); + if (xb.iszero()) return TRUE; + if (qnr==-1) + { + if (xa.iszero()) return TRUE; + } + + s=xb; + s*=s; + if (qnr== -2) s+=s; + if (!qr(xa*xa+s)) + return FALSE; + return TRUE; +*/ +} + +ZZn2 sqrt(const ZZn2& x) +{ +// sqrt(a+ib) = sqrt(a+sqrt(a*a-n*b*b)/2)+ib/(2*sqrt(a+sqrt(a*a-n*b*b)/2)) +// where i*i=n + + ZZn2 w=x; + zzn2_sqrt(&(w.fn),&(w.fn)); + return w; + +/* + ZZn2 w; + ZZn a,s,t,xa,xb; + int qnr=get_mip()->qnr; + + if (x.iszero()) return w; + x.get(xa,xb); + if (xb.iszero()) + { + if (qr(xa)) + { + s=sqrt(xa); + w=s; + } + else + { + s=sqrt(xa/qnr); + w.set((ZZn)0,s); + } + return w; + } + + if (qnr==-1) + { + if (xa.iszero()) + { + if (qr(xb/2)) + { + s=sqrt(xb/2); + w.set(s,s); + } + else + { + s=sqrt(-xb/2); + w.set(-s,s); + } + return w; + } + } +cout << "in sqrt(zzn2)" << endl; + s=xb; + s*=s; + if (qnr==-2) s+=s; + + s=sqrt(xa*xa+s); + + if (s.iszero()) return w; + + if (qr((xa+s)/2)) + { + a=sqrt((xa+s)/2); + } + else + { + a=sqrt((xa-s)/2); + if (a.iszero()) return w; + } + w.set(a,xb/(2*a)); + + return w; +*/ +} + +ZZn2 conj(const ZZn2& x) +{ + ZZn2 u=x; + u.conj(); + return u; +} + +// for use by ZZn4 or ZZn6a + +ZZn2 txx(const ZZn2& w) +{ // multiply w by t^2 where x^4-t is irreducible polynomial for ZZn4 + // + // for p=5 mod 8 t=sqrt(sqrt(-2)), qnr=-2 + // for p=3 mod 8 t=sqrt(1+sqrt(-1)), qnr=-1 + // for p=7 mod 8 and p=2,3 mod 5 t=sqrt(2+sqrt(-1)), qnr=-1 + ZZn2 u=w; + zzn2_txx(&(u.fn)); + return u; +} + +ZZn2 txd(const ZZn2& w) +{ // divide w by t^2 where x^4-t is irreducible polynomial for ZZn4 + // + // for p=5 mod 8 t=sqrt(sqrt(-2)), qnr=-2 + // for p=3 mod 8 t=sqrt(1+sqrt(-1)), qnr=-1 + // for p=7 mod 8 and p=2,3 mod 5 t=sqrt(2+sqrt(-1)), qnr=-1 + ZZn2 u=w; + zzn2_txd(&(u.fn)); + return u; +} + +ZZn2 tx(const ZZn2& w) +{ // multiply w by i, the square root of the qnr + ZZn2 u=w; + zzn2_timesi(&u.fn); + + return u; +} + +// regular ZZn2 powering - but see powl function in zzn.h + +ZZn2 pow(const ZZn2& x,const Big& k) +{ + int i,j,nb,n,nbw,nzs; + ZZn2 u,u2,t[16]; + + if (x.iszero()) return (ZZn2)0; + if (k==0) return (ZZn2)1; + u=x; + if (k==1) return u; +// +// Prepare table for windowing +// + u2=(u*u); + t[0]=u; + + for (i=1;i<16;i++) + t[i]=u2*t[i-1]; + +// Left to right method - with windows + + nb=bits(k); + if (nb>1) for (i=nb-2;i>=0;) + { + n=window(k,i,&nbw,&nzs,5); + for (j=0;j0) u*=t[n/2]; + i-=nbw; + if (nzs) + { + for (j=0;j=1;) + { + n=naf_window(k,k3,i,&nbw,&nzs,11); + + for (j=0;j0) u*=t[n/2]; + if (n<0) u*=conj(t[(-n)/2]); + i-=nbw; + if (nzs) + { + for (j=0;j=0;i--) + { + if (bit(k,i)) + { + w8*=w9; w8-=y; w9*=w9; w9-=two; + } + else + { + w9*=w8; w9-=y; w8*=w8; w8-=two; + } + } + return (w8/2); +} + +ZZn real(const ZZn2 &x) +{ + ZZn r; + x.get(r); + return r; +} + +ZZn imaginary(const ZZn2 &x) +{ + ZZn r,i; + x.get(r,i); + return i; +} + +#ifndef MR_NO_STANDARD_IO + +ostream& operator<<(ostream& s,const ZZn2& xx) +{ + ZZn2 b=xx; + Big x,y; + b.get(x,y); + s << "[" << x << "," << y << "]"; + return s; +} + +#endif + diff --git a/miracl/source/curve/pairing/zzn2.h b/miracl/source/curve/pairing/zzn2.h new file mode 100644 index 0000000..aa840a2 --- /dev/null +++ b/miracl/source/curve/pairing/zzn2.h @@ -0,0 +1,178 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ZZn2.h + * + * AUTHOR : M. Scott + * + * PURPOSE : Definition of class ZZn2 (Arithmetic over n^2) + * + * Note: This code assumes that + * p=5 mod 8 + * OR p=3 mod 4 + */ + +#ifndef ZZN2_H +#define ZZN2_H + +#include "zzn.h" + +#ifdef ZZNS +#define MR_INIT_ZZN2 {fn.a=&at; at.w=a; at.len=UZZNS; fn.b=&bt; bt.w=b; bt.len=UZZNS;} +#define MR_CLONE_ZZN2(x) {at.len=x.at.len; bt.len=x.bt.len; for (int i=0;i. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file ZZn24.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ZZn24 (Arithmetic over n^24) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + */ + +#include "zzn24.h" + +using namespace std; + +// Frobenius X=x^p. Assumes p=7 mod 12 + +ZZn24& ZZn24::powq(const ZZn2& X) +{ + ZZn2 XX=X*X; + ZZn2 XXX=XX*X; + BOOL ku=unitary; + BOOL km=miller; + XXX=txx(XXX); + a.powq(XXX); b.powq(XXX); c.powq(XXX); + b*=X; + b=tx2(b); + c*=XX; + c=tx2(tx2(c)); + unitary=ku; + miller=km; + return *this; +} + +void ZZn24::get(ZZn8& x,ZZn8& y,ZZn8& z) const +{x=a; y=b; z=c;} + +void ZZn24::get(ZZn8& x) const +{x=a; } + +void ZZn24::get1(ZZn8& x) const +{x=b; } + +void ZZn24::get2(ZZn8& x) const +{x=c; } + +ZZn24& ZZn24::operator*=(const ZZn24& x) +{ // optimized to reduce constructor/destructor calls + if (&x==this) + { + ZZn8 A,B,C,D; + if (unitary) + { // Granger & Scott PKC 2010 - only 3 squarings! + + A=a; a*=a; D=a; a+=a; a+=D; A.conj(); A+=A; a-=A; + B=c; B*=B; B=tx(B); D=B; B+=B; B+=D; + C=b; C*=C; D=C; C+=C; C+=D; + + b.conj(); b+=b; c.conj(); c+=c; c=-c; + b+=B; c+=C; + // cout << "unitary" << endl; + } + else + { + if (!miller) + { // Chung-Hasan SQR2 + A=a; A*=A; + B=b*c; B+=B; + C=c; C*=C; + D=a*b; D+=D; + c+=(a+b); c*=c; + + a=A+tx(B); + b=D+tx(C); + c-=(A+B+C+D); + } + else + { +// Chung-Hasan SQR3 - actually calculate 2x^2 ! +// Slightly dangerous - but works as will be raised to p^{k/2}-1 +// which wipes out the 2. + A=a; A*=A; // a0^2 = S0 + C=c; C*=b; C+=C; // 2a1.a2 = S3 + D=c; D*=D; // a2^2 = S4 + c+=a; // a0+a2 + + B=b; B+=c; B*=B; // (a0+a1+a2)^2 =S1 + + c-=b; c*=c; // (a0-a1+a2)^2 =S2 + + C+=C; A+=A; D+=D; + + a=A+tx(C); + b=B-c-C+tx(D); + c+=B-A-D; // is this code telling me something...? + } +/* if you want to play safe! + c+=B; c/=2; + B-=c; B-=C; + c-=A; c-=D; + a=A+tx(C); + b=B+tx(D); +*/ + + } + } + else + { // Karatsuba + ZZn8 Z0,Z1,Z2,Z3,Z4,T0,T1; + + Z0=a*x.a; //9 + Z2=b*x.b; //+6 + + T0=a+b; + T1=x.a+x.b; + Z1=T0*T1; //+9 + Z1-=Z0; + Z1-=Z2; + T0=b+c; + T1=x.b+x.c; + Z3=T0*T1; //+6 + + Z3-=Z2; + + T0=a+c; + T1=x.a+x.c; + T0*=T1; //+9=39 for "special case" + Z2+=T0; + Z2-=Z0; + + b=Z1; + if (!(x.c).iszero()) + { // exploit special form of BN curve line function + Z4=c*x.c; + Z2-=Z4; + Z3-=Z4; + b+=tx(Z4); + } + a=Z0+tx(Z3); + c=Z2; + + if (!x.unitary) unitary=FALSE; + } + return *this; +} + +ZZn24& ZZn24::operator/=(const ZZn8& x) +{ + *this*=inverse(x); + unitary=FALSE; + return *this; +} + +ZZn24& ZZn24::operator/=(const ZZn24& x) +{ + *this*=inverse(x); + if (!x.unitary) unitary=FALSE; + return *this; +} + +ZZn24 conj(const ZZn24& x) +{ + ZZn24 u=x; + u.conj(); + return u; +} + +ZZn24 inverse(const ZZn24& w) +{ + ZZn24 y; + + if (w.unitary) + { + y=conj(w); + return y; + } + + ZZn8 f0; + + y.a=w.a*w.a-tx(w.b*w.c); + y.b=tx(w.c*w.c)-w.a*w.b; + y.c=w.b*w.b-w.a*w.c; + + f0=tx(w.b*y.c)+w.a*y.a+tx(w.c*y.b); + f0=inverse(f0); + + y.c*=f0; + y.b*=f0; + y.a*=f0; + + return y; +} + +ZZn24 operator+(const ZZn24& x,const ZZn24& y) +{ZZn24 w=x; w.a+=y.a; w.b+=y.b; w.c+=y.c; return w; } + +ZZn24 operator+(const ZZn24& x,const ZZn8& y) +{ZZn24 w=x; w.a+=y; return w; } + +ZZn24 operator-(const ZZn24& x,const ZZn24& y) +{ZZn24 w=x; w.a-=y.a; w.b-=y.b; w.c-=y.c; return w; } + +ZZn24 operator-(const ZZn24& x,const ZZn8& y) +{ZZn24 w=x; w.a-=y; return w; } + +ZZn24 operator-(const ZZn24& x) +{ZZn24 w; w.a=-x.a; w.b=-x.b; w.c-=x.c; w.unitary=FALSE; return w; } + +ZZn24 operator*(const ZZn24& x,const ZZn24& y) +{ + ZZn24 w=x; + if (&x==&y) w*=w; + else w*=y; + return w; +} + +ZZn24 operator*(const ZZn24& x,const ZZn8& y) +{ZZn24 w=x; w*=y; return w;} + +ZZn24 operator*(const ZZn8& y,const ZZn24& x) +{ZZn24 w=x; w*=y; return w;} + +ZZn24 operator*(const ZZn24& x,int y) +{ZZn24 w=x; w*=y; return w;} + +ZZn24 operator*(int y,const ZZn24& x) +{ZZn24 w=x; w*=y; return w;} + +ZZn24 operator/(const ZZn24& x,const ZZn24& y) +{ZZn24 w=x; w/=y; return w;} + +ZZn24 operator/(const ZZn24& x,const ZZn8& y) +{ZZn24 w=x; w/=y; return w;} + +#ifndef MR_NO_RAND +ZZn24 randn24(void) +{ZZn24 w; w.a=randn8(); w.b=randn8(); w.c=randn8(); w.unitary=FALSE; return w;} +#endif +ZZn24 tx(const ZZn24& w) +{ + ZZn24 u=w; + + ZZn8 t=u.a; + u.a=tx(u.c); + u.c=u.b; + u.b=t; + + return u; +} + +// regular ZZn24 powering + +// If k is low Hamming weight this will be just as good.. + +ZZn24 pow(const ZZn24& x,const Big& k) +{ + int i,nb; + ZZn24 u=x; + Big e=k; + BOOL invert_it=FALSE; + + if (e==0) return (ZZn24)one(); + + if (e<0) + { + e=-e; + invert_it=TRUE; + } + + nb=bits(e); + if (nb>1) for (i=nb-2;i>=0;i--) + { + u*=u; + if (bit(e,i)) u*=x; + } + + if (invert_it) u=inverse(u); + + return u; +} + +// standard MIRACL multi-exponentiation + +#ifndef MR_STATIC + +ZZn24 pow(int n,const ZZn24* x,const Big* b) +{ + int k,j,i,m,nb,ea; + ZZn24 *G; + ZZn24 r; + m=1<nb) nb=k; + + r=1; + for (i=nb-1;i>=0;i--) + { + ea=0; + k=1; + for (j=0;j. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ZZn24.h + * + * AUTHOR : M. Scott + * + * NOTE: : Must be used in conjunction with ZZn8.cpp zzn4.cpp zzn2.cpp big.cpp zzn.cpp + * : This is designed as a "towering extension", so a ZZn24 consists + * : of three ZZn8. + * + * PURPOSE : Definition of class ZZn24 (Arithmetic over n^24) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + */ + +#ifndef ZZn24_H +#define ZZn24_H + +#include "zzn8.h" + +class ZZn24 +{ + ZZn8 a,b,c; + BOOL unitary; // "unitary" property measns that fast squaring can be used, and inversions are just conjugates + BOOL miller; // "miller" property means that arithmetic on this instance can ignore multiplications + // or divisions by constants - as instance will eventually be raised to (p-1). +public: + ZZn24() {miller=unitary=FALSE;} + ZZn24(int w) {a=(ZZn8)w; b.clear(); c.clear(); miller=FALSE; if (w==1) unitary=TRUE; else unitary=FALSE;} + ZZn24(const ZZn24& w) {a=w.a; b=w.b; c=w.c; miller=w.miller; unitary=w.unitary;} + ZZn24(const ZZn8 &x) {a=x; b.clear(); c.clear(); miller=unitary=FALSE;} + ZZn24(const ZZn8 &x,const ZZn8& y,const ZZn8& z) {a=x; b=y; c=z; miller=unitary=FALSE;} + ZZn24(const ZZn &x) {a=(ZZn8)x; b.clear(); c.clear(); miller=unitary=FALSE;} + ZZn24(const Big &x) {a=(ZZn8)x; b.clear(); c.clear(); miller=unitary=FALSE;} + + void set(const ZZn8 &x,const ZZn8 &y,const ZZn8 &z) {a=x; b=y; c=z; unitary=FALSE;} + void set(const ZZn8 &x) {a=x; b.clear(); c.clear();unitary=FALSE;} + void set(const ZZn8 &x,const ZZn8 &y) {a=x; b=y; c.clear();unitary=FALSE; } + void set1(const ZZn8 &x) {a.clear(); b=x; c.clear();unitary=FALSE;} + void set2(const ZZn8 &x) {a.clear(); b.clear(); c=x; unitary=FALSE;} + void set(const Big &x) {a=(ZZn8)x; b.clear(); c.clear();unitary=FALSE;} + + void get(ZZn8 &,ZZn8 &,ZZn8 &) const; + void get(ZZn8 &) const; + void get1(ZZn8 &) const; + void get2(ZZn8 &) const; + + void clear() {a.clear(); b.clear(); c.clear();} + void mark_as_unitary() {miller=FALSE; unitary=TRUE;} + void mark_as_miller() {miller=TRUE;} + void mark_as_regular() {miller=unitary=FALSE;} + + BOOL is_unitary() {return unitary;} + + ZZn24& conj() {a.conj(); b.conj(); b=-b; c.conj(); return *this;} + + BOOL iszero() const {if (a.iszero() && b.iszero() && c.iszero()) return TRUE; return FALSE; } + BOOL isunity() const {if (a.isunity() && b.iszero() && c.iszero()) return TRUE; return FALSE; } + // BOOL isminusone() const {if (a.isminusone() && b.iszero()) return TRUE; return FALSE; } + + ZZn24& powq(const ZZn2&); + ZZn24& operator=(int i) {a=i; b.clear(); c.clear(); if (i==1) unitary=TRUE; else unitary=FALSE; return *this;} + ZZn24& operator=(const ZZn8& x) {a=x; b.clear(); c.clear(); unitary=FALSE; return *this; } + ZZn24& operator=(const ZZn24& x) {a=x.a; b=x.b; c=x.c; miller=x.miller; unitary=x.unitary; return *this; } + ZZn24& operator+=(const ZZn8& x) {a+=x; unitary=FALSE; return *this; } + ZZn24& operator+=(const ZZn24& x) {a+=x.a; b+=x.b; c+=x.c; unitary=FALSE; return *this; } + ZZn24& operator-=(const ZZn8& x) {a-=x; unitary=FALSE; return *this; } + ZZn24& operator-=(const ZZn24& x) {a-=x.a; b-=x.b; c-=x.c; unitary=FALSE; return *this; } + ZZn24& operator*=(const ZZn24&); + ZZn24& operator*=(const ZZn8& x) {a*=x; b*=x; c*=x; unitary=FALSE; return *this; } + ZZn24& operator*=(int x) {a*=x; b*=x; c*=x; unitary=FALSE; return *this;} + ZZn24& operator/=(const ZZn24&); + ZZn24& operator/=(const ZZn8&); + + friend ZZn24 operator+(const ZZn24&,const ZZn24&); + friend ZZn24 operator+(const ZZn24&,const ZZn8&); + friend ZZn24 operator-(const ZZn24&,const ZZn24&); + friend ZZn24 operator-(const ZZn24&,const ZZn8&); + friend ZZn24 operator-(const ZZn24&); + + friend ZZn24 operator*(const ZZn24&,const ZZn24&); + friend ZZn24 operator*(const ZZn24&,const ZZn8&); + friend ZZn24 operator*(const ZZn8&,const ZZn24&); + + friend ZZn24 operator*(int,const ZZn24&); + friend ZZn24 operator*(const ZZn24&,int); + + friend ZZn24 operator/(const ZZn24&,const ZZn24&); + friend ZZn24 operator/(const ZZn24&,const ZZn8&); + + friend ZZn24 tx(const ZZn24&); + friend ZZn24 pow(const ZZn24&,const Big&); + friend ZZn24 pow(int,const ZZn24*,const Big*); +// friend ZZn6 pow(int,const ZZn6*,const Big*); + + friend ZZn24 inverse(const ZZn24&); + friend ZZn24 conj(const ZZn24&); +#ifndef MR_NO_RAND + friend ZZn24 randn24(void); // random ZZn24 +#endif + friend BOOL operator==(const ZZn24& x,const ZZn24& y) + {if (x.a==y.a && x.b==y.b && x.c==y.c) return TRUE; else return FALSE; } + + friend BOOL operator!=(const ZZn24& x,const ZZn24& y) + {if (x.a!=y.a || x.b!=y.b || x.c!=y.c) return TRUE; else return FALSE; } + +#ifndef MR_NO_STANDARD_IO + friend ostream& operator<<(ostream&,const ZZn24&); +#endif + + ~ZZn24() {} +}; +#ifndef MR_NO_RAND +extern ZZn24 randn24(void); +#endif +#endif + diff --git a/miracl/source/curve/pairing/zzn3.cpp b/miracl/source/curve/pairing/zzn3.cpp new file mode 100644 index 0000000..dab76a5 --- /dev/null +++ b/miracl/source/curve/pairing/zzn3.cpp @@ -0,0 +1,395 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file zzn3.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ZZn3 (Arithmetic over n^3) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * Assumes p=1 mod 3 and p NOT 1 mod 8 + * Irreducible is x^3+cnr (cubic non-residue) + * + */ + +#include "zzn3.h" + +using namespace std; + +// First find a cubic non-residue cnr, which is also a quadratic non-residue +// X is precalculated sixth root of unity (cnr)^(p-1)/6 + +void ZZn3::get(ZZn& x,ZZn& y,ZZn& z) const +{copy(fn.a,x.getzzn()); copy(fn.b,y.getzzn()); copy(fn.c,z.getzzn());} + +void ZZn3::get(ZZn& x) const +{{copy(fn.a,x.getzzn());}} + +ZZn3& ZZn3::operator/=(const ZZn& x) +{ + ZZn t=(ZZn)1/x; + zzn3_smul(&fn,t.getzzn(),&fn); + return *this; +} + +ZZn3& ZZn3::operator/=(int i) +{ + if (i==2) {zzn3_div2(&fn); return *this;} + + ZZn t=one()/i; + zzn3_smul(&fn,t.getzzn(),&fn); + return *this; +} + +ZZn3& ZZn3::operator/=(const ZZn3& x) +{ + *this*=inverse(x); + return *this; +} + +ZZn3 inverse(const ZZn3& w) +{ZZn3 i=w; zzn3_inv(&i.fn); return i;} + +ZZn3 operator+(const ZZn3& x,const ZZn3& y) +{ZZn3 w=x; w+=y; return w; } + +ZZn3 operator+(const ZZn3& x,const ZZn& y) +{ZZn3 w=x; w+=y; return w; } + +ZZn3 operator-(const ZZn3& x,const ZZn3& y) +{ZZn3 w=x; w-=y; return w; } + +ZZn3 operator-(const ZZn3& x,const ZZn& y) +{ZZn3 w=x; w-=y; return w; } + +ZZn3 operator-(const ZZn3& x) +{ZZn3 w; zzn3_negate((zzn3 *)&x.fn,&w.fn); return w; } + +ZZn3 operator*(const ZZn3& x,const ZZn3& y) +{ + ZZn3 w=x; + if (&x==&y) w*=w; + else w*=y; + return w; +} + +ZZn3 operator*(const ZZn3& x,const ZZn& y) +{ZZn3 w=x; w*=y; return w;} + +ZZn3 operator*(const ZZn& y,const ZZn3& x) +{ZZn3 w=x; w*=y; return w;} + +ZZn3 operator*(const ZZn3& x,int y) +{ZZn3 w=x; w*=y; return w;} + +ZZn3 operator*(int y,const ZZn3& x) +{ZZn3 w=x; w*=y; return w;} + +ZZn3 operator/(const ZZn3& x,const ZZn3& y) +{ZZn3 w=x; w/=y; return w;} + +ZZn3 operator/(const ZZn3& x,const ZZn& y) +{ZZn3 w=x; w/=y; return w;} + +ZZn3 operator/(const ZZn3& x,int i) +{ZZn3 w=x; w/=i; return w;} +#ifndef MR_NO_RAND +ZZn3 randn3(void) +{ZZn3 w; zzn3_from_zzns(randn().getzzn(),randn().getzzn(),randn().getzzn(),&w.fn); return w;} +#endif + +ZZn3 rhs(const ZZn3& x) +{ + ZZn3 w; + miracl *mip=get_mip(); + int twist=mip->TWIST; + int qnr=mip->cnr; // the cubic non-residue is also a quadratic non-residue + w=x*x*x; + if (twist) + { + if (twist==MR_QUARTIC_M) + { + w+=tx((ZZn3)getA())*x; + } + if (twist==MR_QUARTIC_D) + { + w+=txd((ZZn3)getA())*x; + } + if (twist==MR_SEXTIC_M || twist==MR_CUBIC_M) + { + w+=tx((ZZn3)getB()); + } + if (twist==MR_SEXTIC_D || twist==MR_CUBIC_D) + { + w+=txd((ZZn3)getB()); + } + if (twist==MR_QUADRATIC) + { + w+=qnr*qnr*getA()*x+(qnr*qnr*qnr)*getB(); + } + } + else + { + w+=getA()*x+getB(); + } + return w; +} + +BOOL is_on_curve(const ZZn3& x) +{ + ZZn3 w; + if (qr(rhs(x))) return TRUE; + return FALSE; +} + +BOOL qr(const ZZn3& x) +{ + Big p=get_modulus(); + ZZn3 r,t; + + t=r=x; + t.powq(); + r*=t; + t.powq(); + r*=t; +// check x^[(p^3-1)/2] = 1 + if (pow(r,(p-1)/2)==1) return TRUE; + else return FALSE; +} + +ZZn3 sqrt(const ZZn3& x) +{ + ZZn3 r,w,t; + Big p=get_modulus(); + + if (!qr(x)) return r; + +// oh boy this is clever! + + switch (get_mip()->pmod8) + { + case 5: + r=(x+x); + r.powq(); + w=r*r; t=w*r; w*=t; + r.powq(); + r*=(w*(x+x)); + r=pow(r,(p-5)/8); + r*=t; + w=r*r; w*=x; w+=w; + r*=x; r*=(w-(ZZn)1); + break; + case 3: + case 7: + r=x; + r.powq(); + t=r*r; + w=t*r; + r.powq(); + r*=(w*x); + r=pow(r,(p-3)/4); + r*=(t*x); + break; + default: break; + } + + return r; +} + +ZZn3 tx(const ZZn3& w) +{ + ZZn3 u=w; + zzn3_timesi(&u.fn); + return u; +} + +ZZn3 tx2(const ZZn3& w) +{ + ZZn3 u=w; + zzn3_timesi2(&u.fn); + return u; +} + + +ZZn3 txd(const ZZn3& w) +{ + ZZn3 u; + ZZn wa,wb,wc; + w.get(wa,wb,wc); + + u.set(wb,wc,(wa/get_mip()->cnr)); + + return u; +} + +// regular ZZn3 powering + +ZZn3 pow(const ZZn3& x,const Big& k) +{ + int i,j,nb,n,nbw,nzs; + ZZn3 u,u2,t[16]; + if (k==0) return (ZZn3)1; + u=x; + if (k==1) return u; +// +// Prepare table for windowing +// + u2=(u*u); + t[0]=u; + + for (i=1;i<16;i++) + t[i]=u2*t[i-1]; + +// Left to right method - with windows + + nb=bits(k); + if (nb>1) for (i=nb-2;i>=0;) + { + n=window(k,i,&nbw,&nzs,5); + for (j=0;j0) u*=t[n/2]; + i-=nbw; + if (nzs) + { + for (j=0;j. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ZZn3.h + * + * AUTHOR : M. Scott + * + * NOTE: : Must be used in conjunction with zzn3.cpp big.cpp and zzn.cpp + * : An element looks like (a+bx+cx^2) + * : where x is the cube root of cnr (a cubic non-residue). + * + * PURPOSE : Definition of class ZZn3 (Arithmetic over n^3) + * + * Note: This code assumes that n=1 mod 3 and x^3+cnr is irreducible for some small cnr; + * + */ + +#ifndef ZZN3_H +#define ZZN3_H + +#include "zzn.h" + +#ifdef ZZNS +#define MR_INIT_ZZN3 {fn.a=&at; at.w=a; at.len=UZZNS; fn.b=&bt; bt.w=b; bt.len=UZZNS; fn.c=&ct; ct.w=c; ct.len=UZZNS;} +#define MR_CLONE_ZZN3(x) {at.len=x.at.len; bt.len=x.bt.len; ct.len=x.ct.len; for (int i=0;i. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file ZZn36.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ZZn36 (Arithmetic over n^36) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#include "zzn36.h" + +using namespace std; + +// Frobenius X=x^p. Assumes p=1 mod 36 + +ZZn36& ZZn36::powq(const ZZn& X) +{ + ZZn XX=X*X; + ZZn XXX=XX*X; + BOOL ku=unitary; + BOOL km=miller; + a.powq(XXX); b.powq(XXX); c.powq(XXX); + b*=X; + c*=XX; + unitary=ku; + miller=km; + return *this; +} + +void ZZn36::get(ZZn12& x,ZZn12& y,ZZn12& z) const +{x=a; y=b; z=c;} + +void ZZn36::get(ZZn12& x) const +{x=a; } + +void ZZn36::get1(ZZn12& x) const +{x=b; } + +void ZZn36::get2(ZZn12& x) const +{x=c; } + +ZZn36& ZZn36::operator*=(const ZZn36& x) +{ // optimized to reduce constructor/destructor calls + if (&x==this) + { + ZZn12 A,B,C,D; + if (unitary) + { // Granger & Scott PKC 2010 - only 3 squarings! + + A=a; a*=a; D=a; a+=a; a+=D; A.conj(); A+=A; a-=A; + B=c; B*=B; B=tx(B); D=B; B+=B; B+=D; + C=b; C*=C; D=C; C+=C; C+=D; + + b.conj(); b+=b; c.conj(); c+=c; c=-c; + b+=B; c+=C; + // cout << "unitary" << endl; + } + else + { + if (!miller) + { // Chung-Hasan SQR2 + A=a; A*=A; + B=b*c; B+=B; + C=c; C*=C; + D=a*b; D+=D; + c+=(a+b); c*=c; + + a=A+tx(B); + b=D+tx(C); + c-=(A+B+C+D); + } + else + { +// Chung-Hasan SQR3 - actually calculate 2x^2 ! +// Slightly dangerous - but works as will be raised to p^{k/2}-1 +// which wipes out the 2. + A=a; A*=A; // a0^2 = S0 + C=c; C*=b; C+=C; // 2a1.a2 = S3 + D=c; D*=D; // a2^2 = S4 + c+=a; // a0+a2 + + B=b; B+=c; B*=B; // (a0+a1+a2)^2 =S1 + + c-=b; c*=c; // (a0-a1+a2)^2 =S2 + + C+=C; A+=A; D+=D; + + a=A+tx(C); + b=B-c-C+tx(D); + c+=B-A-D; // is this code telling me something...? + } +/* if you want to play safe! + c+=B; c/=2; + B-=c; B-=C; + c-=A; c-=D; + a=A+tx(C); + b=B+tx(D); +*/ + + } + } + else + { // Karatsuba + ZZn12 Z0,Z1,Z2,Z3,Z4,T0,T1; + + Z0=a*x.a; //9 + Z2=b*x.b; //+6 + + T0=a+b; + T1=x.a+x.b; + Z1=T0*T1; //+9 + Z1-=Z0; + Z1-=Z2; + T0=b+c; + T1=x.b+x.c; + Z3=T0*T1; //+6 + + Z3-=Z2; + + T0=a+c; + T1=x.a+x.c; + T0*=T1; //+9=39 for "special case" + Z2+=T0; + Z2-=Z0; + + b=Z1; + if (!(x.c).iszero()) + { // exploit special form of BN curve line function + Z4=c*x.c; + Z2-=Z4; + Z3-=Z4; + b+=tx(Z4); + } + a=Z0+tx(Z3); + c=Z2; + + if (!x.unitary) unitary=FALSE; + } + return *this; +} + +ZZn36& ZZn36::operator/=(const ZZn12& x) +{ + *this*=inverse(x); + unitary=FALSE; + return *this; +} + +ZZn36& ZZn36::operator/=(const ZZn36& x) +{ + *this*=inverse(x); + if (!x.unitary) unitary=FALSE; + return *this; +} + +ZZn36 conj(const ZZn36& x) +{ + ZZn36 u=x; + u.conj(); + return u; +} + +ZZn36 inverse(const ZZn36& w) +{ + ZZn36 y; + + if (w.unitary) + { + y=conj(w); + return y; + } + + ZZn12 f0; + + y.a=w.a*w.a-tx(w.b*w.c); + y.b=tx(w.c*w.c)-w.a*w.b; + y.c=w.b*w.b-w.a*w.c; + + f0=tx(w.b*y.c)+w.a*y.a+tx(w.c*y.b); + f0=inverse(f0); + + y.c*=f0; + y.b*=f0; + y.a*=f0; + + return y; +} + +ZZn36 operator+(const ZZn36& x,const ZZn36& y) +{ZZn36 w=x; w.a+=y.a; w.b+=y.b; w.c+=y.c; return w; } + +ZZn36 operator+(const ZZn36& x,const ZZn12& y) +{ZZn36 w=x; w.a+=y; return w; } + +ZZn36 operator-(const ZZn36& x,const ZZn36& y) +{ZZn36 w=x; w.a-=y.a; w.b-=y.b; w.c-=y.c; return w; } + +ZZn36 operator-(const ZZn36& x,const ZZn12& y) +{ZZn36 w=x; w.a-=y; return w; } + +ZZn36 operator-(const ZZn36& x) +{ZZn36 w; w.a=-x.a; w.b=-x.b; w.c-=x.c; w.unitary=FALSE; return w; } + +ZZn36 operator*(const ZZn36& x,const ZZn36& y) +{ + ZZn36 w=x; + if (&x==&y) w*=w; + else w*=y; + return w; +} + +ZZn36 operator*(const ZZn36& x,const ZZn12& y) +{ZZn36 w=x; w*=y; return w;} + +ZZn36 operator*(const ZZn12& y,const ZZn36& x) +{ZZn36 w=x; w*=y; return w;} + +ZZn36 operator*(const ZZn36& x,int y) +{ZZn36 w=x; w*=y; return w;} + +ZZn36 operator*(int y,const ZZn36& x) +{ZZn36 w=x; w*=y; return w;} + +ZZn36 operator/(const ZZn36& x,const ZZn36& y) +{ZZn36 w=x; w/=y; return w;} + +ZZn36 operator/(const ZZn36& x,const ZZn12& y) +{ZZn36 w=x; w/=y; return w;} + +#ifndef MR_NO_RAND +ZZn36 randn36(void) +{ZZn36 w; w.a=randn12(); w.b=randn12(); w.c=randn12(); w.unitary=FALSE; return w;} +#endif +ZZn36 tx(const ZZn36& w) +{ + ZZn36 u=w; + + ZZn12 t=u.a; + u.a=tx(u.c); + u.c=u.b; + u.b=t; + + return u; +} + +// regular ZZn36 powering + +// If k is low Hamming weight this will be just as good.. + +ZZn36 pow(const ZZn36& x,const Big& k) +{ + int i,nb; + ZZn36 u=x; + Big e=k; + BOOL invert_it=FALSE; + + if (e==0) return (ZZn36)one(); + + if (e<0) + { + e=-e; + invert_it=TRUE; + } + + nb=bits(e); + if (nb>1) for (i=nb-2;i>=0;i--) + { + u*=u; + if (bit(e,i)) u*=x; + } + + if (invert_it) u=inverse(u); + + return u; +} + +// standard MIRACL multi-exponentiation + +#ifndef MR_STATIC + +ZZn36 pow(int n,const ZZn36* x,const Big* b) +{ + int k,j,i,m,nb,ea; + ZZn36 *G; + ZZn36 r; + m=1<nb) nb=k; + + r=1; + for (i=nb-1;i>=0;i--) + { + ea=0; + k=1; + for (j=0;j. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ZZn36.h + * + * AUTHOR : M. Scott + * + * NOTE: : Must be used in conjunction with zzn12b.cpp zzn6.cpp zzn3.cpp big.cpp zzn.cpp + * : This is designed as a "towering extension", so a ZZn36 consists + * : of three ZZn12. + * + * PURPOSE : Definition of class zzn36 (Arithmetic over n^36) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * Note: This code assumes that + * p=5 mod 8 + * Irreducible poly is X^36+2 + * + */ + +#ifndef ZZN36_H +#define ZZN36_H + +#include "zzn12b.h" + +class ZZn36 +{ + ZZn12 a,b,c; + BOOL unitary; // "unitary" property measns that fast squaring can be used, and inversions are just conjugates + BOOL miller; // "miller" property means that arithmetic on this instance can ignore multiplications + // or divisions by constants - as instance will eventually be raised to (p-1). +public: + ZZn36() {miller=unitary=FALSE;} + ZZn36(int w) {a=(ZZn12)w; b.clear(); c.clear(); miller=FALSE; if (w==1) unitary=TRUE; else unitary=FALSE;} + ZZn36(const ZZn36& w) {a=w.a; b=w.b; c=w.c; miller=w.miller; unitary=w.unitary;} + ZZn36(const ZZn12 &x) {a=x; b.clear(); c.clear(); miller=unitary=FALSE;} + ZZn36(const ZZn12 &x,const ZZn12& y,const ZZn12& z) {a=x; b=y; c=z; miller=unitary=FALSE;} + ZZn36(const ZZn &x) {a=(ZZn12)x; b.clear(); c.clear(); miller=unitary=FALSE;} + ZZn36(const Big &x) {a=(ZZn12)x; b.clear(); c.clear(); miller=unitary=FALSE;} + + void set(const ZZn12 &x,const ZZn12 &y,const ZZn12 &z) {a=x; b=y; c=z; unitary=FALSE;} + void set(const ZZn12 &x) {a=x; b.clear(); c.clear();unitary=FALSE;} + void set(const ZZn12 &x,const ZZn12 &y) {a=x; b=y; c.clear();unitary=FALSE; } + void set1(const ZZn12 &x) {a.clear(); b=x; c.clear();unitary=FALSE;} + void set2(const ZZn12 &x) {a.clear(); b.clear(); c=x; unitary=FALSE;} + void set(const Big &x) {a=(ZZn12)x; b.clear(); c.clear();unitary=FALSE;} + + void get(ZZn12 &,ZZn12 &,ZZn12 &) const; + void get(ZZn12 &) const; + void get1(ZZn12 &) const; + void get2(ZZn12 &) const; + + void clear() {a.clear(); b.clear(); c.clear();} + void mark_as_unitary() {miller=FALSE; unitary=TRUE;} + void mark_as_miller() {miller=TRUE;} + void mark_as_regular() {miller=unitary=FALSE;} + + BOOL is_unitary() {return unitary;} + + ZZn36& conj() {a.conj(); b.conj(); b=-b; c.conj(); return *this;} + + BOOL iszero() const {if (a.iszero() && b.iszero() && c.iszero()) return TRUE; return FALSE; } + BOOL isunity() const {if (a.isunity() && b.iszero() && c.iszero()) return TRUE; return FALSE; } + // BOOL isminusone() const {if (a.isminusone() && b.iszero()) return TRUE; return FALSE; } + + ZZn36& powq(const ZZn&); + ZZn36& operator=(int i) {a=i; b.clear(); c.clear(); if (i==1) unitary=TRUE; else unitary=FALSE; return *this;} + ZZn36& operator=(const ZZn12& x) {a=x; b.clear(); c.clear(); unitary=FALSE; return *this; } + ZZn36& operator=(const ZZn36& x) {a=x.a; b=x.b; c=x.c; miller=x.miller; unitary=x.unitary; return *this; } + ZZn36& operator+=(const ZZn12& x) {a+=x; unitary=FALSE; return *this; } + ZZn36& operator+=(const ZZn36& x) {a+=x.a; b+=x.b; c+=x.c; unitary=FALSE; return *this; } + ZZn36& operator-=(const ZZn12& x) {a-=x; unitary=FALSE; return *this; } + ZZn36& operator-=(const ZZn36& x) {a-=x.a; b-=x.b; c-=x.c; unitary=FALSE; return *this; } + ZZn36& operator*=(const ZZn36&); + ZZn36& operator*=(const ZZn12& x) {a*=x; b*=x; c*=x; unitary=FALSE; return *this; } + ZZn36& operator*=(int x) {a*=x; b*=x; c*=x; unitary=FALSE; return *this;} + ZZn36& operator/=(const ZZn36&); + ZZn36& operator/=(const ZZn12&); + + friend ZZn36 operator+(const ZZn36&,const ZZn36&); + friend ZZn36 operator+(const ZZn36&,const ZZn12&); + friend ZZn36 operator-(const ZZn36&,const ZZn36&); + friend ZZn36 operator-(const ZZn36&,const ZZn12&); + friend ZZn36 operator-(const ZZn36&); + + friend ZZn36 operator*(const ZZn36&,const ZZn36&); + friend ZZn36 operator*(const ZZn36&,const ZZn12&); + friend ZZn36 operator*(const ZZn12&,const ZZn36&); + + friend ZZn36 operator*(int,const ZZn36&); + friend ZZn36 operator*(const ZZn36&,int); + + friend ZZn36 operator/(const ZZn36&,const ZZn36&); + friend ZZn36 operator/(const ZZn36&,const ZZn12&); + + friend ZZn36 tx(const ZZn36&); + friend ZZn36 pow(const ZZn36&,const Big&); + friend ZZn36 pow(int,const ZZn36*,const Big*); +// friend ZZn6 pow(int,const ZZn6*,const Big*); + + friend ZZn36 inverse(const ZZn36&); + friend ZZn36 conj(const ZZn36&); +#ifndef MR_NO_RAND + friend ZZn36 randn36(void); // random ZZn36 +#endif + friend BOOL operator==(const ZZn36& x,const ZZn36& y) + {if (x.a==y.a && x.b==y.b && x.c==y.c) return TRUE; else return FALSE; } + + friend BOOL operator!=(const ZZn36& x,const ZZn36& y) + {if (x.a!=y.a || x.b!=y.b || x.c!=y.c) return TRUE; else return FALSE; } + +#ifndef MR_NO_STANDARD_IO + friend ostream& operator<<(ostream&,const ZZn36&); +#endif + + ~ZZn36() {} +}; +#ifndef MR_NO_RAND +extern ZZn36 randn36(void); +#endif +#endif + diff --git a/miracl/source/curve/pairing/zzn4.cpp b/miracl/source/curve/pairing/zzn4.cpp new file mode 100644 index 0000000..ce2d9dc --- /dev/null +++ b/miracl/source/curve/pairing/zzn4.cpp @@ -0,0 +1,482 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file zzn4.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ZZn4 (Arithmetic over n^4) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * Note: This code assumes that -2 is a Quadratic Non-Residue, + * so modulus p=5 mod 8 + * OR p=3 mod 8 + * OR p=7 mod 8, p=2,3 mod 5 + * + * For example for p=3 mod 8 the representation is + * + * A+IB, where A=(a+ib), B=(c+id), I=sqrt(1+i) + * where i=sqrt(-1) + */ + +#include "zzn4.h" + +using namespace std; + +ZZn4& ZZn4::powq(const ZZn2 &m) +{ + zzn4_powq(m.getzzn2(),&fn); + return *this; +} + +void ZZn4::get(ZZn2& x,ZZn2& y) const +{zzn2_copy((zzn2 *)&fn.a,x.getzzn2()); zzn2_copy((zzn2 *)&fn.b,y.getzzn2());} + +void ZZn4::get(ZZn2& x) const +{zzn2_copy((zzn2 *)&fn.a,x.getzzn2()); } + +void ZZn4::geth(ZZn2& x) const +{zzn2_copy((zzn2 *)&fn.b,x.getzzn2()); } + +ZZn4& ZZn4::operator/=(const ZZn2& x) +{ + *this*=inverse(x); + fn.unitary=FALSE; + return *this; +} + +ZZn4& ZZn4::operator/=(const ZZn4& x) +{ + *this*=inverse(x); + if (!x.fn.unitary) fn.unitary=FALSE; + return *this; +} + +ZZn4& ZZn4::operator/=(int i) +{ + if (i==2) + { + zzn2_div2(&fn.a); + zzn2_div2(&fn.b); + } + else + { + ZZn t=(ZZn)1/i; + zzn2_smul((zzn2 *)&fn.a,t.getzzn(),(zzn2 *)&fn.a); + zzn2_smul((zzn2 *)&fn.b,t.getzzn(),(zzn2 *)&fn.b); + } + fn.unitary=FALSE; + return *this; +} + +ZZn4 inverse(const ZZn4& w) +{ + ZZn4 y=w; + zzn4_inv((zzn4 *)&y.fn); + return y; +} + +ZZn4 operator+(const ZZn4& x,const ZZn4& y) +{ZZn4 w=x; w+=y; return w; } + +ZZn4 operator+(const ZZn4& x,const ZZn2& y) +{ZZn4 w=x; w+=y; return w; } + +ZZn4 operator+(const ZZn4& x,const ZZn& y) +{ZZn4 w=x; w+=y; return w; } + +ZZn4 operator-(const ZZn4& x,const ZZn4& y) +{ZZn4 w=x; w-=y; return w; } + +ZZn4 operator-(const ZZn4& x,const ZZn2& y) +{ZZn4 w=x; w-=y; return w; } + +ZZn4 operator-(const ZZn4& x,const ZZn& y) +{ZZn4 w=x; w-=y; return w; } + +ZZn4 operator-(const ZZn4& x) +{ZZn4 w; zzn4_negate((zzn4 *)&x.fn,&w.fn); return w; } + +ZZn4 operator*(const ZZn4& x,const ZZn4& y) +{ + ZZn4 w=x; + if (&x==&y) w*=w; + else w*=y; + return w; +} + +ZZn4 operator*(const ZZn4& x,const ZZn2& y) +{ZZn4 w=x; w*=y; return w;} + +ZZn4 operator*(const ZZn2& y,const ZZn4& x) +{ZZn4 w=x; w*=y; return w;} + +ZZn4 operator*(const ZZn4& x,int y) +{ZZn4 w=x; w*=y; return w;} + +ZZn4 operator*(int y,const ZZn4& x) +{ZZn4 w=x; w*=y; return w;} + +ZZn4 operator*(const ZZn4& x,const ZZn& y) +{ZZn4 w=x; w*=y; return w;} + +ZZn4 operator*(const ZZn& y,const ZZn4& x) +{ZZn4 w=x; w*=y; return w;} + +ZZn4 operator/(const ZZn4& x,const ZZn4& y) +{ZZn4 w=x; w/=y; return w;} + +ZZn4 operator/(const ZZn4& x,const ZZn2& y) +{ZZn4 w=x; w/=y; return w;} + +ZZn4 operator/(const ZZn4& x,int i) +{ZZn4 w=x; w/=i; return w;} + +#ifndef MR_NO_RAND +ZZn4 randn4(void) +{ZZn4 w; zzn4_from_zzn2s(randn2().getzzn2(),randn2().getzzn2(),&w.fn); return w;} +#endif + +ZZn4 rhs(const ZZn4& x) +{ + ZZn4 w,A,B; + miracl *mip=get_mip(); + int twist=mip->TWIST; + w=x*x*x; + A=(ZZn4)getA(); B=(ZZn4)getB(); + if (twist) + { + if (twist==MR_QUARTIC_M) + { + w+=tx(A)*x; + } + if (twist==MR_QUARTIC_D) + { + w+=txd(A)*x; + } + if (twist==MR_SEXTIC_M) + { + w+=tx(B); + } + if (twist==MR_SEXTIC_D) + { + w+=txd(B); + } + if (twist==MR_QUADRATIC) + { + w+=tx(tx(A))*x+tx(tx(tx(B))); + } + } + else + { + w+=A*x+B; + } + return w; +} + +BOOL is_on_curve(const ZZn4& x) +{ + ZZn4 w; + w=rhs(x); + + if (qr(w)) return TRUE; + return FALSE; +} + +BOOL qr(const ZZn4& x) +{ + ZZn2 a,s; + + if (x.iszero()) return TRUE; + x.get(a,s); + if (s.iszero()) return TRUE; + + s*=s; + a*=a; a-=txx(s); + if (!qr(a)) return FALSE; + return TRUE; + +// s=sqrt(a); + +// if (qr((x.a+s)/2) || qr((x.a-s)/2)) return TRUE; +// return FALSE; + +} + +ZZn4 sqrt(const ZZn4& x) +{ +// sqrt(a+xb) = sqrt((a+sqrt(a*a-n*b*b))/2)+x.b/(2*sqrt((a+sqrt(a*a-n*b*b))/2)) +// sqrt(a) = x.sqrt(a/n) +// where x*x=n + + ZZn4 w; + ZZn2 a,s,t; + if (x.iszero()) return w; + + x.get(a,s); + if (s.iszero()) + { + if (qr(a)) + { + s=sqrt(a); + w.set(s,0); + } + else + { + s=sqrt(txd(a)); + w.set(0,s); + } + return w; + } + + s*=s; + a*=a; a-=txx(s); + s=sqrt(a); + + if (s.iszero()) return w; + x.get(t); + if (qr((ZZn2)((t+s)/2))) + { + a=sqrt((t+s)/2); + } + else + { + a=sqrt((t-s)/2); + if (a.iszero()) return w; + } + x.geth(t); + w.set(a,t/(2*a)); + + return w; +} + +ZZn4 conj(const ZZn4& x) +{ + ZZn4 u; + zzn4_conj((zzn4 *)&x.fn,(zzn4 *)&u.fn); + return u; +} + +// For use by ZZn8 + +ZZn4 tx(const ZZn4& x) +{ + ZZn4 w=x; + zzn4_tx(&w.fn); + return w; +} + +ZZn4 txd(const ZZn4& x) +{ + ZZn2 u,v; + x.get(u,v); + u=txd(u); + ZZn4 w(v,u); + + return w; +} + +// ZZn4 powering of unitary elements + +ZZn4 powu(const ZZn4& x,const Big& k) +{ + int i,j,nb,n,nbw,nzs; + ZZn4 u,u2,t[11]; + Big k3; + if (k==0) return (ZZn4)one(); + u=x; + if (k==1) return u; +// +// Prepare table for windowing +// + k3=3*k; + u2=(u*u); + t[0]=u; + + for (i=1;i<=10;i++) + t[i]=u2*t[i-1]; + + nb=bits(k3); + for (i=nb-2;i>=1;) + { + n=naf_window(k,k3,i,&nbw,&nzs,11); + + for (j=0;j0) u*=t[n/2]; + if (n<0) u*=conj(t[(-n)/2]); + i-=nbw; + if (nzs) + { + for (j=0;j1) for (i=nb-2;i>=0;) + { + n=window(k,i,&nbw,&nzs,5); + for (j=0;j0) u*=t[n/2]; + i-=nbw; + if (nzs) + { + for (j=0;jnb) nb=k; + + r=1; + for (i=nb-1;i>=0;i--) + { + ea=0; + k=1; + for (j=0;j=0;i--) + { + if (bit(k,i)) + { + w8*=w9; w8-=y; w9*=w9; w9-=two; + } + else + { + w9*=w8; w9-=y; w8*=w8; w8-=two; + } + } + return (w8/2); +} + +ZZn2 real(const ZZn4 &x) +{ + ZZn2 r; + x.get(r); + return r; +} + +ZZn2 imaginary(const ZZn4 &x) +{ + ZZn2 i; + x.geth(i); + return i; +} + +#ifndef MR_NO_STANDARD_IO + +ostream& operator<<(ostream& s,const ZZn4& xx) +{ + ZZn4 b=xx; + ZZn2 x,y; + b.get(x,y); + s << "[" << x << "," << y << "]"; + return s; +} + +#endif + diff --git a/miracl/source/curve/pairing/zzn4.h b/miracl/source/curve/pairing/zzn4.h new file mode 100644 index 0000000..fd4d0cf --- /dev/null +++ b/miracl/source/curve/pairing/zzn4.h @@ -0,0 +1,198 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ZZn4.h + * + * AUTHOR : M. Scott + * + * NOTE: : Must be used in conjunction with zzn2.cpp big.cpp and zzn.cpp + * : This is designed as a "towering extension", so a ZZn4 consists + * : of a pair of ZZn2. An element looks like (a+x^2.b) + x(c+x^2.d) + * + * PURPOSE : Definition of class ZZn4 (Arithmetic over n^4) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * Note: This code assumes that + * p=5 mod 8 + * OR p=3 mod 8 + * OR p=7 mod 8, p=2,3 mod 5 + * + * Irreducible poly is X^2+n, where n=w+sqrt(m), m= {-1,-2} and w= {0,1,2} + * if p=5 mod 8, n=sqrt(-2) + * if p=3 mod 8, n=1+sqrt(-1) + * if p=7 mod 8, p=2,3 mod 5, n=2+sqrt(-1) + * + */ + +#ifndef ZZN4_H +#define ZZN4_H + +#include "zzn2.h" + +#ifdef ZZNS +#define MR_INIT_ZZN4 {fn.a.a=&at; at.w=a; at.len=UZZNS; fn.a.b=&bt; bt.w=b; bt.len=UZZNS; fn.b.a=&ct; ct.w=c; ct.len=UZZNS; fn.b.b=&dt; dt.w=d; dt.len=UZZNS; fn.unitary=FALSE;} +#define MR_CLONE_ZZN4(x) {fn.unitary=x.fn.unitary; at.len=x.at.len; bt.len=x.bt.len; ct.len=x.ct.len; dt.len=x.dt.len; for (int i=0;i. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file ZZn6.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ZZn6 (Arithmetic over n^6) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#include "zzn6.h" + +using namespace std; + +// Frobenius + +ZZn6& ZZn6::powq(void) +{ + ZZn X; + copy(get_mip()->sru,X.getzzn()); + a.powq(); + b.powq(); + b*=X; + return *this; +} + +void ZZn6::get(ZZn3& x,ZZn3& y) const +{x=a; y=b;} + +void ZZn6::get(ZZn3& x) const +{x=a; } + +void ZZn6::geti(ZZn3& y) const +{y=b; } + +ZZn6& ZZn6::operator*=(const ZZn6& x) +{ // optimized to reduce constructor/destructor calls + if (&x==this) + { +/* See Stam & Lenstra, "Efficient subgroup exponentiation in Quadratic .. Extensions", CHES 2002 */ + if (unitary) + { + ZZn3 t=b; t*=t; + b+=a; b*=b; + b-=t; + a=tx(t); + b-=a; + a+=a; a+=one(); + b-=one(); + // cout << "unitary" << endl; + } + else + { + ZZn3 t=a; t+=b; + ZZn3 t2=a; t2+=tx(b); + t*=t2; + b*=a; + t-=b; + t-=tx(b); + b+=b; + a=t; + // cout << "not unitary" << endl; + } + } + else + { + ZZn3 ac=a; ac*=x.a; + ZZn3 bd=b; bd*=x.b; + ZZn3 t=x.a; t+=x.b; + b+=a; b*=t; b-=ac; b-=bd; + a=ac; a+=tx(bd); + + if (!x.unitary) unitary=FALSE; + } + return *this; +} + +ZZn6& ZZn6::operator/=(const ZZn3& x) +{ + *this*=inverse(x); + unitary=FALSE; + return *this; +} + +ZZn6& ZZn6::operator/=(const ZZn& x) +{ + ZZn t=one()/x; + a*=t; + b*=t; + unitary=FALSE; + return *this; +} + +ZZn6& ZZn6::operator/=(int i) +{ + ZZn t=one()/i; + a*=t; + b*=t; + unitary=FALSE; + return *this; +} + +ZZn6& ZZn6::operator/=(const ZZn6& x) +{ + *this*=inverse(x); + if (!x.unitary) unitary=FALSE; + return *this; +} + +ZZn6 tx(const ZZn6& x) +{ + ZZn3 t=tx(x.b); + ZZn6 u(t,x.a); + return u; +} + +ZZn6 tx2(const ZZn6& x) +{ + ZZn6 u(tx(x.a),tx(x.b)); + return u; +} + +ZZn6 tx4(const ZZn6& x) +{ + ZZn6 u(tx2(x.a),tx2(x.b)); + return u; +} + +ZZn6 txd(const ZZn6& x) +{ + ZZn3 t=txd(x.a); + ZZn6 u(x.b,t); + return u; +} + +ZZn6 inverse(const ZZn6& w) +{ + ZZn6 y=conj(w); + if (w.unitary) return y; + ZZn3 u=w.a; + ZZn3 v=w.b; + u*=u; + v*=v; + u-=tx(v); + u=inverse(u); + y*=u; + return y; +} + +ZZn6 operator+(const ZZn6& x,const ZZn6& y) +{ZZn6 w=x; w+=y; return w; } + +ZZn6 operator+(const ZZn6& x,const ZZn3& y) +{ZZn6 w=x; w+=y; return w; } + +ZZn6 operator+(const ZZn6& x,const ZZn& y) +{ZZn6 w=x; w+=y; return w; } + +ZZn6 operator-(const ZZn6& x,const ZZn6& y) +{ZZn6 w=x; w-=y; return w; } + +ZZn6 operator-(const ZZn6& x,const ZZn3& y) +{ZZn6 w=x; w-=y; return w; } + +ZZn6 operator-(const ZZn6& x,const ZZn& y) +{ZZn6 w=x; w-=y; return w; } + +ZZn6 operator-(const ZZn6& x) +{ZZn6 w; w.a=-x.a; w.b=-x.b; w.unitary=FALSE; return w; } + +ZZn6 operator*(const ZZn6& x,const ZZn6& y) +{ + ZZn6 w=x; + if (&x==&y) w*=w; + else w*=y; + return w; +} + +ZZn6 operator*(const ZZn6& x,const ZZn3& y) +{ZZn6 w=x; w*=y; return w;} + +ZZn6 operator*(const ZZn6& x,const ZZn& y) +{ZZn6 w=x; w*=y; return w;} + +ZZn6 operator*(const ZZn3& y,const ZZn6& x) +{ZZn6 w=x; w*=y; return w;} + +ZZn6 operator*(const ZZn& y,const ZZn6& x) +{ZZn6 w=x; w*=y; return w;} + +ZZn6 operator*(const ZZn6& x,int y) +{ZZn6 w=x; w*=y; return w;} + +ZZn6 operator*(int y,const ZZn6& x) +{ZZn6 w=x; w*=y; return w;} + +ZZn6 operator/(const ZZn6& x,const ZZn6& y) +{ZZn6 w=x; w/=y; return w;} + +ZZn6 operator/(const ZZn6& x,const ZZn3& y) +{ZZn6 w=x; w/=y; return w;} + +ZZn6 operator/(const ZZn6& x,const ZZn& y) +{ZZn6 w=x; w/=y; return w;} + +ZZn6 operator/(const ZZn6& x,int i) +{ZZn6 w=x; w/=i; return w;} +#ifndef MR_NO_RAND +ZZn6 randn6(void) +{ZZn6 w; w.a=randn3(); w.b=randn3(); w.unitary=FALSE; return w;} +#endif + +ZZn6 rhs(const ZZn6& x) +{ + ZZn6 w,A,B; + miracl *mip=get_mip(); + int twist=mip->TWIST; + w=x*x*x; + A=(ZZn6)getA(); B=(ZZn6)getB(); + if (twist) + { + if (twist==MR_QUARTIC_M) + { + w+=tx(A)*x; + } + if (twist==MR_QUARTIC_D) + { + w+=txd(A)*x; + } + if (twist==MR_SEXTIC_M) + { + w+=tx(B); + } + if (twist==MR_SEXTIC_D) + { + w+=txd(B); + } + if (twist==MR_QUADRATIC) + { + w+=tx(tx(A))*x+tx(tx(tx(B))); + } + } + else + { + w+=A*x+B; + } + return w; +} + +BOOL qr(const ZZn6& x) +{ + ZZn3 a,s; + if (x.iszero()) return TRUE; + if (x.b.iszero()) return TRUE; + s=x.b; s*=s; + a=x.a; a*=a; a-=tx(s); + if (!qr(a)) return FALSE; + return TRUE; +/* + s=sqrt(a); + if (qr((x.a+s)/2) || qr((x.a-s)/2)) return TRUE; + exit(0); + return FALSE; +*/ +} + +ZZn6 sqrt(const ZZn6& x) +{ +// sqrt(a+xb) = sqrt((a+sqrt(a*a-n*b*b))/2)+x.b/(2*sqrt((a+sqrt(a*a-n*b*b))/2)) +// sqrt(a) = x.sqrt(a/n) +// where x*x=n + + ZZn6 w; + ZZn3 a,s,t; + + if (x.iszero()) return w; + + + if (x.b.iszero()) + { + w.unitary=x.unitary; + a=x.a; + if (qr(a)) + { + + s=sqrt(a); + w.a=s; w.b=0; + } + else + { + a=txd(a); + s=sqrt(a); + w.a=0; w.b=s; + } + return w; + } + + s=x.b; s*=s; + a=x.a; a*=a; a-=tx(s); + s=sqrt(a); + + if (s.iszero()) return w; + + w.unitary=x.unitary; + if (qr((x.a+s)/2)) + { + a=sqrt((x.a+s)/2); + } + else + { + a=sqrt((x.a-s)/2); + if (a.iszero()) return w; + } + + w.a=a; + w.b=x.b/(2*a); + + return w; +} + +ZZn6 conj(const ZZn6& x) +{ + ZZn6 u=x; + u.conj(); + return u; +} + +// ZZn6 powering of unitary elements + +ZZn6 powu(const ZZn6& x,const Big& k) +{ + int i,j,nb,n,nbw,nzs; + ZZn6 u,u2,t[11]; + Big k3; + if (k==0) return (ZZn6)one(); + u=x; + if (k==1) return u; +// +// Prepare table for windowing +// + k3=3*k; + u2=(u*u); + t[0]=u; + + for (i=1;i<=10;i++) + t[i]=u2*t[i-1]; + + nb=bits(k3); + for (i=nb-2;i>=1;) + { + n=naf_window(k,k3,i,&nbw,&nzs,11); + + for (j=0;j0) u*=t[n/2]; + if (n<0) u*=conj(t[(-n)/2]); + i-=nbw; + if (nzs) + { + for (j=0;j1) for (i=nb-2;i>=0;) + { + n=window(k,i,&nbw,&nzs,5); + for (j=0;j0) u*=t[n/2]; + i-=nbw; + if (nzs) + { + for (j=0;jnb) nb=k; + + r=1; + for (i=nb-1;i>=0;i--) + { + ea=0; + k=1; + for (j=0;j. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ZZn6.h + * + * AUTHOR : M. Scott + * + * NOTE: : Must be used in conjunction with zzn6.cpp zzn3.cpp big.cpp and zzn.cpp + * : This is designed as a "towering extension", so a ZZn6 consists + * : of a pair of ZZn3. An element looks like (a+x^2.b+x^4.c) + x(d+x^2.e+x^4.f) + * : where x is the cubic (and quadratic) non-residue + * + * PURPOSE : Definition of class zzn6 (Arithmetic over n^6) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * p = 1 mod 6 + * irreducible poly is x^6+n + * + */ + +#ifndef ZZN6_H +#define ZZN6_H + +#include "zzn3.h" + +class ZZn6 +{ + ZZn3 a,b; + BOOL unitary; +public: + ZZn6() {unitary=FALSE;} + ZZn6(int w) {a=(ZZn3)w; b=0; if (w==1) unitary=TRUE; else unitary=FALSE;} + ZZn6(const ZZn6& w) {a=w.a; b=w.b; unitary=w.unitary;} + ZZn6(const ZZn3 &x,const ZZn3& y) {a=x; b=y; unitary=FALSE; } + ZZn6(const ZZn3 &x) {a=x; b=0; unitary=FALSE; } + ZZn6(const ZZn &x) {a=x; b=0; unitary=FALSE;} + ZZn6(const Big &x) {a=(ZZn)x; b=0; unitary=FALSE;} + + void set(const ZZn3 &x,const ZZn3 &y) {a=x; b=y; unitary=FALSE;} + void set(const ZZn3 &x) {a=x; b.clear(); unitary=FALSE;} + void seti(const ZZn3 &x) {a.clear(); b=x; unitary=FALSE;} + void set(const Big &x) {a=(ZZn)x; b.clear(); unitary=FALSE;} + + void get(ZZn3 &,ZZn3 &) const; + void geti(ZZn3&) const; + void get(ZZn3 &) const; + + void clear() {a=0; b=0; unitary=FALSE;} + void mark_as_unitary() {unitary=TRUE;} + BOOL is_unitary() {return unitary;} + + BOOL iszero() const {if (a.iszero() && b.iszero()) return TRUE; return FALSE; } + BOOL isunity() const {if (a.isunity() && b.iszero()) return TRUE; return FALSE; } + // BOOL isminusone() const {if (a.isminusone() && b.iszero()) return TRUE; return FALSE; } + + ZZn6& powq(void); + ZZn6& operator=(int i) {a=i; b=0; if (i==1) unitary=TRUE; else unitary=FALSE; return *this;} + ZZn6& operator=(const ZZn& x) {a=x; b=0; unitary=FALSE; return *this; } + ZZn6& operator=(const ZZn3& x) {a=x; b=0; unitary=FALSE; return *this; } + ZZn6& operator=(const ZZn6& x) {a=x.a; b=x.b; unitary=x.unitary; return *this; } + ZZn6& operator+=(const ZZn& x) {a+=x; unitary=FALSE; return *this; } + ZZn6& operator+=(const ZZn3& x) {a+=x; unitary=FALSE; return *this; } + ZZn6& operator+=(const ZZn6& x) {a+=x.a; b+=x.b; unitary=FALSE; return *this; } + ZZn6& operator-=(const ZZn& x) {a-=x; unitary=FALSE; return *this; } + ZZn6& operator-=(const ZZn3& x) {a-=x; unitary=FALSE; return *this; } + ZZn6& operator-=(const ZZn6& x) {a-=x.a; b-=x.b; unitary=FALSE; return *this; } + ZZn6& operator*=(const ZZn6&); + ZZn6& operator*=(const ZZn3& x) {a*=x; b*=x; unitary=FALSE; return *this; } + ZZn6& operator*=(const ZZn& x) {a*=x; b*=x; unitary=FALSE; return *this; } + ZZn6& operator*=(int x) {a*=x; b*=x; unitary=FALSE; return *this;} + ZZn6& operator/=(const ZZn6&); + ZZn6& operator/=(const ZZn3&); + ZZn6& operator/=(const ZZn&); + ZZn6& operator/=(int); + ZZn6& conj() {b=-b; return *this;} + + friend ZZn6 operator+(const ZZn6&,const ZZn6&); + friend ZZn6 operator+(const ZZn6&,const ZZn3&); + friend ZZn6 operator+(const ZZn6&,const ZZn&); + friend ZZn6 operator-(const ZZn6&,const ZZn6&); + friend ZZn6 operator-(const ZZn6&,const ZZn3&); + friend ZZn6 operator-(const ZZn6&,const ZZn&); + friend ZZn6 operator-(const ZZn6&); + + friend ZZn6 operator*(const ZZn6&,const ZZn6&); + friend ZZn6 operator*(const ZZn6&,const ZZn3&); + friend ZZn6 operator*(const ZZn6&,const ZZn&); + friend ZZn6 operator*(const ZZn&,const ZZn6&); + friend ZZn6 operator*(const ZZn3&,const ZZn6&); + + friend ZZn6 operator*(int,const ZZn6&); + friend ZZn6 operator*(const ZZn6&,int); + + friend ZZn6 operator/(const ZZn6&,const ZZn6&); + friend ZZn6 operator/(const ZZn6&,const ZZn3&); + friend ZZn6 operator/(const ZZn6&,const ZZn&); + friend ZZn6 operator/(const ZZn6&,int); + + friend ZZn6 rhs(const ZZn6&); + + friend ZZn3 real(const ZZn6& x) {return x.a;} + friend ZZn3 imaginary(const ZZn6& x) {return x.b;} + + friend ZZn6 pow(const ZZn6&,const Big&); + friend ZZn6 powu(const ZZn6&,const Big&); + friend ZZn6 pow(int,const ZZn6*,const Big*); + friend ZZn6 powl(const ZZn6&,const Big&); + friend ZZn6 conj(const ZZn6&); + friend ZZn6 inverse(const ZZn6&); + friend ZZn6 tx(const ZZn6&); + friend ZZn6 tx2(const ZZn6&); + friend ZZn6 tx4(const ZZn6&); + friend ZZn6 txd(const ZZn6&); + +#ifndef MR_NO_RAND + friend ZZn6 randn6(void); // random ZZn6 +#endif + friend BOOL qr(const ZZn6&); + friend ZZn6 sqrt(const ZZn6&); // square root - 0 if none exists + + friend BOOL operator==(const ZZn6& x,const ZZn6& y) + {if (x.a==y.a && x.b==y.b) return TRUE; else return FALSE; } + + friend BOOL operator!=(const ZZn6& x,const ZZn6& y) + {if (x.a!=y.a || x.b!=y.b) return TRUE; else return FALSE; } + +#ifndef MR_NO_STANDARD_IO + friend ostream& operator<<(ostream&,const ZZn6&); +#endif + + ~ZZn6() {} +}; +#ifndef MR_NO_RAND +extern ZZn6 randn6(void); +#endif +#endif + diff --git a/miracl/source/curve/pairing/zzn6a.cpp b/miracl/source/curve/pairing/zzn6a.cpp new file mode 100644 index 0000000..bd962a0 --- /dev/null +++ b/miracl/source/curve/pairing/zzn6a.cpp @@ -0,0 +1,547 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file ZZn6a.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ZZn6 (Arithmetic over n^6) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#include "zzn6a.h" + +using namespace std; + +// Frobenius X=x^p + +ZZn6& ZZn6::powq(const ZZn2& W) +{ + BOOL ku=unitary; + BOOL km=miller; + a.conj(); b.conj(); c.conj(); + b*=W; c*=(W*W); + unitary=ku; + miller=km; + return *this; +} + +void ZZn6::get(ZZn2& x,ZZn2& y,ZZn2& z) const +{x=a; y=b; z=c;} + +void ZZn6::get(ZZn2& x) const +{x=a; } + +void ZZn6::get1(ZZn2& x) const +{x=b; } + +void ZZn6::get2(ZZn2& x) const +{x=c; } + +ZZn6& ZZn6::operator*=(const ZZn6& x) +{ // optimized to reduce constructor/destructor calls + if (&x==this) + { + ZZn2 A,B,C,D; + + if (unitary) + { // Granger & Scott 2009 - only 3 squarings! BUT depends on p=5 mod 8, p=1 mod 3 + A=a; a*=a; D=a; a+=a; a+=D; A.conj(); A+=A; a-=A; + B=c; B*=B; B=txx(B); D=B; B+=B; B+=D; + C=b; C*=C; D=C; C+=C; C+=D; + + b.conj(); b+=b; c.conj(); c+=c; c=-c; + b+=B; c+=C; + } + else + { // Chung-Hasan SQR2 + if (!miller) + { + A=a; A*=A; + B=b*c; B+=B; + C=c; C*=C; + D=a*b; D+=D; + c+=(a+b); c*=c; + + a=A+txx(B); + b=D+txx(C); + c-=(A+B+C+D); + } + else + { // Chung-Hasan SQR3 - calculates 2*W^2 + A=a; A*=A; // a0^2 = S0 + C=c; C*=b; C+=C; // 2a1.a2 = S3 + D=c; D*=D; // a2^2 = S4 + c+=a; // a0+a2 + B=b; B+=c; B*=B; // (a0+a1+a2)^2 =S1 + + c-=b; c*=c; // (a0-a1+a2)^2 =S2 + + C+=C; A+=A; D+=D; + + a=A+txx(C); + b=B-c-C+txx(D); + c+=B-A-D; // is this code telling me something...? + } + } + +// Standard Chung-Hasan SQR3 + +// A=a; A*=a; // a0^2 = S0 +// C=c; C*=b; C+=C; // 2a1.a2 = S3 +// D=c; D*=D; // a2^2 = S4 +// c+=a; // a0+a2 + +// B=b; B+=c; B*=B; // (a0+a1+a2)^2 =S1 + +// c-=b; c*=c; // (a0-a1+a2)^2 =S2 +// c+=B; c/=2; + +// B-=c; B-=C; +// c-=A; c-=D; +// a=A+txx(C); +// b=B+txx(D); + + } + else + { // Karatsuba + ZZn2 Z0,Z1,Z2,Z3,Z4,T0,T1; + Z0=a*x.a; + Z2=b*x.b; + Z4=c*x.c; + T0=a+b; + T1=x.a+x.b; + Z1=T0*T1; + Z1-=Z0; + Z1-=Z2; + T0=b+c; + T1=x.b+x.c; + Z3=T0*T1; + Z3-=Z2; + Z3-=Z4; + T0=a+c; + T1=x.a+x.c; + T0*=T1; + Z2+=T0; + Z2-=Z0; + Z2-=Z4; + + a=Z0+txx(Z3); + b=Z1+txx(Z4); + c=Z2; + + if (!x.unitary) unitary=FALSE; + } + return *this; +} + +ZZn6& ZZn6::operator/=(const ZZn2& x) +{ + *this*=inverse(x); + unitary=FALSE; + return *this; +} + +ZZn6& ZZn6::operator/=(const ZZn& x) +{ + ZZn t=(ZZn)1/x; + a*=t; + b*=t; + c*=t; + unitary=FALSE; + return *this; +} + +ZZn6& ZZn6::operator/=(int i) +{ + ZZn t=(ZZn)1/i; + a*=t; + b*=t; + c*=t; + unitary=FALSE; + return *this; +} + +ZZn6& ZZn6::operator/=(const ZZn6& x) +{ + *this*=inverse(x); + if (!x.unitary) unitary=FALSE; + return *this; +} + +ZZn6 inverse(const ZZn6& w) +{ + ZZn6 y; + ZZn2 f0; + + if (w.unitary) + { + y=w; + y.conj(); + return y; + } + + y.a=w.a*w.a-txx(w.b*w.c); + y.b=txx(w.c*w.c)-w.a*w.b; + y.c=w.b*w.b-w.a*w.c; + + f0=txx(w.b*y.c)+w.a*y.a+txx(w.c*y.b); + f0=inverse(f0); + + y.c*=f0; + y.b*=f0; + y.a*=f0; + + return y; +} + +ZZn6 operator+(const ZZn6& x,const ZZn6& y) +{ZZn6 w=x; w.a+=y.a; w.b+=y.b; w.c+=y.c; return w; } + +ZZn6 operator+(const ZZn6& x,const ZZn2& y) +{ZZn6 w=x; w.a+=y; return w; } + +ZZn6 operator+(const ZZn6& x,const ZZn& y) +{ZZn6 w=x; w.a+=y; return w; } + +ZZn6 operator-(const ZZn6& x,const ZZn6& y) +{ZZn6 w=x; w.a-=y.a; w.b-=y.b; w.c-=y.c; return w; } + +ZZn6 operator-(const ZZn6& x,const ZZn2& y) +{ZZn6 w=x; w.a-=y; return w; } + +ZZn6 operator-(const ZZn6& x,const ZZn& y) +{ZZn6 w=x; w.a-=y; return w; } + +ZZn6 operator-(const ZZn6& x) +{ZZn6 w; w.a=-x.a; w.b=-x.b; w.c-=x.c; w.unitary=FALSE; return w; } + +ZZn6 operator*(const ZZn6& x,const ZZn6& y) +{ + ZZn6 w=x; + if (&x==&y) w*=w; + else w*=y; + return w; +} + +ZZn6 operator*(const ZZn6& x,const ZZn2& y) +{ZZn6 w=x; w*=y; return w;} + +ZZn6 operator*(const ZZn6& x,const ZZn& y) +{ZZn6 w=x; w*=y; return w;} + +ZZn6 operator*(const ZZn2& y,const ZZn6& x) +{ZZn6 w=x; w*=y; return w;} + +ZZn6 operator*(const ZZn& y,const ZZn6& x) +{ZZn6 w=x; w*=y; return w;} + +ZZn6 operator*(const ZZn6& x,int y) +{ZZn6 w=x; w*=y; return w;} + +ZZn6 operator*(int y,const ZZn6& x) +{ZZn6 w=x; w*=y; return w;} + +ZZn6 operator/(const ZZn6& x,const ZZn6& y) +{ZZn6 w=x; w/=y; return w;} + +ZZn6 operator/(const ZZn6& x,const ZZn2& y) +{ZZn6 w=x; w/=y; return w;} + +ZZn6 operator/(const ZZn6& x,const ZZn& y) +{ZZn6 w=x; w/=y; return w;} + +ZZn6 operator/(const ZZn6& x,int i) +{ZZn6 w=x; w/=i; return w;} +#ifndef MR_NO_RAND +ZZn6 randn6(void) +{ZZn6 w; w.a=randn2(); w.b=randn2(); w.c=randn2(); w.unitary=FALSE; return w;} +#endif + +ZZn6 tx(const ZZn6& w) +{ + ZZn6 u=w; + + ZZn2 t=u.a; + u.a=txx(u.c); + u.c=u.b; + u.b=t; + u.unitary=FALSE; + + return u; +} + +ZZn6 conj(const ZZn6& x) +{ + ZZn6 u=x; + u.conj(); + return u; +} + +// x^a.y^b for unitary elements + +ZZn6 powu(const ZZn6& x,const Big& a,const ZZn6 &y,const Big &b) +{ + ZZn6 X=x; + ZZn6 Y=y; + Big A=a; + Big B=b; + Big A3,B3; + ZZn6 S,D,R; + int e1,e2,h1,h2,nb,t; + if (A<0) { A=-A; X=conj(X); } + if (B<0) { B=-B; Y=conj(Y); } +// joint sparse form + jsf(A,B,A3,A,B3,B); + S=X*Y; + D=Y*conj(X); + if (A3>B3) nb=bits(A3)-1; + else nb=bits(B3)-1; + R=1; + while (nb>=0) + { + R*=R; + e1=h1=e2=h2=0; + t=0; + if (bit(A,nb)) {e2=1; t+=8;} + if (bit(A3,nb)) {h2=1; t+=4;} + if (bit(B,nb)) {e1=1; t+=2;} + if (bit(B3,nb)) {h1=1; t+=1;} + + if (t==1 || t==13) R*=Y; + if (t==2 || t==14) R*=conj(Y); + if (t==4 || t==7) R*=X; + if (t==8 || t==11) R*=conj(X); + if (t==5) R*=S; + if (t==10) R*=conj(S); + if (t==9) R*=D; + if (t==6) R*=conj(D); + nb-=1; + } + return R; +} + +// ZZn6 powering of unitary elements + +ZZn6 powu(const ZZn6& x,const Big& k) +{ + int i,j,nb,n,nbw,nzs; + ZZn6 u,u2,t[11]; + Big k3; + if (k==0) return (ZZn6)one(); + u=x; + if (k==1) return u; +// +// Prepare table for windowing +// + k3=3*k; + u2=(u*u); + t[0]=u; + + for (i=1;i<=10;i++) + t[i]=u2*t[i-1]; + + nb=bits(k3); + for (i=nb-2;i>=1;) + { + n=naf_window(k,k3,i,&nbw,&nzs,11); + + for (j=0;j0) u*=t[n/2]; + if (n<0) u*=conj(t[(-n)/2]); + i-=nbw; + if (nzs) + { + for (j=0;j1) for (i=nb-2;i>=0;i--) + { + u*=u; + if (bit(e,i)) u*=x; + } + + if (invert_it) u=inverse(u); + + return u; +} + +/* +ZZn6 pow(const ZZn6& x,const Big& k) +{ + int i,j,nb,n,nbw,nzs; + ZZn6 u,u2,t[16]; + if (k==0) return (ZZn6)1; + u=x; + if (k==1) return u; +// +// Prepare table for windowing +// + u2=(u*u); + t[0]=u; + + for (i=1;i<16;i++) + t[i]=u2*t[i-1]; + +// Left to right method - with windows + + nb=bits(k); + if (nb>1) for (i=nb-2;i>=0;) + { + n=window(k,i,&nbw,&nzs,5); + for (j=0;j0) u*=t[n/2]; + i-=nbw; + if (nzs) + { + for (j=0;j=0;i--) + { + if (bit(k,i)) + { + w8*=w9; w8-=y; w9*=w9; w9-=two; + } + else + { + w9*=w8; w9-=y; w8*=w8; w8-=two; + } + } + return (w8/2); +} + +// double exponention - see Schoenmaker's method from Stam's thesis + +ZZn6 powl(const ZZn6& x,const Big& n,const ZZn6& y,const Big& m,const ZZn6& a) +{ + ZZn6 A,B,C,T,two,vk,vl,va; + int j,nb; + + two=(ZZn)2; + vk=x+x; + vl=y+y; + va=a+a; + + nb=bits(n); + if (bits(m)>nb) nb=bits(m); + + A=two; B=vk; C=vl; + + for (j=nb;j>=1;j--) + { + if (bit(n,j-1)==0 && bit(m,j-1)==0) + { + B*=A; B-=vk; C*=A; C-=vl; A*=A; A-=two; + } + if (bit(n,j-1)==1 && bit(m,j-1)==0) + { + A*=B; A-=vk; C*=B; C-=va; B*=B; B-=two; + } + if (bit(n,j-1)==0 && bit(m,j-1)==1) + { + A*=C; A-=vl; B*=C; B-=va; C*=C; C-=two; + } + if (bit(n,j-1)==1 && bit(m,j-1)==1) + { + T=B*C-va; B*=A; B-=vk; C*=A; C-=vl; A=T; + T=A*vl-B; B=A*vk-C; C=T; + } + } + + return (A/2); +} + + + +#ifndef MR_NO_STANDARD_IO + +ostream& operator<<(ostream& s,const ZZn6& xx) +{ + ZZn6 b=xx; + ZZn2 x,y,z; + b.get(x,y,z); + s << "[" << x << "," << y << "," << z << "]"; + return s; +} + +#endif + diff --git a/miracl/source/curve/pairing/zzn6a.h b/miracl/source/curve/pairing/zzn6a.h new file mode 100644 index 0000000..39f9674 --- /dev/null +++ b/miracl/source/curve/pairing/zzn6a.h @@ -0,0 +1,177 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ZZn6a.h + * + * AUTHOR : M. Scott + * + * NOTE: : Must be used in conjunction with zzn6a.cpp zzn2.cpp big.cpp and zzn.cpp + * : This is designed as a "towering extension", so a ZZn6 consists + * : of three ZZn2. + * + * PURPOSE : Definition of class zzn6 (Arithmetic over n^6) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * Note: This code assumes that + * p=5 mod 8 + * OR p=3 mod 8 + * OR p=7 mod 8, p=2,3 mod 5 + * + * Irreducible poly is X^3-n, where n=w+sqrt(m), m= {-1,-2} and w= {0,1,2} + * if p=5 mod 8, n=sqrt(-2) + * if p=3 mod 8, n=1+sqrt(-1) + * if p=7 mod 8, p=2,3 mod 5, n=2+sqrt(-1) + * + */ + +#ifndef ZZN6A_H +#define ZZN6A_H + +#include "zzn2.h" + +class ZZn6 +{ + ZZn2 a,b,c; + BOOL unitary; // "unitary" property means that fast squaring can be used, and inversions are just conjugates + BOOL miller; // "miller" property means that arithmetic on this instance can ignore multiplications + // or divisions by constants - as instance will eventually be raised to (p-1). +public: + ZZn6() {miller=unitary=FALSE;} + ZZn6(int w) {a=(ZZn2)w; b.clear(); c.clear(); miller=FALSE; if (w==1) unitary=TRUE; else unitary=FALSE;} + ZZn6(const ZZn6& w) {a=w.a; b=w.b; c=w.c; miller=w.miller; unitary=w.unitary;} + ZZn6(const ZZn2 &x) {a=x; b.clear(); c.clear(); miller=unitary=FALSE; } + ZZn6(const ZZn2 &x,const ZZn2& y,const ZZn2& z) {a=x; b=y; c=z; miller=unitary=FALSE; } + ZZn6(const ZZn &x) {a=(ZZn2)x; b.clear(); c.clear(); miller=unitary=FALSE; } + ZZn6(const Big &x) {a=(ZZn2)x; b.clear(); c.clear(); miller=unitary=FALSE; } + + void set(const ZZn2 &x,const ZZn2 &y,const ZZn2 &z) {a=x; b=y; c=z; unitary=FALSE; } + void set(const ZZn2 &x) {a=x; b.clear(); c.clear(); unitary=FALSE; } + void set(const ZZn2 &x,const ZZn2 &y) {a=x; b=y; c.clear(); unitary=FALSE; } + void set1(const ZZn2 &x) {a.clear(); b=x; c.clear(); unitary=FALSE; } + void set2(const ZZn2 &x) {a.clear(); b.clear(); c=x; unitary=FALSE; } + void set(const Big &x) {a=(ZZn2)x; b.clear(); c.clear(); unitary=FALSE; } + + void get(ZZn2 &,ZZn2 &,ZZn2 &) const; + void get(ZZn2 &) const; + void get1(ZZn2 &) const; + void get2(ZZn2 &) const; + + void clear() {a.clear(); b.clear(); c.clear(); unitary=FALSE; } + void mark_as_unitary() {miller=FALSE; unitary=TRUE;} + void mark_as_miller() {miller=TRUE;} + BOOL is_unitary() {return unitary;} + + ZZn6& conj() {a.conj(); b.conj(); b=-b; c.conj(); return *this;} + + BOOL iszero() const {if (a.iszero() && b.iszero() && c.iszero()) return TRUE; return FALSE; } + BOOL isunity() const {if (a.isunity() && b.iszero() && c.iszero()) return TRUE; return FALSE; } + // BOOL isminusone() const {if (a.isminusone() && b.iszero()) return TRUE; return FALSE; } + + ZZn6& powq(const ZZn2&); + ZZn6& operator=(int i) {a=i; b.clear(); c.clear(); if (i==1) unitary=TRUE; else unitary=FALSE; return *this;} + ZZn6& operator=(const ZZn& x) {a=(ZZn2)x; b.clear(); c.clear(); unitary=FALSE; return *this; } + ZZn6& operator=(const ZZn2& x) {a=x; b.clear(); c.clear(); unitary=FALSE; return *this; } + ZZn6& operator=(const ZZn6& x) {a=x.a; b=x.b; c=x.c; miller=x.miller; unitary=x.unitary; return *this; } + ZZn6& operator+=(const ZZn& x) {a+=(ZZn2)x; unitary=FALSE; return *this; } + ZZn6& operator+=(const ZZn2& x) {a+=x; unitary=FALSE; return *this; } + ZZn6& operator+=(const ZZn6& x) {a+=x.a; b+=x.b; c+=x.c; unitary=FALSE; return *this; } + ZZn6& operator-=(const ZZn& x) {a-=(ZZn2)x; unitary=FALSE; return *this; } + ZZn6& operator-=(const ZZn2& x) {a-=x; unitary=FALSE; return *this; } + ZZn6& operator-=(const ZZn6& x) {a-=x.a; b-=x.b; c-=x.c; unitary=FALSE; return *this; } + ZZn6& operator*=(const ZZn6&); + ZZn6& operator*=(const ZZn2& x) {a*=x; b*=x; c*=x; unitary=FALSE; return *this; } + ZZn6& operator*=(const ZZn& x) {a*=x; b*=x; c*=x; unitary=FALSE; return *this; } + ZZn6& operator*=(int x) {a*=x; b*=x; c*=x; unitary=FALSE; return *this;} + ZZn6& operator/=(const ZZn6&); + ZZn6& operator/=(const ZZn2&); + ZZn6& operator/=(const ZZn&); + ZZn6& operator/=(int); + + friend ZZn6 operator+(const ZZn6&,const ZZn6&); + friend ZZn6 operator+(const ZZn6&,const ZZn2&); + friend ZZn6 operator+(const ZZn6&,const ZZn&); + friend ZZn6 operator-(const ZZn6&,const ZZn6&); + friend ZZn6 operator-(const ZZn6&,const ZZn2&); + friend ZZn6 operator-(const ZZn6&,const ZZn&); + friend ZZn6 operator-(const ZZn6&); + + friend ZZn6 operator*(const ZZn6&,const ZZn6&); + friend ZZn6 operator*(const ZZn6&,const ZZn2&); + friend ZZn6 operator*(const ZZn6&,const ZZn&); + friend ZZn6 operator*(const ZZn&,const ZZn6&); + friend ZZn6 operator*(const ZZn2&,const ZZn6&); + + friend ZZn6 operator*(int,const ZZn6&); + friend ZZn6 operator*(const ZZn6&,int); + + friend ZZn6 operator/(const ZZn6&,const ZZn6&); + friend ZZn6 operator/(const ZZn6&,const ZZn2&); + friend ZZn6 operator/(const ZZn6&,const ZZn&); + friend ZZn6 operator/(const ZZn6&,int); + + friend ZZn6 tx(const ZZn6&); + + friend ZZn6 pow(const ZZn6&,const Big&); + friend ZZn6 powu(const ZZn6&,const Big&); + friend ZZn6 powu(const ZZn6&,const Big&,const ZZn6&,const Big&); + friend ZZn6 conj(const ZZn6&); +// friend ZZn6 pow(int,const ZZn6*,const Big*); + friend ZZn6 powl(const ZZn6&,const Big&); + friend ZZn6 powl(const ZZn6&,const Big&,const ZZn6&,const Big&,const ZZn6&); + friend ZZn6 inverse(const ZZn6&); + +#ifndef MR_NO_RAND + friend ZZn6 randn6(void); // random ZZn6 +#endif + friend BOOL operator==(const ZZn6& x,const ZZn6& y) + {if (x.a==y.a && x.b==y.b && x.c==y.c) return TRUE; else return FALSE; } + + friend BOOL operator!=(const ZZn6& x,const ZZn6& y) + {if (x.a!=y.a || x.b!=y.b || x.c!=y.c) return TRUE; else return FALSE; } + +#ifndef MR_NO_STANDARD_IO + friend ostream& operator<<(ostream&,const ZZn6&); +#endif + + ~ZZn6() {} +}; +#ifndef MR_NO_RAND +extern ZZn6 randn6(void); +#endif +#endif + diff --git a/miracl/source/curve/pairing/zzn8.cpp b/miracl/source/curve/pairing/zzn8.cpp new file mode 100644 index 0000000..00e4c03 --- /dev/null +++ b/miracl/source/curve/pairing/zzn8.cpp @@ -0,0 +1,470 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Implementation file zzn8.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ZZn8 (Arithmetic over n^8) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#include "zzn8.h" + +using namespace std; + +// This will now work with p=1 mod 4 or p=3 mod 4 +// In the later case an adjustment is needed + +ZZn8& ZZn8::powq(const ZZn2& X) +{ // Fr is "Frobenius root" + ZZn2 XX=X*X; // square it to get Frobenius constant for ZZn4 + if ((get_mip()->pmod8)%4==3) XX=txx(XX); + a.powq(XX); + b.powq(XX); + b*=X; + if ((get_mip()->pmod8)%4==3) b=tx(b); + return *this; +} + +void ZZn8::get(ZZn4& x,ZZn4& y) const +{x=a; y=b;} + +void ZZn8::get(ZZn4& x) const +{x=a; } + +ZZn8& ZZn8::operator*=(const ZZn8& x) +{ // optimized to reduce constructor/destructor calls + if (&x==this) + { +/* See Stam & Lenstra, "Efficient subgroup exponentiation in Quadratic .. Extensions", CHES 2002 */ + if (unitary) + { + ZZn4 t=b; t*=t; + b+=a; b*=b; + b-=t; + a=tx(t); + b-=a; + a+=a; a+=one(); + b-=one(); + // cout << "in here" << endl; + } + else + { + ZZn4 t=a; t+=b; + ZZn4 t2=a; t2+=tx(b); + t*=t2; + b*=a; + t-=b; + t-=tx(b); + b+=b; + a=t; + } + } + else + { + ZZn4 ac=a; ac*=x.a; + ZZn4 bd=b; bd*=x.b; + ZZn4 t=x.a; t+=x.b; + b+=a; b*=t; b-=ac; b-=bd; + a=ac; a+=tx(bd); + + if (!x.unitary) unitary=FALSE; + } + return *this; +} + +ZZn8& ZZn8::operator/=(const ZZn4& x) +{ + *this*=inverse(x); + unitary=FALSE; + return *this; +} + +ZZn8& ZZn8::operator/=(const ZZn& x) +{ + ZZn t=(ZZn)1/x; + a*=t; + b*=t; + unitary=FALSE; + return *this; +} + +ZZn8& ZZn8::operator/=(int i) +{ + ZZn t=(ZZn)1/i; + a*=t; + b*=t; + unitary=FALSE; + return *this; +} + +ZZn8& ZZn8::operator/=(const ZZn8& x) +{ + *this*=inverse(x); + if (!x.unitary) unitary=FALSE; + return *this; +} + +ZZn8 inverse(const ZZn8& w) +{ + ZZn8 y=conj(w); + if (w.unitary) return y; + ZZn4 u=w.a; + ZZn4 v=w.b; + u*=u; + v*=v; + u-=tx(v); + u=inverse(u); + y*=u; + return y; +} + +ZZn8 operator+(const ZZn8& x,const ZZn8& y) +{ZZn8 w=x; w+=y; return w; } + +ZZn8 operator+(const ZZn8& x,const ZZn4& y) +{ZZn8 w=x; w+=y; return w; } + +ZZn8 operator+(const ZZn8& x,const ZZn& y) +{ZZn8 w=x; w+=y; return w; } + +ZZn8 operator-(const ZZn8& x,const ZZn8& y) +{ZZn8 w=x; w-=y; return w; } + +ZZn8 operator-(const ZZn8& x,const ZZn4& y) +{ZZn8 w=x; w-=y; return w; } + +ZZn8 operator-(const ZZn8& x,const ZZn& y) +{ZZn8 w=x; w-=y; return w; } + +ZZn8 operator-(const ZZn8& x) +{ZZn8 w; w.a=-x.a; w.b=-x.b; w.unitary=FALSE; return w; } + +ZZn8 operator*(const ZZn8& x,const ZZn8& y) +{ + ZZn8 w=x; + if (&x==&y) w*=w; + else w*=y; + return w; +} + +ZZn8 operator*(const ZZn8& x,const ZZn4& y) +{ZZn8 w=x; w*=y; return w;} + +ZZn8 operator*(const ZZn8& x,const ZZn& y) +{ZZn8 w=x; w*=y; return w;} + +ZZn8 operator*(const ZZn4& y,const ZZn8& x) +{ZZn8 w=x; w*=y; return w;} + +ZZn8 operator*(const ZZn& y,const ZZn8& x) +{ZZn8 w=x; w*=y; return w;} + +ZZn8 operator*(const ZZn8& x,int y) +{ZZn8 w=x; w*=y; return w;} + +ZZn8 operator*(int y,const ZZn8& x) +{ZZn8 w=x; w*=y; return w;} + +ZZn8 operator/(const ZZn8& x,const ZZn8& y) +{ZZn8 w=x; w/=y; return w;} + +ZZn8 operator/(const ZZn8& x,const ZZn4& y) +{ZZn8 w=x; w/=y; return w;} + +ZZn8 operator/(const ZZn8& x,const ZZn& y) +{ZZn8 w=x; w/=y; return w;} + +ZZn8 operator/(const ZZn8& x,int i) +{ZZn8 w=x; w/=i; return w;} +#ifndef MR_NO_RAND +ZZn8 randn8(void) +{ZZn8 w; w.a=randn4(); w.b=randn4(); w.unitary=FALSE; return w;} +#endif + + +ZZn8 rhs(const ZZn8& x) +{ + ZZn8 w,A,B; + miracl *mip=get_mip(); + int twist=mip->TWIST; + w=x*x*x; + A=(ZZn8)getA(); B=(ZZn8)getB(); + if (twist) + { + if (twist==MR_QUARTIC_M) + { + w+=tx(A)*x; + } + if (twist==MR_QUARTIC_D) + { + w+=txd(A)*x; + } + if (twist==MR_SEXTIC_M) + { + w+=tx(B); + } + if (twist==MR_SEXTIC_D) + { + w+=txd(B); + } + if (twist==MR_QUADRATIC) + { + w+=tx(tx(A))*x+tx(tx(tx(B))); + } + } + else + { + w+=A*x+B; + } + return w; +} + +BOOL qr(const ZZn8& x) +{ + ZZn4 a,s; + int qnr=get_mip()->qnr; + if (x.iszero()) return TRUE; + if (x.b.iszero()) return TRUE; + s=x.b; s*=s; + a=x.a; a*=a; a-=tx(s); + if (!qr(a)) return FALSE; + return TRUE; +/* + s=sqrt(a); + if (qr((x.a+s)/2) || qr((x.a-s)/2)) return TRUE; + return FALSE; +*/ +} + +ZZn8 sqrt(const ZZn8& x) +{ +// sqrt(a+xb) = sqrt(a+sqrt(a*a-n*b*b)/2)+x.b/(2*sqrt(a+sqrt(a*a-n*b*b)/2)) +// where x*x=n + + ZZn8 w; + ZZn4 a,s; + if (x.iszero()) return w; + + if (x.b.iszero()) + { + a=x.a; + if (qr(a)) + { + s=sqrt(a); + w.a=s; w.b=0; + } + else + { + s=sqrt(txd(a)); + w.a=0; w.b=s; + } + return w; + } + + s=x.b; s*=s; + a=x.a; a*=a; a-=tx(s); + + s=sqrt(a); + if (s.iszero()) return w; + + if (qr((x.a+s)/2)) + { + a=sqrt((x.a+s)/2); + } + else + { + a=sqrt((x.a-s)/2); + if (a.iszero()) return w; + } + + w.a=a; + w.b=x.b/(2*a); + + return w; +} + +ZZn8 conj(const ZZn8& x) +{ + ZZn8 u=x; + u.conj(); + return u; +} + +ZZn8 tx(const ZZn8& x) +{ + ZZn4 t=tx(x.b); + ZZn8 u(t,x.a); + return u; +} + +ZZn8 txd(const ZZn8& x) +{ + ZZn4 u,v; + x.get(u,v); + u=txd(u); + ZZn8 w(v,u); + + return w; +} + +ZZn8 tx2(const ZZn8& x) +{ + ZZn8 u(tx(x.a),tx(x.b)); + return u; +} + +// regular ZZn8 powering - but see powl function in zzn4.h + +ZZn8 pow(const ZZn8& x,const Big& k) +{ + int i,j,nb,n,nbw,nzs; + ZZn8 u,u2,t[16]; + if (k==0) return (ZZn8)1; + u=x; + if (k==1) return u; +// +// Prepare table for windowing +// + u2=(u*u); + t[0]=u; + + for (i=1;i<16;i++) + t[i]=u2*t[i-1]; + +// Left to right method - with windows + + nb=bits(k); + if (nb>1) for (i=nb-2;i>=0;) + { + n=window(k,i,&nbw,&nzs,5); + for (j=0;j0) u*=t[n/2]; + i-=nbw; + if (nzs) + { + for (j=0;jnb) nb=k; + + r=1; + for (i=nb-1;i>=0;i--) + { + ea=0; + k=1; + for (j=0;j=0;i--) + { + if (bit(k,i)) + { + w8*=w9; w8-=y; w9*=w9; w9-=two; + } + else + { + w9*=w8; w9-=y; w8*=w8; w8-=two; + } + } + return (w8/2); +} + +#ifndef MR_NO_STANDARD_IO + +ostream& operator<<(ostream& s,const ZZn8& xx) +{ + ZZn8 b=xx; + ZZn4 x,y; + b.get(x,y); + s << "[" << x << "," << y << "]"; + return s; +} + +#endif + diff --git a/miracl/source/curve/pairing/zzn8.h b/miracl/source/curve/pairing/zzn8.h new file mode 100644 index 0000000..4d6668b --- /dev/null +++ b/miracl/source/curve/pairing/zzn8.h @@ -0,0 +1,164 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ Header file ZZn8.h + * + * AUTHOR : M. Scott + * + * NOTE: : Must be used in conjunction with zzn4.cpp zzn2.cpp big.cpp and zzn.cpp + * : This is designed as a "towering extension", so a ZZn8 consists + * : of a pair of ZZn4. An element looks like (a+x^2.b) + x(c+x^2.d) + * + * PURPOSE : Definition of class ZZn8 (Arithmetic over n^8) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + */ + +#ifndef ZZN8_H +#define ZZN8_H + +#include "zzn4.h" + +class ZZn8 +{ + ZZn4 a,b; + BOOL unitary; +public: + ZZn8() {unitary=FALSE;} + ZZn8(int w) {a=(ZZn4)w; b=0; if (w==1) unitary=TRUE; else unitary=FALSE;} + ZZn8(const ZZn8& w) {a=w.a; b=w.b; unitary=w.unitary; } + ZZn8(const ZZn4 &x,const ZZn4& y) {a=x; b=y; unitary=FALSE;} + ZZn8(const ZZn4 &x) {a=x; b=0; unitary=FALSE; } + ZZn8(const ZZn &x) {a=x; b=0; unitary=FALSE;} + ZZn8(const Big &x) {a=(ZZn)x; b=0; unitary=FALSE;} + + void set(const ZZn4 &x,const ZZn4 &y) {a=x; b=y; unitary=FALSE; } + void set(const ZZn4 &x) {a=x; b=(ZZn4)0; unitary=FALSE;} + void set(const Big &x) {a=(ZZn)x; b=(ZZn4)0; unitary=FALSE; } + + void get(ZZn4 &,ZZn4 &) const; + void get(ZZn4 &) const; + + void clear() {a=0; b=0; unitary=FALSE;} + void mark_as_unitary() {unitary=TRUE;} + BOOL is_unitary() {return unitary;} + + BOOL iszero() const {if (a.iszero() && b.iszero()) return TRUE; return FALSE; } + BOOL isunity() const {if (a.isunity() && b.iszero()) return TRUE; return FALSE; } +// BOOL isminusone() const {if (a.isminusone() && b.iszero()) return TRUE; return FALSE; } + + ZZn8& powq(const ZZn2&); + ZZn8& operator=(int i) {a=i; b=0; if (i==1) unitary=TRUE; else unitary=FALSE; return *this;} + ZZn8& operator=(const ZZn& x) {a=x; b=0; unitary=FALSE; return *this; } + ZZn8& operator=(const ZZn4& x) {a=x; b=0; unitary=FALSE; return *this; } + ZZn8& operator=(const ZZn8& x) {a=x.a; b=x.b; unitary=x.unitary; return *this; } + ZZn8& operator+=(const ZZn& x) {a+=x; unitary=FALSE; return *this; } + ZZn8& operator+=(const ZZn4& x) {a+=x; unitary=FALSE; return *this; } + ZZn8& operator+=(const ZZn8& x) {a+=x.a; b+=x.b; unitary=FALSE; return *this; } + ZZn8& operator-=(const ZZn& x) {a-=x; unitary=FALSE; return *this; } + ZZn8& operator-=(const ZZn4& x) {a-=x; unitary=FALSE; return *this; } + ZZn8& operator-=(const ZZn8& x) {a-=x.a; b-=x.b; unitary=FALSE; return *this; } + ZZn8& operator*=(const ZZn8&); + ZZn8& operator*=(const ZZn4& x) {a*=x; b*=x; unitary=FALSE; return *this; } + ZZn8& operator*=(const ZZn& x) {a*=x; b*=x; unitary=FALSE; return *this; } + ZZn8& operator*=(int x) {a*=x; b*=x; unitary=FALSE; return *this;} + ZZn8& operator/=(const ZZn8&); + ZZn8& operator/=(const ZZn4&); + ZZn8& operator/=(const ZZn&); + ZZn8& operator/=(int); + ZZn8& conj() {b=-b; return *this;} + + friend ZZn8 operator+(const ZZn8&,const ZZn8&); + friend ZZn8 operator+(const ZZn8&,const ZZn4&); + friend ZZn8 operator+(const ZZn8&,const ZZn&); + friend ZZn8 operator-(const ZZn8&,const ZZn8&); + friend ZZn8 operator-(const ZZn8&,const ZZn4&); + friend ZZn8 operator-(const ZZn8&,const ZZn&); + friend ZZn8 operator-(const ZZn8&); + + friend ZZn8 operator*(const ZZn8&,const ZZn8&); + friend ZZn8 operator*(const ZZn8&,const ZZn4&); + friend ZZn8 operator*(const ZZn8&,const ZZn&); + friend ZZn8 operator*(const ZZn&,const ZZn8&); + friend ZZn8 operator*(const ZZn4&,const ZZn8&); + + friend ZZn8 operator*(int,const ZZn8&); + friend ZZn8 operator*(const ZZn8&,int); + + friend ZZn8 operator/(const ZZn8&,const ZZn8&); + friend ZZn8 operator/(const ZZn8&,const ZZn4&); + friend ZZn8 operator/(const ZZn8&,const ZZn&); + friend ZZn8 operator/(const ZZn8&,int); + + friend ZZn8 rhs(const ZZn8&); + + friend ZZn4 real(const ZZn8& x) {return x.a;} + friend ZZn4 imaginary(const ZZn8& x) {return x.b;} + + friend ZZn8 pow(const ZZn8&,const Big&); + friend ZZn8 pow(int,const ZZn8*,const Big*); + friend ZZn8 powl(const ZZn8&,const Big&); + friend ZZn8 conj(const ZZn8&); + friend ZZn8 tx(const ZZn8&); + friend ZZn8 txd(const ZZn8&); + friend ZZn8 tx2(const ZZn8&); + friend ZZn8 inverse(const ZZn8&); +#ifndef MR_NO_RAND + friend ZZn8 randn8(void); // random ZZn8 +#endif + friend BOOL qr(const ZZn8&); + friend ZZn8 sqrt(const ZZn8&); // square root - 0 if none exists + + friend BOOL operator==(const ZZn8& x,const ZZn8& y) + {if (x.a==y.a && x.b==y.b) return TRUE; else return FALSE; } + + friend BOOL operator!=(const ZZn8& x,const ZZn8& y) + {if (x.a!=y.a || x.b!=y.b) return TRUE; else return FALSE; } + +#ifndef MR_NO_STANDARD_IO + friend ostream& operator<<(ostream&,const ZZn8&); +#endif + + ~ZZn8() {} +}; +#ifndef MR_NO_RAND +extern ZZn8 randn8(void); +#endif + +#endif + diff --git a/miracl/source/curve/poly.cpp b/miracl/source/curve/poly.cpp new file mode 100644 index 0000000..1f8c539 --- /dev/null +++ b/miracl/source/curve/poly.cpp @@ -0,0 +1,1074 @@ +/* + * C++ class to implement a polynomial type and to allow + * arithmetic on polynomials whose elements are from + * the finite field mod p + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.6 + */ + +#include "poly.h" + +#include +using namespace std; + +Poly::Poly(const ZZn& c,int p) +{ + start=NULL; + addterm(c,p); +} + +Poly::Poly(Variable &x) +{ + start=NULL; + addterm((ZZn)1,1); +} + +Poly operator-(const Poly& a) +{ + Poly p=a; + p.multerm((ZZn)-1,0); + return p; +} + +Poly operator*(const ZZn& c,Variable x) +{ + Poly t(c,1); + return t; +} + +Poly pow(Variable x,int n) +{ + Poly r((ZZn)1,n); + return r; +} + +BOOL operator==(const Poly& a,const Poly& b) +{ + Poly diff=a-b; + if (iszero(diff)) return TRUE; + return FALSE; +} + +BOOL operator!=(const Poly& a,const Poly& b) +{ + Poly diff=a-b; + if (iszero(diff)) return FALSE; + return TRUE; +} + +void setpolymod(const Poly& p) +{ + int n,m; + Poly h; + term *ptr; + big *f,*rf; + n=degree(p); + if (nn]=getbig(ptr->an); + ptr=ptr->next; + } + ptr=h.start; + while (ptr!=NULL) + { + rf[ptr->n]=getbig(ptr->an); + ptr=ptr->next; + } + + mr_polymod_set(n,rf,f); + + mr_free(rf); + mr_free(f); +} + +Poly::Poly(const Poly& p) +{ + term *ptr=p.start; + term *pos=NULL; + start=NULL; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->n,pos); + ptr=ptr->next; + } +} + + +Poly::~Poly() +{ + term *nx; + while (start!=NULL) + { + nx=start->next; + delete start; + start=nx; + } +} + +ZZn Poly::coeff(int power) const +{ + ZZn c=0; + term *ptr=start; + while (ptr!=NULL) + { + if (ptr->n==power) + { + c=ptr->an; + return c; + } + ptr=ptr->next; + } + return c; +} + +ZZn Poly::F(const ZZn& x) const +{ + ZZn f=0; + int diff; + term *ptr=start; + +// Horner's rule + + if (ptr==NULL) return f; + f=ptr->an; + + while (ptr->next!=NULL) + { + diff=ptr->n-ptr->next->n; + if (diff==1) f=f*x+ptr->next->an; + else f=f*pow(x,diff)+ptr->next->an; + ptr=ptr->next; + } + f*=pow(x,ptr->n); + + return f; +} + +ZZn Poly:: min() const +{ + term *ptr=start; + if (start==NULL) return (ZZn)0; + + while (ptr->next!=NULL) ptr=ptr->next; + return (ptr->an); +} + +Poly compose(const Poly& g,const Poly& b,const Poly& m) +{ // compose polynomials + // assume G(x) = G3x^3 + G2x^2 + G1x^1 +G0 + // Calculate G(B(x) = G3.(B(x))^3 + G2.(B(x))^2 .... + Poly c,t; + term *ptr; + int i,d=degree(g); + Poly *table=new Poly[d+1]; + table[0].addterm((ZZn)1,0); + for (i=1;i<=d;i++) table[i]=(table[i-1]*b)%m; + ptr=g.start; + while (ptr!=NULL) + { + c+=ptr->an*table[ptr->n]; + c=c%m; + ptr=ptr->next; + } + delete [] table; + return c; +} + +Poly compose(const Poly& g,const Poly& b) +{ // compose polynomials + // assume G(x) = G3x^3 + G2x^2 + G1x^1 +G0 + // Calculate G(B(x) = G3.(B(x))^3 + G2.(B(x))^2 .... + Poly c,t; + term *ptr; + int i,d=degree(g); + Poly *table=new Poly[d+1]; + table[0].addterm((ZZn)1,0); + for (i=1;i<=d;i++) table[i]=(table[i-1]*b); + ptr=g.start; + while (ptr!=NULL) + { + c+=ptr->an*table[ptr->n]; + ptr=ptr->next; + } + delete [] table; + return c; +} + +Poly reduce(const Poly &x,const Poly &m) +{ + Poly r; + int i,d; + ZZn t; + big *G,*R; + term *ptr,*pos=NULL; + int degm=degree(m); + int n=degree(x); + + if (degm < FFT_BREAK_EVEN || n-degm < FFT_BREAK_EVEN) + { + r=x%m; + return r; + } + G=(big *)mr_alloc(n+1,sizeof(big)); + char *memg=(char *)memalloc(n+1); + for (i=0;i<=n;i++) G[i]=mirvar_mem(memg,i); + R=(big *)mr_alloc(degm,sizeof(big)); + char *memr=(char *)memalloc(degm); + for (i=0;ian),G[ptr->n]); + ptr=ptr->next; + } + if (!mr_poly_rem(n,G,R)) + { // reset the modulus - things have changed + setpolymod(m); + mr_poly_rem(n,G,R); + } + + r.clear(); + + for (d=degm-1;d>=0;d--) + { + t=R[d]; + if (t.iszero()) continue; + pos=r.addterm(t,d,pos); + } + memkill(memr,degm); + + mr_free(R); + memkill(memg,n+1); + mr_free(G); + + return r; +} + +Poly modmult(const Poly &x,const Poly &y,const Poly &m) +{ /* x*y mod m */ + Poly r=x*y; + r=reduce(r,m); + return r; +} + +Poly operator*(const Poly& a,const Poly& b) +{ + int i,d,dega,degb,deg; + BOOL squaring; + ZZn t; + Poly prod; + term *iptr,*pos; + term *ptr=b.start; + + squaring=FALSE; + if (&a==&b) squaring=TRUE; + + dega=degree(a); + deg=dega; + if (!squaring) + { + degb=degree(b); + if (degb=FFT_BREAK_EVEN) /* deg is minimum - both must be more than FFT_BREAK_EVEN */ + { // use fast methods + big *A,*B,*C; + deg=dega+degb; // degree of product + + A=(big *)mr_alloc(dega+1,sizeof(big)); + if (!squaring) B=(big *)mr_alloc(degb+1,sizeof(big)); + C=(big *)mr_alloc(deg+1,sizeof(big)); + char *memc=(char *)memalloc(deg+1); + for (i=0;i<=deg;i++) C[i]=mirvar_mem(memc,i); + ptr=a.start; + while (ptr!=NULL) + { + A[ptr->n]=getbig(ptr->an); + ptr=ptr->next; + } + + if (!squaring) + { + ptr=b.start; + while (ptr!=NULL) + { + B[ptr->n]=getbig(ptr->an); + ptr=ptr->next; + } + mr_poly_mul(dega,A,degb,B,C); + } + else mr_poly_sqr(dega,A,C); + pos=NULL; + for (d=deg;d>=0;d--) + { + t=C[d]; + if (t.iszero()) continue; + pos=prod.addterm(t,d,pos); + } + memkill(memc,deg+1); + mr_free(C); + mr_free(A); + if (!squaring) mr_free(B); + + return prod; + } + + if (squaring) + { // squaring + pos=NULL; + while (ptr!=NULL) + { // diagonal terms + pos=prod.addterm(ptr->an*ptr->an,ptr->n+ptr->n,pos); + ptr=ptr->next; + } + ptr=b.start; + while (ptr!=NULL) + { // above the diagonal + iptr=ptr->next; + pos=NULL; + while (iptr!=NULL) + { + t=ptr->an*iptr->an; + pos=prod.addterm(t+t,ptr->n+iptr->n,pos); + iptr=iptr->next; + } + ptr=ptr->next; + } + } + else while (ptr!=NULL) + { + pos=NULL; + iptr=a.start; + while (iptr!=NULL) + { + pos=prod.addterm(ptr->an*iptr->an,ptr->n+iptr->n,pos); + iptr=iptr->next; + } + ptr=ptr->next; + } + + return prod; +} + +Poly& Poly::operator%=(const Poly&v) +{ + ZZn m,pq; + int power; + term *rptr=start; + term *vptr=v.start; + term *ptr,*pos; + if (degree(*this)an); + while (rptr!=NULL && rptr->n>=vptr->n) + { + pq=rptr->an*m; + power=rptr->n-vptr->n; + pos=NULL; + ptr=v.start; + while (ptr!=NULL) + { + pos=addterm(ptr->an*pq,ptr->n+power,pos); + ptr=ptr->next; + } + rptr=start; + } + return *this; +} + +Poly operator%(const Poly& u,const Poly&v) +{ + Poly r=u; + r%=v; + return r; +} + +// returns quotient and remainder + +Poly divrem(Poly &r,const Poly& v) +{ + Poly q; + ZZn m; + term *rptr=r.start; + term *vptr=v.start; + term *ptr,*pos; + m=((ZZn)1/vptr->an); + while (rptr!=NULL && rptr->n>=vptr->n) + { + Poly t=v; + ZZn pq=m*rptr->an; + int power=rptr->n-vptr->n; + // quotient + q.addterm(pq,power); + t.multerm(-pq,power); + ptr=t.start; + pos=NULL; + while (ptr!=NULL) + { + pos=r.addterm(ptr->an,ptr->n,pos); + ptr=ptr->next; + } + rptr=r.start; + } + return q; +} + +Poly operator/(const Poly& u,const Poly& v) +{ + Poly q,r=u; + ZZn m; + term *rptr=r.start; + term *vptr=v.start; + term *ptr,*pos; + m=((ZZn)1/vptr->an); + while (rptr!=NULL && rptr->n>=vptr->n) + { + Poly t=v; + ZZn pq=m*rptr->an; + int power=rptr->n-vptr->n; + // quotient + q.addterm(pq,power); + t.multerm(-pq,power); + ptr=t.start; + pos=NULL; + while (ptr!=NULL) + { + pos=r.addterm(ptr->an,ptr->n,pos); + ptr=ptr->next; + } + rptr=r.start; + } + return q; +} + +Poly diff(const Poly& f) +{ + Poly d; + term *pos=NULL; + term *ptr=f.start; + while (ptr!=NULL) + { + pos=d.addterm(ptr->an*ptr->n,ptr->n-1,pos); + ptr=ptr->next; + } + + return d; +} + +Poly gcd(const Poly& f,const Poly& g) +{ + Poly a,b; + a=f; b=g; + term *ptr; + forever + { + if (b.start==NULL) + { + ptr=a.start; + a.multerm((ZZn)1/ptr->an,0); + return a; + } + a%=b; + if (a.start==NULL) + { + ptr=b.start; + b.multerm((ZZn)1/ptr->an,0); + return b; + } + b%=a; + } +} + +Poly pow(const Poly& f,int k) +{ + Poly u; + int w,e,b; + + if (k==0) + { + u.addterm((ZZn)1,0); + return u; + } + u=f; + if (k==1) return u; + + e=k; + b=0; while (k>1) {k>>=1; b++; } + w=(1<0) + { + u=(u*u); + if (e>=w) + { + e-=w; + u=(u*f); + } + w/=2; + } + return u; +} + +Poly pow(const Poly& f,const Big& k,const Poly& m) +{ + Poly u,t,u2,table[16]; + Big w,e; + int i,j,nb,n,nbw,nzs; + if (k==0) + { + u.addterm((ZZn)1,0); + return u; + } + u=f%m; + if (k==1) return u; + if (degree(m)>=FFT_BREAK_EVEN) + { /* Uses FFT for fixed base - much faster for large m */ + setpolymod(m); + + u2=modmult(u,u,m); + table[0]=u; + for (i=1;i<16;i++) + table[i]=modmult(u2,table[i-1],m); + nb=bits(k); + if (nb>1) for (i=nb-2;i>=0;) + { + n=window(k,i,&nbw,&nzs,5); + for (j=0;j0) u=modmult(u,table[n/2],m); + i-=nbw; + if (nzs) + { + for (j=0;j0) + { + u=(u*u)%m; + if (e>=w) + { + e-=w; + u=(u*f)%m; + } + w/=2; + } + } + return u; +} + +int degree(const Poly& p) +{ + if (p.start==NULL) return 0; + else return p.start->n; +} + + +BOOL iszero(const Poly& p) +{ + if (degree(p)==0 && p.coeff(0)==0) return TRUE; + else return FALSE; +} + +BOOL isone(const Poly& p) +{ + if (degree(p)==0 && p.coeff(0)==1) return TRUE; + else return FALSE; +} + +Poly factor(const Poly& f,int d) +{ + Poly c,u,h,g=f; + Big r,p=get_modulus(); +// int lim=0; + while (degree(g) > d) + { +// lim++; +// if (lim>10) break; +// random monic polynomial + u.clear(); + u.addterm((ZZn)1,2*d-1); + for (int i=2*d-2;i>=0;i--) + { + r=rand(p); + u.addterm((ZZn)r,i); + } + r=(pow(p,d)-1)/2; + + c=pow(u,r,g); + c.addterm((ZZn)(-1),0); + + h=gcd(c,g); + if (degree(h)==0 || degree(h)==degree(g)) continue; + if (2*degree(h)>degree(g)) + g=g/h; + else g=h; + } + return g; +} + +void Poly::clear() +{ + term *ptr; + while (start!=NULL) + { + ptr=start->next; + delete start; + start=ptr; + } + +} + +Poly& Poly::operator=(int m) +{ + clear(); + if (m!=0) addterm((ZZn)m,0); + return *this; +} + +Poly& Poly::operator=(const ZZn& m) +{ + clear(); + if (!m.iszero()) addterm(m,0); + return *this; +} + +Poly &Poly::operator=(const Poly& p) +{ + term *ptr,*pos=NULL; + clear(); + ptr=p.start; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->n,pos); + ptr=ptr->next; + } + return *this; +} + +Poly operator+(const Poly& a,const ZZn& z) +{ + Poly p=a; + p.addterm(z,0); + return p; +} + +Poly operator-(const Poly& a,const ZZn& z) +{ + Poly p=a; + p.addterm((-z),0); + return p; +} + + +Poly operator+(const Poly& a,const Poly& b) +{ + Poly sum; + sum=a; + sum+=b; + return sum; +} + +Poly operator-(const Poly& a,const Poly& b) +{ + Poly sum; + sum=a; + sum-=b; + return sum; +} + +Poly& Poly::operator+=(const Poly& p) +{ + term *ptr,*pos=NULL; + ptr=p.start; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->n,pos); + ptr=ptr->next; + } + return *this; +} + +Poly& Poly::operator*=(const ZZn& x) +{ + term *ptr=start; + while (ptr!=NULL) + { + ptr->an*=x; + ptr=ptr->next; + } + return *this; +} + +Poly operator*(const ZZn& z,const Poly &p) +{ + Poly r=p; + r*=z; + return r; +} + +Poly operator*(const Poly &p,const ZZn& z) +{ + Poly r=p; + r*=z; + return r; +} + +Poly operator/(const Poly& a,const ZZn& b) +{ + Poly quo; + quo=a; + quo/=(ZZn)b; + return quo; +} + +Poly& Poly::operator/=(const ZZn& x) +{ + ZZn t=(ZZn)1/x; + term *ptr=start; + while (ptr!=NULL) + { + ptr->an*=t; + ptr=ptr->next; + } + return *this; +} + +Poly& Poly::operator-=(const Poly& p) +{ + term *ptr,*pos=NULL; + ptr=p.start; + while (ptr!=NULL) + { + pos=addterm(-(ptr->an),ptr->n,pos); + ptr=ptr->next; + } + return *this; +} + +void Poly::multerm(const ZZn& a,int power) +{ + term *ptr=start; + while (ptr!=NULL) + { + ptr->an*=a; + ptr->n+=power; + ptr=ptr->next; + } +} + +Poly invmodxn(const Poly& a,int n) +{ // Newton's method to find 1/a mod x^n + int i,k; + Poly b; + k=0; while ((1<n>=n) ptr=ptr->next; + while (ptr!=NULL) + { + pos=b.addterm(ptr->an,ptr->n,pos); + ptr=ptr->next; + } + return b; +} + +Poly divxn(const Poly& a,int n) +{ // divide polynomial by x^n + Poly b; + term *ptr=a.start; + term *pos=NULL; + while (ptr!=NULL) + { + if (ptr->n>=n) + pos=b.addterm(ptr->an,ptr->n-n,pos); + else break; + ptr=ptr->next; + } + return b; +} + +Poly mulxn(const Poly& a,int n) +{ // multiply polynomial by x^n + Poly b; + term *ptr=a.start; + term *pos=NULL; + while (ptr!=NULL) + { + pos=b.addterm(ptr->an,ptr->n+n,pos); + ptr=ptr->next; + } + return b; +} + +Poly reverse(const Poly& a) +{ + term *ptr=a.start; + int deg=degree(a); + Poly b; + while (ptr!=NULL) + { + b.addterm(ptr->an,deg-ptr->n); + ptr=ptr->next; + } + return b; +} + +// add term to polynomial. The pointer pos remembers the last +// accessed element - this is faster. +// Polynomial is stored with large powers first, down to low powers +// e.g. 9x^6 + x^4 + 3x^2 + 1 + +term* Poly::addterm(const ZZn& a,int power,term *pos) +{ + term* newone; + term* ptr; + term *t,*iptr; + ptr=start; + iptr=NULL; + if (a.iszero()) return pos; +// quick scan through to detect if term exists already +// and to find insertion point + if (pos!=NULL) ptr=pos; // start looking from here + while (ptr!=NULL) + { + if (ptr->n==power) + { + ptr->an+=a; + if (ptr->an.iszero()) + { // delete term + if (ptr==start) + { // delete first one + start=ptr->next; + delete ptr; + return start; + } + iptr=ptr; + ptr=start; + while (ptr->next!=iptr)ptr=ptr->next; + ptr->next=iptr->next; + delete iptr; + return ptr; + } + return ptr; + } + if (ptr->n>power) iptr=ptr; + else break; + ptr=ptr->next; + } + newone=new term; + newone->next=NULL; + newone->an=a; + newone->n=power; + pos=newone; + if (start==NULL) + { + start=newone; + return pos; + } + +// insert at the start + + if (iptr==NULL) + { + t=start; + start=newone; + newone->next=t; + return pos; + } + +// insert new term + + t=iptr->next; + iptr->next=newone; + newone->next=t; + return pos; +} + +// A function to differentiate a polynomial +Poly differentiate(const Poly& orig) +{ + Poly newpoly; + term *ptr = orig.start; + term *pos = NULL; + int power; + + while (ptr!=NULL) + { + power = ptr->n; + if(ptr->n > 0) + pos = newpoly.addterm(ptr->an*power,ptr->n-1,pos); + + ptr = ptr->next; + } + + return newpoly; +} + +ZZn makemonic(Poly& p) +{ + term *ptr = p.start; + ZZn r=(ZZn)1/ptr->an; + p.multerm(r,0); + return r; +} + +/* Monic Inverse. Returns GCD */ + +Poly inverse(Poly &u,const Poly&v) +{ + Poly u1, u3, v1, v3, zero, q; + int t=0; + u1 = 1; + u3 = u; + v1 = 0; + v3 = v; + zero = 0; + term *ptr; + + forever + { + if (v3==zero) + { + u=u1; + ZZn r=makemonic(u); + u3*=r; + return u3; + } + q=divrem(u3,v3); + u1 -= v1*q; + +//cout << "."; +//cout << "tick " << t++ << " v3= " << degree(v3) << endl; + + if (u3==zero) + { + u=v1; + ZZn r=makemonic(u); + v3*=r; + return v3; + } + q=divrem(v3,u3); + v1 -= u1*q; + +//cout << "tock " << t++ << " u3= " << degree(u3) << endl; + + } + +} + +// The extended euclidean algorithm +// The result is returned in an array of Polys, with the gcd +// in first place, then the two coefficients +void egcd(Poly result[], const Poly& u, const Poly& v) +{ + Poly u1, u2, u3, v1, v2, v3, zero, q; + int t=0; + u1 = 1; + u2 = 0; + u3 = u; + v1 = 0; + v2 = 1; + v3 = v; + zero = 0; + term *ptr; + + forever + { + if (v3==zero) + { + result[0] = u3; + result[1] = u1; + result[2] = u2; + break; + } + q=u3/v3; + u1 -= v1*q; + u2 -= v2*q; + u3 -= v3*q; + + if (u3==zero) + { + result[0] = v3; + result[1] = v1; + result[2] = v2; + break; + } + q=v3/u3; + v1 -= u1*q; + v2 -= u2*q; + v3 -= u3*q; + + } + +} + +ostream& operator<<(ostream& s,const Poly& p) +{ + BOOL first=TRUE; + ZZn a; + term *ptr=p.start; + if (ptr==NULL) + { + s << "0"; + return s; + } + while (ptr!=NULL) + { + a=ptr->an; + if ((Big)an==0) + s << (Big)a; + else + { + if (a!=(ZZn)1) s << (Big)a << "*x"; + else s << "x"; + if (ptr->n!=1) s << "^" << ptr->n; + } + first=FALSE; + ptr=ptr->next; + } + return s; +} + diff --git a/miracl/source/curve/poly.h b/miracl/source/curve/poly.h new file mode 100644 index 0000000..7eb047a --- /dev/null +++ b/miracl/source/curve/poly.h @@ -0,0 +1,116 @@ +/* + * C++ class to implement a polynomial type and to allow + * arithmetic on polynomials whose elements are from + * the finite field mod p + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * New! it is now possible to assign a polynomial as:- + * + * Variable x; + * Poly P=3*pow(x,3)+2*x+1 // P=3x^3+2x+1 + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.6 + */ + +#ifndef POLY_H +#define POLY_H + +#include "zzn.h" +#include "variable.h" + +#define FFT_BREAK_EVEN 16 + +class term +{ +public: + ZZn an; + int n; + term *next; +}; + +class Poly +{ +public: + term *start; + Poly() {start=NULL;} + Poly(const Poly&); + + Poly(const ZZn&,int); + Poly(Variable &); + + void clear(); + term *addterm(const ZZn&,int,term *pos=NULL); + void multerm(const ZZn&,int); + ZZn F(const ZZn&) const; + ZZn coeff(int) const; + ZZn min() const; + + Poly& operator=(const Poly&); + Poly& operator=(const ZZn&); + Poly& operator=(int); + Poly& operator+=(const Poly&); + Poly& operator-=(const Poly&); + Poly& operator+=(const ZZn& m) {addterm(m,0); return *this; } + Poly& operator-=(const ZZn& m) {addterm((-m),0); return *this; } + Poly& operator%=(const Poly&); + Poly& operator*=(const ZZn&); + Poly& operator/=(const ZZn&); + + friend void setpolymod(const Poly&); + friend BOOL iszero(const Poly&); + friend BOOL isone(const Poly&); + friend Poly divxn(const Poly&,int); + friend Poly mulxn(const Poly&,int); + friend Poly modxn(const Poly&,int); + friend Poly invmodxn(const Poly&,int); + friend Poly reverse(const Poly&); + friend int degree(const Poly&); + friend Poly compose(const Poly&,const Poly&,const Poly&); + friend Poly compose(const Poly&,const Poly&); + friend Poly modmult(const Poly&,const Poly&,const Poly&); + friend void egcd(Poly result[], const Poly&,const Poly&); + friend Poly inverse(Poly&,const Poly&); + friend ZZn makemonic(Poly&); + friend Poly differentiate(const Poly&); + + friend Poly reduce(const Poly&,const Poly&); + friend Poly operator*(const Poly&,const Poly&); + friend Poly operator%(const Poly&,const Poly&); + friend Poly operator/(const Poly&,const Poly&); + friend Poly operator-(const Poly&,const Poly&); + friend Poly operator+(const Poly&,const Poly&); + friend Poly operator-(const Poly&); + friend Poly divrem(Poly&,const Poly&); + + friend Poly operator*(const ZZn& ,Variable); + friend Poly pow(Variable,int); + + + friend Poly operator-(const Poly&,const ZZn&); + friend Poly operator+(const Poly&,const ZZn&); + friend Poly operator*(const Poly&,const ZZn&); + friend Poly operator*(const ZZn&,const Poly&); + + friend Poly operator/(const Poly&,const ZZn&); + + friend Poly gcd(const Poly&,const Poly&); + friend Poly diff(const Poly&); + friend Poly pow(const Poly&,const Big&,const Poly&); + friend Poly pow(const Poly&,int); + + friend BOOL operator==(const Poly&,const Poly&); + friend BOOL operator!=(const Poly&,const Poly&); + + friend Poly factor(const Poly&,int); + friend ostream& operator<<(ostream&,const Poly&); + ~Poly(); +}; + +extern Poly pow(Variable,int); + + +#endif + diff --git a/miracl/source/curve/poly2.cpp b/miracl/source/curve/poly2.cpp new file mode 100644 index 0000000..b55ce09 --- /dev/null +++ b/miracl/source/curve/poly2.cpp @@ -0,0 +1,872 @@ +/* + * C++ class to implement a polynomial type and to allow + * arithmetic on polynomials whose elements are from + * the finite field GF(2^m) + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.6 + */ + +#include "poly2.h" + +Poly2::Poly2(const GF2m& c,int p) +{ + start=NULL; + addterm(c,p); +} + +Poly2::Poly2(Variable &x) +{ + start=NULL; + addterm((GF2m)1,1); +} + +Poly2 operator*(const GF2m& c,Variable x) +{ + Poly2 t(c,1); + return t; +} + +Poly2& Poly2::operator=(const GF2m& m) +{ + clear(); + if (!m.iszero()) addterm(m,0); + return *this; +} + +Poly2 pow2(Variable x,int n) +{ + Poly2 r((GF2m)1,n); + return r; +} + +Poly2::Poly2(const Poly2& p) +{ + term2 *ptr=p.start; + term2 *pos=NULL; + start=NULL; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->n,pos); + ptr=ptr->next; + } +} + +Poly2::~Poly2() +{ + term2 *nx; + while (start!=NULL) + { + nx=start->next; + delete start; + start=nx; + } +} + +GF2m Poly2::coeff(int power) const +{ + GF2m c=0; + term2 *ptr=start; + while (ptr!=NULL) + { + if (ptr->n==power) + { + c=ptr->an; + return c; + } + ptr=ptr->next; + } + return c; +} + +GF2m Poly2::F(const GF2m& x) const +{ + GF2m f=0; + int diff; + term2 *ptr=start; + +// Horner's rule + + if (ptr==NULL) return f; + f=ptr->an; + + while (ptr->next!=NULL) + { + diff=ptr->n-ptr->next->n; + if (diff==1) f=f*x+ptr->next->an; + else f=f*pow(x,diff)+ptr->next->an; + ptr=ptr->next; + } + f*=pow(x,ptr->n); + + return f; +} + +GF2m Poly2:: min() const +{ + term2 *ptr=start; + if (start==NULL) return (GF2m)0; + + while (ptr->next!=NULL) ptr=ptr->next; + return (ptr->an); +} + +Poly2 operator*(const Poly2& a,const Poly2& b) +{ + int i,d,dega,degb,deg; + GF2m t; + Poly2 prod; + term2 *iptr,*pos; + term2 *ptr=b.start; + if (&a==&b) + { // squaring - only diagonal terms count! + pos=NULL; + while (ptr!=NULL) + { // diagonal terms + pos=prod.addterm(ptr->an*ptr->an,ptr->n+ptr->n,pos); + ptr=ptr->next; + } + return prod; + } + + dega=degree(a); + deg=dega; + degb=degree(b); + if (degb=KARAT_BREAK_EVEN) + { // use fast method + int len,m,inc; + + big *A,*B,*C,*T; + deg=dega; + if (degan]=getbig(ptr->an); + ptr=ptr->next; + } + ptr=b.start; + while (ptr!=NULL) + { + B[ptr->n]=getbig(ptr->an); + ptr=ptr->next; + } + + karmul2_poly(deg+1,T,A,B,C); + + pos=NULL; + for (d=dega+degb;d>=0;d--) + { + t=C[d]; + if (t.iszero()) continue; + pos=prod.addterm(t,d,pos); + } + + memkill(memc,len); + memkill(memt,len); + + mr_free(T); + mr_free(C); + mr_free(B); + mr_free(A); + return prod; + } + + while (ptr!=NULL) + { + pos=NULL; + iptr=a.start; + while (iptr!=NULL) + { + pos=prod.addterm(ptr->an*iptr->an,ptr->n+iptr->n,pos); + iptr=iptr->next; + } + ptr=ptr->next; + } + + return prod; +} + +Poly2& Poly2::operator%=(const Poly2& v) +{ + GF2m m,pq; + int power; + term2 *rptr=start; + term2 *vptr=v.start; + term2 *ptr,*pos; + if (degree(*this)an); + + while (rptr!=NULL && rptr->n>=vptr->n) + { + pq=rptr->an*m; + power=rptr->n-vptr->n; + pos=NULL; + ptr=v.start; + while (ptr!=NULL) + { + pos=addterm(ptr->an*pq,ptr->n+power,pos); + ptr=ptr->next; + } + rptr=start; + } + return *this; +} + +Poly2 operator%(const Poly2& u,const Poly2& v) +{ + Poly2 r=u; + r%=v; + return r; +} + +Poly2 fulldiv(Poly2& r,const Poly2 &v) +{ + Poly2 q; + GF2m pq,m; + int power; + term2 *rptr=r.start; + term2 *vptr=v.start; + term2 *ptr,*pos; + m=(GF2m)1/vptr->an; + + while (rptr!=NULL && rptr->n>=vptr->n) + { + pq=rptr->an*m; + power=rptr->n-vptr->n; + q.addterm(pq,power); + + pos=NULL; + ptr=v.start; + while (ptr!=NULL) + { + pos=r.addterm(ptr->an*pq,ptr->n+power,pos); + ptr=ptr->next; + } + rptr=r.start; + } + return q; +} + +Poly2 operator/(const Poly2& u,const Poly2 &v) +{ + Poly2 r=u; + return fulldiv(r,v); +} + +void swap(Poly2 &x,Poly2 &y) +{ + term2 *t; + t=x.start; + x.start=y.start; + y.start=t; +} + +void makemonic(Poly2& p) +{ + term2 *ptr = p.start; + p.multerm((GF2m)1/ptr->an,0); +} + +// A function to differentiate a polynomial +Poly2 differentiate(const Poly2& orig) +{ + Poly2 newpoly; + term2 *ptr = orig.start; + term2 *pos = NULL; + int power; + + while (ptr!=NULL) + { + power = ptr->n; + if(ptr->n > 0) + pos = newpoly.addterm(ptr->an*(GF2m)(power % 2),ptr->n-1,pos); + + ptr = ptr->next; + } + + return newpoly; +} + +GF2m resultant(const Poly2& a,const Poly2 &b) +{ // borrowed from NTL + GF2m lc,r=1; + int d0,d1,d2; + if (iszero(a) || iszero(b)) return (GF2m)0; + if (degree(a)==0 && degree(b)==0) return (GF2m)1; + + Poly2 u=a; + Poly2 v=b; + term2 *ptr; + + forever + { + d0=degree(u); + d1=degree(v); + lc=v.coeff(d1); + + u%=v; + + ptr=v.start; v.start=u.start; u.start=ptr; // swap them + + d2=degree(v); + if (!iszero(v)) + { + lc=pow(lc,d0-d2); + r*=lc; + /* if (d0&d1&1) r=-r; */ + } + else + { + if (d1==0) + { + lc=pow(lc,d0); + r*=lc; + } + else r=0; + break; + } + } + + return r; +} + + +Poly2 operator-(const Poly2& a,const GF2m& z) +{ + Poly2 p=a; + p.addterm((z),0); + return p; +} + +Poly2 operator-(const Poly2& a) +{ + Poly2 p=a; + return p; +} + +Poly2 operator-(const Poly2& a,const Poly2& b) +{ + Poly2 sum; + sum=a; + sum+=b; + return sum; +} + +Poly2 inverse(const Poly2& f,const Poly2& m) +{ + Poly2 r,s,q,p,x; + term2 *ptr; + x=f%m; + r=1; + s=0; + p=m; + while (!iszero(p)) + { // main euclidean loop */ + q=fulldiv(x,p); + r+=s*q; + swap(r,s); + swap(x,p); + } + ptr=x.start; + r.multerm((GF2m)1/ptr->an,0); + return r; +} + +Poly2 gcd(const Poly2& f,const Poly2& g) +{ + Poly2 a,b; + a=f; b=g; + term2 *ptr; + + forever + { + if (b.start==NULL) + { + ptr=a.start; + a.multerm((GF2m)1/ptr->an,0); + return a; + } + a%=b; + if (a.start==NULL) + { + ptr=b.start; + b.multerm((GF2m)1/ptr->an,0); + return b; + } + b%=a; + } +} + +// The extended euclidean algorithm +// The result is returned in an array of Polys, with the gcd +// in first place, then the two coefficients +void egcd(Poly2 result[], const Poly2& u, const Poly2& v) +{ + Poly2 u1, u2, u3, v1, v2, v3, t1, t2, t3, zero, q; + GF2m t; + term2 *ptr; + u1 = 1; + u2 = 0; + u3 = u; + v1 = 0; + v2 = 1; + v3 = v; + zero = 0; + + while(v3 != zero) { + q = u3/v3; + + t1 = u1 - v1*q; + t2 = u2 - v2*q; + t3 = u3 - v3*q; + + u1 = v1; + u2 = v2; + u3 = v3; + + v1 = t1; + v2 = t2; + v3 = t3; + } + + ptr=u3.start; + t=(GF2m)1/ptr->an; + u3.multerm(t,0); + u1.multerm(t,0); + u2.multerm(t,0); + + result[0] = u3; + result[1] = u1; + result[2] = u2; +} + + +Poly2 pow(const Poly2& f,int k) +{ + Poly2 u; + int w,e,b; + + if (k==0) + { + u.addterm((GF2m)1,0); + return u; + } + u=f; + if (k==1) return u; + + e=k; + b=0; while (k>1) {k>>=1; b++; } + w=(1<0) + { + u=(u*u); + if (e>=w) + { + e-=w; + u=(u*f); + } + w/=2; + } + return u; +} + +Poly2 pow(const Poly2& f,const Big& k,const Poly2& m) +{ + Poly2 u,t; + Big w,e; + if (k==0) + { + u.addterm((GF2m)1,0); + return u; + } + u=(f%m); + if (k==1) return u; + + e=k; + w=pow((Big)2,bits(e)-1); + e-=w; w/=2; + while (w>0) + { + u=(u*u)%m; + if (e>=w) + { + e-=w; + u=(u*f)%m; + } + w/=2; + } + return u; +} + +int degree(const Poly2& p) +{ + if (p.start==NULL) return 0; + else return p.start->n; +} + + +BOOL iszero(const Poly2& p) +{ + if (degree(p)==0 && p.coeff(0)==0) return TRUE; + else return FALSE; +} + +BOOL isone(const Poly2& p) +{ + if (degree(p)==0 && p.coeff(0)==1) return TRUE; + else return FALSE; +} + +void Poly2::clear() +{ + term2 *ptr; + while (start!=NULL) + { + ptr=start->next; + delete start; + start=ptr; + } + +} + +Poly2& Poly2::operator=(int m) +{ + clear(); + if (m!=0) addterm((GF2m)m,0); + return *this; +} + +Poly2 &Poly2::operator=(const Poly2& p) +{ + term2 *ptr,*pos=NULL; + clear(); + ptr=p.start; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->n,pos); + ptr=ptr->next; + } + return *this; +} + +Poly2 operator+(const Poly2& a,const Poly2& b) +{ + Poly2 sum; + sum=a; + sum+=b; + return sum; +} + +Poly2 operator+(const Poly2& a,const GF2m& b) +{ + Poly2 sum=a; + sum.addterm(b,0); + return sum; +} + +Poly2& Poly2::operator+=(const Poly2& p) +{ + term2 *ptr,*pos=NULL; + ptr=p.start; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->n,pos); + ptr=ptr->next; + } + return *this; +} + +Poly2& Poly2::operator*=(const GF2m& x) +{ + term2 *ptr=start; + while (ptr!=NULL) + { + ptr->an*=x; + ptr=ptr->next; + } + return *this; +} + +BOOL operator==(const Poly2& a,const Poly2& b) +{ + Poly2 diff=a+b; + if (iszero(diff)) return TRUE; + return FALSE; +} + +BOOL operator!=(const Poly2& a,const Poly2& b) +{ + Poly2 diff=a+b; + if (iszero(diff)) return FALSE; + return TRUE; +} + +Poly2 operator*(const GF2m& z,const Poly2 &p) +{ + Poly2 r=p; + r*=z; + return r; +} + +Poly2 operator*(const Poly2 &p,const GF2m& z) +{ + Poly2 r=p; + r*=z; + return r; +} + +Poly2 operator/(const Poly2& a,const GF2m& b) +{ + Poly2 quo; + quo=a; + quo/=(GF2m)b; + return quo; +} + + +Poly2& Poly2::operator/=(const GF2m& x) +{ + GF2m t=(GF2m)1/x; + term2 *ptr=start; + while (ptr!=NULL) + { + ptr->an*=t; + ptr=ptr->next; + } + return *this; +} + +void Poly2::multerm(const GF2m& a,int power) +{ + term2 *ptr=start; + while (ptr!=NULL) + { + ptr->an*=a; + ptr->n+=power; + ptr=ptr->next; + } +} + +Poly2 invmodxn(const Poly2& a,int n) +{ // Newton's method to find 1/a mod x^n + int i,k; + Poly2 b; + k=0; while ((1<n>=n) ptr=ptr->next; + while (ptr!=NULL) + { + pos=b.addterm(ptr->an,ptr->n,pos); + ptr=ptr->next; + } + return b; +} + +Poly2 divxn(const Poly2& a,int n) +{ // divide polynomial by x^n + Poly2 b; + term2 *ptr=a.start; + term2 *pos=NULL; + while (ptr!=NULL) + { + if (ptr->n>=n) + pos=b.addterm(ptr->an,ptr->n-n,pos); + else break; + ptr=ptr->next; + } + return b; +} + +Poly2 mulxn(const Poly2& a,int n) +{ // multiply polynomial by x^n + Poly2 b; + term2 *ptr=a.start; + term2 *pos=NULL; + while (ptr!=NULL) + { + pos=b.addterm(ptr->an,ptr->n+n,pos); + ptr=ptr->next; + } + return b; +} + +Poly2 reverse(const Poly2& a) +{ + term2 *ptr=a.start; + int deg=degree(a); + Poly2 b; + while (ptr!=NULL) + { + b.addterm(ptr->an,deg-ptr->n); + ptr=ptr->next; + } + return b; +} + +// add term to polynomial. The pointer pos remembers the last +// accessed element - this is faster. +// Polynomial is stored with large powers first, down to low powers +// e.g. 9x^6 + x^4 + 3x^2 + 1 + +term2* Poly2::addterm(const GF2m& a,int power,term2 *pos) +{ + term2* newone; + term2* ptr; + term2 *t,*iptr; + ptr=start; + iptr=NULL; + if (a.iszero()) return pos; +// quick scan through to detect if term exists already +// and to find insertion point + if (pos!=NULL) ptr=pos; // start looking from here + while (ptr!=NULL) + { + if (ptr->n==power) + { + ptr->an+=a; + if (ptr->an.iszero()) + { // delete term + if (ptr==start) + { // delete first one + start=ptr->next; + delete ptr; + return start; + } + iptr=ptr; + ptr=start; + while (ptr->next!=iptr)ptr=ptr->next; + ptr->next=iptr->next; + delete iptr; + return ptr; + } + return ptr; + } + if (ptr->n>power) iptr=ptr; + else break; + ptr=ptr->next; + } + newone=new term2; + newone->next=NULL; + newone->an=a; + newone->n=power; + pos=newone; + if (start==NULL) + { + start=newone; + return pos; + } + +// insert at the start + + if (iptr==NULL) + { + t=start; + start=newone; + newone->next=t; + return pos; + } + +// insert new term + + t=iptr->next; + iptr->next=newone; + newone->next=t; + return pos; +} + +ostream& operator<<(ostream& s,const Poly2& p) +{ + BOOL first=TRUE; + GF2m a; + term2 *ptr=p.start; + if (ptr==NULL) + { + s << "0"; + return s; + } + while (ptr!=NULL) + { + a=ptr->an; + if (!first) s << " + "; + if (ptr->n==0) + s << (Big)a; + else + { + if (a!=(GF2m)1) s << (Big)a << "*x"; + else s << "x"; + if (ptr->n!=1) s << "^" << ptr->n; + } + first=FALSE; + ptr=ptr->next; + } + return s; +} + + +Poly2 compose(const Poly2& q,const Poly2& p) +{ // compose polynomials + // assume P(x) = P3x^3 + P2x^2 + P1x^1 +P0 + // Calculate P(Q(x)) = P3.(Q(x))^3 + P2.(Q(x))^2 .... + + Poly2 poly; + Poly2 temp(p); + int qdegree; + term2 *qptr = q.start; + poly.start = NULL; + + while(qptr != NULL) { + qdegree = qptr->n; + if(qdegree > 0) { + temp = p; + for(int i = 1; i < qdegree; i++) + temp = temp * p; + + poly += temp; + } else { + poly = poly + qptr->an; + } + + qptr = qptr->next; + } + + return poly; +} + + diff --git a/miracl/source/curve/poly2.h b/miracl/source/curve/poly2.h new file mode 100644 index 0000000..f23bcfc --- /dev/null +++ b/miracl/source/curve/poly2.h @@ -0,0 +1,106 @@ +/* + * C++ class to implement a polynomial type and to allow + * arithmetic on polynomials whose elements are from + * the finite field 2^m + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.6 + */ + +#ifndef POLY2_H +#define POLY2_H + +#include "gf2m.h" +#include "variable.h" + +#define KARAT_BREAK_EVEN 8 + +class term2 +{ +public: + GF2m an; + int n; + term2 *next; +}; + +class Poly2 +{ +public: + term2 *start; + Poly2() {start=NULL;} + Poly2(const Poly2&); + + Poly2(const GF2m&,int); + Poly2(Variable &); + + void clear(); + term2 *addterm(const GF2m&,int,term2 *pos=NULL); + void multerm(const GF2m&,int); + GF2m F(const GF2m&) const; + GF2m coeff(int) const; + GF2m min() const; + + Poly2& operator=(const Poly2&); + Poly2& operator=(const GF2m&); + Poly2& operator=(int); + Poly2& operator+=(const Poly2&); + Poly2& operator+=(const GF2m& m) {addterm(m,0); return *this; } + Poly2& operator%=(const Poly2&); + Poly2& operator*=(const GF2m&); + Poly2& operator/=(const GF2m&); + + friend BOOL iszero(const Poly2&); + friend BOOL isone(const Poly2&); + friend Poly2 divxn(const Poly2&,int); + friend Poly2 mulxn(const Poly2&,int); + friend Poly2 modxn(const Poly2&,int); + friend Poly2 invmodxn(const Poly2&,int); + friend Poly2 reverse(const Poly2&); + friend int degree(const Poly2&); + friend Poly2 differentiate(const Poly2&); + friend GF2m resultant(const Poly2&,const Poly2&); + + + friend Poly2 operator*(const Poly2&,const Poly2&); + friend Poly2 operator%(const Poly2&,const Poly2&); + friend Poly2 operator/(const Poly2&,const Poly2&); + friend Poly2 operator+(const Poly2&,const Poly2&); + friend Poly2 operator+(const Poly2&,const GF2m&); + friend Poly2 operator-(const Poly2&,const Poly2&); + friend Poly2 operator-(const Poly2&,const GF2m&); + friend Poly2 operator-(const Poly2&); + friend void egcd(Poly2 result[], const Poly2&,const Poly2&); + + friend Poly2 operator*(const Poly2&,const GF2m&); + friend Poly2 operator*(const GF2m&,const Poly2&); + + friend Poly2 operator/(const Poly2&,const GF2m&); + + friend Poly2 operator*(const GF2m&,Variable); + friend Poly2 pow2(Variable,int); + + friend Poly2 fulldiv(Poly2&,const Poly2&); + friend Poly2 gcd(const Poly2&,const Poly2&); + friend Poly2 inverse(const Poly2&,const Poly2&); + friend void swap(Poly2 &,Poly2 &); + friend void makemonic(Poly2&); + + + friend Poly2 pow(const Poly2&,const Big&,const Poly2&); + friend Poly2 pow(const Poly2&,int); + friend Poly2 compose(const Poly2&,const Poly2&); + + friend BOOL operator==(const Poly2&,const Poly2&); + friend BOOL operator!=(const Poly2&,const Poly2&); + friend ostream& operator<<(ostream&,const Poly2&); + ~Poly2(); +}; + +extern Poly2 operator*(const GF2m&,Variable); +extern Poly2 pow2(Variable,int); + +#endif + diff --git a/miracl/source/curve/poly2mod.cpp b/miracl/source/curve/poly2mod.cpp new file mode 100644 index 0000000..43e4a55 --- /dev/null +++ b/miracl/source/curve/poly2mod.cpp @@ -0,0 +1,278 @@ +/* + * C++ class to implement a polynomial type and to allow + * arithmetic on polynomials whose elements are from + * the finite field GF(2^m). + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * This type is automatically reduced + * wrt a polynomial Modulus. + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.6 + */ + +#include "poly2mod.h" + +extern "C" +{ +extern miracl *mr_mip; +} + +Poly2 Modulus; + +big *GF=NULL; +big *GRF,*T,*W,*Q; + +int N,INC; + +BOOL iszero(const Poly2Mod& m) {return iszero(m.p);} +BOOL isone(const Poly2Mod& m) {return isone(m.p);} +int degree(const Poly2Mod& m) {return degree(m.p);} + +GF2m Poly2Mod::coeff(int i) const {return p.coeff(i);} + +Poly2Mod& Poly2Mod::operator*=(const Poly2Mod &b) +{ + reduce(p*b.p,*this); + return *this; +} + +Poly2Mod operator*(const Poly2Mod &a,const Poly2Mod& b) +{ + Poly2Mod prod=a; + if (&a!=&b) prod*=b; + else prod*=prod; + return prod; +} + +void reduce(const Poly2& p,Poly2Mod& rem) +{ + int m,d; + GF2m t; + big *G; + term2 *ptr,*pos=NULL; + int n=degree(p); + int degm=degree(Modulus); + + if (n-degm < KARAT_BREAK_EVEN) + { + rem=(Poly2Mod)p; + return; + } + + G=(big *)mr_alloc(2*(N+2),sizeof(big)); + + ptr=p.start; + while (ptr!=NULL) + { + G[ptr->n]=getbig(ptr->an); + ptr=ptr->next; + } + + karmul2_poly(N,T,GRF,&G[N],W); // W=(G/x^n) * h + + for (d=N-1;d<2*N;d++) copy(W[d],Q[d-N+1]); + m=N+1; if(m%2==1) m=N+2; // make sure m is even - pad if necessary + + for (d=m;d<2*m;d++) copy(G[d],W[d]); + + karmul2_poly_upper(m,T,GF,Q,W); + + pos=NULL; + rem.clear(); + for (d=N-1;d>=0;d--) + { + add2(W[d],G[d],W[d]); + t=W[d]; + if (t.iszero()) continue; + pos=rem.addterm(t,d,pos); + } + + mr_free(G); +} + +void setmod(const Poly2& p) +{ + int i,n,m; + Poly2 h; + term2 *ptr; + Modulus=p; + + n=degree(p); + if (nan),GF[ptr->n]); + ptr=ptr->next; + } + ptr=h.start; + while (ptr!=NULL) + { + copy(getbig(ptr->an),GRF[ptr->n]); + ptr=ptr->next; + } +} + +Poly2Mod operator+(const Poly2Mod& a,const Poly2Mod& b) + {return (a.p+b.p)%Modulus;} +Poly2Mod operator*(const Poly2Mod& a,const GF2m& z) + {return (z*a.p);} +Poly2Mod operator*(const GF2m& z,const Poly2Mod& m) + {return (z*m.p);} + + +Poly2Mod operator+(const Poly2Mod& a,const GF2m& z) +{ + Poly2Mod p=a; + p.addterm(z,0); + return p; +} + +Poly2Mod operator/(const Poly2Mod& a,const GF2m& z) + {return (a.p/z);} + +Poly2 gcd(const Poly2Mod& m) +{return gcd(m.p,Modulus);} + +Poly2Mod inverse(const Poly2Mod& m) + +{return (Poly2Mod)inverse(m.p,Modulus);} + +// +// Brent & Kung's First Algorithm +// See "Fast Algorithms for Manipulating Formal Power Series +// J.ACM, Vol. 25 No. 4 October 1978 pp 581-595 +// + +Poly2Mod compose(const Poly2Mod& q,const Poly2Mod& p) +{ // compose polynomials + // assume P(x) = P3x^3 + P2x^2 + P1x^1 +P0 + // Calculate P(Q(x)) = P3.(Q(x))^3 + P2.(Q(x))^2 .... + Poly2Mod C,Q,T; + big t; + term2 *xptr,*yptr; + int i,j,ik,L,n=degree(Modulus); + int k=isqrt(n+1,1); + if (k*kn<=ik+k-1) break; + xptr=xptr->next; + } + for (j=k-1;j>=0;j--) + { + x[j]=t; + if (xptr!=NULL) + { + if (ik+j==xptr->n) + { + x[j]=getbig(xptr->an); + xptr=xptr->next; + } + } + // x[j]=q.coeff(i*k+j) + y[j]=t; + yptr=P[j].p.start; + while (yptr!=NULL) + { + if (yptr->n<=L) + { + if (yptr->n==L) y[j]=getbig(yptr->an); + break; + } + yptr=yptr->next; + } + } // y[j]=P[j].coeff(L) + +// Asymptotically slow, but fast in practise ... + gf2m_dotprod(k,x,y,t); + Q.addterm((GF2m)t,L); + } + C+=(Q*T); + if (i + +using namespace std; + +Poly2XY::Poly2XY(const GF2m& c, int p, int y) +{ + start=NULL; + addterm(c,p,y); +} + +Poly2XY::Poly2XY(int p) +{ + start=NULL; + addterm((GF2m)p,0,0); +} + +Poly2XY::Poly2XY(const Poly2XY& p) +{ + term2XY *ptr=p.start; + term2XY *pos=NULL; + start=NULL; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->nx,ptr->ny,pos); + ptr=ptr->next; + } +} + +Poly2XY::Poly2XY(const Poly2& p) +{ + term2 *ptr=p.start; + term2XY *pos=NULL; + start=NULL; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->n,0,pos); + ptr=ptr->next; + } +} + +Poly2XY::~Poly2XY() +{ + term2XY *nx; + while (start!=NULL) + { + nx=start->next; + delete start; + start=nx; + } +} + +GF2m Poly2XY::coeff(int powx,int powy) const +{ + GF2m c=0; + term2XY *ptr=start; + while (ptr!=NULL) + { + if (ptr->nx==powx && ptr->ny==powy) + { + c=ptr->an; + return c; + } + ptr=ptr->next; + } + return c; +} + +Poly2XY diff_dx(const Poly2XY& f) +{ + Poly2XY r; + term2XY *pos=NULL; + term2XY *ptr=f.start; + while (ptr!=NULL) + { + pos=r.addterm(ptr->an*(GF2m)ptr->nx,ptr->nx-1,ptr->ny,pos); + ptr=ptr->next; + } + return r; +} + +Poly2XY diff_dy(const Poly2XY& f) +{ + Poly2XY r; + term2XY *pos=NULL; + term2XY *ptr=f.start; + while (ptr!=NULL) + { + pos=r.addterm(ptr->an*(GF2m)ptr->ny,ptr->nx,ptr->ny-1,pos); + ptr=ptr->next; + } + return r; +} + +Poly2 Poly2XY::F(const GF2m& y) +{ + Poly2 r; + term2 *pos=NULL; + int i,maxy=0; + GF2m f; + term2XY *ptr=start; + + while (ptr!=NULL) + { + if (ptr->ny>maxy) maxy=ptr->ny; + ptr=ptr->next; + } + + // max y is max power of y present + + GF2m *pw=new GF2m[maxy+1]; // powers of y + + pw[0]=(GF2m)1; + for (i=1;i<=maxy;i++) + pw[i]=y*pw[i-1]; + + ptr=start; + while (ptr!=NULL) + { + pos=r.addterm(ptr->an*pw[ptr->ny],ptr->nx,pos); + ptr=ptr->next; + } + + delete [] pw; + + return r; +} + +GF2m Poly2XY::F(const GF2m& x,const GF2m& y) +{ + Poly2 r=F(y); + // cout << "r: " << r << endl; + return r.F(x); +} + +void Poly2XY::clear() +{ + term2XY *ptr; + while (start!=NULL) + { + ptr=start->next; + delete start; + start=ptr; + } + +} + +// Convert a poly2xy object to a poly2 object by just taking the +// "x" value +Poly2 Poly2XY::convert_x() const +{ + term2XY *ptr=start; + term2 *pos=NULL; + Poly2 newpoly; + while (ptr!=NULL) + { + pos = newpoly.addterm(ptr->an,ptr->nx,pos); + ptr = ptr->next; + } + return newpoly; +} + + +// Convert a poly2xy object to a poly2 object by just taking the +// "x" value when the corresponding "y" value is 0 +Poly2 Poly2XY::convert_x2() const +{ + term2XY *ptr=start; + term2 *pos=NULL; + Poly2 newpoly; + while (ptr!=NULL) + { + if(ptr->ny == 0) + pos = newpoly.addterm(ptr->an,ptr->nx,pos); + ptr = ptr->next; + } + return newpoly; +} + +// Convert a poly2xy object to a poly2 object by just taking the +// "x" value when the corresponding "y" value is greater than 0 +Poly2 Poly2XY::convert_x3() const +{ + term2XY *ptr=start; + term2 *pos=NULL; + Poly2 newpoly; + while (ptr!=NULL) + { + if(ptr->ny > 0) + pos = newpoly.addterm(ptr->an,ptr->nx,pos); + ptr = ptr->next; + } + return newpoly; +} + + + +Poly2XY& Poly2XY::operator=(int p) +{ + clear(); + addterm((GF2m)p, 0, 0); + return *this; +} + +Poly2XY& Poly2XY::operator=(const Poly2XY& p) +{ + term2XY *ptr,*pos=NULL; + clear(); + ptr=p.start; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->nx,ptr->ny,pos); + ptr=ptr->next; + } + return *this; + +} + +term2XY* Poly2XY::addterm(const GF2m& a,int powx,int powy,term2XY *pos) +{ + term2XY* newone; + term2XY* ptr; + term2XY *t,*iptr; + ptr=start; + iptr=NULL; + if (a.iszero()) return pos; + + // quick scan through to detect if term exists already + // and to find insertion point + if (pos!=NULL) ptr=pos; + while (ptr!=NULL) + { + if (ptr->nx==powx && ptr->ny==powy) + { + ptr->an+=a; + if (ptr->an.iszero()) + { // delete term + if (ptr==start) + { // delete first one + start=ptr->next; + delete ptr; + return start; + } + iptr=ptr; + ptr=start; + while (ptr->next!=iptr)ptr=ptr->next; + ptr->next=iptr->next; + delete iptr; + return ptr; + } + return ptr; + } + if (ptr->nx>powx) iptr=ptr; + if (ptr->nx==powx && ptr->ny>powy) iptr=ptr; + ptr=ptr->next; + } + newone=new term2XY; + newone->next=NULL; + newone->an=a; + newone->nx=powx; + newone->ny=powy; + + pos=newone; + if (start==NULL) + { + start=newone; + return pos; + } + + // insert at the start + + if (iptr==NULL) + { + t=start; + start=newone; + newone->next=t; + return pos; + } + + // insert new term + + t=iptr->next; + iptr->next=newone; + newone->next=t; + return pos; +} + +ostream& operator<<(ostream& s,const Poly2XY& p) +{ + BOOL first=TRUE; + GF2m a; + term2XY *ptr=p.start; + if (ptr==NULL) + { + s << "0"; + return s; + } + while (ptr!=NULL) + { + a=ptr->an; + if ((Big)anx==0 && ptr->ny==0) + s << a; + else + { + if (a!=(GF2m)1) s << a << "*"; + if (ptr->nx!=0) + { + s << "x"; + if (ptr->nx!=1) s << "^" << ptr->nx; + } + if (ptr->ny!=0) + { + if (ptr->nx!=0) s << "."; + s << "y"; + if (ptr->ny!=1) s << "^" << ptr->ny; + } + } + first=FALSE; + ptr=ptr->next; + } + return s; +} + +/* + Poly2XY operator*(const GF2m& c,Variable x) + { + Poly2XY t(c,1); + return t; + } + */ + +Poly2XY operator*(Variable x,Variable y) +{ + Poly2XY t((GF2m)1,1,1); + return t; +} + +Poly2XY pow2X(Variable x,int n) +{ + Poly2XY r((GF2m)1,n,0); + return r; +} + +Poly2XY pow2Y(Variable y,int n) +{ + Poly2XY r((GF2m)1,0,n); + return r; +} + +Poly2XY operator%(const Poly2XY& u,const Poly2XY& v) +{ + Poly2XY r=u; + r%=v; + return r; +} + +/* + Poly2XY operator*(const Poly2XY& u,const Poly2XY& v) + { + Poly2XY r=u; + r*=v; + return r; + } + */ + +Poly2XY& Poly2XY::operator%=(const Poly2XY& v) +{ + GF2m m,pq; + int power, power2; + term2XY *rptr=start; + term2XY *vptr=v.start; + term2XY *ptr,*pos; + if (degreeX(*this)an); + + while (rptr!=NULL && rptr->nx>=vptr->nx && rptr->ny>=vptr->ny) + { + pq=rptr->an*m; + power=rptr->nx-vptr->nx; + power2=rptr->ny-vptr->ny; + pos=NULL; + ptr=v.start; + while (ptr!=NULL) + { + pos=addterm(ptr->an*pq,ptr->nx+power,ptr->ny+power2,pos); + ptr=ptr->next; + } + rptr=start; + } + + return *this; +} + +int degreeX(const Poly2XY& p) +{ + if (p.start==NULL) return 0; + else return p.start->nx; +} + +int degreeY(const Poly2XY& p) +{ + term2XY *ptr=p.start; + int maxdeg = 0; + + if (p.start==NULL) return 0; + + while (ptr!=NULL) + { + if(ptr->ny > maxdeg) + maxdeg = ptr->ny; + ptr = ptr->next; + } + return maxdeg; +} + +BOOL iszero(const Poly2XY& p) +{ + if (degreeX(p)==0 && degreeY(p)==0 && p.coeff(0,0)==0) return TRUE; + else return FALSE; +} + +Poly2XY operator+(const Poly2XY& a,const Poly2XY& b) +{ + Poly2XY sum; + sum=a; + sum+=b; + return sum; +} + +Poly2XY operator+(const Poly2XY& a,const GF2m& b) +{ + Poly2XY sum=a; + sum.addterm(b,0,0); + return sum; +} + +Poly2XY operator-(const Poly2XY& a,const Poly2XY& b) +{ + Poly2XY sum; + sum=a; + sum-=b; + return sum; +} + +Poly2XY& Poly2XY::operator+=(const Poly2XY& p) +{ + term2XY *ptr,*pos=NULL; + ptr=p.start; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->nx,ptr->ny,pos); + ptr=ptr->next; + } + return *this; +} + +Poly2XY& Poly2XY::operator-=(const Poly2XY& p) +{ + term2XY *ptr,*pos=NULL; + ptr=p.start; + while (ptr!=NULL) + { + pos=addterm(-(ptr->an),ptr->nx,ptr->ny,pos); + ptr=ptr->next; + } + return *this; +} + +Poly2XY& Poly2XY::operator*=(const GF2m& x) +{ + term2XY *ptr=start; + while (ptr!=NULL) + { + ptr->an*=x; + ptr=ptr->next; + } + return *this; +} + +BOOL operator==(const Poly2XY& a,const Poly2XY& b) +{ + Poly2XY diff=a-b; + if (iszero(diff)) return TRUE; + return FALSE; +} + +Poly2XY operator*(const Poly2XY &p,const GF2m& z) +{ + Poly2XY r=p; + r*=z; + return r; +} + +BOOL isone(const Poly2XY& p) +{ + if (degreeX(p)==0 && degreeY(p)==0 && p.coeff(0,0)==1) return TRUE; + else return FALSE; +} + +/* + * This function is only meant to be called from compose. It puts in a value + * for y, and then merges it with the x value + */ +Poly2XY compoY(const Poly2XY& q, const Poly2XY& p) +{ + Poly2XY poly; + Poly2XY temp(p); + Variable x,y; + term2XY *qptr = q.start; + term2XY *pos=NULL; + term2XY *pptr = p.start; + int qdegree = 0; + poly.start = NULL; + + while (qptr!=NULL) { + qdegree = qptr->ny; + // Multiply out y term + if(qdegree > 0) { + temp = p; + for(int i = 1; i < qdegree; i++) + temp = temp * p; + + // Multiply by x term if it exists + if(qptr->nx > 0) + temp = temp * pow2X(x,qptr->nx); + + poly += temp; + } else { + // Multiply by x term if it exists + if(qptr->nx > 0) + poly = poly + pow2X(x,qptr->nx); + else + poly = poly + qptr->an; + } + + qptr = qptr->next; + pptr = p.start; + } + + return poly; +} + +Poly2XY compose(const Poly2XY& q,const Poly2XY& p,const Poly2XY& p2) +{ // compose polynomials + // assume P(x) = P3x^3 + P2x^2 + P1x^1 +P0 + // Calculate P(Q(x)) = P3.(Q(x))^3 + P2.(Q(x))^2 .... + Poly2XY poly; + Poly2XY temp(p); + Variable x,y; + term2XY *qptr = q.start; + term2XY *pos=NULL; + term2XY *pptr = p.start; + int qdegree = 0; + poly.start = NULL; + + while (qptr!=NULL) { + qdegree = qptr->nx; + // Multiply out x term + if(qdegree > 0) { + temp = p; + for(int i = 1; i < qdegree; i++) + temp = temp * p; + + // Multiply by y term if it exists + if(qptr->ny > 0) + temp = temp * pow2Y(y,qptr->ny); + + poly += temp; + } else { + // Multiply by y term if it exists + if(qptr->ny > 0) + poly = poly + pow2Y(y,qptr->ny); + else + poly = poly + qptr->an; + } + + qptr = qptr->next; + pptr = p.start; + } + + // return poly; + + Poly2XY result = compoY(poly, p2); + return result; +} + +Poly2XY operator*(const Poly2XY& a,const Poly2XY& b) +{ + int i,d,dega,degb,deg; + GF2m t; + Poly2XY prod; + term2XY *iptr,*pos; + term2XY *ptr=b.start; + if (&a==&b) + { // squaring - only diagonal terms count! + pos=NULL; + while (ptr!=NULL) + { // diagonal terms + pos=prod.addterm(ptr->an*ptr->an,ptr->nx+ptr->nx,ptr->ny+ptr->ny,pos); + ptr=ptr->next; + } + return prod; + } + +/* + dega=degree(a); + deg=dega; + degb=degree(b); + if (degb=KARAT_BREAK_EVEN) + { // use fast method + int len,m,inc; + + big *A,*B,*C,*T; + deg=dega; + if (degan]=getbig(ptr->an); + ptr=ptr->next; + } + ptr=b.start; + while (ptr!=NULL) + { + B[ptr->n]=getbig(ptr->an); + ptr=ptr->next; + } + + karmul2_poly(deg+1,T,A,B,C); + + pos=NULL; + for (d=dega+degb;d>=0;d--) + { + t=(Big)C[d]; + if (t.iszero()) continue; + pos=prod.addterm(t,d,pos); + } + + memkill(memc,len); + memkill(memt,len); + + mr_free(T); + mr_free(C); + mr_free(B); + mr_free(A); + return prod; + } +*/ + + while (ptr!=NULL) + { + pos=NULL; + iptr=a.start; + while (iptr!=NULL) + { + pos=prod.addterm(ptr->an*iptr->an,ptr->nx+iptr->nx,ptr->ny+iptr->ny,pos); + iptr=iptr->next; + } + ptr=ptr->next; + } + + return prod; +} diff --git a/miracl/source/curve/poly2xy.h b/miracl/source/curve/poly2xy.h new file mode 100644 index 0000000..2928840 --- /dev/null +++ b/miracl/source/curve/poly2xy.h @@ -0,0 +1,85 @@ +/* + * C++ class to implement a bivariate polynomial type and to allow + * arithmetic on polynomials whose coefficients are from + * the finite field of characteristic 2 + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.6 + */ + +#ifndef POLY2XY_H +#define POLY2XY_H + +#include "gf2m.h" +#include "poly2.h" + +class term2XY +{ +public: + GF2m an; + int nx; + int ny; + term2XY *next; +}; + +class Poly2XY +{ +public: + term2XY *start; + Poly2XY() {start=NULL;} + Poly2XY(const Poly2XY&); + Poly2XY(const Poly2&); + Poly2XY(const GF2m&,int,int); + Poly2XY(int); + + void clear(); + term2XY *addterm(const GF2m&,int,int,term2XY *pos=NULL); + GF2m F(const GF2m&,const GF2m&); + Poly2 F(const GF2m&); + GF2m coeff(int,int) const; + Poly2 convert_x() const; + Poly2 convert_x2() const; + Poly2 convert_x3() const; + Poly2XY& operator=(const Poly2XY&); + Poly2XY& operator=(int); + Poly2XY& operator+=(const Poly2XY&); + Poly2XY& operator-=(const Poly2XY&); + Poly2XY& operator%=(const Poly2XY&); + Poly2XY& operator*=(const GF2m&); + + friend Poly2XY diff_dx(const Poly2XY&); + friend Poly2XY diff_dy(const Poly2XY&); + friend BOOL iszero(const Poly2XY&); + friend BOOL isone(const Poly2XY&); + + friend Poly2XY operator*(const Poly2XY&,const Poly2XY&); + friend Poly2XY operator%(const Poly2XY&,const Poly2XY&); + friend Poly2XY operator/(const Poly2XY&,const Poly2XY&); + friend Poly2XY operator+(const Poly2XY&,const Poly2XY&); + friend Poly2XY operator+(const Poly2XY&,const GF2m&); + friend Poly2XY operator-(const Poly2XY&,const Poly2XY&); + friend Poly2XY operator*(const Poly2XY&,const GF2m&); + + // friend Poly2XY operator*(const GF2m&,Variable); + friend Poly2XY operator*(Variable, Variable); + friend Poly2XY pow2X(Variable,int); + friend Poly2XY pow2Y(Variable,int); + friend Poly2XY pow(const Poly2XY&,int); + friend BOOL operator==(const Poly2XY&,const Poly2XY&); + friend int degreeX(const Poly2XY&); + friend int degreeY(const Poly2XY&); + friend Poly2XY compose(const Poly2XY&,const Poly2XY&, const Poly2XY&); + + friend ostream& operator<<(ostream&,const Poly2XY&); + ~Poly2XY(); +}; + +extern Poly2XY operator*(Variable, Variable); +extern Poly2XY pow2X(Variable,int); +extern Poly2XY pow2Y(Variable,int); + +#endif + diff --git a/miracl/source/curve/polymod.cpp b/miracl/source/curve/polymod.cpp new file mode 100644 index 0000000..08ceec5 --- /dev/null +++ b/miracl/source/curve/polymod.cpp @@ -0,0 +1,374 @@ +/* + * C++ class to implement a polynomial type and to allow + * arithmetic on polynomials whose elements are from + * the finite field mod p. + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * This type is automatically reduced + * wrt a polynomial Modulus. + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.6 + */ + +#include "polymod.h" + +Poly Modulus; + +BOOL iszero(const PolyMod& m) {return iszero(m.p);} +BOOL isone(const PolyMod& m) {return isone(m.p);} +int degree(const PolyMod& m) {return degree(m.p);} + +BOOL operator==(const PolyMod& a,const PolyMod& b) +{ + PolyMod diff=a-b; + if (iszero(diff)) return TRUE; + return FALSE; +} + +BOOL operator!=(const PolyMod& a,const PolyMod& b) +{ + PolyMod diff=a-b; + if (iszero(diff)) return FALSE; + return TRUE; +} + + +ZZn PolyMod::coeff(int i) const {return p.coeff(i);} + +PolyMod& PolyMod::operator*=(const PolyMod &b) +{ + int i,m,deg,dega,degb,degm=degree(Modulus); + big *G,*B,*R; + BOOL squaring; + term *ptr=p.start; + term *newone,*iptr; + + squaring=FALSE; + if (this==&b) squaring=TRUE; + + dega=degree(*this); + deg=dega; + if (!squaring) + { + degb=degree(b); + if (degbn!=m) + { + newone=new term; + newone->next=ptr; + newone->an=(ZZn)0; + newone->n=m; + ptr=newone; + if (iptr==NULL) p.start=ptr=newone; + else iptr->next=ptr; + } + R[m]=getbig(ptr->an); + m--; + iptr=ptr; + ptr=ptr->next; + } while (m>=0); + + deg=dega+degb; + + if (!squaring) B=(big *)mr_alloc(degb+1,sizeof(big)); + G=(big *)mr_alloc(deg+1,sizeof(big)); + char *memg=(char *)memalloc(deg+1); + for (i=0;i<=deg;i++) G[i]=mirvar_mem(memg,i); + + if (!squaring) + { + ptr=b.p.start; + while (ptr!=NULL) + { + B[ptr->n]=getbig(ptr->an); + ptr=ptr->next; + } + mr_poly_mul(dega,R,degb,B,G); + } + else mr_poly_sqr(dega,R,G); + + if (!mr_poly_rem(deg,G,R)) + { // reset the modulus - things have changed + setmod(Modulus); + mr_poly_rem(deg,G,R); + } + +// now delete any 0 terms + + ptr=p.start; + iptr=NULL; + while (ptr!=NULL) + { + if (ptr->an.iszero()) + { + if (ptr==p.start) + p.start=ptr->next; + else + iptr->next=ptr->next; + newone=ptr; + ptr=ptr->next; + delete newone; + continue; + } + iptr=ptr; + ptr=ptr->next; + } + + mr_free(R); + memkill(memg,deg+1); + mr_free(G); + if (!squaring) mr_free(B); + + return *this; +} + +PolyMod operator*(const PolyMod &a,const PolyMod& b) +{ + PolyMod prod=a; + prod*=b; + return prod; +} + +void reduce(const Poly& p,PolyMod& rem) +{ + int i,d; + ZZn t; + big *G,*R; + term *ptr,*pos=NULL; + int n=degree(p); + int degm=degree(Modulus); + if (n-degm < FFT_BREAK_EVEN) + { + rem=(PolyMod)p; + return; + } + G=(big *)mr_alloc(n+1,sizeof(big)); + char *memg=(char *)memalloc(n+1); + for (i=0;i<=n;i++) G[i]=mirvar_mem(memg,i); + R=(big *)mr_alloc(degm,sizeof(big)); + char *memr=(char *)memalloc(degm); + for (i=0;ian),G[ptr->n]); + ptr=ptr->next; + } + if (!mr_poly_rem(n,G,R)) + { // reset the Modulus - things have changed + setmod(Modulus); + mr_poly_rem(n,G,R); + } + + rem.clear(); + + for (d=degm-1;d>=0;d--) + { + t=R[d]; + if (t.iszero()) continue; + pos=rem.addterm(t,d,pos); + } + memkill(memr,degm); + mr_free(R); + memkill(memg,n+1); + mr_free(G); + +} + +void setmod(const Poly& p) +{ + Modulus=p; + setpolymod(p); +} + +PolyMod operator-(const PolyMod& a,const PolyMod& b) + {return (a.p-b.p)%Modulus;} +PolyMod operator+(const PolyMod& a,const PolyMod& b) + {return (a.p+b.p)%Modulus;} +PolyMod operator*(const PolyMod& a,const ZZn& z) + {return (z*a.p);} +PolyMod operator*(const ZZn& z,const PolyMod& m) + {return (z*m.p);} + +PolyMod operator+(const PolyMod& a,const ZZn& z) +{ + PolyMod p=a; + p.addterm(z,0); + return p; +} + +PolyMod operator-(const PolyMod& a,const ZZn& z) +{ + PolyMod p=a; + p.addterm((-z),0); + return p; +} + +PolyMod operator/(const PolyMod& a,const ZZn& z) + {return (a.p/z);} + +Poly gcd(const PolyMod& m) + {return gcd(m.p,Modulus);} + + +// +// Brent & Kung's First Algorithm +// See "Fast Algorithms for Manipulating Formal Power Series +// J.ACM, Vol. 25 No. 4 October 1978 pp 581-595 +// + +PolyMod compose(const PolyMod& q,const PolyMod& p) +{ // compose polynomials + // assume P(x) = P3x^3 + P2x^2 + P1x^1 +P0 + // Calculate P(Q(x)) = P3.(Q(x))^3 + P2.(Q(x))^2 .... + PolyMod C,Q,T; + big t; + term *xptr,*yptr; + int i,j,ik,L,n=degree(Modulus); + int k=isqrt(n+1,1); + if (k*kn<=ik+k-1) break; + xptr=xptr->next; + } + for (j=k-1;j>=0;j--) + { + x[j]=t; + if (xptr!=NULL) + { + if (ik+j==xptr->n) + { + x[j]=getbig(xptr->an); + xptr=xptr->next; + } + } + // x[j]=q.coeff(i*k+j) + y[j]=t; + yptr=P[j].p.start; + while (yptr!=NULL) + { + if (yptr->n<=L) + { + if (yptr->n==L) y[j]=getbig(yptr->an); + break; + } + yptr=yptr->next; + } + } // y[j]=P[j].coeff(L) + +// Asymptotically slow, but very fast in practise ... + + nres_dotprod(k,x,y,t); + Q.addterm((ZZn)t,L); + } + C+=(Q*T); + if (i=FFT_BREAK_EVEN ) + { + u2=(u*u); + + table[0]=u; + for (i=1;i<16;i++) + table[i]=u2*table[i-1]; + nb=bits(k); + if (nb>1) for (i=nb-2;i>=0;) + { + n=window(k,i,&nbw,&nzs,5); + for (j=0;j0) u*=table[n/2]; + i-=nbw; + if (nzs) + { + for (j=0;j0) + { + u*=u; + if (e>=w) + { + e-=w; + u*=f; + } + w/=2; + } + } + return u; +} + +ostream& operator<<(ostream& s,const PolyMod& m) + { s << m.p; return s;} + diff --git a/miracl/source/curve/polymod.h b/miracl/source/curve/polymod.h new file mode 100644 index 0000000..554448f --- /dev/null +++ b/miracl/source/curve/polymod.h @@ -0,0 +1,77 @@ +/* + * C++ class to implement a polynomial type and to allow + * arithmetic on polynomials whose elements are from + * the finite field mod p. + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * This type is automatically reduced + * wrt a polynomial Modulus. + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.6 + */ + +#ifndef POLYMOD_H +#define POLYMOD_H + +#include "poly.h" + +extern Poly Modulus; + +class PolyMod +{ +public: + Poly p; + + PolyMod() { } + PolyMod(const Poly& m) {p=m%Modulus; } + PolyMod(const PolyMod& m) {p=m.p; } + void clear() {p.clear();} + term* addterm(const ZZn& z,int i,term *pos=NULL) {return p.addterm(z,i,pos);} + void multerm(const ZZn& z,int i) {p.multerm(z,i);} + ZZn F(const ZZn& z) {return p.F(z); } + ZZn coeff(int i) const; + PolyMod& operator=(int m) {p=m; return *this;} + PolyMod& operator=(const PolyMod& m) {p=m.p; return *this;} + PolyMod& operator=(const Poly& m) {reduce(m,*this); return *this;} + PolyMod& operator+=(const PolyMod& m) {p=(p+m.p)%Modulus;return *this;} + PolyMod& operator-=(const PolyMod& m) {p=(p-m.p)%Modulus;return *this;} + PolyMod& operator+=(const ZZn& m) {addterm(m,0); return *this;} + PolyMod& operator-=(const ZZn& m) {addterm((-m),0); return *this;} + PolyMod& operator*=(const ZZn& z) {p*=z;return *this;} + PolyMod& operator/=(const ZZn& z) {p/=z;return *this;} + PolyMod& operator*=(const PolyMod&); + + friend void setmod(const Poly&); + friend void reduce(const Poly&,PolyMod&); + + friend BOOL iszero(const PolyMod&); + friend BOOL isone(const PolyMod&); + friend int degree(const PolyMod&); + + friend PolyMod operator*(const PolyMod&,const PolyMod&); + friend PolyMod operator-(const PolyMod&,const PolyMod&); + friend PolyMod operator+(const PolyMod&,const PolyMod&); + friend PolyMod operator-(const PolyMod&,const ZZn&); + friend PolyMod operator+(const PolyMod&,const ZZn&); + + friend BOOL operator==(const PolyMod&,const PolyMod&); + friend BOOL operator!=(const PolyMod&,const PolyMod&); + + friend PolyMod operator*(const PolyMod&,const ZZn&); + friend PolyMod operator*(const ZZn&,const PolyMod&); + friend PolyMod compose(const PolyMod&,const PolyMod&); + + friend PolyMod operator/(const PolyMod&,const ZZn&); + friend Poly gcd(const PolyMod&); + friend PolyMod pow(const PolyMod&,const Big&); + friend ostream& operator<<(ostream& ,const PolyMod&); + ~PolyMod() {} +}; + +extern void setmod(const Poly&); + +#endif + diff --git a/miracl/source/curve/polyxy.cpp b/miracl/source/curve/polyxy.cpp new file mode 100644 index 0000000..548bc71 --- /dev/null +++ b/miracl/source/curve/polyxy.cpp @@ -0,0 +1,628 @@ +/* + * C++ class to implement a bivariate polynomial type and to allow + * arithmetic on such polynomials whose coefficients are from + * the finite field mod p + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.6 + */ + +#include "polyxy.h" + +PolyXY::PolyXY(const ZZn& c, int p, int y) +{ + start=NULL; + addterm(c,p,y); +} + +PolyXY::PolyXY(int p) +{ + start=NULL; + addterm((ZZn)p,0,0); +} + +PolyXY::PolyXY(const PolyXY& p) +{ + termXY *ptr=p.start; + termXY *pos=NULL; + start=NULL; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->nx,ptr->ny,pos); + ptr=ptr->next; + } +} + +PolyXY::PolyXY(const Poly& p) +{ + term *ptr=p.start; + termXY *pos=NULL; + start=NULL; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->n,0,pos); + ptr=ptr->next; + } +} + +PolyXY::~PolyXY() +{ + termXY *nx; + while (start!=NULL) + { + nx=start->next; + delete start; + start=nx; + } +} + +ZZn PolyXY::coeff(int powx,int powy) const +{ + ZZn c=0; + termXY *ptr=start; + while (ptr!=NULL) + { + if (ptr->nx==powx && ptr->ny==powy) + { + c=ptr->an; + return c; + } + ptr=ptr->next; + } + return c; +} + +PolyXY diff_dx(const PolyXY& f) +{ + PolyXY r; + termXY *pos=NULL; + termXY *ptr=f.start; + while (ptr!=NULL) + { + pos=r.addterm(ptr->an*ptr->nx,ptr->nx-1,ptr->ny,pos); + ptr=ptr->next; + } + return r; +} + +PolyXY diff_dy(const PolyXY& f) +{ + PolyXY r; + termXY *pos=NULL; + termXY *ptr=f.start; + while (ptr!=NULL) + { + pos=r.addterm(ptr->an*ptr->ny,ptr->nx,ptr->ny-1,pos); + ptr=ptr->next; + } + return r; +} + +Poly PolyXY::F(const ZZn& y) +{ + Poly r; + term *pos=NULL; + int i,maxy=0; + ZZn f; + termXY *ptr=start; + + while (ptr!=NULL) + { + if (ptr->ny>maxy) maxy=ptr->ny; + ptr=ptr->next; + } + + // max y is max power of y present + + ZZn *pw=new ZZn[maxy+1]; // powers of y + + pw[0]=(ZZn)1; + for (i=1;i<=maxy;i++) + pw[i]=y*pw[i-1]; + + ptr=start; + while (ptr!=NULL) + { + pos=r.addterm(ptr->an*pw[ptr->ny],ptr->nx,pos); + ptr=ptr->next; + } + + delete [] pw; + + return r; +} + +ZZn PolyXY::F(const ZZn& x,const ZZn& y) +{ + Poly r=F(y); + return r.F(x); +} + +void PolyXY::clear() +{ + termXY *ptr; + while (start!=NULL) + { + ptr=start->next; + delete start; + start=ptr; + } + +} + +PolyXY& PolyXY::operator=(const PolyXY& p) +{ + termXY *ptr,*pos=NULL; + clear(); + ptr=p.start; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->nx,ptr->ny,pos); + ptr=ptr->next; + } + return *this; + +} + +termXY* PolyXY::addterm(const ZZn& a,int powx,int powy,termXY *pos) +{ + termXY* newone; + termXY* ptr; + termXY *t,*iptr; + ptr=start; + iptr=NULL; + if (a.iszero()) return pos; + + // quick scan through to detect if term exists already + // and to find insertion point + if (pos!=NULL) ptr=pos; + while (ptr!=NULL) + { + if (ptr->nx==powx && ptr->ny==powy) + { + ptr->an+=a; + if (ptr->an.iszero()) + { // delete term + if (ptr==start) + { // delete first one + start=ptr->next; + delete ptr; + return start; + } + iptr=ptr; + ptr=start; + while (ptr->next!=iptr)ptr=ptr->next; + ptr->next=iptr->next; + delete iptr; + return ptr; + } + return ptr; + } + if (ptr->nx>powx) iptr=ptr; + if (ptr->nx==powx && ptr->ny>powy) iptr=ptr; + ptr=ptr->next; + } + newone=new termXY; + newone->next=NULL; + newone->an=a; + newone->nx=powx; + newone->ny=powy; + + pos=newone; + if (start==NULL) + { + start=newone; + return pos; + } + + // insert at the start + + if (iptr==NULL) + { + t=start; + start=newone; + newone->next=t; + return pos; + } + + // insert new term + + t=iptr->next; + iptr->next=newone; + newone->next=t; + return pos; +} + +ostream& operator<<(ostream& s,const PolyXY& p) +{ + BOOL first=TRUE; + ZZn a; + termXY *ptr=p.start; + if (ptr==NULL) + { + s << "0"; + return s; + } + while (ptr!=NULL) + { + a=ptr->an; + if ((Big)anx==0 && ptr->ny==0) + s << a; + else + { + if (a!=(ZZn)1) s << a << "*"; + if (ptr->nx!=0) + { + s << "x"; + if (ptr->nx!=1) s << "^" << ptr->nx; + } + if (ptr->ny!=0) + { + if (ptr->nx!=0) s << "."; + s << "y"; + if (ptr->ny!=1) s << "^" << ptr->ny; + } + } + first=FALSE; + ptr=ptr->next; + } + return s; +} + +PolyXY& PolyXY::operator=(int p) +{ + clear(); + addterm((ZZn)p, 0, 0); + return *this; +} + +/* +PolyXY operator*(Variable x,Variable y) +{ + PolyXY t((ZZn)1,1,1); + return t; +} +*/ + +PolyXY powX(Variable x,int n) +{ + PolyXY r((ZZn)1,n,0); + return r; +} + +PolyXY powY(Variable y,int n) +{ + PolyXY r((ZZn)1,0,n); + return r; +} + + +PolyXY operator%(const PolyXY& u,const PolyXY& v) +{ + PolyXY r=u; + r%=v; + return r; +} + +PolyXY& PolyXY::operator%=(const PolyXY& v) +{ + ZZn m,pq; + int power, power2; + termXY *rptr=start; + termXY *vptr=v.start; + termXY *ptr,*pos; + if (degreeX(*this)an); + + while (rptr!=NULL && rptr->nx>=vptr->nx && rptr->ny>=vptr->ny) + { + pq=rptr->an*m; + power=rptr->nx-vptr->nx; + power2=rptr->ny-vptr->ny; + pos=NULL; + ptr=v.start; + while (ptr!=NULL) + { + pos=addterm(ptr->an*pq,ptr->nx+power,ptr->ny+power2,pos); + ptr=ptr->next; + } + rptr=start; + } + + return *this; +} + +int degreeX(const PolyXY& p) +{ + if (p.start==NULL) return 0; + else return p.start->nx; +} + +int degreeY(const PolyXY& p) +{ + termXY *ptr=p.start; + int maxdeg = 0; + + if (p.start==NULL) return 0; + + while (ptr!=NULL) + { + if(ptr->ny > maxdeg) + maxdeg = ptr->ny; + ptr = ptr->next; + } + return maxdeg; +} + +BOOL iszero(const PolyXY& p) +{ + if (degreeX(p)==0 && degreeY(p)==0 && (p.coeff(0,0)==0)) return TRUE; + else return FALSE; +} + +PolyXY operator+(const PolyXY& a,const PolyXY& b) +{ + PolyXY sum; + sum=a; + sum+=b; + return sum; +} + +PolyXY operator+(const PolyXY& a,const ZZn& b) +{ + PolyXY sum=a; + sum.addterm(b,0,0); + return sum; +} + +PolyXY operator-(const PolyXY& a,const PolyXY& b) +{ + PolyXY sum; + sum=a; + sum-=b; + return sum; +} + +PolyXY& PolyXY::operator+=(const PolyXY& p) +{ + termXY *ptr,*pos=NULL; + ptr=p.start; + while (ptr!=NULL) + { + pos=addterm(ptr->an,ptr->nx,ptr->ny,pos); + ptr=ptr->next; + } + return *this; +} + +PolyXY& PolyXY::operator-=(const PolyXY& p) +{ + termXY *ptr,*pos=NULL; + ptr=p.start; + while (ptr!=NULL) + { + pos=addterm(-(ptr->an),ptr->nx,ptr->ny,pos); + ptr=ptr->next; + } + return *this; +} + +PolyXY& PolyXY::operator*=(const ZZn& x) +{ + termXY *ptr=start; + while (ptr!=NULL) + { + ptr->an*=x; + ptr=ptr->next; + } + return *this; +} + +BOOL operator==(const PolyXY& a,const PolyXY& b) +{ + PolyXY diff=a-b; + if (iszero(diff)) return TRUE; + return FALSE; +} + +PolyXY operator*(const PolyXY &p,const ZZn& z) +{ + PolyXY r=p; + r*=z; + return r; +} + +BOOL isone(const PolyXY& p) +{ + if (degreeX(p)==0 && degreeY(p)==0 && p.coeff(0,0)==1) return TRUE; + else return FALSE; +} + +/* + * This function is only meant to be called from compose. It puts in a value + * for y, and then merges it with the x value + */ +PolyXY compoY(const PolyXY& q, const PolyXY& p) +{ + PolyXY poly; + PolyXY temp(p); + Variable x,y; + termXY *qptr = q.start; + termXY *pos=NULL; + termXY *pptr = p.start; + int qdegree = 0; + poly.start = NULL; + + while (qptr!=NULL) { + qdegree = qptr->ny; + // Multiply out y term + if(qdegree > 0) { + temp = p; + for(int i = 1; i < qdegree; i++) + temp = temp * p;// Multiply by x term if it exists + if(qptr->nx > 0) + temp = temp * powX(x,qptr->nx); + + temp = temp * qptr->an; + poly += temp; + } else { + // Multiply by x term if it exists + if(qptr->nx > 0) { + // poly = poly + powX(x,qptr->nx); + temp = powX(x,qptr->nx); + temp = temp * qptr->an; + poly = poly + temp; + } else + poly = poly + qptr->an; + } + + qptr = qptr->next; + pptr = p.start; + } + + return poly; +} + + +PolyXY compose(const PolyXY& q,const PolyXY& p,const PolyXY& p2) +{ // compose polynomials + // assume P(x) = P3x^3 + P2x^2 + P1x^1 +P0 + // Calculate P(Q(x)) = P3.(Q(x))^3 + P2.(Q(x))^2 .... + PolyXY poly; + PolyXY temp(p); + Variable x,y; + termXY *qptr = q.start; + termXY *pos=NULL; + termXY *pptr = p.start; + int qdegree = 0; + poly.start = NULL; + + while (qptr!=NULL) { + qdegree = qptr->nx; + // Multiply out x term + if(qdegree > 0) { + temp = p; + for(int i = 1; i < qdegree; i++) + temp = temp * p; + + // Multiply by y term if it exists + if(qptr->ny > 0)temp = temp * powY(y,qptr->ny); + + temp = temp * qptr->an; + poly += temp; + } else { + // Multiply by y term if it exists + if(qptr->ny > 0) { + temp = powY(y,qptr->ny); + temp = temp * qptr->an; + poly = poly + temp; + // poly = poly + (qptr->an * powY(y,qptr->ny)); + } + else + poly = poly + qptr->an; + } + + qptr = qptr->next; + pptr = p.start; + } + + // return poly; + + PolyXY result = compoY(poly, p2); + return result; +} + + +PolyXY operator*(const PolyXY& a,const PolyXY& b) +{ + int i,d,dega,degb,deg; + ZZn t; + PolyXY prod; + termXY *iptr,*pos; + termXY *ptr=b.start; + if (&a==&b) + { // squaring - only diagonal terms count! + pos=NULL; + while (ptr!=NULL) + { // diagonal terms + pos=prod.addterm(ptr->an*ptr->an,ptr->nx+ptr->nx,ptr->ny+ptr->ny,pos + ); + ptr=ptr->next; + } + return prod; + } + + while (ptr!=NULL) { + pos=NULL; + iptr=a.start; + while (iptr!=NULL) + { + pos=prod.addterm(ptr->an*iptr->an,ptr->nx+iptr->nx,ptr->ny+iptr->ny, + pos); + iptr=iptr->next; + } + ptr=ptr->next; + } + + return prod; +} + +// Convert a polyxy object to a poly object by just taking the +// "x" value +Poly PolyXY::convert_x() const +{ + termXY *ptr=start; + term *pos=NULL; + Poly newpoly; + while (ptr!=NULL) + { + pos = newpoly.addterm(ptr->an,ptr->nx,pos); + ptr = ptr->next; + } + return newpoly; +} + +// Convert a polyxy object to a poly object by just taking the +// "x" value when the corresponding "y" value is 0 +Poly PolyXY::convert_x2() const +{ + termXY *ptr=start; + term *pos=NULL; + Poly newpoly; + while (ptr!=NULL) + { + if(ptr->ny == 0) + pos = newpoly.addterm(ptr->an,ptr->nx,pos); + ptr = ptr->next; + } + return newpoly; +} + +// Convert a polyxy object to a poly object by just taking the +// "x" value when the corresponding "y" value is greater than 0 +Poly PolyXY::convert_x3() const +{ + termXY *ptr=start; + term *pos=NULL; + Poly newpoly; + while (ptr!=NULL) + { + if(ptr->ny > 0) + pos = newpoly.addterm(ptr->an,ptr->nx,pos); + ptr = ptr->next; + } + return newpoly; +} + diff --git a/miracl/source/curve/polyxy.h b/miracl/source/curve/polyxy.h new file mode 100644 index 0000000..cd45bb9 --- /dev/null +++ b/miracl/source/curve/polyxy.h @@ -0,0 +1,83 @@ +/* + * C++ class to implement a bivariate polynomial type and to allow + * arithmetic on polynomials whose coefficients are from + * the finite field mod p + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.6 + */ + +#ifndef POLYXY_H +#define POLYXY_H + +#include "zzn.h" +#include "poly.h" + +class termXY +{ +public: + ZZn an; + int nx; + int ny; + termXY *next; +}; + +class PolyXY +{ +public: + termXY *start; + PolyXY() {start=NULL;} + PolyXY(const PolyXY&); + PolyXY(const Poly&); + PolyXY(const ZZn&,int,int); + PolyXY(int); + + void clear(); + termXY *addterm(const ZZn&,int,int,termXY *pos=NULL); + ZZn F(const ZZn&,const ZZn&); + Poly F(const ZZn&); + ZZn coeff(int,int) const; + Poly convert_x() const; + Poly convert_x2() const; + Poly convert_x3() const; + PolyXY& operator=(const PolyXY&); + PolyXY& operator=(int); + PolyXY& operator+=(const PolyXY&); + PolyXY& operator-=(const PolyXY&); + PolyXY& operator%=(const PolyXY&); + PolyXY& operator*=(const ZZn&); + + friend PolyXY diff_dx(const PolyXY&); + friend PolyXY diff_dy(const PolyXY&); + friend BOOL iszero(const PolyXY&); + friend BOOL isone(const PolyXY&); + + friend PolyXY operator*(const PolyXY&,const PolyXY&); + friend PolyXY operator%(const PolyXY&,const PolyXY&); + friend PolyXY operator/(const PolyXY&,const PolyXY&); + friend PolyXY operator+(const PolyXY&,const PolyXY&); + friend PolyXY operator+(const PolyXY&,const ZZn&); + friend PolyXY operator-(const PolyXY&,const PolyXY&); + friend PolyXY operator*(const PolyXY&,const ZZn&); + + // friend PolyXY operator*(Variable, Variable); + friend PolyXY powX(Variable,int); + friend PolyXY powY(Variable,int); + friend PolyXY pow(const PolyXY&,int); + friend BOOL operator==(const PolyXY&,const PolyXY&); + friend int degreeX(const PolyXY&); + friend int degreeY(const PolyXY&); + friend PolyXY compose(const PolyXY&,const PolyXY&, const PolyXY&); + + friend ostream& operator<<(ostream&,const PolyXY&); + ~PolyXY(); +}; + +extern PolyXY powX(Variable,int); +extern PolyXY powY(Variable,int); + +#endif + diff --git a/miracl/source/curve/process.cpp b/miracl/source/curve/process.cpp new file mode 100644 index 0000000..840c43e --- /dev/null +++ b/miracl/source/curve/process.cpp @@ -0,0 +1,363 @@ +// +// Program to pre-process the .raw file of modular polynomials +// to produce a .pol file, with coefficients reduced mod p +// +// .pol file format +// ,,<1st coef.>,<1st power of X>,<1st power of Y>,<2nd coeff>.. +// Each polynomial ends with zero powers of X and Y +// +// + +#include +#include +#include +#include +#include "big.h" + +using namespace std; + +Miracl precision=1000; + +// Code to parse formula in command line +// This code isn't mine, but its public domain +// Shamefully I forget the source +// +// NOTE: It may be necessary on some platforms to change the operators * and # +// + +#if defined(unix) +#define TIMES '.' +#define RAISE '^' +#else +#define TIMES '*' +#define RAISE '#' +#endif + +Big tt; +static char *ss; + +void eval_power (Big& oldn,Big& n,char op) +{ + if (op) n=pow(oldn,toint(n)); // power(oldn,size(n),n,n); +} + +void eval_product (Big& oldn,Big& n,char op) +{ + switch (op) + { + case TIMES: + n*=oldn; + break; + case '/': + n=oldn/n; + break; + case '%': + n=oldn%n; + } +} + +void eval_sum (Big& oldn,Big& n,char op) +{ + switch (op) + { + case '+': + n+=oldn; + break; + case '-': + n=oldn-n; + } +} + +void eval (void) +{ + Big oldn[3]; + Big n; + int i; + char oldop[3]; + char op; + char minus; + for (i=0;i<3;i++) + { + oldop[i]=0; + } +LOOP: + while (*ss==' ') + ss++; + if (*ss=='-') /* Unary minus */ + { + ss++; + minus=1; + } + else + minus=0; + while (*ss==' ') + ss++; + if (*ss=='(' || *ss=='[' || *ss=='{') /* Number is subexpression */ + { + ss++; + eval (); + n=tt; + } + else /* Number is decimal value */ + { + for (i=0;ss[i]>='0' && ss[i]<='9';i++) + ; + if (!i) /* No digits found */ + { + cout << "Error - invalid number" << endl; + exit (20); + } + op=ss[i]; + ss[i]=0; + n=atoi(ss); + ss+=i; + *ss=op; + } + if (minus) n=-n; + do + op=*ss++; + while (op==' '); + if (op==0 || op==')' || op==']' || op=='}') + { + eval_power (oldn[2],n,oldop[2]); + eval_product (oldn[1],n,oldop[1]); + eval_sum (oldn[0],n,oldop[0]); + tt=n; + return; + } + else + { + if (op==RAISE) + { + eval_power (oldn[2],n,oldop[2]); + oldn[2]=n; + oldop[2]=RAISE; + } + else + { + if (op==TIMES || op=='/' || op=='%') + { + eval_power (oldn[2],n,oldop[2]); + oldop[2]=0; + eval_product (oldn[1],n,oldop[1]); + oldn[1]=n; + oldop[1]=op; + } + else + { + if (op=='+' || op=='-') + { + eval_power (oldn[2],n,oldop[2]); + oldop[2]=0; + eval_product (oldn[1],n,oldop[1]); + oldop[1]=0; + eval_sum (oldn[0],n,oldop[0]); + oldn[0]=n; + oldop[0]=op; + } + else /* Error - invalid operator */ + { + cout << "Error - invalid operator" << endl; + exit (20); + } + } + } + } + goto LOOP; +} + +int main(int argc, char **argv) +{ + ofstream ofile; + ifstream ifile; + int ip,lp,nx,ny,max; + Big p,c; + BOOL gotP,gotI,gotO,dir; + int Base; + miracl *mip=&precision; + set_io_buffer_size(2048); + argv++; argc--; + if (argc<1) + { + cout << "incorrect usage" << endl; + cout << "Program pre-processes Modular Polynomials with respect" << endl; + cout << "to a given prime modulus" << endl; + cout << "process <-i input> <-o output>" << endl; + cout << "OR" << endl; + cout << "process <-i input> <-o output> " << endl; +#if defined(unix) + cout << "e.g. process -f 2^192-2^64-1 -i mueller.raw -o p192.pol" << endl; +#else + cout << "e.g. process -f 2#192-2#64-1 -i mueller.raw -o p192.pol" << endl; +#endif + cout << "processes the file mueller.raw to p192.pol for the given modulus" << endl; + cout << "To input P in Hex, precede with -h" << endl; + cout << "To search downwards for a prime, use flag -d" << endl; + cout << "Use flag -m to limit polynomials processed to those" << endl; + cout << "associated with primes less than or equal to " << endl; + cout << "\nFreeware from Certivox, Dublin, Ireland" << endl; + cout << "Full C++ source code and MIRACL multiprecision library available" << endl; + cout << "email mscott@indigo.ie" << endl; + return 0; + } + + ip=0; + gprime(1000); + gotP=gotI=gotO=dir=FALSE; + p=0; + max=0; + Base=10; + while (ipIOBASE=Base; + p=argv[ip++]; + mip->IOBASE=10; + gotP=TRUE; + continue; + } + cout << "Error in command line" << endl; + return 0; + } + if (!gotP || !gotI || !gotO) + { + cout << "Error in command line" << endl; + return 0; + } + + if (!prime(p)) + { + int incr=0; + cout << "That number is not prime!" << endl; + if (dir) + { + cout << "Looking for next lower prime" << endl; + p-=1; incr++; + while (!prime(p)) { p-=1; incr++; } + cout << "Prime P = P-" << incr << endl; + } + else + { + cout << "Looking for next higher prime" << endl; + p+=1; incr++; + while (!prime(p)) { p+=1; incr++; } + cout << "Prime P = P+" << incr << endl; + } + cout << "Prime P = " << p << endl; + } + cout << "P mod 24 = " << p%24 << endl; + cout << "P is " << bits(p) << " bits long" << endl; + + cout << "Prime " << flush; + ofile << p << endl; + forever + { + ifile >> lp; + if (ifile.eof()) break; + if (max>0 && lp>max) break; + + cout << "\b\b\b\b"; + cout << setw(4) << lp << flush; + ofile << lp << endl; + forever + { + ifile >> c >> nx >> ny; + + // reduce coefficients mod p + c=c%p; + + ofile << c << endl; + ofile << nx << endl; + ofile << ny << endl; + + if (nx==0 && ny==0) break; + } + } + cout << endl; + return 0; +} + diff --git a/miracl/source/curve/ps_big.cpp b/miracl/source/curve/ps_big.cpp new file mode 100644 index 0000000..297efbf --- /dev/null +++ b/miracl/source/curve/ps_big.cpp @@ -0,0 +1,867 @@ +/* + * C++ class to implement a power series type and to allow + * arithmetic on it + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.7 + */ + +#include "ps_big.h" + +#define FFT + +// +// all calulations are mod x^psN +// Power series is stored {as offset, pwr and a0+a1.x+a2.x^2+a3.x^3....} +// where the power of x is to be multiplied by pwr, and the whole power +// series is to be divided by x^offset +// + +int psN; + +// +// Copy Constructor +// + +Ps_Big::Ps_Big(const Ps_Big& p) +{ + term_ps_big *ptr=p.start; + term_ps_big *pos=NULL; + int pw; + start=NULL; + offset=p.offset; + pwr=p.pwr; + while (ptr!=NULL) + { + pw=ptr->n*p.pwr-p.offset; // conversion needed + if (pw>=psN) break; + pos=addterm(ptr->an,pw,pos); + ptr=ptr->next; + } +} + +// +// decompresses PS by reducing pwr +// + +void Ps_Big::decompress(int m) +{ // m is divisor of current pwr + // e.g pwr is 6 and PS = 1 + x + x^2 + // If m=2 then pwr becomes 3 and PS = 1 +x^2 +x^4.... + term_ps_big *ptr=start; + if (start==NULL || m==1 || pwr==1) return; // it is fully decompressed + while (ptr!=NULL) + { + ptr->n*=m; + ptr=ptr->next; + } + pwr/=m; +} + +// +// Sets new pwr value. Parameter must exactly divide +// all powers in the series +// + +void Ps_Big::compress(int p) +{ + term_ps_big *ptr=start; + if (p==1) return; + while (ptr!=NULL) + { + ptr->n/=p; + ptr=ptr->next; + } + pwr=p; +} + +// +// insert missing terms with 0 coefficients +// + +void Ps_Big::pad() +{ // insert any missing 0 coefficients + int i=0; + term_ps_big *ptr=start; + term_ps_big *pos=NULL; + while (ptr!=NULL) + { + while (in) + { + pos=addterm((Big)0,i*pwr-offset,pos); + i++; + } + i++; + ptr=ptr->next; + } + while (ian); + if (b>m) m=b; + ptr=ptr->next; + } + return m; +} + +// +// set new offset, so first power of x is 0 +// + +void Ps_Big::norm() +{ + int m; + term_ps_big *ptr; + if (start==NULL) return; +// +// remove any leading 0 terms +// + while (start->an.iszero()) + { + ptr=start->next; + delete start; + start=ptr; + if (start==NULL) return; + } + ptr=start; + m=start->n; + if (m!=0) + { + offset-=m*pwr; + while (ptr!=NULL) + { + ptr->n-=m; + ptr=ptr->next; + } + } +} + +// +// Dedekind Eta function (1-x)(1-x^2)(1-x^3).... +// + +Ps_Big eta() +{ // simple repeating pattern + BOOL even; + int one,ce,co,c; + Ps_Big n; + term_ps_big *pos=NULL; + n.addterm(1,0); + n.addterm(-1,1); + n.addterm(-1,2); + ce=2;co=1; + even=TRUE; + c=2; + one=1; + while (can.iszero()) t++; + if (t>1) return FALSE; + ptr=ptr->next; + } + return TRUE; +} + +// +// add a term to a PS +// + +term_ps_big* Ps_Big::addterm(const Big& a,int power,term_ps_big *pos) +{ + term_ps_big* newone; + term_ps_big* ptr; + term_ps_big *t,*iptr; + int dc,pw; + ptr=start; + iptr=NULL; +// +// intelligently determine the most compressed form to use +// for example if coefficient a=1 always, and power = -7 -5 -3 -1 1 3.... +// then set pwr=2, offset=7 and PS = 1 + x + x^2 +// + pw=power+offset; + if (one_term() && pw!=0) + { // when PS has only one term, pwr is undefined + if (pw<0) + pwr=-pw; + else pwr=pw; + } + + dc=igcd(pw,pwr); + + if (dc != pwr) decompress(pwr/dc); + power=pw/pwr; +// quick scan through to detect if term exists already +// and to find insertion point + if (pos!=NULL) ptr=pos; + while (ptr!=NULL) + { + if (ptr->n==power) + { + ptr->an+=a; + + if (ptr->an.iszero()) + { // delete term + if (ptr==start) + { // delete first one + start=ptr->next; + delete ptr; + norm(); + return start; + } + iptr=ptr; + ptr=start; + while (ptr->next!=iptr)ptr=ptr->next; + ptr->next=iptr->next; + delete iptr; + return ptr; + } + return ptr; + } + if (ptr->nnext; + } + newone=new term_ps_big; + newone->next=NULL; + newone->an=a; + newone->n=power; + pos=newone; + if (start==NULL) + { + start=newone; + norm(); + return pos; + } + +// insert at the start + + if (iptr==NULL) + { + t=start; + start=newone; + newone->next=t; + norm(); + return pos; + } + +// insert new term + + t=iptr->next; + iptr->next=newone; + newone->next=t; + return pos; +} + +// +// Destructor +// + +Ps_Big::~Ps_Big() +{ + term_ps_big *nx; + while (start!=NULL) + { + nx=start->next; + delete start; + start=nx; + } +} + +// +// get coefficient of actual power +// + +Big Ps_Big::coeff(int power) const +{ + Big c=0; + term_ps_big *ptr=start; + if ((power+offset)%pwr != 0) return c; // no such term + power=(power+offset)/pwr; + + while (ptr!=NULL) + { + if (ptr->n==power) + { + c=ptr->an; + return c; + } + ptr=ptr->next; + } + return c; +} + +// +// get coefficient of "Internal" power +// + +Big Ps_Big::cf(int power) const +{ + Big c=0; + term_ps_big *ptr=start; + + while (ptr!=NULL) + { + if (ptr->n==power) + { + c=ptr->an; + return c; + } + ptr=ptr->next; + } + return c; +} + +// +// Zeroise PS and reclaim space +// + +void Ps_Big::clear() +{ + term_ps_big *ptr; + while (start!=NULL) + { + ptr=start->next; + delete start; + start=ptr; + } + offset=0; + pwr=1; +} + +// Note: real power = internal power * pwr - offset + +Ps_Big& Ps_Big::operator+=(const Ps_Big& p) +{ + term_ps_big *ptr=p.start; + term_ps_big *pos=NULL; + int pw; + while (ptr!=NULL) + { + pw=ptr->n*p.pwr-p.offset; // convert compressed to real + if (pw>=psN) break; + pos=addterm(ptr->an,pw,pos); + ptr=ptr->next; + } + return *this; +} + +Ps_Big operator-(const Ps_Big& p) +{ + Ps_Big r=p; + + term_ps_big *ptr=r.start; + while (ptr!=NULL) + { + ptr->an=(-ptr->an); + ptr=ptr->next; + } + + return r; +} + +Ps_Big& Ps_Big::operator-=(const Ps_Big& p) +{ + term_ps_big *ptr=p.start; + term_ps_big *pos=NULL; + int pw; + + while (ptr!=NULL) + { + pw=ptr->n*p.pwr-p.offset; + if (pw>=psN) break; + pos=addterm(-(ptr->an),pw,pos); + ptr=ptr->next; + } + return *this; +} + +Ps_Big operator+(const Ps_Big& a,const Ps_Big& b) +{ + Ps_Big sum=a; + sum+=b; + return sum; +} + +Ps_Big operator-(const Ps_Big& a,const Ps_Big& b) +{ + Ps_Big sum=a; + sum-=b; + return sum; +} + +// +// In situ multiplication. Coeeficients in multiplicand +// are directly overwritten. Saves a lot of copying. +// + +Ps_Big& Ps_Big::operator*=(Ps_Big& b) +{ + term_ps_big *ptr,*bptr; + int g,d,deg,ka,kb; + if (IsInt()) + { + if (start!=NULL) *this = start->an*b; + return *this; + } + if (b.IsInt()) + { + if (b.start==NULL) clear(); + else *this *=(b.start->an); + return *this; + } + g=igcd(pwr,b.pwr); + deg=psN/g; + + +#ifdef FFT + if (deg>=FFT_BREAK_EVEN) + { + big *A,*B; + A=(big *)mr_alloc(deg,sizeof(big)); + B=(big *)mr_alloc(deg,sizeof(big)); + ka=pwr/g; + decompress(ka); + pad(); + ptr=start; + while (ptr!=NULL) + { + d=ptr->n; + if (d>=deg) break; + A[d]=(ptr->an).getbig(); + ptr=ptr->next; + } + kb=b.pwr/g; + b.decompress(kb); + bptr=b.start; + while (bptr!=NULL) + { + d=bptr->n; + if (d>=deg) break; + B[d]=(bptr->an).getbig(); + bptr=bptr->next; + } + mr_ps_big_mul(deg,A,B,A); + mr_free(B); mr_free(A); + b.compress(kb); + } + else + { +#endif + *this=*this*b; + return *this; +#ifdef FFT + } +#endif + norm(); + offset+=b.offset; + return *this; +} + +Ps_Big operator*(Ps_Big& a,Ps_Big& b) +{ + Ps_Big prod; + Big t; + term_ps_big *aptr,*bptr,*pos; + int ka,kb,i,pa,pb,d,deg,g; + + if (a.IsInt()) + { + if (a.start==NULL) return prod; + else return (a.start->an*b); + } + + if (b.IsInt()) + { + if (b.start==NULL) return prod; + else return (b.start->an*a); + } + + g=igcd(a.pwr,b.pwr); + + deg=psN/g; + +#ifdef FFT + if (deg>=FFT_BREAK_EVEN) + { // use fast methods + big *A,*B,*C; + A=(big *)mr_alloc(deg,sizeof(big)); + B=(big *)mr_alloc(deg,sizeof(big)); + C=(big *)mr_alloc(deg,sizeof(big)); + char *memc=(char *)memalloc(deg); + for (i=0;in; + if (d >= deg) break; + A[d]=(aptr->an).getbig(); + aptr=aptr->next; + } + kb=b.pwr/g; + b.decompress(kb); + bptr=b.start; + while (bptr!=NULL) + { + d=bptr->n; + if (d >= deg) break; + B[d]=(bptr->an).getbig(); + bptr=bptr->next; + } + mr_ps_big_mul(deg,A,B,C); + pos=NULL; + for (d=0;dn*b.pwr-b.offset; + pos=NULL; + while (aptr!=NULL) + { + pa=aptr->n*a.pwr-a.offset; + if (pb+pa>=psN) break; + pos=prod.addterm(aptr->an*bptr->an,pa+pb,pos); + aptr=aptr->next; + } + bptr=bptr->next; + } +#ifdef FFT + } +#endif + + if (prod.start!=NULL) prod.offset=a.offset+b.offset; + return prod; +} + +Ps_Big operator/(const Big& num,const Ps_Big& b) +{ + Ps_Big quo; + term_ps_big *pos=NULL; + int pw=b.pwr; + Big w,v0=b.cf(0); + + for (int n=0;n=psN) break; + if (n==0) w=num; + else w=0; + for (int k=0;k=psN) break; + w=a.cf(n); + for (int k=0;kan/=x; + ptr=ptr->next; + } + return *this; +} + +Ps_Big& Ps_Big::operator/=(int m) +{ + term_ps_big *ptr=start; + while (ptr!=NULL) + { + ptr->an/=m; + ptr=ptr->next; + } + return *this; +} + +Ps_Big operator/(const Ps_Big& a,const Big& b) +{ + Ps_Big quo; + quo=a; + quo/=b; + return quo; +} + +Ps_Big operator/(const Ps_Big& a,int m) +{ + Ps_Big quo; + quo=a; + quo/=m; + return quo; +} + +Ps_Big& Ps_Big::operator=(int m) +{ + clear(); + if (m!=0) addterm((Big)m,0); + return *this; +} + +Ps_Big& Ps_Big::operator=(const Ps_Big& p) +{ + term_ps_big *ptr,*pos=NULL; + clear(); + int pw; + + pwr=p.pwr; + offset=p.offset; + ptr=p.start; + while (ptr!=NULL) + { + pw=ptr->n*p.pwr-p.offset; + if (pw>=psN) break; + pos=addterm(ptr->an,pw,pos); + ptr=ptr->next; + } + + return *this; +} + +Ps_Big& Ps_Big::operator*=(const Big& x) +{ + term_ps_big *ptr=start; + if (x.iszero()) + { + clear(); + return *this; + } + while (ptr!=NULL) + { + ptr->an*=x; + ptr=ptr->next; + } + return *this; +} + +Ps_Big operator*(const Big& z,const Ps_Big &p) +{ + Ps_Big r=p; + r*=z; + return r; +} + +Ps_Big operator*(const Ps_Big &p,const Big& z) +{ + Ps_Big r=p; + r*=z; + return r; +} + +Ps_Big pow(Ps_Big &a,int k) +{ + Ps_Big res; + int w,e; + + if (k==0) + { + res=1; + return res; + } + res=a; + if (k==1) return res; + + e=k; w=1; + while (w<=e) w<<=1; + w>>=1; + e-=w; w/=2; + while (w>0) + { + res*=res; + if (e>=w) + { + e-=w; + res*=a; + } + w/=2; + } + res.offset*=k; + + return res; +} + + +Ps_Big power(const Ps_Big &a,int e) +{ // return f(a^e), e is +ve + Ps_Big res; + term_ps_big *ptr,*pos=NULL; + + ptr=a.start; + while (ptr!=NULL) + { + if ((ptr->n*a.pwr)*e < psN) + { + pos=res.addterm(ptr->an,ptr->n,pos); + ptr=ptr->next; + } + else break; + } + + res.pwr=e*a.pwr; + res.offset=e*a.offset; + + return res; +} + +ostream& operator<<(ostream& s,const Ps_Big& p) +{ + BOOL first=TRUE; + Big a; + term_ps_big *ptr=p.start; + int pw; + + if (ptr==NULL) + { + s << "0"; + return s; + } + + while (ptr!=NULL) + { + a=ptr->an; + if (a.iszero()) + { + ptr=ptr->next; + continue; + } + if (a < (Big)0) + { + a=(-a); + s << " - "; + } + else if (!first) s << " + "; + + first=FALSE; + pw=ptr->n*p.pwr-p.offset; + if (pw==0) + { + s << a; + ptr=ptr->next; + continue; + } + + if (a==1) s << "x"; + else s << a << "*x"; + + if (pw!=1) s << "^" << pw; + ptr=ptr->next; + } + return s; +} + diff --git a/miracl/source/curve/ps_big.h b/miracl/source/curve/ps_big.h new file mode 100644 index 0000000..1bfd89a --- /dev/null +++ b/miracl/source/curve/ps_big.h @@ -0,0 +1,87 @@ +/* + * C++ class to implement a power series type with Big coefficients + * and to allow arithmetic on it + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.7 + */ + +#ifndef PS_BIG_H +#define PS_BIG_H + +#include "big.h" + +#define FFT_BREAK_EVEN 16 + +extern int psN; + +// F(x) = (c0+c1*x^(offset+pwr)+c2.x^(offset+2*pwr)+c3.x^(offset+3*pwr) ..) + +class term_ps_big +{ +public: + Big an; + int n; + term_ps_big *next; +}; + +class Ps_Big +{ +public: + term_ps_big *start; + int pwr; + int offset; + + Ps_Big() {start=NULL; offset=0; pwr=1; } + Ps_Big(const Ps_Big&); + void clear(); + void compress(int); + void decompress(int); + void norm(); + void pad(); + int max(); + BOOL one_term() const; + BOOL IsInt() const; + void divxn(int n) {offset+=n;} + void mulxn(int n) {offset-=n;} + int first() {return (-offset);} + term_ps_big *addterm(const Big&,int,term_ps_big *pos=NULL); + void multerm(const Big&,int); + Big coeff(int) const; + Big cf(int) const; + Ps_Big& operator*=(Ps_Big&); + Ps_Big& operator=(const Ps_Big&); + Ps_Big& operator=(int); + Ps_Big& operator+=(const Ps_Big&); + Ps_Big& operator-=(const Ps_Big&); + Ps_Big& operator*=(const Big&); + Ps_Big& operator/=(const Big&); + Ps_Big& operator/=(int); + + friend Ps_Big eta(void); + friend Ps_Big operator*(Ps_Big&,Ps_Big&); + friend Ps_Big operator%(const Ps_Big&,const Ps_Big&); + friend Ps_Big operator/(Ps_Big&,Ps_Big&); + friend Ps_Big operator/(const Big&,const Ps_Big&); + friend Ps_Big operator-(const Ps_Big&,const Ps_Big&); + friend Ps_Big operator-(const Ps_Big&); + friend Ps_Big operator+(const Ps_Big&,const Ps_Big&); + friend Ps_Big operator*(const Ps_Big&,const Big&); + friend Ps_Big operator*(const Big&,const Ps_Big&); + + friend Ps_Big operator/(const Ps_Big&,const Big&); + friend Ps_Big operator/(const Ps_Big&,int); + + friend Ps_Big pow(Ps_Big&,int); + friend Ps_Big power(const Ps_Big&,int); + friend ostream& operator<<(ostream&,const Ps_Big&); + ~Ps_Big(); +}; + +extern Ps_Big eta(void); + +#endif + diff --git a/miracl/source/curve/ps_zzn.cpp b/miracl/source/curve/ps_zzn.cpp new file mode 100644 index 0000000..953ad78 --- /dev/null +++ b/miracl/source/curve/ps_zzn.cpp @@ -0,0 +1,869 @@ +/* + * C++ class to implement a power series type and to allow + * arithmetic on it + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library It is not complete, and may not work in other + * applications + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.7 + */ + +#include "ps_zzn.h" + +#define FFT + +// +// all calulations are mod x^psN +// Power series is stored {as offset, pwr and a0+a1.x+a2.x^2+a3.x^3....} +// where the power of x is to be multiplied by pwr, and the whole power +// series is to be divided by x^offset +// + +int psN; + +// +// Copy Constructor +// + +Ps_ZZn::Ps_ZZn(const Ps_ZZn& p) +{ + term_ps_zzn *ptr=p.start; + term_ps_zzn *pos=NULL; + int pw; + start=NULL; + offset=p.offset; + pwr=p.pwr; + while (ptr!=NULL) + { + pw=ptr->n*p.pwr-p.offset; // conversion needed + if (pw>=psN) break; + pos=addterm(ptr->an,pw,pos); + ptr=ptr->next; + } +} + +// +// decompresses PS by reducing pwr +// + +void Ps_ZZn::decompress(int m) +{ // m is divisor of current pwr + // e.g pwr is 6 and PS = 1 + x + x^2 + // If m=2 then pwr becomes 3 and PS = 1 +x^2 +x^4.... + term_ps_zzn *ptr=start; + if (start==NULL || m==1 || pwr==1) return; // it is fully decompressed + while (ptr!=NULL) + { + ptr->n*=m; + ptr=ptr->next; + } + pwr/=m; +} + +// +// Sets new pwr value. Parameter must exactly divide +// all powers in the series +// + +void Ps_ZZn::compress(int p) +{ + term_ps_zzn *ptr=start; + if (p==1) return; + while (ptr!=NULL) + { + ptr->n/=p; + ptr=ptr->next; + } + pwr=p; +} + +// +// insert missing terms with 0 coefficients +// + +void Ps_ZZn::pad() +{ // insert any missing 0 coefficients + int i=0; + term_ps_zzn *ptr=start; + term_ps_zzn *pos=NULL; + while (ptr!=NULL) + { + while (in) + { + pos=addterm((ZZn)0,i*pwr-offset,pos); + i++; + } + i++; + ptr=ptr->next; + } + while (ian); + if (b>m) m=b; + ptr=ptr->next; + } + return m; +} + +// +// set new offset, so first power of x is 0 +// + +void Ps_ZZn::norm() +{ + int m; + term_ps_zzn *ptr; + if (start==NULL) return; +// +// remove any leading 0 terms +// + while (start->an.iszero()) + { + ptr=start->next; + delete start; + start=ptr; + if (start==NULL) return; + } + ptr=start; + m=start->n; + if (m!=0) + { + offset-=m*pwr; + while (ptr!=NULL) + { + ptr->n-=m; + ptr=ptr->next; + } + } +} + +// +// Dedekind Eta function (1-x)(1-x^2)(1-x^3).... +// + +Ps_ZZn eta() +{ // simple repeating pattern + BOOL even; + int one,ce,co,c; + term_ps_zzn *pos=NULL; + Ps_ZZn n; + n.addterm((ZZn)1,0); + n.addterm((ZZn)-1,1); + n.addterm((ZZn)-1,2); + ce=2;co=1; + even=TRUE; + c=2; + one=1; + while (can.iszero()) t++; + if (t>1) return FALSE; + ptr=ptr->next; + } + return TRUE; +} + +// +// add a term to a PS +// + +term_ps_zzn* Ps_ZZn::addterm(const ZZn& a,int power,term_ps_zzn* pos) +{ + term_ps_zzn* newone; + term_ps_zzn* ptr; + term_ps_zzn *t,*iptr; + int dc,pw; + ptr=start; + iptr=NULL; + +// +// intelligently determine the most compressed form to use +// for example if coefficient a=1 always, and power = -7 -5 -3 -1 1 3.... +// then set pwr=2, offset=7 and PS = 1 + x + x^2 +// + pw=power+offset; + if (one_term() && pw!=0) + { // when PS has only one term, pwr is undefined + if (pw<0) + pwr=-pw; + else pwr=pw; + } + + dc=igcd(pw,pwr); + + if (dc != pwr) decompress(pwr/dc); + power=pw/pwr; +// quick scan through to detect if term exists already +// and to find insertion point + if (pos!=NULL) ptr=pos; + while (ptr!=NULL) + { + if (ptr->n==power) + { + ptr->an+=a; + + if (ptr->an.iszero()) + { // delete term + if (ptr==start) + { // delete first one + start=ptr->next; + delete ptr; + norm(); + return start; + } + iptr=ptr; + ptr=start; + while (ptr->next!=iptr)ptr=ptr->next; + ptr->next=iptr->next; + delete iptr; + return ptr; + } + return ptr; + } + if (ptr->nnext; + } + newone=new term_ps_zzn; + newone->next=NULL; + newone->an=a; + newone->n=power; + pos=newone; + if (start==NULL) + { + start=newone; + norm(); + return pos; + } + +// insert at the start + + if (iptr==NULL) + { + t=start; + start=newone; + newone->next=t; + norm(); + return pos; + } + +// insert new term + + t=iptr->next; + iptr->next=newone; + newone->next=t; + return pos; +} + +// +// Destructor +// + +Ps_ZZn::~Ps_ZZn() +{ + term_ps_zzn *nx; + while (start!=NULL) + { + nx=start->next; + delete start; + start=nx; + } +} + +// +// get coefficient of actual power +// + +ZZn Ps_ZZn::coeff(int power) const +{ + ZZn c=0; + term_ps_zzn *ptr=start; + if ((power+offset)%pwr != 0) return c; // no such term + power=(power+offset)/pwr; + + while (ptr!=NULL) + { + if (ptr->n==power) + { + c=ptr->an; + return c; + } + ptr=ptr->next; + } + return c; +} + +// +// get coefficient of "Internal" power +// + +ZZn Ps_ZZn::cf(int power) const +{ + ZZn c=0; + term_ps_zzn *ptr=start; + + while (ptr!=NULL) + { + if (ptr->n==power) + { + c=ptr->an; + return c; + } + ptr=ptr->next; + } + return c; +} + +// +// Zeroise PS and reclaim space +// + +void Ps_ZZn::clear() +{ + term_ps_zzn *ptr; + while (start!=NULL) + { + ptr=start->next; + delete start; + start=ptr; + } + offset=0; + pwr=1; +} + +// Note: real power = internal power * pwr - offset + +Ps_ZZn& Ps_ZZn::operator+=(const Ps_ZZn& p) +{ + term_ps_zzn *ptr=p.start; + term_ps_zzn *pos=NULL; + int pw; + while (ptr!=NULL) + { + pw=ptr->n*p.pwr-p.offset; // convert compressed to real + if (pw>=psN) break; + pos=addterm(ptr->an,pw,pos); + ptr=ptr->next; + } + return *this; +} + +Ps_ZZn operator-(const Ps_ZZn& p) +{ + Ps_ZZn r=p; + term_ps_zzn *ptr=r.start; + while (ptr!=NULL) + { + ptr->an=(-ptr->an); + ptr=ptr->next; + } + return r; +} + +Ps_ZZn& Ps_ZZn::operator-=(const Ps_ZZn& p) +{ + term_ps_zzn *ptr=p.start; + term_ps_zzn *pos=NULL; + int pw; + + while (ptr!=NULL) + { + pw=ptr->n*p.pwr-p.offset; + if (pw>=psN) break; + pos=addterm(-(ptr->an),pw,pos); + ptr=ptr->next; + } + return *this; +} + +Ps_ZZn operator+(const Ps_ZZn& a,const Ps_ZZn& b) +{ + Ps_ZZn sum=a; + sum+=b; + return sum; +} + +Ps_ZZn operator-(const Ps_ZZn& a,const Ps_ZZn& b) +{ + Ps_ZZn sum=a; + sum-=b; + return sum; +} + +// +// In situ multiplication. Coeeficients in multiplicand +// are directly overwritten. Saves a lot of copying. +// + +Ps_ZZn& Ps_ZZn::operator*=(Ps_ZZn& b) +{ + term_ps_zzn *ptr,*bptr; + int g,d,deg,ka,kb; + if (IsInt()) + { + if (start!=NULL) *this = start->an*b; + return *this; + } + if (b.IsInt()) + { + if (b.start==NULL) clear(); + else *this *=(b.start->an); + return *this; + } + g=igcd(pwr,b.pwr); + deg=psN/g; + + +#ifdef FFT + if (deg>=FFT_BREAK_EVEN) + { + big *A,*B; + A=(big *)mr_alloc(deg,sizeof(big)); + B=(big *)mr_alloc(deg,sizeof(big)); + ka=pwr/g; + decompress(ka); + pad(); + ptr=start; + while (ptr!=NULL) + { + d=ptr->n; + if (d>=deg) break; + A[d]=getbig(ptr->an); + ptr=ptr->next; + } + kb=b.pwr/g; + b.decompress(kb); + bptr=b.start; + while (bptr!=NULL) + { + d=bptr->n; + if (d>=deg) break; + B[d]=getbig(bptr->an); + bptr=bptr->next; + } + mr_ps_zzn_mul(deg,A,B,A); + mr_free(B); mr_free(A); + b.compress(kb); + } + else + { +#endif + *this=*this*b; + return *this; +#ifdef FFT + } +#endif + norm(); + offset+=b.offset; + return *this; +} + +Ps_ZZn operator*(Ps_ZZn& a,Ps_ZZn& b) +{ + Ps_ZZn prod; + ZZn t; + term_ps_zzn *aptr,*bptr,*pos; + int ka,kb,i,pa,pb,d,deg,g; + + if (a.IsInt()) + { + if (a.start==NULL) return prod; + else return (a.start->an*b); + } + + if (b.IsInt()) + { + if (b.start==NULL) return prod; + else return (b.start->an*a); + } + + g=igcd(a.pwr,b.pwr); + + deg=psN/g; + +#ifdef FFT + if (deg>=FFT_BREAK_EVEN) + { // use fast methods + big *A,*B,*C; + A=(big *)mr_alloc(deg,sizeof(big)); + B=(big *)mr_alloc(deg,sizeof(big)); + C=(big *)mr_alloc(deg,sizeof(big)); + char *memc=(char *)memalloc(deg); + for (i=0;in; + if (d >= deg) break; + A[d]=getbig(aptr->an); + aptr=aptr->next; + } + kb=b.pwr/g; + b.decompress(kb); + bptr=b.start; + while (bptr!=NULL) + { + d=bptr->n; + if (d >= deg) break; + B[d]=getbig(bptr->an); + bptr=bptr->next; + } + mr_ps_zzn_mul(deg,A,B,C); + pos=NULL; + for (d=0;dn*b.pwr-b.offset; + pos=NULL; + while (aptr!=NULL) + { + pa=aptr->n*a.pwr-a.offset; + if (pb+pa>=psN) break; + pos=prod.addterm(aptr->an*bptr->an,pa+pb,pos); + aptr=aptr->next; + } + bptr=bptr->next; + } +#ifdef FFT + } +#endif + + if (prod.start!=NULL) prod.offset=a.offset+b.offset; + return prod; +} + +Ps_ZZn operator/(const ZZn& num,const Ps_ZZn& b) +{ + Ps_ZZn quo; + term_ps_zzn *pos=NULL; + int pw=b.pwr; + ZZn w,v0=b.cf(0); + + for (int n=0;n=psN) break; + if (n==0) w=num; + else w=0; + for (int k=0;k=psN) break; + w=a.cf(n); + for (int k=0;kan/=x; + ptr=ptr->next; + } + return *this; +} + +Ps_ZZn& Ps_ZZn::operator/=(int m) +{ + term_ps_zzn *ptr=start; + while (ptr!=NULL) + { + ptr->an/=m; + ptr=ptr->next; + } + return *this; +} + +Ps_ZZn operator/(const Ps_ZZn& a,const ZZn& b) +{ + Ps_ZZn quo; + quo=a; + quo/=b; + return quo; +} + +Ps_ZZn operator/(const Ps_ZZn& a,int m) +{ + Ps_ZZn quo; + quo=a; + quo/=m; + return quo; +} + + +Ps_ZZn& Ps_ZZn::operator=(int m) +{ + clear(); + if (m!=0) addterm((ZZn)m,0); + return *this; +} + +Ps_ZZn& Ps_ZZn::operator=(const Ps_ZZn& p) +{ + term_ps_zzn *ptr; + term_ps_zzn *pos=NULL; + clear(); + int pw; + + pwr=p.pwr; + offset=p.offset; + ptr=p.start; + while (ptr!=NULL) + { + pw=ptr->n*p.pwr-p.offset; + if (pw>=psN) break; + pos=addterm(ptr->an,pw,pos); + ptr=ptr->next; + } + + return *this; +} + +Ps_ZZn& Ps_ZZn::operator*=(const ZZn& x) +{ + term_ps_zzn *ptr=start; + if (x.iszero()) + { + clear(); + return *this; + } + while (ptr!=NULL) + { + ptr->an*=x; + ptr=ptr->next; + } + return *this; +} + +Ps_ZZn operator*(const ZZn& z,const Ps_ZZn &p) +{ + Ps_ZZn r=p; + r*=z; + return r; +} + +Ps_ZZn operator*(const Ps_ZZn &p,const ZZn& z) +{ + Ps_ZZn r=p; + r*=z; + return r; +} + +Ps_ZZn pow(Ps_ZZn &a,int k) +{ + Ps_ZZn res; + int w,e; + + if (k==0) + { + res=1; + return res; + } + res=a; + if (k==1) return res; + + e=k; w=1; + while (w<=e) w<<=1; + w>>=1; + e-=w; w/=2; + while (w>0) + { + res*=res; + if (e>=w) + { + e-=w; + res*=a; + } + w/=2; + } + res.offset*=k; + + return res; +} + + +Ps_ZZn power(const Ps_ZZn &a,int e) +{ // return f(a^e), e is +ve + Ps_ZZn res; + term_ps_zzn *ptr; + term_ps_zzn *pos=NULL; + + ptr=a.start; + while (ptr!=NULL) + { + if ((ptr->n*a.pwr)*e < psN) + { + pos=res.addterm(ptr->an,ptr->n,pos); + ptr=ptr->next; + } + else break; + } + + res.pwr=e*a.pwr; + res.offset=e*a.offset; + + return res; +} + +ostream& operator<<(ostream& s,const Ps_ZZn& p) +{ + BOOL first=TRUE; + ZZn a; + term_ps_zzn *ptr=p.start; + int pw; + + if (ptr==NULL) + { + s << "0"; + return s; + } + + while (ptr!=NULL) + { + a=ptr->an; + if (a.iszero()) + { + ptr=ptr->next; + continue; + } + if ((Big)a < get_modulus()/2) + { + a=(-a); + s << " - "; + } + else if (!first) s << " + "; + + first=FALSE; + pw=ptr->n*p.pwr-p.offset; + if (pw==0) + { + s << a; + ptr=ptr->next; + continue; + } + + if (a==(ZZn)1) s << "x"; + else s << a << "*x"; + + if (pw!=1) s << "^" << pw; + ptr=ptr->next; + } + return s; +} + diff --git a/miracl/source/curve/ps_zzn.h b/miracl/source/curve/ps_zzn.h new file mode 100644 index 0000000..791dbcf --- /dev/null +++ b/miracl/source/curve/ps_zzn.h @@ -0,0 +1,87 @@ +/* + * C++ class to implement a power series type and to allow + * arithmetic on it. COefficinets are of type ZZn + * + * WARNING: This class has been cobbled together for a specific use with + * the MIRACL library. It is not complete, and may not work in other + * applications + * + * See Knuth The Art of Computer Programming Vol.2, Chapter 4.7 + */ + +#ifndef PS_ZZN_H +#define PS_ZZN_H + +#include "zzn.h" + +#define FFT_BREAK_EVEN 16 + +extern int psN; + +// F(x) = (c0+c1*x^(offset+pwr)+c2.x^(offset+2*pwr)+c3.x^(offset+3*pwr) ..) + +class term_ps_zzn +{ +public: + ZZn an; + int n; + term_ps_zzn *next; +}; + +class Ps_ZZn +{ +public: + term_ps_zzn *start; + int pwr; + int offset; + + Ps_ZZn() {start=NULL; offset=0; pwr=1; } + Ps_ZZn(const Ps_ZZn&); + void clear(); + void compress(int); + void decompress(int); + void norm(); + void pad(); + int max(); + BOOL one_term() const; + BOOL IsInt() const; + void divxn(int n) {offset+=n;} + void mulxn(int n) {offset-=n;} + int first() {return (-offset);} + term_ps_zzn *addterm(const ZZn&,int,term_ps_zzn *pos=NULL); + void multerm(const ZZn&,int); + ZZn coeff(int) const; + ZZn cf(int) const; + Ps_ZZn& operator*=(Ps_ZZn&); + Ps_ZZn& operator=(const Ps_ZZn&); + Ps_ZZn& operator=(int); + Ps_ZZn& operator+=(const Ps_ZZn&); + Ps_ZZn& operator-=(const Ps_ZZn&); + Ps_ZZn& operator*=(const ZZn&); + Ps_ZZn& operator/=(const ZZn&); + Ps_ZZn& operator/=(int); + + friend Ps_ZZn eta(); + friend Ps_ZZn operator*(Ps_ZZn&,Ps_ZZn&); + friend Ps_ZZn operator%(const Ps_ZZn&,const Ps_ZZn&); + friend Ps_ZZn operator/(Ps_ZZn&,Ps_ZZn&); + friend Ps_ZZn operator-(const Ps_ZZn&,const Ps_ZZn&); + friend Ps_ZZn operator-(const Ps_ZZn&); + friend Ps_ZZn operator+(const Ps_ZZn&,const Ps_ZZn&); + friend Ps_ZZn operator*(const Ps_ZZn&,const ZZn&); + friend Ps_ZZn operator*(const ZZn&,const Ps_ZZn&); + + friend Ps_ZZn operator/(const ZZn&,const Ps_ZZn&); + friend Ps_ZZn operator/(const Ps_ZZn&,const ZZn&); + friend Ps_ZZn operator/(const Ps_ZZn&,int); + + friend Ps_ZZn pow(Ps_ZZn&,int); + friend Ps_ZZn power(const Ps_ZZn&,int); + friend ostream& operator<<(ostream&,const Ps_ZZn&); + ~Ps_ZZn(); +}; + +extern Ps_ZZn eta(); + +#endif + diff --git a/miracl/source/curve/schoof.cpp b/miracl/source/curve/schoof.cpp new file mode 100644 index 0000000..a994293 --- /dev/null +++ b/miracl/source/curve/schoof.cpp @@ -0,0 +1,1564 @@ +// Schoof's Original Algorithm! +// Mike Scott June 1999 mike@compapp.dcu.ie +// Counts points on GF(p) Elliptic Curve, y^2=x^3+Ax+B a prerequisite +// for implemention of Elliptic Curve Cryptography +// +// cl /O2 /GX schoof.cpp ecn.cpp zzn.cpp big.cpp crt.cpp poly.cpp polymod.cpp miracl.lib +// g++ -O2 schoof.cpp ecn.cpp zzn.cpp big.cpp crt.cpp poly.cpp polymod.cpp miracl.a -o schoof +// +// !!!!!!!!!!!!!!!!!!!!!!!! +// NOTE! September 1999. This program has been rendered effectively obsolete +// by the implementation of the superior Schoof-Elkies-Atkin Algorithm +// This has O(log(p)^5) complexity compared with O(log(p)^6), and so will +// always be faster. +// +// Read the comments at the head of the file +// ftp://ftp.computing.dcu.ie/pub/crypto/sea.cpp +// for more details +// +// However this program is self-contained and hence easier to use. +// It is quite adequate for counting points on up to 256 bit curves (that is +// for primes p < 256 bits in length) assuming a reasonably powerful PC +// It also works for the smallest curves, and so is ideal for educational +// use +// +// It is now straightforward to create an executable that runs under Linux. +// See ftp://ftp.computing.dcu.ie/pub/crypto/README for details +// +// For elliptic curves defined over GF(2^m), see the utility schoof2.exe +// +// !!!!!!!!!!!!!!!!!!!!!!!! +// +// The self-contained Windows Command Prompt executable for this program may +// obtained from ftp://ftp.computing.dcu.ie/pub/crypto/schoof.exe +// +// Basic algorithm is due to Schoof +// "Elliptic Curves Over Finite Fields and the Computation of Square Roots +// mod p", Rene Schoof, Math. Comp., Vol. 44 pp 483-494 +// Expression for Mod 2 Cardinality from "Counting Points on Elliptic +// Curves over Finite Fields", Rene Schoof, Jl. de Theorie des Nombres +// de Bordeaux 7 (1995) pp 219-254 +// Another useful reference is +// "Elliptic Curve Public Key Cryptosystems", Menezes, +// Kluwer Academic Publishers, Chapter 7 +// Thanks are due to Richard Crandall for the tip about using prime powers +// +// ** +// This program implements Schoof's original algorithm, augmented by +// the use of prime powers. By finding the Number of Points mod the product +// of many small primes and large prime powers, the final search for NP is +// greatly speeded up. +// Final phase search uses Pollard Lambda ("kangaroo") algorithm +// This final phase effectively stretches the range of Schoof's +// algorithm by about 70-80 bits. +// This approach is only feasible due to the use of fast FFT methods +// for large degree polynomial multiplication +// ** +// +// Ref "Monte Carlo Methods for Index Computation" +// by J.M. Pollard in Math. Comp. Vol. 32 1978 pp 918-924 +// Ref "A New Polynomial Factorisation Algorithm and its implementation", +// Victor Shoup, Jl. Symbolic Computation, 1996 +// +// +// An "ideal" curve is defined as one with with prime number of points. +// +// When using the "schoof" program, the -s option is particularly useful +// and allows automatic search for an "ideal" curve. If a curve order is +// exactly divisible by a small prime, that curve is immediately abandoned, +// and the program moves on to the next, incrementing the B parameter of +// the curve. This is a fairly arbitrary but simple way of moving on to +// the "next" curve. +// +// NOTE: The output file can be used directly with for example the ECDSA +// programs IF AND ONLY IF an ideal curve is found. If you wish to use +// a less-than-ideal curve, you will first have to factor NP completely, and +// find a random point of large prime order. +// +// This implementation is free. No terms, no conditions. It requires +// version 4.24 or greater of the MIRACL library (a Shareware, Commercial +// product, but free for non-profit making use), +// available from ftp://ftp.computing.dcu.ie/pub/crypto/miracl.zip +// +// However this program may be used (unmodified) to generate curves for +// commercial use. +// +// 32-bit build only +// +// Revision history +// +// Rev. 1 June 1999 - included prime powers +// Rev. 2 June 1999 - tweaked some inner loops +// Rev. 3 July 1999 - changed from rational to projective coordinates +// power windowing helps X^PP, Y^PP calculations +// Rev. 4 August 1999 - suppressed unnecessary creation of ZZn temporaries +// in poly.cpp and polymod.cpp +// Rev. 5 September 1999 - Use fast modular composition to calculate X^PP +// Half required size of ZZn's +// More & Faster Kangaroos! +// Rev. 6 October 1999 - Revamped Poly class +// 25% Faster technique for finding tau mod lp +// Rev. 7 November 1999 - Calculation of Y^PP eliminated! +// +// Rev. 8 November 1999 - Find Y^PP using composition - faster tau search +// Rev. 9 December 1999 - Various optimisations +// Rev. 10 March 2000 - Eigenvalue Heuristic introduced +// +// Timings for test curve Y^2=X^3-3X+49 mod 65112*2^144-1 (160 bits) +// Pentium Pro 180MHz +// +// Rev. 0 - 100 minutes +// Rev. 1 - 67 minutes +// Rev. 2 - 57 minutes +// Rev. 3 - 51 minutes +// Rev. 4 - 46 minutes +// Rev. 5 - 31 minutes +// Rev. 6 - 25 minutes +// Rev. 7 - 22 minutes +// Rev. 8 - 21 minutes +// Rev. 9 - 18 minutes +// Rev. 10 - 13 minutes +// +// 160 bit curve - 13 minutes +// 192 bit curve - 60 minutes +// 224 bit curve - 176 minutes +// 256 bit curve - 355 minutes +// +// This execution time can be related directly to +// the O(log(p)^6) complexity of the algorithm as implemented here. +// +// Note that a small speed-up can be obtained by using an integer-only +// build of MIRACL. See mirdef.hio +// +// + +#include +#include +#include +#include +#include "ecn.h" // Elliptic Curve Class +#include "crt.h" // Chinese Remainder Theorem Class + +// poly.h implements polynomial arithmetic. FFT methods are used for maximum +// speed, as the polynomials get very big. For example when searching for the +// curve cardinality mod the prime 31, the polynomials are of degree (31*31-1)/2 +// = 480. But all that gruesome detail is hidden away. +// +// polymod.h implements polynomial arithmetic wrt to a preset poynomial +// modulus. This looks a bit neater. Function setmod() sets the modulus +// to be used. Again fast FFT methods are used. + +#include "poly.h" +#include "polymod.h" + +using namespace std; + +#ifndef MR_NOFULLWIDTH +Miracl precision=10; // max. 10x32 bits per big number +#else +Miracl precision(10,MAXBASE); +#endif + +PolyMod MY2,MY4; + +ZZn A,B; // Here ZZn are integers mod the prime p + // Montgomery representation is used internally + +BOOL Edwards=FALSE; + +// Elliptic curve Point duplication formula + +void elliptic_dup(PolyMod& X,PolyMod& Y,PolyMod& Z) +{ // (X,Y,Z)=2.(X,Y,Z) + PolyMod W1,W2,W3,W4; + + W2=Z*Z; // 1 + if (A==(ZZn)(-3)) + { + W4=3*(X-W2)*(X+W2); // 2 (and save 1) + } + else + { + W3=A*(W2*W2); // 2 + W1=X*X; // 3 + W4=3*W1+W3; + } + Z*=(2*Y); // 4 Z has an implied y + W2=MY2*(Y*Y); // 5 + W3=4*X*W2; // 6 + W1=W4*W4; // 7 + X=W1-2*W3; + W2*=W2; // 8 + W2*=8; + W3-=X; + W3*=W4; // 9 + Y=W3-W2; + X*=MY2; // fix up - move implied y from Z to Y + Y*=MY2; + Z*=MY2; +} + +// +// This is addition formula for two distinct points on an elliptic curve +// Works with projective coordinates which are automatically reduced wrt a +// polynomial modulus +// Remember that the expression for the Y coordinate of each point +// (a function of X) is implicitly multiplied by Y. +// We know Y^2=X^3+AX+B, but we don't have an expression for Y +// So if Y^2 ever crops up - substitute for it + +void elliptic_add(PolyMod& XT,PolyMod& YT,PolyMod& ZT,PolyMod& X,PolyMod& Y,PolyMod& Z) +{ // add (X,Y,Z) to (XT,YT,ZT) on an elliptic curve + + PolyMod W1,W2,W3,W4,W5,W6; + + if (!isone(Z)) + { // slower if Z!=1 + W3=Z*Z; // 1x + W1=XT*W3; // 2x + W3*=Z; // 3x + W2=YT*W3; // 4x + } + else + { + W1=XT; + W2=YT; // W2 has an implied y + } + W6=ZT*ZT; // 1 + W4=X*W6; // 2 + W6*=ZT; // 3 + W5=Y*W6; // 4 W5 has an implied y + + W1-=W4; + W2-=W5; + if (iszero(W1)) + { + if (iszero(W2)) + { // should have doubled + elliptic_dup(XT,YT,ZT); + return; + } + else + { // point at infinity + ZT.clear(); + return; + } + } + + W4=W1+2*W4; + W5=W2+2*W5; + + ZT*=W1; // 5 + + if (!isone(Z)) ZT*=Z; // 5x + + W6=W1*W1; // 6 + W1*=W6; // 7 + W6*=W4; // 8 + W4=MY2*(W2*W2); // 9 Substitute for Y^2 + + XT=W4-W6; + + W6=W6-2*XT; + W2*=W6; // 10 + W1*=W5; // 11 + W5=W2-W1; + + YT=W5/(ZZn)2; +} + +// +// Program to compute the order of a point on an elliptic curve +// using Pollard's lambda method for catching kangaroos. +// +// As a way of counting points on an elliptic curve, this +// has complexity O(p^(1/4)) +// +// However Schoof puts a spring in the step of the kangaroos +// allowing them to make bigger jumps, and lowering overall complexity +// to O(p^(1/4)/sqrt(L)) where L is the product of the Schoof primes +// +// See "Monte Carlo Methods for Index Computation" +// by J.M. Pollard in Math. Comp. Vol. 32 1978 pp 918-924 +// +// This code has been considerably speeded up using ideas from +// "Parallel Collision Search with Cryptographic Applications", J. Crypto., +// Vol. 12, 1-28, 1999 +// + +#define STORE 80 +#define HERD 5 + +ECn wild[STORE],tame[STORE]; +Big wdist[STORE],tdist[STORE]; +int wname[STORE],tname[STORE]; + +Big kangaroo(Big p,Big order,Big ordermod) +{ + ECn ZERO,K[2*HERD],TE[2*HERD],X,P,G,table[50],trap; + Big start[2*HERD],txc,wxc,mean,leaps,upper,lower,middle,a,b,x,y,n,w,t,nrp; + int i,jj,j,m,sp,nw,nt,cw,ct,k,distinguished; + Big D[2*HERD],s,distance[50],real_order; + BOOL bad,collision,abort; + forever + { + +// find a random point on the curve + do + { + x=rand(p); + } while (!P.set(x,x)); + + lower=p+1-2*sqrt(p)-3; // lower limit of search + upper=p+1+2*sqrt(p)+3; // upper limit of search + + w=1+(upper-lower)/ordermod; + leaps=sqrt(w); + mean=HERD*leaps/2; // ideal mean for set S=1/2*w^(0.5) + distinguished=1<<(bits(leaps/16)); + for (s=1,m=1;;m++) + { /* find table size */ + distance[m-1]=s*ordermod; + s*=2; + if ((2*s/m)>mean) break; + } + table[0]=ordermod*P; + for (i=1;i1) + middle+=(ordermod+order-middle%ordermod); + + for (i=0;i=STORE) + { + abort=TRUE; + break; + } + cout << "." << flush; + tame[nt]=K[jj]; + tdist[nt]=D[jj]; + tname[nt]=jj; + for (k=0;k=STORE) + { + abort=TRUE; + break; + } + cout << "." << flush; + wild[nw]=K[jj]; + wdist[nw]=D[jj]; + wname[nw]=jj; + for (k=0;kPRIMES[i]; + if (sp==0) break; + if (real_order%sp==0) + { + G=P; + G*=(real_order/sp); + if (G==ZERO) + { + real_order/=sp; + continue; + } + } + i++; + } + if (real_order <= 4*sqrt(p)) + { + cout << "Low Order point used - trying again" << endl; + continue; + } + real_order=nrp; + for (i=0;(sp=get_mip()->PRIMES[i])!=0;i++) + while (real_order%sp==0) real_order/=sp; + if (real_order==1) + { // all factors of nrp were considered + cout << "NP= " << nrp << endl; + break; + } + if (prime(real_order)) + { // all factors of NP except for one last one.... + G=P; + G*=(nrp/real_order); + if (G==ZERO) + { + cout << "Failed - trying again" << endl; + continue; + } + else + { + cout << "NP= " << nrp << endl; + break; + } + } +// Couldn't be bothered factoring nrp completely +// Probably not an interesting curve for Cryptographic purposes anyway..... +// But if 20 random points are all "killed" by nrp, its almost +// certain to be the true NP, and not a multiple of a small order. + + bad=FALSE; + for (i=0;i<20;i++) + { + do + { + x=rand(p); + } while (!P.set(x,x)); + G=P; + G*=nrp; + if (G!=ZERO) + { + bad=TRUE; + break; + } + } + if (bad) + { + cout << "Failed - trying again" << endl; + continue; + } + cout << "NP is composite and not ideal for Cryptographic use" << endl; + cout << "NP= " << nrp << " (probably)" << endl; + break; + } + return nrp; +} + +// Code to parse formula in command line +// This code isn't mine, but its public domain +// Shamefully I forget the source +// +// NOTE: It may be necessary on some platforms to change the operators * and # + +#if defined(unix) +#define TIMES '.' +#define RAISE '^' +#else +#define TIMES '*' +#define RAISE '#' +#endif + +Big tt; +static char *ss; + +void eval_power (Big& oldn,Big& n,char op) +{ + if (op) n=pow(oldn,toint(n)); // power(oldn,size(n),n,n); +} + +void eval_product (Big& oldn,Big& n,char op) +{ + switch (op) + { + case TIMES: + n*=oldn; + break; + case '/': + n=oldn/n; + break; + case '%': + n=oldn%n; + } +} + +void eval_sum (Big& oldn,Big& n,char op) +{ + switch (op) + { + case '+': + n+=oldn; + break; + case '-': + n=oldn-n; + } +} + +void eval (void) +{ + Big oldn[3]; + Big n; + int i; + char oldop[3]; + char op; + char minus; + for (i=0;i<3;i++) + { + oldop[i]=0; + } +LOOP: + while (*ss==' ') + ss++; + if (*ss=='-') /* Unary minus */ + { + ss++; + minus=1; + } + else + minus=0; + while (*ss==' ') + ss++; + if (*ss=='(' || *ss=='[' || *ss=='{') /* Number is subexpression */ + { + ss++; + eval (); + n=tt; + } + else /* Number is decimal value */ + { + for (i=0;ss[i]>='0' && ss[i]<='9';i++) + ; + if (!i) /* No digits found */ + { + cout << "Error - invalid number" << endl; + exit (20); + } + op=ss[i]; + ss[i]=0; + n=atoi(ss); + ss+=i; + *ss=op; + } + if (minus) n=-n; + do + op=*ss++; + while (op==' '); + if (op==0 || op==')' || op==']' || op=='}') + { + eval_power (oldn[2],n,oldop[2]); + eval_product (oldn[1],n,oldop[1]); + eval_sum (oldn[0],n,oldop[0]); + tt=n; + return; + } + else + { + if (op==RAISE) + { + eval_power (oldn[2],n,oldop[2]); + oldn[2]=n; + oldop[2]=RAISE; + } + else + { + if (op==TIMES || op=='/' || op=='%') + { + eval_power (oldn[2],n,oldop[2]); + oldop[2]=0; + eval_product (oldn[1],n,oldop[1]); + oldn[1]=n; + oldop[1]=op; + } + else + { + if (op=='+' || op=='-') + { + eval_power (oldn[2],n,oldop[2]); + oldop[2]=0; + eval_product (oldn[1],n,oldop[1]); + oldop[1]=0; + eval_sum (oldn[0],n,oldop[0]); + oldn[0]=n; + oldop[0]=op; + } + else /* Error - invalid operator */ + { + cout << "Error - invalid operator" << endl; + exit (20); + } + } + } + } + goto LOOP; +} + +mr_utype qpow(mr_utype x,int y) +{ // quick and dirty power function + mr_utype r=x; + for (int i=1;i " << endl; + cout << "OR" << endl; + cout << "schoof -f " << endl; +#if defined(unix) + cout << "e.g. schoof -f 2^192-2^64-1 -3 35317045537" << endl; +#else + cout << "e.g. schoof -f 2#192-2#64-1 -3 35317045537" << endl; +#endif + cout << "To output to a file, use flag -o " << endl; + cout << "To search downwards for a prime, use flag -d" << endl; + cout << "To input P, A and B in Hex, precede with -h" << endl; + cout << "To search for NP prime incrementing B, use flag -s" << endl; + cout << "(For Edwards curve the search is for NP=4*prime)" << endl; + cout << "\nFreeware from Certivox, Dublin, Ireland" << endl; + cout << "Full C++ source code and MIRACL multiprecision library available" << endl; + cout << "Also faster Schoof-Elkies-Atkin implementation" << endl; + cout << "email mscott@indigo.ie" << endl; + return 0; + } + + ip=0; + gprime(10000); // generate small primes < 1000 + search=fout=dir=gotP=gotA=gotB=FALSE; + p=0; a=0; b=0; + +// Interpret command line + Base=10; + while (ipIOBASE=Base; + p=argv[ip++]; + mip->IOBASE=10; + gotP=TRUE; + continue; + } + if (!gotA) + { + mip->IOBASE=Base; + a=argv[ip++]; + mip->IOBASE=10; + gotA=TRUE; + continue; + } + if (!gotB) + { + mip->IOBASE=Base; + b=argv[ip++]; + mip->IOBASE=10; + gotB=TRUE; + continue; + } + cout << "Error in command line" << endl; + return 0; + } + + if (!gotP || !gotA || !gotB) + { + cout << "Error in command line" << endl; + return 0; + } + + if (!prime(p)) + { + int incr=0; + cout << "That number is not prime!" << endl; + if (dir) + { + cout << "Looking for next lower prime" << endl; + p-=1; incr++; + while (!prime(p)) { p-=1; incr++; } + cout << "Prime P = P-" << incr << endl; + } + else + { + cout << "Looking for next higher prime" << endl; + p+=1; incr++; + while (!prime(p)) { p+=1; incr++; } + cout << "Prime P = P+" << incr << endl; + } + cout << "Prime P = " << p << endl; + } + pbits=bits(p); + cout << "P mod 24 = " << p%24 << endl; + cout << "P is " << pbits << " bits long" << endl; + +// loop for "-s" search option + + forever { + + fft_reset(); // reset FFT tables + + + if (Edwards) + { + modulo(p); + EB=b; + EA=a; + AZ=(ZZn)1/(EA-EB); + A2=2*(EA+EB)/(EA-EB); + A4=1; AW=1; + + AW*=AZ; A2*=AZ; A4*=AZ; + + A4*=AW; + + T=4*A2; + T1=3*T; + T3=18*36*(2*A4); + + A=T3-3*T1*T1; + B=-T1*T3+2*T1*T1*T1; + ecurve((Big)A,(Big)B,p,MR_AFFINE); // initialise Elliptic Curve + + } + else + { + ecurve(a,b,p,MR_AFFINE); // initialise Elliptic Curve + A=a; + B=b; + } + +// The elliptic curve as a Polynomial + + Y2=0; + Y2.addterm(B,0); + Y2.addterm(A,1); + Y2.addterm((ZZn)1,3); + + Y4=Y2*Y2; + cout << "Counting the number of points (NP) on the curve" << endl; + if (Edwards) + { + cout << "X^2+" << EA << "*Y^2=X^2*Y^2+" << EB << endl; + cout << "Equivalent to Weierstrass form" << endl; + } + cout << "y^2= " << Y2 << " mod " << p << endl; + + delta=-16*(4*A*A*A+27*B*B); + if (delta==0) + { + cout << "Not Allowed! 4A^3+27B^2 = 0" << endl; + if (search) {b+=1; continue; } + else return 0; + } + anomalous=FALSE; + j_invariant=(-1728*64*A*A*A)/delta; + + cout << "j-invariant= " << j_invariant << endl; + + if (j_invariant==0 || j_invariant==1728) + { + anomalous=TRUE; + cout << "Warning: j-invariant is " << j_invariant << endl; + } + if (pbits<14) + { // do it the simple way + nrp=1; + x=0; + while (x100 && pbits<=120) d=pow((Big)2,56); + if (pbits>120 && pbits<=140) d=pow((Big)2,64); + if (pbits>140 && pbits<=200) d=pow((Big)2,72); + if (pbits>200) d=pow((Big)2,80); + +/* + if (pbits<200) d=pow((Big)2,72); + else d=pow((Big)2,80); +*/ + + d=sqrt(p/d); + if (d<256) d=256; + + mr_utype l[100]; + int pp[100]; // primes and powers + +// see how many primes will be needed +// l[.] is the prime, pp[.] is the power + + for (s=1,nl=0;s<=d;nl++) + { + int tp=mip->PRIMES[nl]; + pp[nl]=1; // every prime included once... + s*=tp; + for (i=0;iPRIMES[i]; + int p=qpow(cp,pp[i]+1); + if (pPRIMES[nl-1]; + + cout << nl << " primes used (plus largest prime powers), largest is " << L << endl; + + for (i=0;iPRIMES[i]; + + int start_prime; // start of primes & largest prime powers + for (i=0;;i++) + { + if (pp[i]!=1) + { + mr_utype p=qpow(l[i],pp[i]); + for (j=0;l[j]j;m--) l[m]=l[m-1]; + l[j]=p; // insert largest prime power in table + } + else + { + start_prime=i; + break; + } + } + +// table of primes and prime powers now looks like:- +// 2 3 5 7 9 11 13 16 17 19 .... +// S p p + +// where S is start_prime, and p marks the largest prime powers in the range +// CRT uses primes starting from S, but small primes are kept in anyway, +// as they allow quick abort if searching for prime NP. + +// Calculate Divisor Polynomials - Schoof 1985 p.485 +// Set the first few by hand.... + + P[1]=1; P[2]=2; P[3]=0; P[4]=0; + + P2[1]=1; P3[1]=1; + + P2[2]=P[2]*P[2]; + P3[2]=P2[2]*P[2]; + + P[3].addterm(-(A*A),0); P[3].addterm(12*B,1); + P[3].addterm(6*A,2) ; P[3].addterm((ZZn)3,4); + + P2[3]=P[3]*P[3]; + P3[3]=P2[3]*P[3]; + + P[4].addterm((ZZn)(-4)*(8*B*B+A*A*A),0); + P[4].addterm((ZZn)(-16)*(A*B),1); + P[4].addterm((ZZn)(-20)*(A*A),2); + P[4].addterm((ZZn)80*B,3); + P[4].addterm((ZZn)20*A,4); + P[4].addterm((ZZn)4,6); + + P2[4]=P[4]*P[4]; + P3[4]=P2[4]*P[4]; + + lower=5; // next one to be calculated + + // Finding the order modulo 2 + // If GCD(X^P-X,X^3+AX+B) == 1 , trace=1 mod 2, else trace=0 mod 2 + + XX=0; + XX.addterm((ZZn)1,1); + + setmod(Y2); + XP=pow(XX,p); + G=gcd(XP-XX); + t[0]=0; + if (isone(G)) t[0]=1; + cout << "NP mod 2 = " << (p+1-(int)t[0])%2; + if ((p+1-(int)t[0])%2==0) + { + cout << " ***" << endl; + if (search && !Edwards) {b+=1; continue; } + } + else cout << endl; + + PolyMod one,XT,YT,ZT,XL,YL,ZL,ZL2,ZT2,ZT3; + one=1; // polynomial = 1 + + Crt CRT(nl-start_prime,&l[start_prime]); // initialise for application of the + // chinese remainder thereom + +// now look for trace%prime for prime=3,5,7,11 etc +// actual trace is found by combining these via CRT + + escape=FALSE; + for (i=1;ilower) lower=lp+2; + + for (tau=0;tau<=lp/2;tau++) permisso[tau]=TRUE; + + setmod(P[lp]); + MY2=Y2; + MY4=Y4; +// These next are time-consuming calculations of X^P, Y^P, X^(P*P) and Y^(P*P) + + cout << "X^P " << flush; + XP=pow(XX,p); + +// Eigenvalue search - see Menezes +// Batch the GCDs as they are slow. +// This gives us product of both eigenvalues - a polynomial of degree (lp-1) +// But thats a lot better than (lp^2-1)/2 + eigen=FALSE; + if (!anomalous && prime((Big)lp)) + { + PolyMod Xcoord,batch; + batch=1; + cout << "\b\b\b\bGCD " << flush; + for (tau=1;tau<=(lp-1)/2;tau++) + { + if (tau%2==0) + Xcoord=(XP-XX)*P2[tau]*MY2+(PolyMod)P[tau-1]*P[tau+1]; + else + Xcoord=(XP-XX)*P2[tau]+(PolyMod)P[tau-1]*P[tau+1]*MY2; + batch*=Xcoord; + } + Fl=gcd(batch); // just one GCD! + if (degree(Fl)==(lp-1)) eigen=TRUE; + } + + if (eigen) + { + setmod(Fl); + MY2=Y2; + MY4=Y4; + +// +// Only the Y-coordinate is calculated. No need for X^P ! +// + cout << "\b\b\b\bY^P" << flush; + YP=pow(MY2,(p-1)/2); + cout << "\b\b\b"; + +// +// Now looking for value of lambda which satisfies +// (X^P,Y^P) = lambda.(XX,YY). +// +// Note that it appears to be sufficient to only compare the Y coordinates (!?) +// + cout << "NP mod " << lp << " = " << flush; + Pf[0]=0; P2f[0]=0; P3f[0]=0; + Pf[1]=1; P2f[1]=1; P3f[1]=1; + low=2; + for (lambda=1;lambda<=(lp-1)/2;lambda++) + { + int res=0; + PolyMod Ry,Ty; + tau=(lambda+invers(lambda,lp)*p)%lp; + + cout << setw(3) << (p+1-tau)%lp << flush; + +// Get Divisor Polynomials as needed - this time mod the new (small) modulus Fl + + for (jj=low;jj<=lambda+2;jj++) + Pf[jj]=(PolyMod)P[jj]; + if (lambda+3>low) low=lambda+3; + +// compare Y-coordinates - 5 polynomial mod-muls required + + P2f[lambda+1]=Pf[lambda+1]*Pf[lambda+1]; + P3f[lambda]=P2f[lambda]*Pf[lambda]; + if (lambda%2==0) + { + Ry=(Pf[lambda+2]*P2f[lambda-1]-Pf[lambda-2]*P2f[lambda+1])/4; + Ty=MY4*YP*P3f[lambda]; + } + else + { + if (lambda==1) Ry=(Pf[lambda+2]*P2f[lambda-1]+P2f[lambda+1])/4; + else Ry=(Pf[lambda+2]*P2f[lambda-1]-Pf[lambda-2]*P2f[lambda+1])/4; + Ty=YP*P3f[lambda]; + } + + if (degree(gcd(Ty-Ry))!=0) res=1; + if (degree(gcd(Ty+Ry))!=0) res=2; + if (res!=0) + { // has it doubled, or become point at infinity? + if (res==2) + { // it doubled - wrong sign + tau=(lp-tau)%lp; + cout << "\b\b\b"; + cout << setw(3) << (p+1-tau)%lp << flush; + } + t[i]=tau; + if ((p+1-tau)%lp==0) + { + cout << " ***" << endl; + if (search && (!Edwards || lp!=4)) escape=TRUE; + } + else cout << endl; + break; + } + cout << "\b\b\b"; + } + for (jj=0;jjlow) low=tau+3; + + if (tau%2==0) + { // 4 mod-muls + Rx=ZT2*(XPYP2*P2f[tau]-Pf[tau-1]*Pf[tau+1]); + Tx=XTYP2*P2f[tau]; + } + else + { // 4 mod-muls + Rx=(ZT2XP*P2f[tau]-ZT2YP2*Pf[tau-1]*Pf[tau+1]); + Tx=XT*P2f[tau]; + } + if (iszero(Rx-Tx)) + { // we have a result. Now compare Y's + if (tau%2==0) + { + Ry=ZT3YP*(Pf[tau+2]*P2f[tau-1]-Pf[tau-2]*P2f[tau+1]); + Ty=4*YT*YP4*P2f[tau]*Pf[tau]; + } + else + { + if (tau==1) Ry=ZT3YP*(Pf[tau+2]*P2f[tau-1]+P2f[tau+1]); + else Ry=ZT3YP*(Pf[tau+2]*P2f[tau-1]-Pf[tau-2]*P2f[tau+1]); + Ty=4*YT*P2f[tau]*Pf[tau]; + } + + if (iszero(Ry-Ty)) res=1; + else res=2; + } + + if (res!=0) + { // has it doubled, or become point at infinity? + if (res==2) + { // it doubled - wrong sign + tau=lp-tau; + cout << "\b\b\b"; + cout << setw(3) << (p+1-tau)%lp << flush; + } + t[i]=tau; + if ((p+1-tau)%lp==0) + { + cout << " ***" << endl; + if (search && (!Edwards || lp!=4)) escape=TRUE; + } + else cout << endl; + break; + } + cout << "\b\b\b"; + } + for (jj=0;jjIOBASE=16; + ofile << p << endl; + + ofile << a << endl; + ofile << b << endl; + // generate a random point on the curve + // point will be of prime order for "ideal" curve, otherwise any point + if (!Edwards) + { + do { + x=rand(p); + } while (!P.set(x,x)); + P.get(x,y); + ofile << nrp << endl; + } + else + { + ZZn X,Y,Z,R,TA,TB,TC,TD,TE; + forever + { + X=randn(); + R=(X*X-EB)/(X*X-EA); + if (!qr(R))continue; + Y=sqrt(R); + break; + } + Z=1; +// double point twice (4*P) + for (i=0;i<2;i++) + { + TA = X*X; + TB = Y*Y; + TC = TA+TB; + TD = TA-TB; + TE = (X+Y)*(X+Y)-TC; + + X = TC*TD; + Y = TE*(TC-2*EB*Z*Z); + Z = TD*TE; + } + X/=Z; + Y/=Z; + x=X; + y=Y; + ofile << nrp/4 << endl; + } + ofile << x << endl; + ofile << y << endl; + mip->IOBASE=10; + } + if (p==nrp) + { + cout << "WARNING: Curve is anomalous" << endl; + return 0; + } + + if (p+1==nrp) + { + cout << "WARNING: Curve is supersingular" << endl; + } + +// check MOV condition for curves of Cryptographic interest +// if (pbits<128) return 0; + + d=1; + for (i=1;i<50;i++) + { + d=modmult(d,p,nrp); + if (d==1) + { + if (i==1 || prime(nrp)) cout << "WARNING: Curve fails MOV condition - K = " << i << endl; + else cout << "WARNING: Curve fails MOV condition - K <= " << i << endl; + + return 0; + } + } + + return 0; +} + + diff --git a/miracl/source/curve/schoof.txt b/miracl/source/curve/schoof.txt new file mode 100644 index 0000000..f039126 --- /dev/null +++ b/miracl/source/curve/schoof.txt @@ -0,0 +1,29 @@ +To build the Schoof application, you must compile and link the modules +together, with MIRACL C++ classes, and with the MIRACL library. + +A precompiled Windows executable is available from +ftp://ftp.compapp.dcu.ie/pub/crypto/schoof.exe + +So for Borland C++ (although MS C++ is a fair bit quicker) + +bcc32 schoof.cpp poly.cpp polymod.cpp ecn.cpp big.cpp zzn.cpp crt.cpp +miracl.lib + +For Microsoft C++ + +cl /O2 /GX schoof.cpp poly.cpp polymod.cpp ecn.cpp big.cpp zzn.cpp crt.cpp miracl.lib + +On UNIX using g++, something like + +g++ -I. -c poly.cpp +g++ -I. -c polymod.cpp + + +g++ -I. schoof.cpp poly.o polymod.o big.o zzn.o ecn.o crt.o +miracl.a /usr/lib/libm.a -o schoof + +should work + +Note that the headers poly.h and polymod.h are assumed to be in +the local directiory + diff --git a/miracl/source/curve/schoof2.cpp b/miracl/source/curve/schoof2.cpp new file mode 100644 index 0000000..2c11472 --- /dev/null +++ b/miracl/source/curve/schoof2.cpp @@ -0,0 +1,1351 @@ +// Schoof's Original Algorithm - GF(2^m) Version! +// Mike Scott March 2000 mike@compapp.dcu.ie +// +// Counts points on GF(2^m) Elliptic Curve, y^2+xy = x^3+Ax^2+B a prerequisite +// for implementation of Elliptic Curve Cryptography +// +// The self-contained Windows Command Prompt executable for this program may +// obtained from ftp://ftp.computing.dcu.ie/pub/crypto/schoof2.exe +// +// Basic algorithm is due to Schoof +// "Elliptic Curves Over Finite Fields and the Computation of Square Roots +// mod p", Rene Schoof, Math. Comp., Vol. 44 pp 483-494 +// Another very useful reference particularly for GF(2^m) curves is +// "Elliptic Curve Public Key Cryptosystems", Menezes, +// Kluwer Academic Publishers, Chapter 7 +// Thanks are due to Richard Crandall for the tip about using prime powers +// +// ** +// This program implements Schoof's original algorithm, augmented by +// the use of prime powers. By finding the Number of Points mod the product +// of many small primes and large prime powers, the final search for NP is +// greatly speeded up. +// Final phase search uses Pollard Lambda ("kangaroo") algorithm +// This final phase effectively stretches the range of Schoof's +// algorithm by about 70-80 bits. +// This approach is only feasible due to the use of fast multiplication +// methods for large degree polynomial multiplication +// ** +// +// Ref "Monte Carlo Methods for Index Computation" +// by J.M. Pollard in Math. Comp. Vol. 32 1978 pp 918-924 +// +// An "ideal" curve is defined as one with with +// (i) 2*(a prime) number of points if trace(A)=1, or +// (ii) 4*(a prime) number of points if trace(A)=0. +// +// Note that the number of points on the curve is invariant if we substitute +// B by B^2 (this is trivial, but I haven't seen it anywhere). +// +// Proof: if (x,y) is a point on +// y^2+xy=x^3+Ax^2+B +// Then clearly (X,Y) = (x^2,y^2) is a point on +// y^4+x^2.y^2=x^6+Ax^4+B^2 (square both sides) +// +// so Y^2+XY=X^3+AX^2+B^2 +// +// When using the "schoof2" program, the -s option is particularly useful +// and allows automatic search for an "ideal" curve. If a curve order is +// exactly divisible by a small prime >2, that curve is immediately abandoned, +// and the program moves on to the next, incrementing the B parameter of +// the curve. This is a fairly arbitrary but simple way of moving on to +// the "next" curve (but note the point made above about B -> B^2). +// +// NOTE: The output file can be used directly with for example the ECDSA +// programs IF AND ONLY IF an ideal curve is found. If you wish to use +// a less-than-ideal curve, you will first have to factor NP completely, and +// find a random point of large prime order. +// +// This implementation is free. No terms, no conditions. It requires +// version 4.30 or greater of the MIRACL library (a Shareware, Commercial +// product, but free for non-profit making use), +// available from ftp://ftp.computing.dcu.ie/pub/crypto/miracl.zip +// +// However this program may be used (unmodified) to generate curves for +// commercial use. +// +// Revision history +// +// Timings for test curve Y^2+XY=X^3+X^2+52 mod 2^191 +// Pentium III 450MHz +// +// Rev. 0 - 45 minutes +// Rev. 1 - 41 minutes +// Rev. 2 - 36 minutes +// +// Note that a small speed-up can be obtained by using an integer-only +// build of MIRACL. See mirdef.hio +// +// Pentium III 450MHz +// +// GF(2^191) - 36 minutes +// GF(2^223) - 1.9 hours +// GF(2^251) - 4 hours +// GF(2^283) - 12.3 hours +// +// + +#include +#include +#include +#include +#include "ec2.h" // GF(2^m) Elliptic Curve Class +#include "crt.h" // Chinese Remainder Theorem Class + +// poly2.h implements polynomial arithmetic. Karatsuba multiplication is +// used for maximum speed, as the polynomials get very big. For example when +// searching for the curve cardinality mod the prime 31, the polynomials are +// of degree (31*31-1)/2 = 480. But all that gruesome detail is hidden away. +// +// poly2mod.h implements polynomial arithmetic wrt to a preset polynomial +// modulus. This looks a bit neater. Function setmod() sets the modulus +// to be used. + +#include "poly2.h" +#include "poly2mod.h" + +using namespace std; + +Miracl precision=12; // max. 12x32 bits per big number + +Poly2Mod MFX,XX; + +Big B; +Big D; +Big A; + +void elliptic_dup(Poly2Mod& X,Poly2Mod& Y,Poly2Mod& Yy,Poly2Mod& Z) +{ // point doubling + Poly2Mod W1,W2,W3,W4,W5y,W5; + + W1=(Z*Z); // Z^2 + W2=X*X; // X^2 + W3=W2*W2; // X^4 + + W4=X*W1; // =Z + + X=(X+D*W1); + X=X*X; + X=X*X; + + W5=W4+W2+Y*Z; + W5y=Yy*Z; + + Z=W4; + + Y=W3*Z+W5*X; + Yy=W5y*X; +} + +// +// This is addition formula for two distinct points on an elliptic curve +// Works with projective coordinates which are automatically reduced wrt a +// polynomial modulus +// Remember that the expression for the Y coordinate of each point +// is of the form A(x)+B(x).y +// We know Y^2=X^3+AX^2+B+XY, but we don't have an explicit expression for Y +// So if Y^2 ever crops up - substitute for it. + +void elliptic_add(Poly2Mod& XT,Poly2Mod& XTy,Poly2Mod& YT,Poly2Mod& YTy,Poly2Mod& ZT,Poly2Mod& X,Poly2Mod& Y,Poly2Mod& Yy) +{ // add (X,Y,Z) to (XT,YT,ZT) on an elliptic curve + // The point Y is of the form A(x)+B(x).y + + Poly2Mod ZT2,ZT3,W1,W2,W3,W4,W5,W5y,W6,W6y,W7,W8,W8y,W9,W9y; + + ZT2=(ZT*ZT); + + W3=XT+X*ZT2; + + ZT3=ZT2*ZT; + W5=ZT3*Y; + W5y=ZT3*Yy; + + W6=YT+W5; + W6y=YTy+W5y; + + if (iszero(W3)) + { + if (iszero(W6) && iszero(W6y)) + { // should have doubled! + elliptic_dup(XT,YT,YTy,ZT); + XTy=0; + return; + } + + ZT.clear(); + return; + } + + + ZT*=W3; + + W8=W6*X+ZT*Y; + W8y=W6y*X+ZT*Yy; + + W9=W6+ZT; + + W1=ZT*ZT; + W2=W6y*W6y; + + XT=A*W1+W3*W3*W3+W6*W9+W2*MFX; + XTy=W9*W6y+W6y*W6+W2*XX; + + W2=W6y*XTy; + + YT=W9*XT+W2*MFX+W8*W1; + YTy=XT*W6y+W9*XTy+W2*XX+W1*W8y; +} + +// +// Program to compute the order of a point on an elliptic curve +// using Pollard's lambda method for catching kangaroos. +// +// As a way of counting points on an elliptic curve, this +// has complexity O(p^(1/4)) +// +// However Schoof puts a spring in the step of the kangaroos +// allowing them to make bigger jumps, and lowering overall complexity +// to O(p^(1/4)/sqrt(L)) where L is the product of the Schoof primes +// +// See "Monte Carlo Methods for Index Computation" +// by J.M. Pollard in Math. Comp. Vol. 32 1978 pp 918-924 +// +// This code has been considerably speeded up using ideas from +// "Parallel Collision Search with Cryptographic Applications", J. Crypto., +// Vol. 12, 1-28, 1999 +// + +#define STORE 80 +#define HERD 5 + +EC2 wild[STORE],tame[STORE]; +Big wdist[STORE],tdist[STORE]; +int wname[STORE],tname[STORE]; + +Big kangaroo(Big p,Big order,Big ordermod,int TR,BOOL &found) +{ + EC2 ZERO,K[2*HERD],TE[2*HERD],X,P,G,table[50],trap; + Big start[2*HERD],txc,wxc,mean,leaps,upper,lower,middle,a,b,x,y,n,w,t,nrp; + int i,jj,j,m,sp,nw,nt,cw,ct,k,distinguished; + Big D[2*HERD],s,distance[50],real_order; + BOOL bad,collision,abort; + + found=FALSE; + forever + { + +// find a random point on the curve + do + { + x=rand(p); + } while (!P.set(x,x)); + lower=p+1-2*sqrt(p)-3; // lower limit of search + upper=p+1+2*sqrt(p)+3; // upper limit of search + + w=1+(upper-lower)/ordermod; + leaps=sqrt(w); + mean=HERD*leaps/2; // ideal mean for set S=1/2*w^(0.5) + distinguished=1<<(bits(leaps/16)); + + distinguished++; // powers of 2 create "resonances" with 2^m + // so bump it up to odd. + + for (s=1,m=1;;m++) + { /* find table size */ + distance[m-1]=s*ordermod; + s*=2; + if ((2*s/m)>mean) break; + } + table[0]=ordermod*P; + for (i=1;i1) + middle+=(ordermod+order-middle%ordermod); + + for (i=0;i=STORE) + { + abort=TRUE; + break; + } + cout << "." << flush; + tame[nt]=K[jj]; + tdist[nt]=D[jj]; + tname[nt]=jj; + for (k=0;k=STORE) + { + abort=TRUE; + break; + } + cout << "." << flush; + wild[nw]=K[jj]; + wdist[nw]=D[jj]; + wname[nw]=jj; + for (k=0;kPRIMES[i]; + if (sp==0) break; + if (real_order%sp==0) + { + G=P; + G*=(real_order/sp); + if (G==ZERO) + { + real_order/=sp; + continue; + } + } + i++; + } + if (real_order <= 4*sqrt(p)) + { + cout << "Low Order point used - trying again" << endl; + continue; + } + real_order=nrp; + for (i=0;(sp=get_mip()->PRIMES[i])!=0;i++) + while (real_order%sp==0) real_order/=sp; + if (real_order==1) + { // all factors of nrp were considered + cout << "NP= " << nrp << endl; + break; + } + if (prime(real_order)) + { // all factors of NP except for one last one.... + G=P; + G*=(nrp/real_order); + if (G==ZERO) + { + cout << "Failed - trying again" << endl; + continue; + } + else + { + cout << "NP= " << nrp << endl; + break; + } + } + +// Couldn't be bothered factoring nrp completely +// Probably not an interesting curve for Cryptographic purposes anyway..... +// But if 20 random points are all "killed" by nrp, its almost +// certain to be the true NP, and not a multiple of a small order. + + bad=FALSE; + for (i=0;i<20;i++) + { + do + { + x=rand(p); + } while (!P.set(x,x)); + G=P; + G*=nrp; + if (G!=ZERO) + { + bad=TRUE; + break; + } + } + if (bad) + { + cout << "Failed - trying again" << endl; + continue; + } + cout << "NP is composite and not ideal for Cryptographic use" << endl; + cout << "NP= " << nrp << " (probably)" << endl; + break; + } + return nrp; +} + +int qpow(int x,int y) +{ // quick and dirty power function + int r=x; + for (int i=1;i " << endl << endl; + cout << "e.g. schoof2 1 52 191 9" << endl << endl; + cout << "To input A and B in Hex, precede with -h" << endl; + cout << "To output to a file, use flag -o " << endl; + cout << "To search for NP a near-prime, incrementing B, use flag -s" << endl; + cout << "\nFreeware from Certivox, Dublin, Ireland" << endl; + cout << "Full C++ source code and MIRACL multiprecision library available" << endl; + cout << "email mscott@indigo.ie" << endl; + return 0; + } + + ip=0; + gprime(10000); // generate small primes < 1000 + search=fout=gotM=gotA=gotB=gota=gotb=gotc=FALSE; + M=a=b=c=0; + +// Interpret command line + Base=10; + while (ipIOBASE=Base; + aa=argv[ip++]; + mip->IOBASE=10; + gotA=TRUE; + continue; + } + if (!gotB) + { + mip->IOBASE=Base; + bb=argv[ip++]; + mip->IOBASE=10; + gotB=TRUE; + continue; + } + if (!gotM) + { + M=atoi(argv[ip++]); + gotM=TRUE; + continue; + } + if (!gota) + { + a=atoi(argv[ip++]); + gota=TRUE; + continue; + } + if (!gotb) + { + b=atoi(argv[ip++]); + gotb=TRUE; + continue; + } + if (!gotc) + { + c=atoi(argv[ip++]); + gotc=TRUE; + continue; + } + cout << "Error in command line" << endl; + return 0; + } + + if ((!gotM || !gotA || !gotB) || a==0) + { + cout << "Error in command line" << endl; + return 0; + } + +// loop for "-s" search option + p=pow((Big)2,M); + forever { + + A=aa; + if (bb>=p) bb%=p; + + B=bb; + if (!ecurve2(M,a,b,c,A,B,TRUE,MR_AFFINE)) // initialise Elliptic Curve + { + cout << "Illegal Curve Parameters" << endl; + return 0; + } + +// D=mip->C; + GF2m At=B; + for (i=1;iPRIMES[i]; + + int start_prime; // start of primes & largest prime powers + for (i=0;;i++) + { + if (pp[i]!=1) + { + int p=qpow(l[i],pp[i]); + for (j=0;l[j]

IOBASE=128; + cinstr(m,text); + + mip->IOBASE=10; + do + { + bigbits(160,k); + } while (egcd(k,p1,t)!=1); + powltr(3,k,p,a); /* a=3^k mod p */ + powmod(y,k,p,b); + mad(b,m,m,p,p,b); /* b=m*y^k mod p */ + printf("Ciphertext= \n"); + cotnum(a,stdout); + cotnum(b,stdout); + + zero(m); /* proof of pudding... */ + + subtract(p1,x,t); + powmod(a,t,p,m); + mad(m,b,b,p,p,m); /* m=b/a^x mod p */ + + printf("Plaintext= \n"); + mip->IOBASE=128; + cotnum(m,stdout); + mip->IOBASE=10; + +/* RSA. Generate primes p & q. Use e=65537, and find d=1/e mod (p-1)(q-1) */ + + printf("\nNow generating 512-bit random primes p and q\n"); + do + { + bigbits(512,p); + if (subdivisible(p,2)) incr(p,1,p); + while (!isprime(p)) incr(p,2,p); + + bigbits(512,q); + if (subdivisible(q,2)) incr(q,1,q); + while (!isprime(q)) incr(q,2,q); + + multiply(p,q,n); /* n=p.q */ + + lgconv(65537L,e); + decr(p,1,p1); + decr(q,1,q1); + multiply(p1,q1,phi); /* phi =(p-1)*(q-1) */ + } while (xgcd(e,phi,d,d,t)!=1); + + cotnum(p,stdout); + cotnum(q,stdout); + printf("n = p.q = \n"); + cotnum(n,stdout); + +/* set up for chinese remainder thereom */ +/* primes[0]=p; + primes[1]=q; + crt_init(&ch,2,primes); +*/ + +/* use simple CRT as only two primes */ + + xgcd(p,q,inv,inv,inv); /* 1/p mod q */ + + copy(d,dp); + copy(d,dq); + divide(dp,p1,p1); /* dp=d mod p-1 */ + divide(dq,q1,q1); /* dq=d mod q-1 */ + mip->IOBASE=128; + cinstr(m,text); + mip->IOBASE=10; + printf("Encrypting test string\n"); + powmod(m,e,n,c); + printf("Ciphertext= \n"); + cotnum(c,stdout); + + zero(m); + + printf("Decrypting test string\n"); + + powmod(c,dp,p,pm[0]); /* get result mod p */ + powmod(c,dq,q,pm[1]); /* get result mod q */ + + subtract(pm[1],pm[0],pm[1]); /* poor man's CRT */ + mad(inv,pm[1],inv,q,q,m); + multiply(m,p,m); + add(m,pm[0],m); + +/* crt(&ch,pm,m); combine them using CRT */ + + printf("Plaintext= \n"); + mip->IOBASE=128; + cotnum(m,stdout); +/* crt_end(&ch); */ + return 0; +} + diff --git a/miracl/source/pk-demo.cpp b/miracl/source/pk-demo.cpp new file mode 100644 index 0000000..c9010e0 --- /dev/null +++ b/miracl/source/pk-demo.cpp @@ -0,0 +1,211 @@ +/* + * Example program demonstrates 1024 bit Diffie-Hellman, El Gamal and RSA + * and 168 bit Elliptic Curve Diffie-Hellman + * + * Requires: big.cpp ecn.cpp + */ + +#include +#include "ecn.h" +#include "big.h" +#include + +//using namespace std; + +/* large 1024 bit prime p for which (p-1)/2 is also prime */ +char *primetext=(char *) +"155315526351482395991155996351231807220169644828378937433223838972232518351958838087073321845624756550146945246003790108045940383194773439496051917019892370102341378990113959561895891019716873290512815434724157588460613638202017020672756091067223336194394910765309830876066246480156617492164140095427773547319"; + +/* NIST p192 bit elliptic curve prime 2#192-2#64-1 */ + +char *ecp=(char *)"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"; + +/* elliptic curve parameter B */ + +char *ecb=(char *)"64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1"; + +/* elliptic curve - point of prime order (x,y) */ + +char *ecx=(char *)"188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"; +char *ecy=(char *)"07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"; + +char *text=(char *)"MIRACL - Best multi-precision library in the World!\n"; + +#ifndef MR_NOFULLWIDTH +Miracl precision(50,0); +#else +Miracl precision(50,MAXBASE); +#endif + +// If MR_STATIC is defined in mirdef.h, it is assumed to be 100 + +//Miracl precision(120,(1<<26)); + +int main() +{ + int ia,ib; + time_t seed; + Big a,b,p,q,n,phi,pa,pb,key,e,d,m,c,x,y,k,inv,t; + Big primes[2],pm[2]; + ECn g,ea,eb; + miracl *mip=&precision; + + time(&seed); + irand((long)seed); /* change parameter for different values */ + + cout << "First Diffie-Hellman Key exchange .... " << endl; + + p=primetext; + +/* offline calculations could be done quicker using Comb method + - See brick.cpp. Note use of "truncated exponent" of 160 bits - + could be output from hash function SHA (see mrshs.c) */ + + cout << "\nAlice's offline calculation" << endl; + a=rand(160,2); + +/* 3 generates the prime sub-group of size (p-1)/2 */ + + pa=pow(3,a,p); // pa =3^a mod p + + cout << "Bob's offline calculation" << endl; + b=rand(160,2); + pb=pow(3,b,p); + + cout << "Alice calculates Key=" << endl; + key=pow(pb,a,p); + cout << key << endl; + + cout << "Bob calculates Key=" << endl; + key=pow(pa,b,p); + cout << key << endl; + + cout << "Alice and Bob's keys should be the same!" << endl; + +/* + Now Elliptic Curve version of the above. + Curve is y^2=x^3+Ax+B mod p, where A=-3, B and p as above + "Primitive root" is the point (x,y) above, which is of large prime order q. + In this case actually + q=FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831 + +*/ + cout << "\nLets try that again using elliptic curves...." << endl; + a=-3; + mip->IOBASE=16; + b=ecb; + p=ecp; + ecurve(a,b,p,MR_BEST); // means use PROJECTIVE if possible, else AFFINE coordinates + x=ecx; + y=ecy; + mip->IOBASE=10; + g=ECn(x,y); + ea=eb=g; + + cout << "Alice's offline calculation" << endl; + a=rand(160,2); + ea*=a; + ia=ea.get(pa); /* is compressed form of public key */ + + cout << "Bob's offline calculation" << endl; + b=rand(160,2); + eb*=b; + ib=eb.get(pb); /* is compressed form of public key */ + + cout << "Alice calculates Key=" << endl; + eb=ECn(pb,ib); /* decompress eb */ + eb*=a; + eb.get(key); + cout << key << endl; + + cout << "Bob calculates Key=" << endl; + ea=ECn(pa,ia); /* decompress ea */ + ea*=b; + ea.get(key); + cout << key << endl; + + cout << "Alice and Bob's keys should be the same! (but much smaller)" << endl; + + +/* El Gamal's Method */ + + cout << "\nTesting El Gamal's public key method" << endl; + p=primetext; + x=rand(160,2); + y=pow(3,x,p); + do + { + k=rand(160,2); + } while (gcd(p-1,k)!=1); + + mip->IOBASE=256; + a=pow(3,k,p); + b=modmult(pow(y,k,p),(Big)text,p); + mip->IOBASE=10; + cout << "Ciphertext= \n" << a << "\n" << b << endl; + + m=modmult(b,pow(a,p-1-x,p),p); + mip->IOBASE=256; + cout << "Plaintext= \n" << m << endl; + mip->IOBASE=10; + +/* RSA. Generate primes p & q. Use e=65537, and find d=1/e mod (p-1)(q-1) */ + + cout << "\nNow generating 512-bit random primes p and q" << endl; + for(;;) + { + p=rand(512,2); // random 512 bit number + if (p%2==0) p+=1; + while (!prime(p)) p+=2; + + q=rand(512,2); + if (q%2==0) q+=1; + while (!prime(q)) q+=2; + + n=p*q; + + e=65537; + phi=(p-1)*(q-1); + if (gcd(e,phi)!=1) continue; + d=inverse(e,phi); + break; + } + cout << p << endl; + cout << q << endl; + cout << "n = p.q = \n"; + cout << n << endl; + +/* set up for chinese remainder thereom */ + +// primes[0]=p; +// primes[1]=q; + +// Crt chinese(2,primes); + + inv=inverse(p,q); // precalculate this + + mip->IOBASE=256; + + cout << "Encrypting test string" << endl; + c=pow((Big)text,e,n); // c=m^e mod n + mip->IOBASE=10; + cout << "Ciphertext= \n"; + cout << c << endl; + + cout << "Decrypting test string" << endl; + + pm[0]=pow(c%p,d%(p-1),p); /* get result mod p */ + pm[1]=pow(c%q,d%(q-1),q); /* get result mod q */ + + t=modmult(inv,pm[1]-pm[0],q); // use CRT in simple way, as only 2 primes + m=t*p+pm[0]; + + // m=chinese.eval(pm); /* combine them using CRT */ + + mip->IOBASE=256; + cout << "Plaintext= \n"; + cout << m << endl; + return 0; +} + + diff --git a/miracl/source/pm.cpp b/miracl/source/pm.cpp new file mode 100644 index 0000000..7918cb2 --- /dev/null +++ b/miracl/source/pm.cpp @@ -0,0 +1,26 @@ +/* + * Simple program to find pseudo-mersenne primes + */ + +#include +#include "big.h" + +using namespace std; + +Miracl precision=100; + +int main() +{ + int i,w; + Big p; + + for (i=112;i<=256;i+=8) + { + p=pow((Big)2,i); + p=p-1; w=1; + while (p%4!=3 || !prime(p)) {p-=1; w++;} + cout << "2^" << i << "-" << w << " is a prime" << endl; + } + + return 0; +} diff --git a/miracl/source/pm112.ecs b/miracl/source/pm112.ecs new file mode 100644 index 0000000..e10f96f --- /dev/null +++ b/miracl/source/pm112.ecs @@ -0,0 +1,7 @@ +112 +FFFFFFFFFFFFFFFFFFFFFFFFFF43 +-3 +95 +1000000000000012C7BC5597F06E9 +96A0C1B4DFA5D4C440A18D75404A +5A1DD6900A5F8364080CE10B3B04 diff --git a/miracl/source/pm128.ecs b/miracl/source/pm128.ecs new file mode 100644 index 0000000..9fba81d --- /dev/null +++ b/miracl/source/pm128.ecs @@ -0,0 +1,7 @@ +128 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF53 +-3 +296 +10000000000000001DC2477C699BA68EB +485FB797EE2A8423D648BA1CC787B2DA +CFB112182C0E946DEFDCD04A2153B950 diff --git a/miracl/source/pm160.ecs b/miracl/source/pm160.ecs new file mode 100644 index 0000000..f82fdd0 --- /dev/null +++ b/miracl/source/pm160.ecs @@ -0,0 +1,7 @@ +160 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 +-3 +17F +FFFFFFFFFFFFFFFFFFFF0E3F01A04F4B717F3225 +A8ADC5EED594E2009B7D04AD027BFEEB75666F1 +20FB2D5CAF7643D3AC4D389F111C6CCC5545C9DA diff --git a/miracl/source/pollard.c b/miracl/source/pollard.c new file mode 100644 index 0000000..f0d5ae8 --- /dev/null +++ b/miracl/source/pollard.c @@ -0,0 +1,171 @@ +/* + * Program to factor big numbers using Pollards (p-1) method. + * Works when for some prime divisor p of n, p-1 has itself + * only small factors. + * See "Speeding the Pollard and Elliptic Curve Methods" + * by Peter Montgomery, Math. Comp. Vol. 48 Jan. 1987 pp243-264 + * + */ + +#include +#include +#include "miracl.h" + +#define LIMIT1 10000 /* must be int, and > MULT/2 */ +#define LIMIT2 1000000L /* may be long */ +#define MULT 2310 /* must be int, product of small primes 2.3.. */ +#define NEXT 13 /* next small prime */ + +miracl *mip; +static BOOL plus[1+MULT/2],minus[1+MULT/2]; + +void marks(long start) +{ /* mark non-primes in this interval. Note * + * that those < NEXT are dealt with already */ + int i,pr,j,k; + for (j=1;j<=MULT/2;j+=2) plus[j]=minus[j]=TRUE; + for (i=0;;i++) + { /* mark in both directions */ + pr=mip->PRIMES[i]; + if (prstart) break; + k=pr-start%pr; + for (j=k;j<=MULT/2;j+=pr) + plus[j]=FALSE; + k=start%pr; + for (j=k;j<=MULT/2;j+=pr) + minus[j]=FALSE; + } +} + +int main() +{ /* factoring program using Pollards (p-1) method */ + long i,p,pa,interval; + big n,t,b,bw,bvw,bd,bp,q; + static big bu[1+MULT/2]; + static BOOL cp[1+MULT/2]; + int phase,m,pos,btch,iv; + mip=mirsys(30,0); + n=mirvar(0); + t=mirvar(0); + b=mirvar(0); + q=mirvar(0); + bw=mirvar(0); + bvw=mirvar(0); + bd=mirvar(0); + bp=mirvar(0); + gprime(LIMIT1); + for (m=1;m<=MULT/2;m+=2) + if (igcd(MULT,m)==1) + { + bu[m]=mirvar(0); + cp[m]=TRUE; + } + else cp[m]=FALSE; + printf("input number to be factored\n"); + cinnum(n,stdin); + if (isprime(n)) + { + printf("this number is prime!\n"); + return 0; + } + phase=1; + p=0; + btch=50; + i=0; + convert(2,b); /* if "degenerate case" comes up (see below) try 3 */ + printf("phase 1 - trying all primes less than %d\n",LIMIT1); + printf("prime= %8ld",p); + forever + { + if (phase==1) + { /* looking for all factors of (p-1) < LIMIT1 */ + p=mip->PRIMES[i]; + if (mip->PRIMES[i+1]==0) + { + phase=2; + printf("\nphase 2 - trying last prime less than %ld\n" + ,LIMIT2); + printf("prime= %8ld",p); + power(b,8,n,bw); + convert(1,t); + copy(b,bp); + copy(b,bu[1]); + for (m=3;m<=MULT/2;m+=2) + { /* store bu[m] = b^(m*m) */ + mad(t,bw,bw,n,n,t); + mad(bp,t,t,n,n,bp); + if (cp[m]) copy(bp,bu[m]); + } + power(b,MULT,n,t); + power(t,MULT,n,t); + mad(t,t,t,n,n,bd); /* bd=b^(2*MULT*MULT) */ + iv=(int)(p/MULT); + if (p%MULT>MULT/2) iv++; + interval=(long)iv*MULT; + p=interval+1; + marks(interval); + power(t,2*iv-1,n,bw); + power(t,iv,n,bvw); + power(bvw,iv,n,bvw); /* bvw = b^(MULT*MULT*iv*iv) */ + subtract(bvw,bu[p%MULT],q); + btch*=100; + i++; + continue; + } + pa=p; + while ((LIMIT1/p) > pa) pa*=p; + power(b,(int)pa,n,b); + decr(b,1,q); + } + else + { /* looking for last prime factor of (p-1) < LIMIT2 */ + p+=2; + pos=(int)(p%MULT); + if (pos>MULT/2) + { /* increment giant step */ + iv++; + interval=(long)iv*MULT; + p=interval+1; + marks(interval); + pos=1; + mad(bw,bd,bd,n,n,bw); + mad(bvw,bw,bw,n,n,bvw); + } + if (!cp[pos]) continue; + + /* if neither interval+/-pos is prime, don't bother */ + if (!plus[pos] && !minus[pos]) continue; + subtract(bvw,bu[pos],t); + mad(q,t,t,n,n,q); /* batching gcds */ + } + if (i++%btch==0) + { /* try for a solution */ + printf("\b\b\b\b\b\b\b\b%8ld",p); + fflush(stdout); + egcd(q,n,t); + if (size(t)==1) + { + if (p>LIMIT2) break; + else continue; + } + if (mr_compare(t,n)==0) + { + printf("\ndegenerate case"); + break; + } + printf("\nfactors are\n"); + if (isprime(t)) printf("prime factor "); + else printf("composite factor "); + cotnum(t,stdout); + divide(n,t,n); + if (isprime(n)) printf("prime factor "); + else printf("composite factor "); + cotnum(n,stdout); + return 0; + } + } + printf("\nfailed to factor\n"); + return 0; +} + diff --git a/miracl/source/pollard.cpp b/miracl/source/pollard.cpp new file mode 100644 index 0000000..b046600 --- /dev/null +++ b/miracl/source/pollard.cpp @@ -0,0 +1,171 @@ +/* + * Program to factor big numbers using Pollards (p-1) method. + * Works when for some prime divisor p of n, p-1 has only + * small factors. + * See "Speeding the Pollard and Elliptic Curve Methods" + * by Peter Montgomery, Math. Comp. Vol. 48 Jan. 1987 pp243-264 + * + * Requires: big.cpp zzn.cpp + */ + +#include +#include +#include "zzn.h" + +using namespace std; + +#define LIMIT1 10000 /* must be int, and > MULT/2 */ +#define LIMIT2 2000000L /* may be long */ +#define MULT 2310 /* must be int, product of small primes 2.3.. */ +#define NEXT 13 /* next small prime */ + +Miracl precision=50; /* number of ints per ZZn */ + +miracl *mip; +static long p; +static int iv; +static ZZn b,bw,bvw,bd,q,bu[1+MULT/2]; +static BOOL cp[1+MULT/2],Plus[1+MULT/2],Minus[1+MULT/2]; + +void marks(long start) +{ /* mark non-primes in this interval. Note * + * that those < NEXT are dealt with already */ + int i,pr,j,k; + for (j=1;j<=MULT/2;j+=2) Plus[j]=Minus[j]=TRUE; + for (i=0;;i++) + { /* mark in both directions */ + pr=mip->PRIMES[i]; + if (prstart) break; + k=pr-start%pr; + for (j=k;j<=MULT/2;j+=pr) + Plus[j]=FALSE; + k=start%pr; + for (j=k;j<=MULT/2;j+=pr) + Minus[j]=FALSE; + } +} + + +void next_phase() +{ /* now changing gear */ + ZZn bp,t; + long interval; + bw=pow(b,8); + t=1; + bp=bu[1]=b; + for (int m=3;m<=MULT/2;m+=2) + { /* store bu[m] = b^(m*m) */ + t*=bw; + bp*=t; + if (cp[m]) bu[m]=bp; + } + t=pow(b,MULT); + t=pow(t,MULT); + bd=t*t; /* bd = b^(2*MULT*MULT) */ + iv=p/MULT; + if (p%MULT>MULT/2) iv++; + interval=(long)iv*MULT; + p=interval+1; + marks(interval); + bw=pow(t,(2*iv-1)); + bvw=pow(t,iv); + bvw=pow(bvw,iv); /* bvw = b^(MULT*MULT*iv*iv) */ + q=bvw-bu[p%MULT]; +} + +int giant_step() +{ /* increment giant step */ + long interval; + iv++; + interval=(long)iv*MULT; + p=interval+1; + marks(interval); + bw*=bd; + bvw*=bw; + return 1; +} + +int main() +{ /* factoring program using Pollards (p-1) method */ + int phase,m,pos,btch; + long i,pa; + Big n,t; + mip=&precision; + gprime(LIMIT1); + for (m=1;m<=MULT/2;m+=2) + if (igcd(MULT,m)==1) cp[m]=TRUE; + else cp[m]=FALSE; + cout << "input number to be factored\n"; + cin >> n; + if (prime(n)) + { + cout << "this number is prime!\n"; + return 0; + } + modulo(n); /* do all arithmetic mod n */ + phase=1; + p=0; + btch=50; + i=0; + b=2; + cout << "phase 1 - trying all primes less than " << LIMIT1; + cout << "\nprime= " << setw(8) << p; + forever + { /* main loop */ + if (phase==1) + { /* looking for all factors of (p-1) < LIMIT1 */ + p=mip->PRIMES[i]; + if (mip->PRIMES[i+1]==0) + { + phase=2; + cout << "\nphase 2 - trying last prime less than "; + cout << LIMIT2 << "\nprime= " << setw(8) << p; + next_phase(); + btch*=100; + i++; + continue; + } + pa=p; + while ((LIMIT1/p) > pa) pa*=p; + b=pow(b,(int)pa); /* b = b^pa mod n */ + q=b-1; + } + else + { /* looking for last prime factor of (p-1) < LIMIT2 */ + p+=2; + pos=p%MULT; + if (pos>MULT/2) pos=giant_step(); + + /* if neither interval+/-pos is prime, don't bother */ + if (!Plus[pos] && !Minus[pos]) continue; + if (!cp[pos]) continue; + q*=(bvw-bu[pos]); /* batch gcd's in q */ + } + if (i++%btch==0) + { /* try for a solution */ + cout << "\b\b\b\b\b\b\b\b" << setw(8) << p << flush; + t=gcd((Big)q,n); + if (t==1) + { + if (p>LIMIT2) break; + else continue; + } + if (t==n) + { + cout << "\ndegenerate case"; + break; + } + if (prime(t)) cout << "\nprime factor " << t; + else cout << "\ncomposite factor " << t; + n/=t; + if (prime(n)) cout << "\nprime factor " << n; + else cout << "\ncomposite factor " << n; + cout << endl; + return 0; + } + } + cout << "\nfailed to factor\n"; + return 0; +} + diff --git a/miracl/source/qsieve.c b/miracl/source/qsieve.c new file mode 100644 index 0000000..e083b52 --- /dev/null +++ b/miracl/source/qsieve.c @@ -0,0 +1,531 @@ +/* + * Program to factor big numbers using Pomerance-Silverman-Montgomery + * multiple polynomial quadratic sieve. + * See "The Multiple Polynomial Quadratic Sieve", R.D. Silverman, + * Math. Comp. Vol. 48, 177, Jan. 1987, pp329-339 + */ + +#include +#include +#include +#include "miracl.h" + +#define SSIZE 100000 /* Maximum sieve size */ + +static big NN,TT,DD,RR,VV,PP,XX,YY,DG,IG,AA,BB; +static big *x,*y,*z,*w; +static unsigned int **EE,**G; +static int *epr,*r1,*r2,*rp,*b,*pr,*e,*hash; +static unsigned char *logp,*sieve; +static int mm,mlf,jj,nbts,nlp,lp,hmod,hmod2; +static BOOL partial; +static miracl *mip; + +int knuth(int mm,int *epr,big N,big D) +{ /* Input number to be factored N and find best multiplier k * + * for use over a factor base epr[] of size mm. Set D=k.N. */ + double dp,fks,top; + BOOL found; + int i,j,bk,nk,kk,r,p; + static int K[]={0,1,2,3,5,6,7,10,11,13,14,15,17,0}; + top=(-10.0e0); + found=FALSE; + nk=0; + bk=0; + epr[0]=1; + epr[1]=2; + do + { /* search for best Knuth-Schroepel multiplier */ + kk=K[++nk]; + if (kk==0) + { /* finished */ + kk=K[bk]; + found=TRUE; + } + premult(N,kk,D); + fks=log(2.0e0)/(2.0e0); + r=remain(D,8); + if (r==1) fks*=(4.0e0); + if (r==5) fks*=(2.0e0); + fks-=log((double)kk)/(2.0e0); + i=0; + j=1; + while (jPRIMES[++i]; + r=remain(D,p); + if (spmd(r,(p-1)/2,p)<=1) + { /* use only if Jacobi symbol = 0 or 1 */ + epr[++j]=p; + dp=(double)p; + if (kk%p==0) fks+=log(dp)/dp; + else fks+=2*log(dp)/(dp-1.0e0); + } + } + if (fks>top) + { /* find biggest fks */ + top=fks; + bk=nk; + } + } while (!found); + return kk; +} + +BOOL factored(long lptr,big T) +{ /* factor quadratic residue */ + BOOL facted; + int i,j,r,st; + partial=FALSE; + facted=FALSE; + for (j=1;j<=mm;j++) + { /* now attempt complete factorisation of T */ + r=(int)(lptr%epr[j]); + if (r<0) r+=epr[j]; + if (r!=r1[j] && r!=r2[j]) continue; + while (subdiv(T,epr[j],XX)==0) + { /* cast out epr[j] */ + e[j]++; + copy(XX,T); + } + st=size(T); + if (st==1) + { + facted=TRUE; + break; + } + if (size(XX)<=epr[j]) + { /* st is prime < epr[mm]^2 */ + if (st>=MR_TOOBIG || (st/epr[mm])>(1+mlf/50)) break; + if (st<=epr[mm]) + for (i=j;i<=mm;i++) + if (st==epr[i]) + { + e[i]++; + facted=TRUE; + break; + } + if (facted) break; + lp=st; /* factored with large prime */ + partial=TRUE; + facted=TRUE; + break; + } + } + return facted; +} + +BOOL gotcha(void) +{ /* use new factorisation */ + int r,j,i,k,n,rb,had,hp; + unsigned int t; + BOOL found; + found=TRUE; + if (partial) + { /* check partial factorisation for usefulness */ + had=lp%hmod; + forever + { /* hash search for matching large prime */ + hp=hash[had]; + if (hp<0) + { /* failed to find match */ + found=FALSE; + break; + } + if (pr[hp]==lp) break; /* hash hit! */ + had=(had+(hmod2-lp%hmod2))%hmod; + } + if (!found && nlp>=mlf) return FALSE; + } + copy(PP,XX); + convert(1,YY); + for (k=1;k<=mm;k++) + { /* build up square part in YY * + * reducing e[k] to 0s and 1s */ + if (e[k]<2) continue; + r=e[k]/2; + e[k]%=2; + expint(epr[k],r,TT); + multiply(TT,YY,YY); + } +/* debug only + printf("\nX= "); + cotnum(XX,stdout); + printf("Y= "); + cotnum(YY,stdout); + if (e[0]==1) printf("-1"); + else printf("1"); + for (k=1;k<=mm;k++) + { + if (e[k]==0) continue; + printf(".%d",epr[k]); + } + if (partial) printf(".%d\n",lp); + else printf("\n"); +*/ + if (partial) + { /* factored with large prime */ + if (!found) + { /* store new partial factorization */ + hash[had]=nlp; + pr[nlp]=lp; + copy(XX,z[nlp]); + copy(YY,w[nlp]); + for (n=0,rb=0,j=0;j<=mm;j++) + { + G[nlp][n]|=((e[j]&1)<>rb); + e[j]+=(t&1); + if (e[j]==2) + { + premult(YY,epr[j],YY); + divide(YY,NN,NN); + e[j]=0; + } + if (++rb==nbts) n++,rb=0; + } + premult(YY,lp,YY); + divide(YY,NN,NN); + } + } + else + { + printf("\b\b\b\b\b\b "); + fflush(stdout); + } + if (found) + { + for (k=mm;k>=0;k--) + { /* use new factorization in search for solution */ + if (e[k]%2==0) continue; + if (b[k]<0) + { /* no solution this time */ + found=FALSE; + break; + } + i=b[k]; + mad(XX,x[i],XX,NN,NN,XX); /* This is very inefficient - */ + mad(YY,y[i],YY,NN,NN,YY); /* There must be a better way! */ + for (n=0,rb=0,j=0;j<=mm;j++) + { /* Gaussian elimination */ + t=(EE[i][n]>>rb); + e[j]+=(t&1); + if (++rb==nbts) n++,rb=0; + } + } + for (j=0;j<=mm;j++) + { /* update YY */ + if (e[j]<2) continue; + convert(epr[j],TT); + power(TT,e[j]/2,NN,TT); + mad(YY,TT,YY,NN,NN,YY); + } + if (!found) + { /* store details in E, x and y for later */ + b[k]=jj; + copy(XX,x[jj]); + copy(YY,y[jj]); + for (n=0,rb=0,j=0;j<=mm;j++) + { + EE[jj][n]|=((e[j]&1)<20) mm=(d*d*d*d)/4096; + +/* only half the primes (on average) wil be used, so generate twice as + many (+ a bit for luck) */ + + dp=(double)2*(double)(mm+100); /* number of primes to generate */ + maxp=(int)(dp*(log(dp*log(dp)))); /* Rossers upper bound */ + gprime(maxp); + + epr=(int *)mr_alloc(mm+1,sizeof(int)); + + k=knuth(mm,epr,NN,DD); + + if (nroot(DD,2,RR)) + { + printf("%dN is a perfect square!\n",k); + printf("factors are\n"); + if (isprime(RR)) printf("prime factor "); + else printf("composite factor "); + cotnum(RR,stdout); + divide(NN,RR,NN); + if (isprime(NN)) printf("prime factor "); + else printf("composite factor "); + cotnum(NN,stdout); + return (-1); + } + + printf("using multiplier k= %d\n",k); + printf("and %d small primes as factor base\n",mm); + gprime(0); /* reclaim PRIMES space */ + + mlf=2*mm; + +/* now get space for arrays */ + + r1=(int *)mr_alloc((mm+1),sizeof(int)); + r2=(int *)mr_alloc((mm+1),sizeof(int)); + rp=(int *)mr_alloc((mm+1),sizeof(int)); + b=(int *)mr_alloc((mm+1),sizeof(int)); + e=(int *)mr_alloc((mm+1),sizeof(int)); + + logp=(unsigned char *)mr_alloc(mm+1,1); + + pr=(int *)mr_alloc((mlf+1),sizeof(int)); + hash=(int *)mr_alloc((2*mlf+1),sizeof(int)); + + sieve=(unsigned char *)mr_alloc(SSIZE+1,1); + + x=(big *)mr_alloc(mm+1,sizeof(big *)); + y=(big *)mr_alloc(mm+1,sizeof(big *)); + z=(big *)mr_alloc(mlf+1,sizeof(big *)); + w=(big *)mr_alloc(mlf+1,sizeof(big *)); + + for (i=0;i<=mm;i++) + { + x[i]=mirvar(0); + y[i]=mirvar(0); + } + for (i=0;i<=mlf;i++) + { + z[i]=mirvar(0); + w[i]=mirvar(0); + } + + EE=(unsigned int **)mr_alloc(mm+1,sizeof(unsigned int *)); + G=(unsigned int **)mr_alloc(mlf+1,sizeof(unsigned int *)); + + pak=1+mm/(8*sizeof(int)); + for (i=0;i<=mm;i++) + { + b[i]=(-1); + EE[i]=(unsigned int *)mr_alloc(pak,sizeof(int)); + } + + for (i=0;i<=mlf;i++) + G[i]=(unsigned int *)mr_alloc(pak,sizeof(int)); + return 1; +} + +int main() +{ /* factoring via quadratic sieve */ + unsigned int i,j,a,*SV; + unsigned char logpi; + int k,S,r,s1,s2,s,NS,logm,ptr,threshold,epri; + long M,la,lptr; +#ifndef MR_FULLWIDTH + mip=mirsys(-36,0); +#else + mip=mirsys(-36,MAXBASE); +#endif + if (initv()<0) return 0; + + hmod=2*mlf+1; /* set up hash table */ + convert(hmod,TT); + while (!isprime(TT)) decr(TT,2,TT); + hmod=size(TT); + hmod2=hmod-2; + for (k=0;k0) logm++; /* logm = log(M) */ + rp[0]=logp[0]=0; + for (k=1;k<=mm;k++) + { /* find root mod each prime, and approx log of each prime */ + r=subdiv(DD,epr[k],TT); + rp[k]=sqrmp(r,epr[k]); + logp[k]=0; + r=epr[k]; + while((r/=2)>0) logp[k]++; + } + r=subdiv(DD,8,TT); /* take special care of 2 */ + if (r==5) logp[1]++; + if (r==1) logp[1]+=2; + + threshold=logm+logb2(RR)-2*logp[mm]; + + jj=0; + nlp=0; + premult(DD,2,DG); + nroot(DG,2,DG); + + lgconv(M,TT); + divide(DG,TT,DG); + nroot(DG,2,DG); + if (subdiv(DG,2,TT)==0) incr(DG,1,DG); + if (subdiv(DG,4,TT)==1) incr(DG,2,DG); + printf("working... 0"); + + forever + { /* try a new polynomial */ + r=mip->NTRY; + mip->NTRY=1; /* speed up search for prime */ + do + { /* looking for suitable prime DG = 3 mod 4 */ + do { + incr(DG,4,DG); + } while(!isprime(DG)); + decr(DG,1,TT); + subdiv(TT,2,TT); + powmod(DD,TT,DG,TT); /* check D is quad residue */ + } while (size(TT)!=1); + mip->NTRY=r; + incr(DG,1,TT); + subdiv(TT,4,TT); + powmod(DD,TT,DG,BB); + negify(DD,TT); + mad(BB,BB,TT,DG,TT,TT); + negify(TT,TT); + premult(BB,2,AA); + xgcd(AA,DG,AA,AA,AA); + mad(AA,TT,TT,DG,DG,AA); + multiply(AA,DG,TT); + add(BB,TT,BB); /* BB^2 = DD mod DG^2 */ + multiply(DG,DG,AA); /* AA = DG*DG */ + xgcd(DG,DD,IG,IG,IG); /* IG = 1/DG mod DD */ + + r1[0]=r2[0]=0; + for (k=1;k<=mm;k++) + { /* find roots of quadratic mod each prime */ + s=subdiv(BB,epr[k],TT); + r=subdiv(AA,epr[k],TT); + r=invers(r,epr[k]); /* r = 1/AA mod p */ + s1=(epr[k]-s+rp[k]); + s2=(epr[k]-s+epr[k]-rp[k]); + r1[k]=smul(s1,r,epr[k]); + r2[k]=smul(s2,r,epr[k]); + } + + for (ptr=(-NS);ptr +#include +#include +#include "big.h" + +using namespace std; + +#define SSIZE 1000000 /* Maximum sieve size */ + +Miracl precision=(30); /* number of bytes per big */ + +static int pk[]={0,1,2,3,5,6,7,10,11,13,14,15,17,0}; +static Big NN,DD,DG,TT,RR,VV,PP,IG,AA,BB; +static Big *x,*y,*z,*w; +static int *epr,*r1,*r2,*rp,*pr; +static int *b,*e,*hash; +static unsigned int **EE,**G; +static unsigned char *logp,*sieve; +static int mm,mlf,jj,nbts,nlp,lp,hmod,hmod2; +static BOOL partial; +static miracl *mip; + +int knuth(int mm,int *epr,Big& N,Big& D) +{ /* Input number to be factored N, find best multiplier k * + * set D=k.N */ + Big T; + double fks,dp,top; + BOOL found; + int i,j,bk,nk,kk,rem,p; + + top=(-10.0e0); + found=FALSE; + nk=0; + bk=0; + epr[0]=1; + epr[1]=2; + + do + { /* search for best Knuth-Schroepel multiplier */ + kk=pk[++nk]; + if (kk==0) + { /* finished */ + kk=pk[bk]; + found=TRUE; + } + D=kk*N; + fks=log(2.0e0)/(2.0e0); + rem=D%8; + if (rem==1) fks*=(4.0e0); + if (rem==5) fks*=(2.0e0); + fks-=log((double)kk)/(2.0e0); + i=0; + j=1; + while (jPRIMES[++i]; + rem=D%p; + if (spmd(rem,(p-1)/2,p)<=1) /* x = spmd(a,b,c) = a^b mod c */ + { /* use only if Jacobi symbol = 0 or 1 */ + epr[++j]=p; + dp=(double)p; + if (kk%p==0) fks+=log(dp)/dp; + else fks+=2*log(dp)/(dp-1.0e0); + } + } + if (fks>top) + { /* find biggest fks */ + top=fks; + bk=nk; + } + } while (!found); + return kk; +} + +int initv() +{ /* initialize */ + Big T; + double dp; + int i,k,digits,pak,maxp; + + nbts=8*sizeof(int); + + cout << "input number to be factored N= \n"; + cin >> NN; + if (prime(NN)) + { + cout << "this number is prime!\n"; + return (-1); + } + T=NN; + digits=1; /* digits in N */ + while ((T/=10)>0) digits++; + + if (digits<10) mm=digits; + else mm=25; + if (digits>20) mm=(digits*digits*digits*digits)/4096; + dp=(double)2*(mm+100); /* number of primes to generate */ + + maxp=(int)(dp*(log(dp*log(dp)))); /* Rossers upper bound */ + gprime(maxp); + + epr=(int *)mr_alloc(mm+1,sizeof(int)); + + k=knuth(mm,epr,NN,DD); + + RR=sqrt(DD); + + if (RR*RR==DD) + { + cout << k << "N is a perfect square!" << endl; + cout << "factors are" << endl; + if (prime(RR)) cout << "prime factor "; + else cout << "composite factor "; + cout << RR << endl; + NN=NN/RR; + if (prime(NN)) cout << "prime factor "; + else cout << "composite factor "; + cout << NN << endl; + return (-1); + } + cout << "using multiplier k= " << k; + cout << "\nand " << mm << " small primes as factor base\n"; + gprime(0); /* reclaim PRIMES space */ + + mlf=2*mm; + + r1=(int *)mr_alloc((mm+1),sizeof(int)); + r2=(int *)mr_alloc((mm+1),sizeof(int)); + rp=(int *)mr_alloc((mm+1),sizeof(int)); + b=(int *)mr_alloc((mm+1),sizeof(int)); + e=(int *)mr_alloc((mm+1),sizeof(int)); + + logp=(unsigned char *)mr_alloc(mm+1,1); + + pr=(int *)mr_alloc((mlf+1),sizeof(int)); + hash=(int *)mr_alloc(2*mlf+1,sizeof(int)); + + sieve=(unsigned char *)mr_alloc(SSIZE+1,1); + + x=new Big[mm+1]; + y=new Big[mm+1]; + z=new Big[mlf+1]; + w=new Big[mlf+1]; + + EE=(unsigned int **)mr_alloc(mm+1,sizeof(unsigned int *)); + G=(unsigned int **) mr_alloc(mlf+1,sizeof(unsigned int *)); + + + pak=1+mm/(8*sizeof(int)); + + for (i=0;i<=mm;i++) + { + x[i]=0; + y[i]=0; + b[i]=(-1); + EE[i]=(unsigned int *)mr_alloc(pak,sizeof(int)); + } + for (i=0;i<=mlf;i++) + { + z[i]=0; + w[i]=0; + G[i]=(unsigned int *)mr_alloc(pak,sizeof(int)); + } + + return 1; +} + +BOOL gotcha(Big& NN,Big& P) +{ /* use new factorisation */ + Big XX,YY,T; + int r,j,i,k,n,rb,had,hp; + BOOL found; + found=TRUE; + if (partial) + { /* check partial factorisation for usefulness */ + had=lp%hmod; + forever + { /* hash search for matching large prime */ + hp=hash[had]; + if (hp<0) + { /* failed to find match */ + found=FALSE; + break; + } + if (pr[hp]==lp) break; /* hash hit! */ + had=(had+(hmod2-lp%hmod2))%hmod; + } + if (!found && nlp>=mlf) return FALSE; + } + XX=P; + YY=1; + for (k=1;k<=mm;k++) + { /* build up square part in YY * + * reducing e[k] to 0s and 1s */ + if (e[k]<2) continue; + r=e[k]/2; + e[k]%=2; + T=epr[k]; + YY*=pow(T,r); + } + if (partial) + { /* factored with large prime */ + if (!found) + { /* store new partial factorization */ + hash[had]=nlp; + pr[nlp]=lp; + z[nlp]=XX; + w[nlp]=YY; + for (n=0,rb=0,j=0;j<=mm;j++) + { + G[nlp][n]|=((e[j]&1)<>rb)&1); + if (e[j]==2) + { + YY=(YY*epr[j])%NN; + e[j]=0; + } + if (++rb==nbts) n++,rb=0; + } + YY=(YY*lp)%NN; + } + } + else cout << "\b\b\b\b\b " << flush; + if (found) + { + for (k=mm;k>=0;k--) + { /* use new factorization in search for solution */ + if (e[k]%2==0) continue; + if (b[k]<0) + { /* no solution this time */ + found=FALSE; + break; + } + i=b[k]; + XX=(XX*x[i])%NN; /* This is very inefficient - */ + YY=(YY*y[i])%NN; /* There must be a better way! */ + for (n=0,rb=0,j=0;j<=mm;j++) + { /* Gaussian elimination */ + e[j]+=((EE[i][n]>>rb)&1); + if (++rb==nbts) n++,rb=0; + } + } + for (j=0;j<=mm;j++) + { /* update YY */ + if (e[j]<2) continue; + T=epr[j]; + YY=(YY*pow(T,e[j]/2,NN))%NN; /* x = pow(a,b,c) = a^b mod c */ + } + if (!found) + { /* store details in EE, x and y for later */ + b[k]=jj; + x[jj]=XX; + y[jj]=YY; + for (n=0,rb=0,j=0;j<=mm;j++) + { + EE[jj][n]|=((e[j]&1)<(1+mlf/50)) break; + if (st<=epr[mm]) + for (i=j;i<=mm;i++) + if (st==epr[i]) + { + e[i]++; + facted=TRUE; + break; + } + if (facted) break; + lp=st; /* factored with large prime */ + partial=TRUE; + facted=TRUE; + break; + } + } + return facted; +} + +void new_poly() +{ /* form the next polynomial */ + int i,r,s,s1,s2; + + r=mip->NTRY; /* MR_NTRY is global - number of trys at proving */ + mip->NTRY=1; /* a probable prime */ + do + { /* looking for suitable prime DG = 3 mod 4 */ + do DG+=4; while(!prime(DG)); + TT=(DG-1)/2; + TT=pow(DD,TT,DG); /* check DD is quad residue */ + } while (TT!=1); + mip->NTRY=r; + TT=(DG+1)/4; + BB=pow(DD,TT,DG); + TT=(DD-BB*BB)/DG; + AA=inverse(2*BB,DG); + AA=(AA*TT)%DG; + BB=AA*DG+BB; /* BB^2 = DD mod DG^2 */ + AA=DG*DG; + IG=inverse(DG,DD); /* IG = 1/DG mod DD */ + r1[0]=r2[0]=0; + for (i=1;i<=mm;i++) + { /* find roots of quadratic mod each prime */ + s=BB%epr[i]; + r=AA%epr[i]; + r=invers(r,epr[i]); /* r = 1/AA mod p */ + s1=(epr[i]-s+rp[i]); + s2=(epr[i]-s+epr[i]-rp[i]); + r1[i]=smul(s1,r,epr[i]); /* s1 = s1*r mod epr[i] */ + r2[i]=smul(s2,r,epr[i]); + } +} + + +int main() +{ /* factoring via quadratic sieve */ + unsigned int i,j,a,*SV; + unsigned char logpi; + int k,S,r,s1,s2,NS,logm,ptr,threshold,epri; + long M,la,lptr; + mip=&precision; + if (initv()<0) return 0; + hmod=2*mlf+1; /* set up hash table */ + TT=hmod; + while (!prime(TT)) TT-=2; + hmod=toint(TT); + hmod2=hmod-2; + for (k=0;k0) logm++; /* logm = log(M) */ + + rp[0]=logp[0]=0; + for (k=1;k<=mm;k++) + { /* find root mod each prime, and approx log of each prime */ + r=DD%epr[k]; + rp[k]=sqrmp(r,epr[k]); /* = square root of r mod epr[k] */ + logp[k]=0; + r=epr[k]; + while((r/=2)>0) logp[k]++; + } + r=DD%8; /* take special care of 2 */ + if (r==5) logp[1]++; + if (r==1) logp[1]+=2; + threshold=logm-2*logp[mm]; + + jj=0; + nlp=0; + + TT=RR; + while ((TT/=2)>0) threshold++; /* add in number of bits in RR */ + DG=sqrt(DD*2); + DG=sqrt(DG/M); + if (DG%2==0) ++DG; + if (DG%4==1) DG+=2; + cout << "working... 0" << flush; + forever + { /* try a new polynomial */ + + new_poly(); + + for (ptr=(-NS);ptr /*** IBM-PC specific section ***/ +#include +#include +#include "miracl.h" + +#define ESC 27 +#define SPACE 32 +#define BELL 7 + +#define DVERT 186 +#define DHORZ 205 +#define DTLHC 201 +#define DTRHC 187 +#define DBLHC 200 +#define DBRHC 188 +#define VERT 179 +#define HORZ 196 +#define TLHC 218 +#define TRHC 191 +#define BLHC 192 +#define BRHC 217 +#define LSIDE 199 +#define RSIDE 182 + +/* Globals */ +/* set colours B/W Colours (suggested) */ + +static int ORDINARY=0x17; /* 0x07 0x17 blue-white */ +static int INVER =0x40; /* 0x70 0x40 red-black */ +static int BOLD =0x70; /* 0x0F 0x70 white-black */ +static int BLINKING=0xF4; /* 0x87 0xF4 white-red (blink) */ +static int HELPCOL =0x02; /* 0x07 0x02 black-green */ +static int PRESSED =0x4F; /* 0x0F 0x4F red-white (bold) */ +static int STATCOL =0x74; /* 0x07 0x74 white-red */ +static int BGROUND =0x07; /* 0x07 0x07 black-white */ + +static int dmode; + +#if MIRACL==16 + /*** Constants 16-bit values ***/ + +static char cpi[] = "636254619847503442989626/202526135627569822173415"; +static char clg2[]= "505741081295988878347013/729630149959545241557174"; +static char clg10[]="979037493951642967431763/425190581199586827388880"; + +#else + /*** Constants 32-bit values ***/ + +static char cpi[] = "67165660610256098973103849091/21379493784309731162770152371"; +static char clg2[]= "16574595208316928044019202463/23912086311780807469140302041"; +static char clg10[]="2379577069267877188193568690/1033437190446551110271192309"; + +#endif + +static char ceps[]="1/100000000000000000000000000000000000"; + + /*** Device independent data ***/ + +static char *settings[4][4]= +{" ","HYP","","", + "Be ","B2 ","B10","", + "RAD","DEG","GRA","", + "DEC","HEX","OCT","BIN"}; + +static int nops[]= {1,2,1,3}; /* number of options */ +static int opp[] = {0,1,1,2,2,3,3,2}; /* operator precedence */ + +static char *keys[6][7]= +{"SIN","COS","TAN","EXP","F-D","CLR","OFF", + "ASN","ACS","ATN","LOG","SET","MOD","DEL", + " 7 "," 8 "," 9 ","Y^X","XY"," "," RM", /******/ + " 4 "," 5 "," 6 "," X","X"," x "," M+", + " 1 "," 2 "," 3 ","1/X"," "," - ","+/-", + " 0 "," / "," . "," ( "," ) "," + "," = "}; + +static int qkeys[6][7]= +{'s','k','t','e','f','c','o', + 'S','K','T','l','g','%','<', + '7','8','9','y','x','\\','r', + '4','5','6','q','v','*','m', + '1','2','3','i','p','-',';', + '0','/','.','(',')','+','='}; + +static char *htext[]= +{"Arrow keys find, space bar activates OR", + "use numeric keys (with A-F for hex),", + "brackets, and mnemonic keys as below: ", + " FUNCTION KEY FUNCTION KEY", + " SIN s ASN S ", + " COS k ACS K ", + " TAN t ATN T ", + " EXP(e/2/10) e LOG(e/2/10) l ", + " Y^X ^ or y XY x ", /******/ + " X q X v ", + " 1/X i p ", + " F-D f SET g ", + " MOD % CLR c ", + " d or \\ x b or * ", + " - - + , or + ", + " OFF ESC or o DEL DEL or < ", + " RM r M+ m ", + " +/- ; = RET or = ", + "Note: / means 'over' as in fractions ", + "F-D converts fraction <--> decimal ", + "SET changes settings - use arrow keys ", + "Alternative arrow keys - u h j n ", + "This program is Public Domain - ", + "Certivox, Ireland mscott@indigo.ie "}; /******/ + +static char display[]= " MIRACL RATIONAL CALCULATOR V3.2 "; +static char status[]= " "; +static char oldstat[]= " "; + +static miracl *mip; + +static int erptr=0; +static int mmptr=6; +static int exptr=10; +static int typtr=16; +static int stptr[]={22,26,30,34}; + +static int dbeg=2; +static int dlen=37; +static int top=7; +static int width=80; /* screen width can be 40 or 80 columns */ +static char mybuff[40]; + +static flash x,y[8],m,t; +static flash radeg,loge2,loge10,eps; +static int ipt,op[8],prop[8],sp,brkt,lgbase; +static BOOL flag,newx,result,hyp,degrees,delim; +static int option[]={0,0,0,0}; + +/* Device specific code - IBM-PC versions */ + +static void curser(int x,int y) +{ /* position cursor at x,y */ + union REGS regs; + regs.h.ah=2; + regs.h.dh=y-1; + regs.h.dl=x-1; + regs.h.bh=0; /* Video page 0 */ + int86(0x10,®s,®s); /* Use Dos Interrupt 10h */ +} + +static void screen(void) +{ /* initialise screen */ + union REGS regs; + regs.h.ah=0x0F; /* get screen mode */ + regs.h.al=0; + int86(0x10,®s,®s); + dmode=regs.h.al; + if ((dmode&2)!=0) width=80; + else width=40; + regs.h.ah=6; /* clear screen */ + regs.h.al=0; + regs.h.cl=0; + regs.h.ch=0; + regs.h.dl=width-1; + regs.h.dh=24; + regs.h.bh=BGROUND; + regs.h.bl=0; + int86(0x10,®s,®s); +} + +static void restore(void) +{ /* restore situation */ + union REGS inregs,outregs; + inregs.h.ah=0; /* reset initial display mode */ + inregs.h.al=dmode; + int86(0x10,&inregs,&outregs); +} + +static void apchar(int attr,int x,int y,char ch) +{ /* output character with attribute at x,y */ + union REGS regs; + curser(x,y); + regs.h.ah=9; /* output a character */ + regs.h.al=ch; + regs.h.bh=0; + regs.h.bl=attr; + regs.h.cl=1; + regs.h.ch=0; + int86(0x10,®s,®s); +} + +static void aprint(int attr,int x,int y,char *text) +{ /* attribute print */ + while (*text!='\0') + { + apchar(attr,x++,y,*text); + text++; + } +} + +static void lclr(int x,int y) +{ /* clear from x,y to end of line */ + aprint(BGROUND,x,y," "); +} + +static void cset(int k) +{ /* select special character set */ + return; +} + +static int gethit(void) +{ /* get single keystroke */ + int ch; + ch=getch(); + if (ch!=0) return ch; + ch=getch(); + if (ch==72) return 'u'; /* transform some useful extended codes */ + if (ch==75) return 'h'; + if (ch==77) return 'j'; + if (ch==80) return 'n'; + if (ch==83) return 127; + return 0; +} + +/*** Device independent code ***/ + +static int arrow(int c) +{ /* check for arrow key * + * returns 1 for up, 2 for down, * + * 3 for right, 4 for left, else 0 */ + if (c=='u') return 1; + if (c=='n') return 2; + if (c=='j') return 3; + if (c=='h') return 4; + return 0; +} + +static void instat(int ptr,char *strg) +{ /* insert a status setting into status line */ + strncpy(&status[ptr],strg,strlen(strg)); +} + +static void getstat(void) +{ /* set status line */ + int i; + if (mip->ERNUM) instat(erptr,"ERROR"); + else instat(erptr," "); + if (mip->EXACT) instat(exptr,"EXACT"); + else instat(exptr," "); + if (size(m)!=0) instat(mmptr,"MEM"); + else instat(mmptr," "); + if (mip->RPOINT) instat(typtr,"POINT"); + else instat(typtr,"FRACT"); + for (i=0;i<4;i++) + instat(stptr[i],settings[i][option[i]]); +} + +static void setopts(void) +{ /* set options */ + if (option[0]==0) hyp=FALSE; + else hyp=TRUE; + lgbase=0; + if (option[1]==1) lgbase=2; + if (option[1]==2) lgbase=10; + if (option[2]==0) degrees=FALSE; + else degrees=TRUE; + mip->IOBASE=10; + if (option[3]==1) mip->IOBASE=16; + if (option[3]==2) mip->IOBASE=8; + if (option[3]==3) mip->IOBASE=2; +} + +static void show(BOOL force) +{ /* output display */ + if (force || strcmp(oldstat,status)!=0) + { + if (mip->ERNUM) aprint(BLINKING,2,2,status); + else aprint(STATCOL,2,2,status); + strcpy(oldstat,status); + } + aprint(BOLD,dbeg,3,display); +} + +static void clr(void) +{ /* clear input buffer */ + mybuff[0]='0'; + mybuff[1]='\0'; + ipt=0; + delim=FALSE; +} + +static void just(char *buff) +{ /* justify buff into display (if possible) * + * and update status */ + int i,mp,df; + BOOL dot; + dot=FALSE; + mp=0; + while (mp<=dlen && buff[mp]!='\0') + { + if (buff[mp]=='.') dot=TRUE; + if (mp==dlen && !dot) mip->ERNUM=(-1); + mp++; + } + if (mp>dlen) mp=dlen; + if (!mip->ERNUM) + { + df=dlen-mp; + for (i=0;iIOBUFF); + just((char *)mip->IOBUFF); + getstat(); + show(TRUE); +} + +static BOOL next(int ch) +{ /* get next digit - returns FALSE if there is a problem */ + int cv; + result=FALSE; + if (ipt>=dlen) return FALSE; + if (ch=='/' || ch=='.') + { + if (delim || (ch=='/' && ipt==0)) return FALSE; + delim=TRUE; + } + else + { + if (ch>='A' && ch<='F') cv=10+(ch-'A'); + else cv=ch-'0'; + if (mip->IOBASE<=cv) return FALSE; + } + if (ipt==0 && ch=='0') clr(); + else + { + mybuff[ipt++]=ch; + mybuff[ipt]='\0'; + } + just(mybuff); + cinstr(x,mybuff); + newx=TRUE; + return TRUE; +} + +static void swap(void) +{ /* swap x with top of stack */ + flash t; + t=x; + x=y[sp]; + y[sp]=t; +} + +static int prec(int no) +{ /* return new operator precedence */ + return 4*brkt+opp[no]; +} + +static void equals(int no) +{ /* perform binary operation */ + BOOL pop; + newx=FALSE; + pop=TRUE; + while (pop) + { + if (prec(no)>prop[sp]) + { /* if higher precedence, keep this one pending */ + if (sp==top) + { + mip->ERNUM=(-1); + result=FALSE; + newx=TRUE; + } + else sp++; + return; + } + newx=TRUE; + if (flag && op[sp]!=3 && op[sp]!=0) swap(); + switch (op[sp]) + { + case 7: fdiv(x,y[sp],t); + ftrunc(t,t,t); + fmul(t,y[sp],t); + fsub(x,t,x); + break; + case 6: fpowf(x,y[sp],x); + break; + case 5: frecip(y[sp],t); + fpowf(x,t,x); + break; + case 4: fdiv(x,y[sp],x); + break; + case 3: fmul(x,y[sp],x); + break; + case 2: fsub(x,y[sp],x); + break; + case 1: fadd(x,y[sp],x); + break; + case 0: break; + } + if (sp>0 && (prec(no)<=prop[sp-1])) sp--; + else pop=FALSE; + } +} + +static void chekit(int no) +{ /* deal with operator */ + if (flag && newx) equals(no); + else newx=FALSE; + flag=ON; + copy(x,y[sp]); + op[sp]=no; + prop[sp]=prec(no); +} + +static void clrall(void) +{ /* clear all */ + mip->ERNUM=0; + zero(x); + zero(y[0]); + zero(m); + sp=0; + op[sp]=0; + prop[sp]=0; + brkt=0; + mip->RPOINT=ON; + mip->EXACT=TRUE; +} + +static BOOL act(int p,int q) +{ /* act on selected key */ + int k,n,c; + aprint(PRESSED,4+5*p,6+3*q,keys[q][p]); + switch(p+7*q) + { + case 0: if (degrees) fmul(x,radeg,x); + if (hyp) fsinh(x,x); + else fsin(x,x); + newx=TRUE; + break; + case 1: if (degrees) fmul(x,radeg,x); + if (hyp) fcosh(x,x); + else fcos(x,x); + newx=TRUE; + break; + case 2: if (degrees) fmul(x,radeg,x); + if (hyp) ftanh(x,x); + else ftan(x,x); + newx=TRUE; + break; + case 3: if (lgbase>0) + { + n=size(x); + if (abs(n)RPOINT=!mip->RPOINT; + newx=TRUE; + break; + case 5: clrall(); + newx=TRUE; + break; + case 6: return TRUE; + case 7: if (hyp) fasinh(x,x); + else fasin(x,x); + if (degrees) fdiv(x,radeg,x); + newx=TRUE; + break; + case 8: if (hyp) facosh(x,x); + else facos(x,x); + if (degrees) fdiv(x,radeg,x); + newx=TRUE; + break; + case 9: if (hyp) fatanh(x,x); + else fatan(x,x); + if (degrees) fdiv(x,radeg,x); + newx=TRUE; + break; + case 10: flog(x,x); + if (lgbase==2) fdiv(x,loge2,x); + if (lgbase==10) fdiv(x,loge10,x); + newx=TRUE; + break; + case 11: newx=TRUE; + k=3; + forever + { + aprint(INVER,2+stptr[k],2,settings[k][option[k]]); + curser(2+stptr[k],2); + c=arrow(gethit()); + if (c==1) + { + if (option[k]==nops[k]) option[k]=0; + else option[k]+=1; + continue; + } + aprint(STATCOL,2+stptr[k],2,settings[k][option[k]]); + if (c==0 || c==2) break; + if (c==4 && k>0) k--; + if (c==3 && k<3) k++; + } + setopts(); + break; + case 12: chekit(7); + break; + case 13: result=FALSE; + if (ipt==0) break; + ipt--; + mybuff[ipt]='\0'; + if (ipt==0) clr(); + just(mybuff); + cinstr(x,mybuff); + newx=TRUE; + break; + case 14: if (!next('7')) putchar(BELL); + break; + case 15: if (!next('8')) putchar(BELL); + break; + case 16: if (!next('9')) putchar(BELL); + break; + case 17: chekit(6); + break; + case 18: chekit(5); + break; + case 19: chekit(4); + break; + case 20: copy(m,x); + newx=TRUE; + break; + case 21: if (!next('4')) putchar(BELL); + break; + case 22: if (!next('5')) putchar(BELL); + break; + case 23: if (!next('6')) putchar(BELL); + break; + case 24: fmul(x,x,x); + newx=TRUE; + break; + case 25: froot(x,2,x); + newx=TRUE; + break; + case 26: chekit(3); + break; + case 27: brkt=0; + chekit(0); + flag=OFF; + fadd(m,x,m); + newx=TRUE; + break; + case 28: if (!next('1')) putchar(BELL); + break; + case 29: if (!next('2')) putchar(BELL); + break; + case 30: if (!next('3')) putchar(BELL); + break; + case 31: frecip(x,x); + newx=TRUE; + break; + case 32: fpi(x); + newx=TRUE; + break; + case 33: chekit(2); + break; + case 34: negify(x,x); + newx=TRUE; + break; + case 35: if (!next('0')) putchar(BELL); + break; + case 36: if (!next('/')) putchar(BELL); + break; + case 37: if (!next('.')) putchar(BELL); + break; + case 38: if (ipt>0) + { + putchar(BELL); + result=FALSE; + } + else + { + zero(x); + brkt+=1; + newx=TRUE; + } + break; + case 39: if (brkt>0) + { + chekit(0); + brkt-=1; + } + else + { + putchar(BELL); + result=FALSE; + } + break; + case 40: chekit(1); + break; + case 41: brkt=0; + equals(0); + flag=OFF; + break; + } + return FALSE; +} + +int main() +{ /* MIRACL rational calculator */ + int i,j,k,p,q,c,hpos; + BOOL over,help; + screen(); +#if MIRACL==16 + mip=mirsys(10,0); /*** 16-bit computer ***/ +#else + mip=mirsys(6,0); /*** 32-bit computer ***/ +#endif + mip->ERCON=TRUE; + x=mirvar(0); + for (i=0;i<=top;i++) y[i]=mirvar(0); + m=mirvar(0); + t=mirvar(0); + radeg=mirvar(0); + loge2=mirvar(0); + loge10=mirvar(0); + eps=mirvar(0); + mip->pi=mirvar(0); + cinstr(mip->pi,cpi); /* read in constants */ + fpmul(mip->pi,1,180,radeg); + cinstr(loge2,clg2); + cinstr(loge10,clg10); + cinstr(eps,ceps); + help=OFF; + show(TRUE); + p=6; + q=0; + flag=OFF; + newx=OFF; + over=FALSE; + + + setopts(); + clrall(); + drawit(); + while (!over) + { /* main loop */ + if (mip->ERNUM) + { + aprint(ORDINARY,4+5*p,6+3*q,keys[q][p]); + p=5,q=0; + } + if (width==80 || !help) + { + aprint(INVER,4+5*p,6+3*q,keys[q][p]); + curser(1,24); + c=gethit(); + aprint(ORDINARY,4+5*p,6+3*q,keys[q][p]); + } + else while ((c=gethit())!='H') ; + result=TRUE; + if ((k=arrow(c))!=0) + { /* arrow key hit */ + if (k==1 && q>0) q--; + if (k==2 && q<5) q++; + if (k==3 && p<6) p++; + if (k==4 && p>0) p--; + continue; + } + if (c=='H') + { /* switch help on/off */ + help=!help; + for (i=1;i<=24;i++) + { + if (width==80) hpos=41; + else hpos=1; + if (help) aprint(HELPCOL,hpos,i,htext[i-1]); + else lclr(hpos,i); + } + if (width==40 && !help) drawit(); + continue; + } + if (c>='A' && c<='F') + { /* hex only */ + if (!next(c)) putchar(BELL); + else show(FALSE); + continue; + } + for (j=0;j<6;j++) + for (i=0;i<7;i++) + if (c==qkeys[j][i]) p=i,q=j,c=' '; + if (c==8 || c==127) p=6,q=1,c=' '; /* aliases */ + if (c==',' || c=='a') p=5,q=5,c=' '; + if (c=='O' || c==ESC) p=6,q=0,c=' '; + if (c==13) p=6,q=5,c=' '; + if (c=='[' || c=='{') p=3,q=5,c=' '; + if (c==']' || c=='}') p=4,q=5,c=' '; + if (c=='d') p=5,q=2,c=' '; + if (c=='b') p=5,q=3,c=' '; + if (c=='^') p=3,q=2,c=' '; + if (c==' ') over=act(p,q); + else continue; + absol(x,t); + if (fcomp(t,eps)<0) zero(x); + if (result) + { /* output result to display */ + cotstr(x,mip->IOBUFF); + just((char *)mip->IOBUFF); + if (mip->ERNUM<0) + { /* convert to radix and try again */ + mip->ERNUM=0; + mip->RPOINT=ON; + cotstr(x,mip->IOBUFF); + putchar(BELL); + just((char *)mip->IOBUFF); + } + clr(); + } + if (newx) + { /* update display */ + getstat(); + show(FALSE); + } + } + curser(1,24); + restore(); + return 0; +} + diff --git a/miracl/source/romaker.c b/miracl/source/romaker.c new file mode 100644 index 0000000..07dd127 --- /dev/null +++ b/miracl/source/romaker.c @@ -0,0 +1,199 @@ +/* + * This program reads in GF(p) elliptic curve details from a .ecs file, and automatically generates + * ROMs containing parameters and precomputed data for a targetted processor. + * + * The .ecs file may be one of the provided standard nist elliptic curves (e.g. secp192.ecs), or it can + * be generated by the schoof or sea applications + * + * Compile on a PC using a standard MIRACL header. Note that on a 32-bit processor (i.e. MIRACL is defined as 32) + * this program can create ROMS for 32-bit, 16-bit and 8-bit processors. To create a ROM for a 64-bit processor + * this program must be compiled and run on a 64-bit processor (e.g. core 2 under Linux). + * + * cl /O2 romaker.c miracl.lib + * + * The output of this program can be pasted directly into an application like ecdhp*.c + * + */ + +#include +#include +#include +#include "miracl.h" + +//#define MICROSOFT64 + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static int answer(void) +{ + char ch; + scanf("%c",&ch); + getchar(); + if (ch=='Y' || ch=='y') return 1; + return 0; +} + +/* NOTE! May be necessary to change %lx in certain cases + e.g. for Microsoft 64-bit compilers, change to %I64x */ + +void bprint(mr_small *n,int len,int words,int wsize,BOOL last) +{ + int i,j,k; + BOOL first=TRUE; + mr_small e,w=((mr_small)1<=words) break; + e/=w; + } + } + if (last) printf("};\n"); + else printf(",\n"); +} + +int main() +{ + FILE *fp; + big e,n,a,b,x,y,r,t; + epoint *g; + BOOL last; + ebrick binst; + char fname[100]; + int nb,bits,window,len,bptr,m,i,j,winsize,special,wsize,words,inca; + miracl *mip=mirsys(50,0); + n=mirvar(0); + e=mirvar(0); + a=mirvar(0); + b=mirvar(0); + x=mirvar(0); + y=mirvar(0); + r=mirvar(0); + t=mirvar(0); + + printf("Enter name of .ecs file= "); + gets(fname); + strip(fname); + strcat(fname,".ecs"); + + if ((fp=fopen(fname,"rt"))==NULL) + { + printf("Unable to open file %s\n",fname); + return 0; + } + fscanf(fp,"%d\n",&bits); + + mip->IOBASE=16; + cinnum(n,fp); + cinnum(a,fp); + cinnum(b,fp); + cinnum(r,fp); + cinnum(x,fp); + cinnum(y,fp); + mip->IOBASE=10; + + nb=logb2(n); + printf("modulus is %d bits in length\n",nb); + printf("Enter window size in bits (1-10)= "); + scanf("%d",&window); + getchar(); + + printf("Have you MR_SPECIAL defined in application mirdef.h (Y/N)?"); + special=answer(); + + printf("Do you want to include curve A parameter in rom - no need if its small (=-3 for example) (Y/N)?"); + inca=answer(); + + printf("Enter word size of application processor (8, 16, 32 or 64 bit)= "); + scanf("%d",&wsize); + getchar(); + + if (wsize!=8 && wsize!=16 && wsize!=32 && wsize!=64 || wsize>MIRACL) + { + printf("Error - Unsupported word size\n"); + exit(0); + } + + ebrick_init(&binst,x,y,a,b,n,window,nb); + + len=MR_ROUNDUP(bits,MIRACL); + words=MR_ROUNDUP(bits,wsize); + + printf("\n--------------------CUT HERE----------------------\n\n"); + printf("#define CURVE_BITS %d\n",bits); + printf("#define WINDOW %d\n",window); + printf("#define WORDS %d\n",words); + + printf("\nstatic const mr_small rom[]={\n"); + + bprint(n->w,len,words,wsize,FALSE); + if (inca) bprint(a->w,len,words,wsize,FALSE); + bprint(b->w,len,words,wsize,FALSE); + bprint(r->w,len,words,wsize,FALSE); + bprint(x->w,len,words,wsize,FALSE); + bprint(y->w,len,words,wsize,TRUE); + + printf("\nstatic const mr_small prom[]={\n"); + bptr=0; + last=FALSE; + winsize=2*(1<len=len; + for (j=0;jw[j]=binst.table[bptr++]; + if (special) redc(t,t); + if (i==winsize-1) last=TRUE; + bprint(t->w,len,words,wsize,last); + } + + ebrick_end(&binst); + + return 0; +} + + diff --git a/miracl/source/romaker2.c b/miracl/source/romaker2.c new file mode 100644 index 0000000..207da84 --- /dev/null +++ b/miracl/source/romaker2.c @@ -0,0 +1,183 @@ +/* + * This program reads in GF(2^m) elliptic curve details from a .ecs file, and automatically generates + * ROMs containing parameters and precomputed data for a targetted processor. + * + * The .ecs file may be one of the provided standard nist elliptic curves (e.g. secp192.ecs), or it can + * be generated by the schoof or sea applications + * + * Compile on a PC using a standard MIRACL header. Note that on a 32-bit processor (i.e. MIRACL is defined as 32) + * this program can create ROMS for 32-bit, 16-bit and 8-bit processors. To create a ROM for a 64-bit processor + * this program must be compiled and run on a 64-bit processor (e.g. core 2 under Linux). + * + * cl /O2 romaker2.c miracl.lib + * + * The output of this program can be pasted directly into an application like ecdh2m*.c + * + */ + +#include +#include +#include +#include "miracl.h" + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static int answer(void) +{ + char ch; + scanf("%c",&ch); + getchar(); + if (ch=='Y' || ch=='y') return 1; + return 0; +} + +/* NOTE! May be necessary to change %lx in certain cases + e.g. for Microsoft 64-bit compilers, change to %I64x */ + +void bprint(mr_small *n,int len,int words,int wsize,BOOL last) +{ + int i,j,k; + BOOL first=TRUE; + mr_small e,w=((mr_small)1<=words) break; + e/=w; + } + } + if (last) printf("};\n"); + else printf(",\n"); +} + +int main() +{ + FILE *fp; + int m,a,b,c; + big e,a2,a6,x,y,r,t; + epoint *g; + ebrick2 binst; + char fname[100]; + BOOL last; + int i,j,len,bptr,nb,window,wsize,words,winsize; + miracl *mip=mirsys(50,0); + e=mirvar(0); + a2=mirvar(0); + a6=mirvar(0); + x=mirvar(0); + y=mirvar(0); + r=mirvar(0); + t=mirvar(0); + + printf("Enter name of .ecs file= "); + gets(fname); + strip(fname); + strcat(fname,".ecs"); + + if ((fp=fopen(fname,"rt"))==NULL) + { + printf("Unable to open file %s\n",fname); + return 0; + } + fscanf(fp,"%d\n",&m); + + mip->IOBASE=16; + cinnum(a2,fp); + cinnum(a6,fp); + cinnum(r,fp); + cinnum(x,fp); + cinnum(y,fp); + mip->IOBASE=10; + + fscanf(fp,"%d\n",&a); + fscanf(fp,"%d\n",&b); + fscanf(fp,"%d\n",&c); + + printf("modulus is %d bits in length\n",m); + nb=m; + printf("Enter window size in bits (1-10)= "); + scanf("%d",&window); + getchar(); + printf("Enter word size of application processor (8, 16, 32 or 64 bit)= "); + scanf("%d",&wsize); + getchar(); + + if (wsize!=8 && wsize!=16 && wsize!=32 && wsize!=64 || wsize>MIRACL) + { + printf("Error - Unsupported word size\n"); + exit(0); + } + + + if (!ebrick2_init(&binst,x,y,a2,a6,m,a,b,c,window,nb)) + { + printf("Failed to Initialize\n"); + return 0; + } + + len=MR_ROUNDUP(m,MIRACL); + words=MR_ROUNDUP(m,wsize); + printf("\n--------------------CUT HERE----------------------\n\n"); + printf("#define CURVE_M %d\n",m); + printf("#define CURVE_A %d\n",a); + printf("#define CURVE_B %d\n",b); + printf("#define CURVE_C %d\n",c); + printf("#define WINDOW %d\n",window); + printf("#define WORDS %d\n",words); + + printf("\nstatic const mr_small rom[]={\n"); + + bprint(a6->w,len,words,wsize,FALSE); + bprint(r->w,len,words,wsize,FALSE); + bprint(x->w,len,words,wsize,FALSE); + bprint(y->w,len,words,wsize,TRUE); + + printf("\nstatic const mr_small prom[]={\n"); + bptr=0; + last=FALSE; + winsize=2*(1<len=len; + for (j=0;jw[j]=binst.table[bptr++]; + + if (i==winsize-1) last=TRUE; + bprint(t->w,len,words,wsize,last); + } + + + ebrick2_end(&binst); + + return 0; +} + + diff --git a/miracl/source/roots.c b/miracl/source/roots.c new file mode 100644 index 0000000..5cab1ca --- /dev/null +++ b/miracl/source/roots.c @@ -0,0 +1,26 @@ +/* + * Program to calculate square roots + */ + +#include +#include "miracl.h" + +int main() +{ /* Find roots */ + flash x,y; + miracl *mip=mirsys(40,0); + x=mirvar(0); + y=mirvar(0); + mip->RPOINT=ON; + printf("enter number\n"); + cinnum(x,stdin); + printf("to the power of 1/2\n"); + froot(x,2,y); + cotnum(y,stdout); + fpower(y,2,x); + printf("to the power of 2 = \n"); + cotnum(x,stdout); + if (mip->EXACT) printf("Result is exact!\n"); + return 0; +} + diff --git a/miracl/source/roots.cpp b/miracl/source/roots.cpp new file mode 100644 index 0000000..bd5ae8b --- /dev/null +++ b/miracl/source/roots.cpp @@ -0,0 +1,32 @@ +/* + * Program to calculate roots + * + * Requires: flash.cpp + * + */ + +#include +#include "flash.h" + +using namespace std; + +Miracl precision=50; + +int main() +{ /* Find roots */ + Flash x,y; + int n; + miracl *mip=&precision; + mip->RPOINT=ON; + cout << "enter number\n"; + cin >> x; + cout << "to the power of 1/2\n"; + y=sqrt(x); + cout << y; + x=y*y; + cout << "\nto the power of 2 = \n"; + cout << x; + if (mip->EXACT) cout << "\nResult is exact!\n"; + return 0; +} + diff --git a/miracl/source/rsat.c b/miracl/source/rsat.c new file mode 100644 index 0000000..41045dd --- /dev/null +++ b/miracl/source/rsat.c @@ -0,0 +1,133 @@ +/* RSA program for comparison + +Use this mirdef.h file + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN +#define mr_utype int +#define mr_unsign32 unsigned int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define MR_STATIC 16 +#define MR_GENERIC_MT +#define MR_COMBA 16 +#define MR_ALWAYS_BINARY +#define mr_dltype long long +#define mr_unsign64 unsigned long long +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + +For some compilers replace long long with __int64 +If I/O is not wanted add these lines as well + +#define MR_NO_STANDARD_IO +#define MR_NO_FILE_IO + +To build on a PC using Microsoft C, execute this batch file +(the modules mrio1.c and mrio2.c can be removed if no I/O required) + +mex 16 ms86 mrcomba +cl /c /O2 /W3 mrcomba.c +cl /c /O2 /W3 mrcore.c +cl /c /O2 /W3 mrarth0.c +cl /c /O2 /W3 mrarth1.c +cl /c /O2 /W3 mrarth2.c +cl /c /O2 /W3 mrio1.c +cl /c /O2 /W3 mrio2.c +cl /c /O2 /W3 mrbits.c +cl /c /O2 /W3 mrxgcd.c +cl /c /O2 /W3 mrmonty.c +cl /c /O2 /W3 mrpower.c +copy mrmuldv.c32 mrmuldv.c +cl /c /O2 /W3 mrmuldv.c + +rem +rem Create library 'miracl.lib' +del miracl.lib + +lib /OUT:miracl.lib mrio2.obj mrio1.obj mrcomba.obj mrbits.obj +lib /OUT:miracl.lib miracl.lib mrarth2.obj mrpower.obj mrxgcd.obj +lib /OUT:miracl.lib miracl.lib mrmonty.obj mrarth1.obj mrarth0.obj mrcore.obj mrmuldv.obj + +del mr*.obj + +cl /O2 rsat.c miracl.lib + +*/ + +#include +#include +#include "miracl.h" + +#define WORDS 16 + +static const mr_small rom[]={ +0xe69486b3, 0x72a0e606, 0x3ecbe4f9, 0xc1f74ed2, 0x506b7584, 0x36dd2b64, 0xf54934bd, 0x299440dd, +0x73b02a3c, 0x3fe08d6, 0xde4acb63, 0x635ebdec, 0x857f31ba, 0xd72eef27, 0xd8e8e11f, 0xf58dd26d, +0xb2838293, 0x793eb355, 0x1454cd06, 0xd7aedb5e, 0x9b06ea9c, 0xa4e860e2, 0xe0464051, 0xbd30c0f5, +0x3aaef142, 0x1e998792, 0xabb18c9f, 0x1532799b, 0x92f44cbf, 0xf9fff267, 0x184a0ca0, 0x99ceb83b, +0x44630477, 0xf715eeaf, 0x29dd4350, 0x2bfa348c, 0x359cf903, 0x79e8c798, 0x4e30cdd3, 0xc662d5e9, +0xf7cac6d2, 0x57feb08e, 0x3edc8797, 0xece9d3f3, 0x3aa2126, 0xe4c9f4c5, 0x909b40bf, 0xa3b3e19e, +0x21ad01b7, 0xfb7f2239, 0xb83888ae, 0x3a74923e, 0xbcaf4713, 0x189aeb41, 0x95842ae1, 0x28cb2b4e, +0x7c74a0d7, 0x14665a61, 0x1d21086a, 0x6376fbbd, 0xb74d887f, 0xfbfff6ef, 0x6586b315, 0x6689d027 +}; + +/* Test driver program */ +/* Max stack requirement << 8K */ + +int main() +{ + big p,q,dp,dq,m,c,m1; + + int i,romptr; + miracl instance; /* sizeof(miracl)= 2124 bytes from the stack */ +#ifndef MR_STATIC + miracl *mr_mip=mirsys(&instance,WORDS*8,16); + char *mem=memalloc(_MIPP_ ,7); +#else + miracl *mr_mip=mirsys(&instance,MR_STATIC*8,16); /* size of bigs is fixed */ + char mem[MR_BIG_RESERVE(7)]; /* reserve space on the stack for 7 bigs */ + memset(mem,0,MR_BIG_RESERVE(7)); /* clear this memory */ + +#endif + +/* Initialise bigs */ + + p=mirvar_mem(_MIPP_ mem,0); + q=mirvar_mem(_MIPP_ mem,1); + dp=mirvar_mem(_MIPP_ mem,2); + dq=mirvar_mem(_MIPP_ mem,3); + m=mirvar_mem(_MIPP_ mem,4); + c=mirvar_mem(_MIPP_ mem,5); + m1=mirvar_mem(_MIPP_ mem,6); + + romptr=0; + + init_big_from_rom(p,WORDS,rom,256,&romptr); + init_big_from_rom(q,WORDS,rom,256,&romptr); + init_big_from_rom(dp,WORDS,rom,256,&romptr); + init_big_from_rom(dq,WORDS,rom,256,&romptr); + + bigbits(_MIPP_ 512,c); + +/* count clocks, instructions and CPI from here.. */ +//for (i=0;i<100000;i++) +//{ + powmod(_MIPP_ c,dp,p,m); + powmod(_MIPP_ c,dq,q,m1); +//} +/* to here... */ + +#ifndef MR_NO_STANDARD_IO +otnum(_MIPP_ m,stdout); +otnum(_MIPP_ m1,stdout); +#endif + +#ifndef MR_STATIC + memkill(_MIPP_ mem,7); +#else + memset(mem,0,MR_BIG_RESERVE(6)); /* clear this stack memory */ +#endif + + mirexit(_MIPPO_ ); /* clears workspace memory */ + return 0; +} diff --git a/miracl/source/sample.c b/miracl/source/sample.c new file mode 100644 index 0000000..ce7e883 --- /dev/null +++ b/miracl/source/sample.c @@ -0,0 +1,29 @@ +/* + * Example program + */ + +#include +#include "miracl.h" + +int main() +{ /* Brents example program */ + flash x,pi; + miracl *mip=mirsys(-35,0); + x=mirvar(0); + pi=mirvar(0); + mip->RPOINT=ON; + printf("Calculating pi..\n"); + fpi(pi); + cotnum(pi,stdout); /* output pi */ + printf("Calculating exp(pi*(163/9)^0.5)\n"); + fconv(163,9,x); + froot(x,2,x); + fmul(x,pi,x); + fexp(x,x); + cotnum(x,stdout); + printf("Calculating exp(pi*(163)^0.5)\n"); + fpower(x,3,x); + cotnum(x,stdout); + return 0; +} + diff --git a/miracl/source/sample.cpp b/miracl/source/sample.cpp new file mode 100644 index 0000000..674b4e2 --- /dev/null +++ b/miracl/source/sample.cpp @@ -0,0 +1,33 @@ +/* + * Example program + * + * Requires: flash.cpp + * + */ + +#include +#include "flash.h" + +using namespace std; + +/* +#ifndef MR_NOFULLWIDTH +Miracl precision(-35,0); +#else +Miracl precision(-35,MAXBASE); +#endif +*/ + +Miracl precision=8; + + +int main() +{ /* Brents example program */ + Flash x; + cout << pi() << endl; + x=exp(pi()*sqrt((Flash)(char *)"163/9")); + cout << x << endl; + cout << pow(x,3) << endl; + return 0; +} + diff --git a/miracl/source/secp160.ecs b/miracl/source/secp160.ecs new file mode 100644 index 0000000..d7a336a --- /dev/null +++ b/miracl/source/secp160.ecs @@ -0,0 +1,8 @@ +160 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF +-3 +1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45 +100000000000000000001F4C8F927AED3CA752257 +4A96B5688EF573284664698968C38BB913CBFC82 +23A628553168947D59DCC912042351377AC5FB32 + diff --git a/miracl/source/secp192.ecs b/miracl/source/secp192.ecs new file mode 100644 index 0000000..7096b71 --- /dev/null +++ b/miracl/source/secp192.ecs @@ -0,0 +1,7 @@ +192 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF +-3 +64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1 +FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831 +188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012 +07192B95FFC8DA78631011ED6B24CDD573F977A11E794811 diff --git a/miracl/source/secp224.ecs b/miracl/source/secp224.ecs new file mode 100644 index 0000000..02ef977 --- /dev/null +++ b/miracl/source/secp224.ecs @@ -0,0 +1,8 @@ +224 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001 +-3 +B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4 +FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D +B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21 +BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34 + diff --git a/miracl/source/secp256.ecs b/miracl/source/secp256.ecs new file mode 100644 index 0000000..331bede --- /dev/null +++ b/miracl/source/secp256.ecs @@ -0,0 +1,7 @@ +256 +FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF +-3 +5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b +FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551 +6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296 +4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5 diff --git a/miracl/source/secp384.ecs b/miracl/source/secp384.ecs new file mode 100644 index 0000000..c84f263 --- /dev/null +++ b/miracl/source/secp384.ecs @@ -0,0 +1,7 @@ +384 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF +-3 +b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973 +aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7 +3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f diff --git a/miracl/source/secp521.ecs b/miracl/source/secp521.ecs new file mode 100644 index 0000000..1e84d85 --- /dev/null +++ b/miracl/source/secp521.ecs @@ -0,0 +1,7 @@ +521 +01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF +-3 +0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00 +01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409 +00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66 +011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650 diff --git a/miracl/source/smartmip.mcs b/miracl/source/smartmip.mcs new file mode 100644 index 0000000..736f669 --- /dev/null +++ b/miracl/source/smartmip.mcs @@ -0,0 +1,506 @@ +; +; SmartMips Macros file for GCC compiler +; +; Triple register is ACX|HI|LO +; MUL_START. Initialise registers. Make $5 and $6 point to multipliers a +; and b. $7 points at result c. +; Initialise Triple register to 0 +; See makemcs.txt for more information about this file +; +; + +MACRO PMUL_START + ASM ( + "ADDU $5,$0,%%0\n" + "ADDU $6,$0,%%1\n" + "ADDU $7,$0,%%2\n" + "ADDU $4,$0,%%3\n" + "MTLHX $0\n" + "MTLHX $0\n" + "MTLHX $0\n" +ENDM + +MACRO PMUL + "LW $3,4*%d($5)\n" + "MADDU $3,$4\n" + "SW $0,4*%d($6)\n" + "MFLHXU $3\n" + "SW $3,4*%d($7)\n" +ENDM + +MACRO PMUL_END + "MFLHXU $3\n" + "MULTU $3,$4\n" + "MFLXHU $3\n" + "SW $3,0($6)\n" + "MFLXHU $3\n" + "SW $3,4($6)\n" + : + :"r"(a),"r"(b),"r"(c),"r"(sn) + :"$3","$4","$5","$6","$7","memory" + ); +ENDM + + +MACRO MUL_START + ASM ( + "ADDU $5,$0,%%0\n" + "ADDU $6,$0,%%1\n" + "ADDU $7,$0,%%2\n" + "MTLHX $0\n" + "MTLHX $0\n" + "MTLHX $0\n" +ENDM +; +; STEP macro. Calculates a double-register partial product +; and adds it to the triple register total +; Parameters 1 & 2: Indices i and j for partial product multipliers a[i] +; and b[j] +; STEP 1 even +MACRO STEP + "LW $2,4*%d($5)\n" + "LW $3,4*%d($6)\n" + "MADDU $2,$3\n" +ENDM +MACRO STEP1M + "LW $2,4*%d($5)\n" + "LW $3,4*%d($6)\n" +ENDM +MACRO STEP1A + "MADDU $2,$3\n" +ENDM +MACRO STEP2M + "LW $8,4*%d($5)\n" + "LW $9,4*%d($6)\n" +ENDM +MACRO STEP2A + "MADDU $8,$9\n" +ENDM + +; +; MFIN macro. Finish column calculation. Store Sum for this column +; and get Carry for next +; Parameter 1: Index k for Column Sum c[k] +MACRO MFIN + "MFLHXU $2\n" + "SW $2,4*%d($7)\n" +ENDM +; +; LAST +; +MACRO LAST + "LW $2,4*%d($5)\n" + "LW $3,4*%d($6)\n" + "MADDU $2,$3\n" +ENDM +; +; MUL_END +; Parameter 1: Index for final carry c[.] +MACRO MUL_END + "MFLHXU $2\n" + "SW $2,4*%d($7)\n" + : + :"r"(a),"r"(b),"r"(c) + :"$2","$3","$4","$5","$6","$7","$8","$9","memory" + ); +ENDM +; +; Binary Macros +; +MACRO MULB_START + ASM ( + "ADDU $5,$0,%%0\n" + "ADDU $6,$0,%%1\n" + "ADDU $7,$0,%%2\n" + "MTLHX $0\n" + "MTLHX $0\n" +ENDM +MACRO STEPB + "LW $2,4*%d($5)\n" + "LW $3,4*%d($6)\n" + "MADDP $2,$3\n" +ENDM +MACRO STEPB1M + "LW $2,4*%d($5)\n" + "LW $3,4*%d($6)\n" +ENDM +MACRO STEPB1A + "MADDP $2,$3\n" +ENDM +MACRO STEPB2M + "LW $8,4*%d($5)\n" + "LW $9,4*%d($6)\n" +ENDM +MACRO STEPB2A + "MADDP $8,$9\n" +ENDM +MACRO MBFIN + "MFLHXU $2\n" + "SW $2,4*%d($7)\n" +ENDM +MACRO MULB_END + : + :"r"(a),"r"(b),"r"(c) + :"$2","$3","$4","$5","$6","$7","$8","$9","memory" + ); +ENDM +; +; SQR_START +; +MACRO SQR_START + ASM ( + "ADDU $5,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "MTLHX $0\n" + "MTLHX $0\n" + "MTLHX $0\n" +ENDM +; +; DSTEP macro. Calculates a double-register partial product +; and add it twice to a triple register total +; Parameters 1 & 2 : Indices of partial product multipliers +MACRO DSTEP + "LW $2,4*%d($5)\n" + "LW $3,4*%d($5)\n" + "MADDU $2,$3\n" + "MADDU $2,$3\n" +ENDM +MACRO DSTEP1M + "LW $2,4*%d($5)\n" + "LW $3,4*%d($5)\n" +ENDM +MACRO DSTEP1A + "MADDU $2,$3\n" + "MADDU $2,$3\n" +ENDM +MACRO DSTEP2M + "LW $8,4*%d($5)\n" + "LW $9,4*%d($5)\n" +ENDM +MACRO DSTEP2A + "MADDU $8,$9\n" + "MADDU $8,$9\n" +ENDM +; +; SELF macro. Calculate the double-register square and +; add it to a triple register total +; Parameter 1 : Index of diagonal element +MACRO SELF + "LW $2,4*%d($5)\n" + "MADDU $2,$2\n" +ENDM +; +; SFIN macro. Finish column calculation for squaring. Store Sum +; and get Carry for next column. +; Parameter 1: Index of Column Sum +MACRO SFIN + "MFLHXU $2\n" + "SW $2,4*%d($7)\n" +ENDM +; +; SQR_END +; Parameter 1: Index for final carry +MACRO SQR_END + "MFLHXU $2\n" + "SW $2,4*%d($7)\n" + : + :"r"(a),"r"(c) + :"$2","$3","$4","$5","$6","$7","8","9","memory" + ); +ENDM +; +; REDC_START macro +; +MACRO REDC_START + ASM ( + "ADDU $5,$0,%%0\n" + "ADDU $6,$0,%%1\n" + "ADDU $7,$0,%%2\n" + "MTLHX $0\n" + "MTLHX $0\n" + "LW $2,($5)\n" + "MTLHX $2\n" +ENDM +; +; RFINU macro - this is terrible! Note that mul instruction is signed, and therefore no good here. +; The ACX|HI|LO register must be saved, as it will be overwritten by MULTU +; +MACRO RFINU + "MFLHXU $4\n" /* extract ACX|HI|LO */ + "MFLHXU $8\n" + "MFLHXU $9\n" + "MULTU $4,$7\n" /* sp=LO*ndash */ + "MFLHXU $3\n" /* $3 = LO */ + "LW $2,($6)\n" /* get b[0] */ + "SW $3,4*%d($5)\n" /* store in a[.] */ + "MTLHX $9\n" /* restore ACX|HI|LO */ + "MTLHX $8\n" + "MTLHX $4\n" + "MADDU $2,$3\n" /* += sp*b[0] */ + "MFLHXU $0\n" /* shift out LO */ + "LW $3,4*(%d+1)($5)\n" + "ADDIU $2,$0,1\n" + "MADDU $3,$2\n" +ENDM +; +; RFIND macro +; +MACRO RFIND + "MFLHXU $3\n" + "SW $3,4*%d($5)\n" + "LW $3,4*(%d+1)($5)\n" + "ADDIU $2,$0,1\n" + "MADDU $3,$2\n" +ENDM +; +; REDC_END +; +MACRO REDC_END + "MFLHXU $3\n" + "MFLHXU $2\n" + "SW $3,4*%d($5)\n" + "SW $2,4*(%d+1)($5)\n" + : + :"r"(a),"r"(b),"r"(ndash) + :"$2","$3","$4","$5","$6","$7","8","9","memory" + ); +ENDM +; +; ADD_START macro - initialise for add/subtract, do first one +; $4 holds the carry bit +; +MACRO ADD_START + ASM ( + "ADDU $6,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "ADDU $8,$0,%%3\n" + "LW $2,($6)\n" + "LW $3,($7)\n" + "ADDU $5,$3,$2\n" + "SW $5,($8)\n" + "SLTU $4,$5,$3\n" +ENDM +; +; ADD macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO ADD + "LW $3,4*%d($6)\n" + "LW $2,4*%d($7)\n" + "ADDU $5,$3,$2\n" + "SLTU $9,$5,$3\n" + "ADDU $2,$5,$4\n" + "SLTU $4,$2,$5\n" + "OR $4,$9,$4\n" + "SW $2,4*%d($8)\n" +ENDM +; +; ADD_END macro. Catch carry +; +MACRO ADD_END + "ADDU %%2,$0,$4\n" + : + :"r"(a),"r"(b),"r"(carry),"r"(c) + :"$2","$3","$4","$5","$6","$7","$8","9","memory" + ); +ENDM +; +; INC_START macro. Do first one +; +MACRO INC_START + ASM ( + "ADDU $6,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "LW $3,($6)\n" + "LW $2,($7)\n" + "ADDU $5,$2,$3\n" + "SW $5,($6)\n" + "SLTU $4,$5,$3\n" +ENDM +; +; INC macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO INC + "LW $3,4*%d($6)\n" + "LW $2,4*%d($7)\n" + "ADDU $5,$3,$2\n" + "SLTU $8,$5,$3\n" + "ADDU $2,$5,$4\n" + "SLTU $4,$2,$5\n" + "OR $4,$8,$4\n" + "SW $2,4*%d($6)\n" +ENDM +; +; INC_END macro. Catch carry +; +MACRO INC_END + "ADDU %%2,$0,$4\n" + : + :"r"(a),"r"(b),"r"(carry) + :"$2","$3","$4","$5","$6","$7","$8","memory" + ); +ENDM +; +; SUB_START macro +; +MACRO SUB_START + ASM ( + "ADDU $6,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "ADDU $8,$0,%%3\n" + "LW $3,($6)\n" + "LW $2,($7)\n" + "SUBU $5,$3,$2\n" + "SW $5,($8)\n" + "SLTU $4,$3,$5\n" +ENDM +; +; SUB macro. Subtract two numbers in memory and store result in memory. +; +MACRO SUB + "LW $3,4*%d($6)\n" + "LW $2,4*%d($7)\n" + "SUBU $5,$3,$2\n" + "SLTU $9,$3,$5\n" + "SUBU $2,$5,$4\n" + "SLTU $4,$5,$2\n" + "OR $4,$9,$4\n" + "SW $2,4*%d($8)\n" +ENDM +; +; SUB_END macro. Catch carry +; +MACRO SUB_END + "ADDU %%2,$0,$4\n" + : + :"r"(a),"r"(b),"r"(carry),"r"(c) + :"$2","$3","$4","$5","$6","$7","$8","9","memory" + ); +ENDM +; +; DEC_START macro +; +MACRO DEC_START + ASM ( + "ADDU $6,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "LW $3,($6)\n" + "LW $2,($7)\n" + "SUBU $5,$3,$2\n" + "SW $5,($6)\n" + "SLTU $4,$3,$5\n" +ENDM +; +; DEC macro. Subtract two numbers in memory and store result in memory. +; +MACRO DEC + "LW $3,4*%d($6)\n" + "LW $2,4*%d($7)\n" + "SUBU $5,$3,$2\n" + "SLTU $8,$3,$5\n" + "SUBU $2,$5,$4\n" + "SLTU $4,$5,$2\n" + "OR $4,$8,$4\n" + "SW $2,4*%d($6)\n" +ENDM +; +; DEC_END macro. Catch carry +; +MACRO DEC_END + "ADDU %%2,$0,$4\n" + : + :"r"(a),"r"(b),"r"(carry) + :"$2","$3","$4","$5","$6","$7","8","memory" + ); +ENDM +; +; KADD_START macro. Zero Carry flag +; +MACRO KADD_START + ASM ( + "ADDU $6,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "ADDU $8,$0,%%3\n" + "ADDU $9,$0,%%4\n" + "ADDU $4,$0,$0\n" + "k%d:\n" +ENDM +; +; KASL macro. Important that carry flag is undisturbed! +; +MACRO KASL + "SUBIU $9,$9,1\n" + "BLEZ $9,k%d\n" + "NOP\n" + "ADDIU $6,$6,4*%d\n" + "ADDIU $7,$7,4*%d\n" + "J k%d\n" + "ADDIU $8,$8,4*%d\n" + "k%d\n" +ENDM +; +; KADD_END macro +; +MACRO KADD_END + "ADDU %%2,$0,$4\n" + : + :"r"(a),"r"(b),"r"(carry),"r"(c),"r"(n) + :"$2","$3","$4","$5","$6","$7","$8","$9","memory" + ); +ENDM +; +; KINC_START macro. Set carry to Zero +; +MACRO KINC_START + __asm { + "ADDU $6,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "ADDU $9,$0,%%4\n" + "ADDU $4,$0,$0\n" + "k%d:\n" +ENDM +; +; KIDL macro. Important that carry flag is undisturbed! +; +MACRO KIDL + "SUBIU $9,$9,1\n" + "BLEZ $9,k%d\n" + "NOP\n" + "ADDIU $6,$6,4*%d\n" + "J k%d\n" + "ADDIU $7,$7,4*%d\n" + "k%d\n" +ENDM +; +; KINC_END macro +; +MACRO KINC_END + "ADDU %%2,$0,$4\n" + : + :"r"(a),"r"(b),"r"(carry),"r"(n) + :"$2","$3","$4","$5","$6","$7","$8","$9","memory" + ); +ENDM +; +; KDEC_START macro. Set carry +; +MACRO KDEC_START + ASM ( + "ADDU $6,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "ADDU $9,$0,%%4\n" + "ADDU $4,$0,$0\n" + "k%d:\n" +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + "ADDU %%2,$0,$4\n" + : + :"r"(a),"r"(b),"r"(carry),"r"(n) + :"$2","$3","$4","$5","$6","$7","$8","$9","memory" + ); +ENDM + diff --git a/miracl/source/sparc32.mcs b/miracl/source/sparc32.mcs new file mode 100644 index 0000000..7a32f51 --- /dev/null +++ b/miracl/source/sparc32.mcs @@ -0,0 +1,486 @@ +; +; 32-bit SPARC v8 version. Don't forget the delay slot! +; +; Sorry about all the %'s! Each % must be input here as %% +; Triple register is %l2|%l1|%l0 +; MUL_START. Initialise registers. Make %o0 and %o1 point to multipliers a +; and b. %o2 points at result c. +; Initialise Triple register to 0 +; See makemcs.txt for more information about this file +; + +MACRO PMUL_START + __asm__ __volatile__ ( + "mov %%0,%%%%o0\n" + "mov %%1,%%%%o1\n" + "mov %%2,%%%%o2\n" + "mov %%3,%%%%o3\n" + "mov %%%%g0,%%%%l0\n" +ENDM + +MACRO PMUL + "ld [%%%%o0+4*%d],%%%%l1\n" + "umul %%%%l1,%%%%o3,%%%%l1\n" + "rd %%%%y,%%%%l2\n" + "addcc %%%%l1,%%%%l0,%%%%l1\n" + "addxcc %%%%l2,%%%%g0,%%%%l0\n" + "st %%%%g0,[%%%%o1+4*%d]\n" + "st %%%%l1,[%%%%o2+4*%d]\n" +ENDM + +MACRO PMUL_END + "umul %%%%l0,%%%%o3,%%%%l1\n" + "rd %%%%y,%%%%l2\n" + "st %%%%l1,[%%%%o1]\n" + "st %%%%l2,[%%%%o1+4]\n" + : + :"r"(a),"r"(b),"r"(c),"r"(sn) + :"l0","l1","l2","o0","o1","o2","o3","memory" + ); +ENDM + + +MACRO MUL_START + __asm__ __volatile__ ( + "mov %%0,%%%%o0\n" + "mov %%1,%%%%o1\n" + "mov %%2,%%%%o2\n" + "mov %%%%g0,%%%%l0\n" + "mov %%%%g0,%%%%l1\n" + "mov %%%%g0,%%%%l2\n" +ENDM +; +; STEP macro. Calculates a double-register partial product +; and adds it to the triple register total +; Parameters 1 & 2: Indices i and j for partial product multipliers a[i] +; and b[j] +MACRO STEP + "ld [%%%%o0+4*%d],%%%%l3\n" + "ld [%%%%o1+4*%d],%%%%l4\n" + "umul %%%%l3,%%%%l4,%%%%l3\n" + "rd %%%%y,%%%%l4\n" + "addcc %%%%l0,%%%%l3,%%%%l0\n" + "addxcc %%%%l1,%%%%l4,%%%%l1\n" + "addx %%%%l2,%%%%g0,%%%%l2\n" +ENDM +MACRO STEP1M + "ld [%%%%o0+4*%d],%%%%l3\n" + "ld [%%%%o1+4*%d],%%%%l4\n" + "umul %%%%l3,%%%%l4,%%%%l3\n" + "rd %%%%y,%%%%l4\n" +ENDM +MACRO STEP1A + "addcc %%%%l0,%%%%l3,%%%%l0\n" + "addxcc %%%%l1,%%%%l4,%%%%l1\n" + "addx %%%%l2,%%%%g0,%%%%l2\n" +ENDM +MACRO STEP2M + "ld [%%%%o0+4*%d],%%%%l5\n" + "ld [%%%%o1+4*%d],%%%%l6\n" + "umul %%%%l5,%%%%l6,%%%%l5\n" + "rd %%%%y,%%%%l6\n" +ENDM +MACRO STEP2A + "addcc %%%%l0,%%%%l5,%%%%l0\n" + "addxcc %%%%l1,%%%%l6,%%%%l1\n" + "addx %%%%l2,%%%%g0,%%%%l2\n" +ENDM +; +; LAST +; +MACRO LAST + "ld [%%%%o0+4*%d],%%%%l3\n" + "ld [%%%%o1+4*%d],%%%%l4\n" + "umul %%%%l3,%%%%l4,%%%%l3\n" + "add %%%%l0,%%%%l3,%%%%l0\n" +ENDM +; +; MFIN macro. Finish column calculation. Store Sum for this column +; and get Carry for next +; Parameter 1: Index k for Column Sum c[k] +MACRO MFIN + "st %%%%l0,[%%%%o2+4*%d]\n" + "mov %%%%l1,%%%%l0\n" + "mov %%%%l2,%%%%l1\n" + "mov %%%%g0,%%%%l2\n" +ENDM +; +; MUL_END +; Parameter 1: Index for final carry c[.] +MACRO MUL_END + "st %%%%l0,[%%%%o2+4*%d]\n" + : + :"r"(a),"r"(b),"r"(c) + :"l0","l1","l2","l3","l4","l5","l6","o0","o1","o2","memory" + ); +ENDM +; +; SQR_START +; +MACRO SQR_START + __asm__ __volatile__ ( + "mov %%0,%%%%o0\n" + "mov %%1,%%%%o2\n" + "mov %%%%g0,%%%%l0\n" + "mov %%%%g0,%%%%l1\n" + "mov %%%%g0,%%%%l2\n" +ENDM +; +; DSTEP macro. Calculates a double-register partial product +; and add it twice to a triple register total +; Parameters 1 & 2 : Indices of partial product multipliers +MACRO DSTEP + "ld [%%%%o0+4*%d],%%%%l3\n" + "ld [%%%%o0+4*%d],%%%%l4\n" + "umul %%%%l3,%%%%l4,%%%%l3\n" + "rd %%%%y,%%%%l4\n" + "addcc %%%%l0,%%%%l3,%%%%l0\n" + "addxcc %%%%l1,%%%%l4,%%%%l1\n" + "addx %%%%l2,%%%%g0,%%%%l2\n" + "addcc %%%%l0,%%%%l3,%%%%l0\n" + "addxcc %%%%l1,%%%%l4,%%%%l1\n" + "addx %%%%l2,%%%%g0,%%%%l2\n" +ENDM +MACRO DSTEP1M + "ld [%%%%o0+4*%d],%%%%l3\n" + "ld [%%%%o0+4*%d],%%%%l4\n" + "umul %%%%l3,%%%%l4,%%%%l3\n" + "rd %%%%y,%%%%l4\n" +ENDM +MACRO DSTEP1A + "addcc %%%%l0,%%%%l3,%%%%l0\n" + "addxcc %%%%l1,%%%%l4,%%%%l1\n" + "addx %%%%l2,%%%%g0,%%%%l2\n" + "addcc %%%%l0,%%%%l3,%%%%l0\n" + "addxcc %%%%l1,%%%%l4,%%%%l1\n" + "addx %%%%l2,%%%%g0,%%%%l2\n" +ENDM +MACRO DSTEP2M + "ld [%%%%o0+4*%d],%%%%l5\n" + "ld [%%%%o0+4*%d],%%%%l6\n" + "umul %%%%l5,%%%%l6,%%%%l5\n" + "rd %%%%y,%%%%l6\n" +ENDM +MACRO DSTEP2A + "addcc %%%%l0,%%%%l5,%%%%l0\n" + "addxcc %%%%l1,%%%%l6,%%%%l1\n" + "addx %%%%l2,%%%%g0,%%%%l2\n" + "addcc %%%%l0,%%%%l5,%%%%l0\n" + "addxcc %%%%l1,%%%%l6,%%%%l1\n" + "addx %%%%l2,%%%%g0,%%%%l2\n" +ENDM +; +; SELF macro. Calculate the double-register square and +; add it to a triple register total +; Parameter 1 : Index of diagonal element +MACRO SELF + "ld [%%%%o0+4*%d],%%%%l3\n" + "umul %%%%l3,%%%%l3,%%%%l3\n" + "rd %%%%y,%%%%l4\n" + "addcc %%%%l0,%%%%l3,%%%%l0\n" + "addxcc %%%%l1,%%%%l4,%%%%l1\n" + "addx %%%%l2,%%%%g0,%%%%l2\n" +ENDM +; +; SFIN macro. Finish column calculation for squaring. Store Sum +; and get Carry for next column. +; Parameter 1: Index of Column Sum +MACRO SFIN + "st %%%%l0,[%%%%o2+4*%d]\n" + "mov %%%%l1,%%%%l0\n" + "mov %%%%l2,%%%%l1\n" + "mov %%%%g0,%%%%l2\n" +ENDM +; +; SQR_END +; Parameter 1: Index for final carry +MACRO SQR_END + "st %%%%l0,[%%%%o2+4*%d]\n" + : + :"r"(a),"r"(c) + :"l0","l1","l2","l3","l4","l5","l6","o0","o2","memory" + ); +ENDM +; +; REDC_START +; +MACRO REDC_START + __asm__ __volatile__ ( + "mov %%0,%%%%o0\n" + "mov %%1,%%%%o1\n" + "mov %%2,%%%%o2\n" + "mov %%%%g0,%%%%l1\n" + "mov %%%%g0,%%%%l2\n" + "ld [%%%%o0],%%%%l0\n" +ENDM +; +; RFINU macro +; +MACRO RFINU + "umul %%%%l0,%%%%o2,%%%%l3\n" + "st %%%%l3,[%%%%o0+4*%d]\n" + "ld [%%%%o1],%%%%l4\n" + "umul %%%%l3,%%%%l4,%%%%l3\n" + "rd %%%%y,%%%%l4\n" + "addcc %%%%l0,%%%%l3,%%%%l0\n" + "addxcc %%%%l1,%%%%l4,%%%%l1\n" + "addx %%%%l2,%%%%g0,%%%%l2\n" + "mov %%%%l1,%%%%l0\n" + "mov %%%%l2,%%%%l1\n" + "mov %%%%g0,%%%%l2\n" + "ld [%%%%o0+4*(%d+1)],%%%%l3\n" + "addcc %%%%l0,%%%%l3,%%%%l0\n" + "addx %%%%l1,%%%%l2,%%%%l1\n" +ENDM +; +; RFIND macro +; +MACRO RFIND + "st %%%%l0,[%%%%o0+4*%d]\n" + "mov %%%%l1,%%%%l0\n" + "mov %%%%l2,%%%%l1\n" + "mov %%%%g0,%%%%l2\n" + "ld [%%%%o0+4*(%d+1)],%%%%l3\n" + "addcc %%%%l0,%%%%l3,%%%%l0\n" + "addx %%%%l1,%%%%l2,%%%%l1\n" +ENDM +; +; REDC_END +; +MACRO REDC_END + "st %%%%l0,[%%%%o0+4*%d]\n" + "st %%%%l1,[%%%%o0+4*(%d+1)]\n" + : + :"r"(a),"r"(b),"r"(ndash) + :"l0","l1","l2","l3","l4","l5","l6","o0","o1","o2","memory" + ); +ENDM +; +; ADD_START macro - initialise for add. Do first one +; +MACRO ADD_START + __asm__ __volatile__ ( + "mov %%1,%%%%o0\n" + "mov %%2,%%%%o1\n" + "mov %%3,%%%%o2\n" + "ld [%%%%o0],%%%%l0\n" + "ld [%%%%o1],%%%%l1\n" + "addcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o2]\n" +ENDM +; +; ADD macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO ADD + "ld [%%%%o0+4*%d],%%%%l0\n" + "ld [%%%%o1+4*%d],%%%%l1\n" + "addxcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o2+4*%d]\n" +ENDM +; +; ADD_END macro. Catch Carry +; +MACRO ADD_END + "addx %%%%g0,%%%%g0,%%%%l0\n" + "mov %%%%l0,%%0\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(c) + :"o0","o1","o2","l0","l1","memory" + ); +ENDM +; +; INC_START macro +; +MACRO INC_START + __asm__ __volatile__ ( + "mov %%1,%%%%o0\n" + "mov %%2,%%%%o1\n" + "ld [%%%%o0],%%%%l0\n" + "ld [%%%%o1],%%%%l1\n" + "addcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o0]\n" +ENDM +; +; INC macro. Increment number in memory. Don't forget carry +; +MACRO INC + "ld [%%%%o0+4*%d],%%%%l0\n" + "ld [%%%%o1+4*%d],%%%%l1\n" + "addxcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o0+4*%d]\n" +ENDM +; +; INC_END macro. Catch Carry +; +MACRO INC_END + "addx %%%%g0,%%%%g0,%%%%l0\n" + "mov %%%%l0,%%0\n" + :"=r"(carry) + :"r"(a),"r"(b) + :"o0","o1","l0","l1","memory" + ); +ENDM +; +; SUB_START macro. Do first one. +; +MACRO SUB_START + __asm__ __volatile__ ( + "mov %%1,%%%%o0\n" + "mov %%2,%%%%o1\n" + "mov %%3,%%%%o2\n" + "ld [%%%%o0],%%%%l0\n" + "ld [%%%%o1],%%%%l1\n" + "subcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o2]\n" +ENDM +; +; SUB macro. Subtract two numbers in memory and store result in memory. +; +MACRO SUB + "ld [%%%%o0+4*%d],%%%%l0\n" + "ld [%%%%o1+4*%d],%%%%l1\n" + "subxcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o2+4*%d]\n" +ENDM +; +; SUB_END macro. Catch Carry +; +MACRO SUB_END + "addx %%%%g0,%%%%g0,%%%%l0\n" + "mov %%%%l0,%%0\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(c) + :"o0","o1","o2","l0","l1","memory" + ); +ENDM +; +; DEC_START macro. Do first one. +; +MACRO DEC_START + __asm__ __volatile__ ( + "mov %%1,%%%%o0\n" + "mov %%2,%%%%o1\n" + "ld [%%%%o0],%%%%l0\n" + "ld [%%%%o1],%%%%l1\n" + "subcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o0]\n" +ENDM +; +; DEC macro. Decrement from number in memory. Don't forget borrow. +; +MACRO DEC + "ld [%%%%o0+4*%d],%%%%l0\n" + "ld [%%%%o1+4*%d],%%%%l1\n" + "subxcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o0+4*%d]\n" +ENDM +; +; DEC_END macro +; +MACRO DEC_END + "addx %%%%g0,%%%%g0,%%%%l0\n" + "mov %%%%l0,%%0\n" + :"=r"(carry) + :"r"(a),"r"(b) + :"o0","o1","l0","l1","memory" + ); +ENDM +; +; KADD_START macro. Zero carry flag +; +MACRO KADD_START + __asm__ __volatile__ ( + "mov %%1,%%%%o0\n" + "mov %%2,%%%%o1\n" + "mov %%3,%%%%o2\n" + "mov %%4,%%%%o3\n" + "addcc %%%%g0,%%%%g0,%%%%g0\n" + "k%d:\n" +ENDM +; +; KASL macro. Leave carry flag undisturbed +; Save carry in l0, and then restore it in delay slot +; +MACRO KASL + "addx %%%%g0,%%%%g0,%%%%l0\n" + "subcc %%%%o3,1,%%%%o3\n" + "be k%d\n" + "addcc %%%%l0,-1,%%%%g0\n" + "add %%%%o0,4*%d,%%%%o0\n" + "add %%%%o1,4*%d,%%%%o1\n" + "add %%%%o2,4*%d,%%%%o2\n" + "ba k%d\n" + "add %%%%g0,%%%%g0,%%%%g0\n" + "k%d:\n" +ENDM +; +; KADD_END macro +; +MACRO KADD_END + "addx %%%%g0,%%%%g0,%%%%l0\n" + "mov %%%%l0,%%0\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(c),"r"(n) + :"o0","o1","o2","o3","l0","l1","memory" + ); +ENDM +; +; KINC_START macro. Zero carry flag. +; +MACRO KINC_START + __asm__ __volatile__ ( + "mov %%1,%%%%o0\n" + "mov %%2,%%%%o1\n" + "mov %%3,%%%%o3\n" + "addcc %%%%g0,%%%%g0,%%%%g0\n" + "k%d:\n" +ENDM +; +; KIDL macro +; +MACRO KIDL + "addx %%%%g0,%%%%g0,%%%%l0\n" + "subcc %%%%o3,1,%%%%o3\n" + "be k%d\n" + "addcc %%%%l0,-1,%%%%g0\n" + "add %%%%o0,4*%d,%%%%o0\n" + "add %%%%o1,4*%d,%%%%o1\n" + "ba k%d\n" + "add %%%%g0,%%%%g0,%%%%g0\n" + "k%d:\n" +ENDM +; +; KINC_END macro +; +MACRO KINC_END + "addx %%%%g0,%%%%g0,%%%%l0\n" + "mov %%%%l0,%%0\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(n) + :"o0","o1","o3","l0","l1","memory" + ); +ENDM +; +; KDEC_START macro +; +MACRO KDEC_START + __asm__ __volatile__ ( + "mov %%1,%%%%o0\n" + "mov %%2,%%%%o1\n" + "mov %%3,%%%%o3\n" + "addcc %%%%g0,%%%%g0,%%%%g0\n" + "k%d:\n" +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + "addx %%%%g0,%%%%g0,%%%%l0\n" + "mov %%%%l0,%%0\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(n) + :"o0","o1","o3","l0","l1","memory" + ); +ENDM + diff --git a/miracl/source/sparc64.mcs b/miracl/source/sparc64.mcs new file mode 100644 index 0000000..6bd5fde --- /dev/null +++ b/miracl/source/sparc64.mcs @@ -0,0 +1,468 @@ +; +; 64-bit SPARC V9 version. Don't forget the delay slot! +; +; Sorry about all the %'s! Each % must be input here as %% +; Triple register is %l1|%l0 (Bottom 32 bits of l0 and all of l1) +; MUL_START. Initialise registers. Make %o0 and %01 point to multipliers a +; and b. %o2 points at result c. +; Initialise Triple register to 0 +; See makemcs.txt for more information about this file +; + +MACRO PMUL_START + __asm__ __volatile__ ( + "mov %%0,%%%%o0\n" + "mov %%1,%%%%o1\n" + "mov %%2,%%%%o2\n" + "mov %%3,%%%%o3\n" + "mov %%%%g0,%%%%l0\n" +ENDM + +MACRO PMUL + "ld [%%%%o0+4*%d],%%%%l1\n" + "mulx %%%%l1,%%%%o3,%%%%l1\n" + "addc %%%%l1,%%%%l0,%%%%l1\n" + "st %%%%g0,[%%%%o1+4*%d]\n" + "srlx %%%%l1,32,%%%%l0\n" + "st %%%%l1,[%%%%o2+4*%d]\n" +ENDM + +MACRO PMUL_END + "mulx %%%%l0,%%%%o3,%%%%l1\n" + "st %%%%l1,[%%%%o1]\n" + "srlx %%%%l1,32,%%%%l1\n" + "st %%%%l1,[%%%%o1+4]\n" + : + :"r"(a),"r"(b),"r"(c),"r"(sn) + :"l0","l1","o0","o1","o2","o3","memory" + ); +ENDM + +MACRO MUL_START + __asm__ __volatile__ ( + "mov %%0,%%%%o0\n" + "mov %%1,%%%%o1\n" + "mov %%2,%%%%o2\n" + "mov %%%%g0,%%%%l0\n" + "mov %%%%g0,%%%%l1\n" +ENDM +; +; STEP macro. Calculates a double-register partial product +; and adds it to the triple register total +; Parameters 1 & 2: Indices i and j for partial product multipliers a[i] +; and b[j] +MACRO STEP + "ld [%%%%o0+4*%d],%%%%l2\n" + "ld [%%%%o1+4*%d],%%%%l3\n" + "mulx %%%%l2,%%%%l3,%%%%l2\n" + "srlx %%%%l2,32,%%%%l3\n" + "addcc %%%%l0,%%%%l2,%%%%l0\n" + "addc %%%%l1,%%%%l3,%%%%l1\n" +ENDM +MACRO STEP1M + "ld [%%%%o0+4*%d],%%%%l2\n" + "ld [%%%%o1+4*%d],%%%%l3\n" + "mulx %%%%l2,%%%%l3,%%%%l2\n" + "srlx %%%%l2,32,%%%%l3\n" +ENDM +MACRO STEP1A + "addcc %%%%l0,%%%%l2,%%%%l0\n" + "addc %%%%l1,%%%%l3,%%%%l1\n" +ENDM +MACRO STEP2M + "ld [%%%%o0+4*%d],%%%%l4\n" + "ld [%%%%o1+4*%d],%%%%l5\n" + "mulx %%%%l4,%%%%l5,%%%%l4\n" + "srlx %%%%l4,32,%%%%l5\n" +ENDM +MACRO STEP2A + "addcc %%%%l0,%%%%l4,%%%%l0\n" + "addc %%%%l1,%%%%l5,%%%%l1\n" +ENDM +; +; LAST +; +MACRO LAST + "ld [%%%%o0+4*%d],%%%%l2\n" + "ld [%%%%o1+4*%d],%%%%l3\n" + "mulx %%%%l2,%%%%l3,%%%%l2\n" + "add %%%%l0,%%%%l2,%%%%l0\n" +ENDM +; +; MFIN macro. Finish column calculation. Store Sum for this column +; and get Carry for next +; Parameter 1: Index k for Column Sum c[k] +MACRO MFIN + "st %%%%l0,[%%%%o2+4*%d]\n" + "mov %%%%l1,%%%%l0\n" + "srlx %%%%l1,32,%%%%l1\n" +ENDM +; +; MUL_END +; Parameter 1: Index for final carry c[.] +MACRO MUL_END + "st %%%%l0,[%%%%o2+4*%d]\n" + : + :"r"(a),"r"(b),"r"(c) + :"l0","l1","l2","l3","l4","l5","o0","o1","o2","memory" + ); +ENDM +; +; SQR_START +; +MACRO SQR_START + __asm__ __volatile__ ( + "mov %%0,%%%%o0\n" + "mov %%1,%%%%o2\n" + "mov %%%%g0,%%%%l0\n" + "mov %%%%g0,%%%%l1\n" +ENDM +; +; DSTEP macro. Calculates a double-register partial product +; and add it twice to a triple register total +; Parameters 1 & 2 : Indices of partial product multipliers +MACRO DSTEP + "ld [%%%%o0+4*%d],%%%%l2\n" + "ld [%%%%o0+4*%d],%%%%l3\n" + "mulx %%%%l2,%%%%l3,%%%%l2\n" + "srlx %%%%l2,32,%%%%l3\n" + "addcc %%%%l0,%%%%l2,%%%%l0\n" + "addc %%%%l1,%%%%l3,%%%%l1\n" + "addcc %%%%l0,%%%%l2,%%%%l0\n" + "addc %%%%l1,%%%%l3,%%%%l1\n" +ENDM +MACRO DSTEP1M + "ld [%%%%o0+4*%d],%%%%l2\n" + "ld [%%%%o0+4*%d],%%%%l3\n" + "mulx %%%%l2,%%%%l3,%%%%l2\n" + "srlx %%%%l2,32,%%%%l3\n" +ENDM +MACRO DSTEP1A + "addcc %%%%l0,%%%%l2,%%%%l0\n" + "addc %%%%l1,%%%%l3,%%%%l1\n" + "addcc %%%%l0,%%%%l2,%%%%l0\n" + "addc %%%%l1,%%%%l3,%%%%l1\n" +ENDM +MACRO DSTEP2M + "ld [%%%%o0+4*%d],%%%%l4\n" + "ld [%%%%o0+4*%d],%%%%l5\n" + "mulx %%%%l4,%%%%l5,%%%%l4\n" + "srlx %%%%l4,32,%%%%l5\n" +ENDM +MACRO DSTEP2A + "addcc %%%%l0,%%%%l4,%%%%l0\n" + "addc %%%%l1,%%%%l5,%%%%l1\n" + "addcc %%%%l0,%%%%l4,%%%%l0\n" + "addc %%%%l1,%%%%l5,%%%%l1\n" +ENDM +; +; SELF macro. Calculate the double-register square and +; add it to a triple register total +; Parameter 1 : Index of diagonal element +MACRO SELF + "ld [%%%%o0+4*%d],%%%%l2\n" + "mulx %%%%l2,%%%%l2,%%%%l2\n" + "srlx %%%%l2,32,%%%%l3\n" + "addcc %%%%l0,%%%%l2,%%%%l0\n" + "addc %%%%l1,%%%%l3,%%%%l1\n" +ENDM +; +; SFIN macro. Finish column calculation for squaring. Store Sum +; and get Carry for next column. +; Parameter 1: Index of Column Sum +MACRO SFIN + "st %%%%l0,[%%%%o2+4*%d]\n" + "mov %%%%l1,%%%%l0\n" + "srlx %%%%l1,32,%%%%l1\n" +ENDM +; +; SQR_END +; Parameter 1: Index for final carry +MACRO SQR_END + "st %%%%l0,[%%%%o2+4*%d]\n" + : + :"r"(a),"r"(c) + :"l0","l1","l2","l3","l4","l5","o0","o2","memory" + ); +ENDM +; +; REDC_START +; +MACRO REDC_START + __asm__ __volatile__ ( + "mov %%0,%%%%o0\n" + "mov %%1,%%%%o1\n" + "mov %%2,%%%%o2\n" + "mov %%%%g0,%%%%l1\n" + "ld [%%%%o0],%%%%l0\n" +ENDM +; +; RFINU macro +; +MACRO RFINU + "mulx %%%%l0,%%%%o2,%%%%l2\n" + "st %%%%l2,[%%%%o0+4*%d]\n" + "sllx %%%%l2,32,%%%%l2\n" + "ld [%%%%o1],%%%%l3\n" + "srlx %%%%l2,32,%%%%l2\n" + "mulx %%%%l2,%%%%l3,%%%%l2\n" + "srlx %%%%l2,32,%%%%l3\n" + "addcc %%%%l0,%%%%l2,%%%%l0\n" + "addc %%%%l1,%%%%l3,%%%%l1\n" + "mov %%%%l1,%%%%l0\n" + "srlx %%%%l1,32,%%%%l1\n" + "ld [%%%%o0+4*(%d+1)],%%%%l2\n" + "addcc %%%%l0,%%%%l2,%%%%l0\n" + "addx %%%%l1,%%%%g0,%%%%l1\n" +ENDM +; +; RFIND macro +; +MACRO RFIND + "st %%%%l0,[%%%%o0+4*%d]\n" + "mov %%%%l1,%%%%l0\n" + "srlx %%%%l1,32,%%%%l1\n" + "ld [%%%%o0+4*(%d+1)],%%%%l2\n" + "addcc %%%%l0,%%%%l2,%%%%l0\n" + "addx %%%%l1,%%%%g0,%%%%l1\n" +ENDM +; +; REDC_END +; +MACRO REDC_END + "st %%%%l0,[%%%%o0+4*%d]\n" + "st %%%%l1,[%%%%o0+4*(%d+1)]\n" + : + :"r"(a),"r"(b),"r"(ndash) + :"l0","l1","l2","l3","l4","l5","o0","o1","o2","memory" + ); +ENDM +; +; ADD_START macro - initialise for add. Do first one +; +MACRO ADD_START + __asm__ __volatile__ ( + "mov %%1,%%%%o0\n" + "mov %%2,%%%%o1\n" + "mov %%3,%%%%o2\n" + "ld [%%%%o0],%%%%l0\n" + "ld [%%%%o1],%%%%l1\n" + "addcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o2]\n" +ENDM +; +; ADD macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO ADD + "ld [%%%%o0+4*%d],%%%%l0\n" + "ld [%%%%o1+4*%d],%%%%l1\n" + "addxcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o2+4*%d]\n" +ENDM +; +; ADD_END macro. Catch Carry +; +MACRO ADD_END + "addx %%%%g0,%%%%g0,%%%%l0\n" + "mov %%%%l0,%%0\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(c) + :"o0","o1","o2","l0","l1","memory" + ); +ENDM +; +; INC_START macro +; +MACRO INC_START + __asm__ __volatile__ ( + "mov %%1,%%%%o0\n" + "mov %%2,%%%%o1\n" + "ld [%%%%o0],%%%%l0\n" + "ld [%%%%o1],%%%%l1\n" + "addcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o0]\n" +ENDM +; +; INC macro. Increment number in memory. Don't forget carry +; +MACRO INC + "ld [%%%%o0+4*%d],%%%%l0\n" + "ld [%%%%o1+4*%d],%%%%l1\n" + "addxcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o0+4*%d]\n" +ENDM +; +; INC_END macro. Catch Carry +; +MACRO INC_END + "addx %%%%g0,%%%%g0,%%%%l0\n" + "mov %%%%l0,%%0\n" + :"=r"(carry) + :"r"(a),"r"(b) + :"o0","o1","l0","l1","memory" + ); +ENDM +; +; SUB_START macro. Do first one. +; +MACRO SUB_START + __asm__ __volatile__ ( + "mov %%1,%%%%o0\n" + "mov %%2,%%%%o1\n" + "mov %%3,%%%%o2\n" + "ld [%%%%o0],%%%%l0\n" + "ld [%%%%o1],%%%%l1\n" + "subcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o2]\n" +ENDM +; +; SUB macro. Subtract two numbers in memory and store result in memory. +; +MACRO SUB + "ld [%%%%o0+4*%d],%%%%l0\n" + "ld [%%%%o1+4*%d],%%%%l1\n" + "subxcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o2+4*%d]\n" +ENDM +; +; SUB_END macro. Catch Carry +; +MACRO SUB_END + "addx %%%%g0,%%%%g0,%%%%l0\n" + "mov %%%%l0,%%0\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(c) + :"o0","o1","o2","l0","l1","memory" + ); +ENDM +; +; DEC_START macro. Do first one. +; +MACRO DEC_START + __asm__ __volatile__ ( + "mov %%1,%%%%o0\n" + "mov %%2,%%%%o1\n" + "ld [%%%%o0],%%%%l0\n" + "ld [%%%%o1],%%%%l1\n" + "subcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o0]\n" +ENDM +; +; DEC macro. Decrement from number in memory. Don't forget borrow. +; +MACRO DEC + "ld [%%%%o0+4*%d],%%%%l0\n" + "ld [%%%%o1+4*%d],%%%%l1\n" + "subxcc %%%%l0,%%%%l1,%%%%l0\n" + "st %%%%l0,[%%%%o0+4*%d]\n" +ENDM +; +; DEC_END macro +; +MACRO DEC_END + "addx %%%%g0,%%%%g0,%%%%l0\n" + "mov %%%%l0,%%0\n" + :"=r"(carry) + :"r"(a),"r"(b) + :"o0","o1","l0","l1","memory" + ); +ENDM +; +; KADD_START macro. Zero carry flag +; +MACRO KADD_START + __asm__ __volatile__ ( + "mov %%1,%%%%o0\n" + "mov %%2,%%%%o1\n" + "mov %%3,%%%%o2\n" + "mov %%4,%%%%o3\n" + "addcc %%%%g0,%%%%g0,%%%%g0\n" + "k%d:\n" +ENDM +; +; KASL macro. Leave carry flag undisturbed +; Save carry in l0, and then restore it in delay slot +; +MACRO KASL + "addx %%%%g0,%%%%g0,%%%%l0\n" + "subcc %%%%o3,1,%%%%o3\n" + "be k%d\n" + "addcc %%%%l0,-1,%%%%g0\n" + "add %%%%o0,4*%d,%%%%o0\n" + "add %%%%o1,4*%d,%%%%o1\n" + "add %%%%o2,4*%d,%%%%o2\n" + "ba k%d\n" + "add %%%%g0,%%%%g0,%%%%g0\n" + "k%d:\n" +ENDM +; +; KADD_END macro +; +MACRO KADD_END + "addx %%%%g0,%%%%g0,%%%%l0\n" + "mov %%%%l0,%%0\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(c),"r"(n) + :"o0","o1","o2","o3","l0","l1","memory" + ); +ENDM +; +; KINC_START macro. Zero carry flag. +; +MACRO KINC_START + __asm__ __volatile__ ( + "mov %%1,%%%%o0\n" + "mov %%2,%%%%o1\n" + "mov %%3,%%%%o3\n" + "addcc %%%%g0,%%%%g0,%%%%g0\n" + "k%d:\n" +ENDM +; +; KIDL macro +; +MACRO KIDL + "addx %%%%g0,%%%%g0,%%%%l0\n" + "subcc %%%%o3,1,%%%%o3\n" + "be k%d\n" + "addcc %%%%l0,-1,%%%%g0\n" + "add %%%%o0,4*%d,%%%%o0\n" + "add %%%%o1,4*%d,%%%%o1\n" + "ba k%d\n" + "add %%%%g0,%%%%g0,%%%%g0\n" + "k%d:\n" +ENDM +; +; KINC_END macro +; +MACRO KINC_END + "addx %%%%g0,%%%%g0,%%%%l0\n" + "mov %%%%l0,%%0\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(n) + :"o0","o1","o3","l0","l1","memory" + ); +ENDM +; +; KDEC_START macro +; +MACRO KDEC_START + __asm__ __volatile__ ( + "mov %%1,%%%%o0\n" + "mov %%2,%%%%o1\n" + "mov %%3,%%%%o3\n" + "addcc %%%%g0,%%%%g0,%%%%g0\n" + "k%d:\n" +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + "addx %%%%g0,%%%%g0,%%%%l0\n" + "mov %%%%l0,%%0\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(n) + :"o0","o1","o3","l0","l1","memory" + ); +ENDM + diff --git a/miracl/source/sse2.mcs b/miracl/source/sse2.mcs new file mode 100644 index 0000000..8c7d759 --- /dev/null +++ b/miracl/source/sse2.mcs @@ -0,0 +1,480 @@ +; MCS macro file for Microsoft compilers with SSE2 support +; +; Triple register is xmm0 +; MUL_START. Initialise registers. Make ebx and esi point to multipliers a +; and b. edi points at result c. +; Initialise Triple register to 0 +; See makemcs.txt for more information about this file. +; + +MACRO PMUL_START + ASM { + push PBP + push DDI + push DSI + mov PBX,a + mov DSI,b + mov PDI,c + xor DCX,DCX + mov DBP,sn +ENDM + +MACRO PMUL + mov DAX,DBP + mul POINTER [PBX+N*%d] + add DAX,DCX + adc DDX,0 + mov DCX,DDX + mov POINTER [PSI+N*%d],0 + mov [PDI+N*%d],DAX +ENDM + +MACRO PMUL_END + mov DAX,DBP + mul DCX + mov [PSI],DAX + mov [PSI+N],DDX + pop DSI + pop DDI + pop PBP + } +ENDM + +MACRO MUL_START + ASM { + push DDI + push DSI + mov PBX,a + mov PSI,b + mov PDI,c + pxor xmm0,xmm0 +ENDM +; +; STEP macro. Calculates a double-register partial product +; and adds it to the triple register total +; Parameters 1 & 2: Indices i and j for partial product multipliers a[i] +; and b[j] +MACRO STEP + movd xmm1,[PBX+N*%d] + movd xmm2,[PSI+N*%d] + pmuludq xmm1,xmm2 + pshufd xmm1,xmm1,0xd8 + paddq xmm0,xmm1 +ENDM +MACRO STEP1M + movd xmm1,[PBX+N*%d] + movd xmm2,[PSI+N*%d] + pmuludq xmm1,xmm2 +ENDM +MACRO STEP1A + pshufd xmm1,xmm1,0xd8 + paddq xmm0,xmm1 +ENDM +MACRO STEP2M + movd xmm3,[PBX+N*%d] + movd xmm4,[PSI+N*%d] + pmuludq xmm3,xmm4 +ENDM +MACRO STEP2A + pshufd xmm3,xmm3,0xd8 + paddq xmm0,xmm3 +ENDM +; +; MFIN macro. Finish column calculation. Store Sum for this column +; and get Carry for next +; Parameter 1: Index k for Column Sum c[k] +MACRO MFIN + movd [PDI+N*%d],xmm0 + movq xmm7,xmm0 + psrlq xmm7,MIRACL + psrldq xmm0,MIRACL/4 + paddq xmm0,xmm7 +ENDM +; +; MUL_END +; Parameter 1: Index for final carry c[.] +MACRO MUL_END + movd [PDI+N*%d],xmm0 + pop DSI + pop DDI + } +ENDM +; +; LAST +; +MACRO LAST + movd xmm1,[PBX+N*%d] + movd xmm2,[PSI+N*%d] + pmuludq xmm1,xmm2 + paddq xmm0,xmm1 +ENDM +; +; SQR_START +; +MACRO SQR_START + ASM { + push DDI + push DSI + mov PBX,a + mov PSI,c + pxor xmm0,xmm0 +ENDM +; +; DSTEP macro. Calculates a double-register partial product +; and add it twice to a triple register total +; Parameters 1 & 2 : Indices of partial product multipliers +MACRO DSTEP + movd xmm1,[PBX+N*%d] + movd xmm2,[PBX+N*%d] + pmuludq xmm1,xmm2 + pshufd xmm1,xmm1,0xd8 + paddq xmm0,xmm1 + paddq xmm0,xmm1 +ENDM +MACRO DSTEP1M + movd xmm1,[PBX+N*%d] + movd xmm2,[PBX+N*%d] + pmuludq xmm1,xmm2 +ENDM +MACRO DSTEP1A + pshufd xmm1,xmm1,0xd8 + paddq xmm0,xmm1 + paddq xmm0,xmm1 +ENDM +MACRO DSTEP2M + movd xmm3,[PBX+N*%d] + movd xmm4,[PBX+N*%d] + pmuludq xmm3,xmm4 +ENDM +MACRO DSTEP2A + pshufd xmm3,xmm3,0xd8 + paddq xmm0,xmm3 + paddq xmm0,xmm3 +ENDM +; +; SELF macro. Calculate the double-register square and +; add it to a triple register total +; Parameter 1 : Index of diagonal element +MACRO SELF + movd xmm1,[PBX+N*%d] + pmuludq xmm1,xmm1 + pshufd xmm1,xmm1,0xd8 + paddq xmm0,xmm1 +ENDM +; +; SFIN macro. Finish column calculation for squaring. Store Sum +; and get Carry for next column. +; Parameter 1: Index of Column Sum +MACRO SFIN + movd [PSI+N*%d],xmm0 + movq xmm7,xmm0 + psrlq xmm7,MIRACL + psrldq xmm0,MIRACL/4 + paddq xmm0,xmm7 +ENDM +; +; SQR_END +; Parameter 1: Index for final carry +MACRO SQR_END + movd [PSI+N*%d],xmm0 + pop DSI + pop DDI + } +ENDM +; +; REDC_START macro +; +MACRO REDC_START + ASM { + push DDI + push DSI + mov PBX,a + mov PSI,b + movd xmm6,ndash + movd xmm0,[PBX] +ENDM +; +; RFINU macro +; +MACRO RFINU + movq xmm7,xmm0 + pmuludq xmm7,xmm6 + movd [PBX+N*%d],xmm7 + movd xmm1,[PSI] + pmuludq xmm1,xmm7 + pshufd xmm1,xmm1,0xd8 + paddq xmm0,xmm1 + movq xmm7,xmm0 + psrlq xmm7,MIRACL + psrldq xmm0,MIRACL/4 + paddq xmm0,xmm7 + movd xmm1,[PBX+N*(%d+1)] + paddq xmm0,xmm1 +ENDM +; +; RFIND macro +; +MACRO RFIND + movd [PBX+N*%d],xmm0 + movq xmm7,xmm0 + psrlq xmm7,MIRACL + psrldq xmm0,MIRACL/4 + paddq xmm0,xmm7 + movd xmm1,[PBX+N*(%d+1)] + paddq xmm0,xmm1 +ENDM +; +; REDC_END +; +MACRO REDC_END + movd [PBX+N*%d],xmm0 + movq xmm7,xmm0 + psrlq xmm7,MIRACL + psrldq xmm0,MIRACL/4 + paddq xmm0,xmm7 + movd [PBX+N*(%d+1)],xmm0 + pop DSI + pop DDI + } +ENDM +; +; ADD_START macro - initialise for add/subtract. Do the first one. +; +MACRO ADD_START + ASM { + push PSI + push PDI + mov PSI,a + mov PBX,b + mov PDI,c + mov DAX,[PSI] + add DAX,[PBX] + mov [PDI],DAX +ENDM +; +; ADD macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO ADD + mov DAX,[PSI+N*%d] + adc DAX,[PBX+N*%d] + mov [PDI+N*%d],DAX +ENDM +; +; ADD_END macro. Catch Carry +; +MACRO ADD_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + pop PDI + pop PSI + } +ENDM +; +; DOUBLE_START macro +; +MACRO DOUBLE_START + ASM { + mov PBX,a + mov DAX,[PBX] + add [PBX],DAX +ENDM +; +; DOUBLE macro +; +MACRO DOUBLE + mov DAX,[PBX+N*%d] + adc [PBX+N*%d],DAX +ENDM +; +; DOUBLE_END +; +MACRO DOUBLE_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + } +ENDM +; +; INC_START macro - initialise for increment/decrement. Do first one. +; +MACRO INC_START + ASM { + push PDI + mov PBX,b + mov PDI,a + mov DAX,[PBX] + add [PDI],DAX +ENDM +; +; INC macro. Increment number in memory. Don't forget carry +; +MACRO INC + mov DAX,[PBX+N*%d] + adc [PDI+N*%d],DAX +ENDM +; +; INC_END macro. Catch Carry +; +MACRO INC_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + pop PDI + } +ENDM +; +; SUB_START macro. Do first one +; +MACRO SUB_START + ASM { + push PSI + push PDI + mov PSI,a + mov PBX,b + mov PDI,c + mov DAX,[PSI] + sub DAX,[PBX] + mov [PDI],DAX +ENDM +; +; SUB macro. Subtract two numbers in memory and store result in memory. +; +MACRO SUB + mov eax,[PSI+N*%d] + sbb eax,[PBX+N*%d] + mov [PDI+N*%d],DAX +ENDM +; +; SUB_END macro +; +MACRO SUB_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + pop PDI + pop PSI + } +ENDM +; +; DEC_START macro +; +MACRO DEC_START + ASM { + push PDI + mov PBX,b + mov PDI,a + mov DAX,[PBX] + sub [PDI],DAX +ENDM +; +; DEC macro. Decrement from number in memory. Don't forget borrow. +; +MACRO DEC + mov DAX,[PBX+N*%d] + sbb [PDI+N*%d],DAX +ENDM +; +; DEC_END macro. Catch carry +; +MACRO DEC_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + pop PDI + } +ENDM +; +; KADD_START macro. Zero carry flag. +; +MACRO KADD_START + ASM { + push PSI + push PDI + mov PSI,a + mov PBX,b + mov PDI,c + mov PCX,n + xor DAX,DAX + k%d: +ENDM +; +; KASL macro. Important that carry flag is undisturbed +; +MACRO KASL + dec PCX + je k%d + lea PSI,[PSI+N*%d] + lea PBX,[PBX+N*%d] + lea PDI,[PDI+N*%d] + jmp k%d + k%d: +ENDM +; +; KADD_END macro +; +MACRO KADD_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + pop PDI + pop PSI + } +ENDM +; +; KINC_START macro. Zero Carry Flag +; +MACRO KINC_START + ASM { + push PDI + mov PDI,a + mov PBX,b + mov PCX,n + xor DAX,DAX + k%d: +ENDM +; +; KIDL macro. Important that carry flag is undisturbed! +; +MACRO KIDL + dec PCX + je k%d + lea PBX,[PBX+N*%d] + lea PDI,[PDI+N*%d] + jmp k%d + k%d: +ENDM +; +; KINC_END macro +; +MACRO KINC_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + pop PDI + } +ENDM +; +; KDEC_START macro. Zero Carry flag +; +MACRO KDEC_START + ASM { + push PDI + mov PDI,a + mov PBX,b + mov PCX,n + xor DAX,DAX + k%d: +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + pop PDI + } +ENDM + diff --git a/miracl/source/tc86.mcs b/miracl/source/tc86.mcs new file mode 100644 index 0000000..1278413 --- /dev/null +++ b/miracl/source/tc86.mcs @@ -0,0 +1,409 @@ +; MCS macro file for Turbo C 16-bit compiler +; +; Triple register is cl|DDI|DBP +; MUL_START. Initialise registers. Make PBX and PSI point to multipliers a +; and b. PDI points at result c. Note PDI is shared. +; Initialise Triple register to 0 +; See makemcs.txt for more information about this file. +; +MACRO PMUL_START + ASM push PBP + ASM push DDI + ASM push DSI + ASM mov PBX,a + ASM mov DSI,b + ASM mov PDI,c + ASM xor DCX,DCX + ASM mov DBP,sn +ENDM + +MACRO PMUL + ASM mov DAX,DBP + ASM mul POINTER [PBX+N*%d] + ASM add DAX,DCX + ASM adc DDX,0 + ASM mov DCX,DDX + ASM mov POINTER [PSI+N*%d],0 + ASM mov [PDI+N*%d],DAX +ENDM + +MACRO PMUL_END + ASM mov DAX,DBP + ASM mul DCX + ASM mov [PSI],DAX + ASM mov [PSI+N],DDX + ASM pop DSI + ASM pop DDI + ASM pop PBP +ENDM + +MACRO MUL_START + ASM push PBP + ASM push DDI + ASM push DSI + ASM mov PBX,a + ASM mov PSI,b + ASM mov PDI,c + ASM push PDI + ASM xor DCX,DCX + ASM xor DDI,DDI + ASM xor DBP,DBP +ENDM +; +; STEP macro. Calculates a double-register partial product +; and adds it to the triple register total +; Parameters 1 & 2: Indices i and j for partial product multipliers a[i] +; and b[j] +MACRO STEP + ASM mov DAX,[PBX+N*%d] + ASM mul POINTER [PSI+N*%d] + ASM add DBP,DAX + ASM adc DDI,DDX + ASM adc cl,ch +ENDM +; +; MFIN macro. Finish column calculation. Store Sum for this column +; and get Carry for next +; Parameter 1: Index k for Column Sum c[k] +MACRO MFIN + ASM mov DDX,DDI + ASM pop PDI + ASM mov [PDI+N*%d],DBP + ASM push PDI + ASM mov DBP,DDX + ASM mov DDI,DCX + ASM xor cl,cl +ENDM +; +; MUL_END +; Parameter 1: Index for final carry c[.] +MACRO MUL_END + ASM pop PDI + ASM mov [PDI+N*%d],DBP + ASM pop DSI + ASM pop DDI + ASM pop PBP +ENDM +; +; LAST +; +MACRO LAST + ASM mov DAX,[PBX+N*%d] + ASM mul POINTER [PSI+N*%d] + ASM add DBP,DAX +ENDM +; +; SQR_START +; +MACRO SQR_START + ASM push PBP + ASM push DDI + ASM push DSI + ASM mov PBX,a + ASM mov PSI,c + ASM xor DCX,DCX + ASM xor DDI,DDI + ASM xor DBP,DBP +ENDM +; +; DSTEP macro. Calculates a double-register partial product +; and add it twice to a triple register total +; Parameters 1 & 2 : Indices of partial product multipliers +MACRO DSTEP + ASM mov DAX,[PBX+N*%d] + ASM mul POINTER [PBX+N*%d] + ASM add DBP,DAX + ASM adc DDI,DDX + ASM adc cl,ch + ASM add DBP,DAX + ASM adc DDI,DDX + ASM adc cl,ch +ENDM +; +; SELF macro. Calculate the double-register square and +; add it to a triple register total +; Parameter 1 : Index of diagonal element +MACRO SELF + ASM mov DAX,[PBX+N*%d] + ASM mul DAX + ASM add DBP,DAX + ASM adc DDI,DDX + ASM adc cl,ch +ENDM +; +; SFIN macro. Finish column calculation for squaring. Store Sum +; and get Carry for next column. +; Parameter 1: Index of Column Sum +MACRO SFIN + ASM mov [PSI+N*%d],DBP + ASM mov DBP,DDI + ASM mov DDI,DCX + ASM xor cl,cl +ENDM +; +; SQR_END +; Parameter 1: Index for final carry +MACRO SQR_END + ASM mov [PSI+N*%d],DBP + ASM pop DSI + ASM pop DDI + ASM pop PBP +ENDM +; +; REDC_START macro +; +MACRO REDC_START + ASM push PBP + ASM push DDI + ASM push DSI + ASM mov PBX,a + ASM mov PSI,b + ASM mov DDX,ndash + ASM push DDX + ASM xor DDI,DDI + ASM xor DCX,DCX + ASM mov DBP,[PBX] +ENDM +; +; RFINU macro +; +MACRO RFINU + ASM mov DAX,DBP + ASM pop DDX + ASM push DDX + ASM mul DDX + ASM mov [PBX+N*%d],DAX + ASM mul POINTER [PSI] + ASM add DBP,DAX + ASM adc DDI,DDX + ASM adc cl,ch + ASM mov DBP,DDI + ASM mov DDI,DCX + ASM xor DCX,DCX + ASM add DBP,[PBX+N*(%d+1)] + ASM adc DDI,DCX +ENDM +; +; RFIND macro +; +MACRO RFIND + ASM mov [PBX+N*%d],DBP + ASM mov DBP,DDI + ASM mov DDI,DCX + ASM xor DCX,DCX + ASM add DBP,[PBX+N*(%d+1)] + ASM adc DDI,DCX +ENDM +; +; REDC_END +; +MACRO REDC_END + ASM mov [PBX+N*%d],DBP + ASM mov [PBX+N*(%d+1)],DDI + ASM pop DDX + ASM pop DSI + ASM pop DDI + ASM pop PBP +ENDM +; +; ADD_START macro - initialise for add/subtract. Do the first one. +; +MACRO ADD_START + ASM push PSI + ASM push PDI + ASM mov PSI,a + ASM mov PBX,b + ASM mov PDI,c + ASM mov DAX,[PSI] + ASM add DAX,[PBX] + ASM mov [PDI],DAX +ENDM +; +; ADD macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO ADD + ASM mov DAX,[PSI+N*%d] + ASM adc DAX,[PBX+N*%d] + ASM mov [PDI+N*%d],DAX +ENDM +; +; ADD_END macro. Catch Carry +; +MACRO ADD_END + ASM mov DAX,0 + ASM adc DAX,DAX + ASM mov carry,DAX + ASM pop PDI + ASM pop PSI +ENDM +; +; INC_START macro - initialise for increment/decrement. Do first one. +; decrement b from a +MACRO INC_START + ASM push PDI + ASM mov PBX,b + ASM mov PDI,a + ASM mov DAX,[PBX] + ASM add [PDI],DAX +ENDM +; +; INC macro. Increment number in memory. Don't forget carry +; +MACRO INC + ASM mov DAX,[PBX+N*%d] + ASM adc [PDI+N*%d],DAX +ENDM +; +; INC_END macro. Catch Carry +; +MACRO INC_END + ASM mov DAX,0 + ASM adc DAX,DAX + ASM mov carry,DAX + ASM pop PDI +ENDM +; +; SUB_START macro. Do first one +; +MACRO SUB_START + ASM push PSI + ASM push PDI + ASM mov PSI,a + ASM mov PBX,b + ASM mov PDI,c + ASM mov DAX,[PSI] + ASM sub DAX,[PBX] + ASM mov [PDI],DAX +ENDM +; +; SUB macro. Subtract two numbers in memory and store result in memory. +; +MACRO SUB + ASM mov DAX,[PSI+N*%d] + ASM sbb DAX,[PBX+N*%d] + ASM mov [PDI+N*%d],DAX +ENDM +; +; SUB_END macro +; +MACRO SUB_END + ASM mov DAX,0 + ASM adc DAX,DAX + ASM mov carry,DAX + ASM pop PDI + ASM pop PSI +ENDM +; +; DEC_START macro +; +MACRO DEC_START + ASM push PDI + ASM mov PBX,b + ASM mov PDI,a + ASM mov DAX,[PBX] + ASM sub [PDI],DAX +ENDM +; +; DEC macro. Decrement from number in memory. Don't forget borrow. +; +MACRO DEC + ASM mov DAX,[PBX+N*%d] + ASM sbb [PDI+N*%d],DAX +ENDM +; +; DEC_END macro. Catch carry +; +MACRO DEC_END + ASM mov DAX,0 + ASM adc DAX,DAX + ASM mov carry,DAX + ASM pop PDI +ENDM +; +; KADD_START macro. Zero carry flag. +; +MACRO KADD_START + ASM push PSI + ASM push PDI + ASM mov PSI,a + ASM mov PBX,b + ASM mov PDI,c + ASM mov PCX,n + ASM xor DAX,DAX + k%d: +ENDM +; +; KASL macro. Important that carry flag is undisturbed +; +MACRO KASL + ASM dec PCX + ASM je k%d + ASM lea PSI,[PSI+N*%d] + ASM lea PBX,[PBX+N*%d] + ASM lea PDI,[PDI+N*%d] + ASM jmp k%d + k%d: +ENDM +; +; KADD_END macro +; +MACRO KADD_END + ASM mov DAX,0 + ASM adc DAX,DAX + ASM mov carry,DAX + ASM pop PDI + ASM pop PSI +ENDM +; +; KINC_START macro. Zero Carry Flag +; +MACRO KINC_START + ASM push PDI + ASM mov PDI,a + ASM mov PBX,b + ASM mov PCX,n + ASM xor DAX,DAX + k%d: +ENDM +; +; KIDL macro. Important that carry flag is undisturbed! +; +MACRO KIDL + ASM dec PCX + ASM je k%d + ASM lea PBX,[PBX+N*%d] + ASM lea PDI,[PDI+N*%d] + ASM jmp k%d + k%d: +ENDM +; +; KINC_END macro +; +MACRO KINC_END + ASM mov DAX,0 + ASM adc DAX,DAX + ASM mov carry,DAX + ASM pop PDI +ENDM +; +; KDEC_START macro. Zero Carry flag +; +MACRO KDEC_START + ASM push PDI + ASM mov PDI,a + ASM mov PBX,b + ASM mov PCX,n + ASM xor DAX,DAX + k%d: +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + ASM mov DAX,0 + ASM adc DAX,DAX + ASM mov carry,DAX + ASM pop PDI +ENDM + diff --git a/miracl/source/threadmp.cpp b/miracl/source/threadmp.cpp new file mode 100644 index 0000000..68f88d5 --- /dev/null +++ b/miracl/source/threadmp.cpp @@ -0,0 +1,115 @@ +/* + + Example program to illustrate MIRACL multi-threading with openMP + Make sure miracl library is built with MR_OPENMP_MT defined in mirdef.h + This allows multi-threading in C++. + + For multithreading in C use MR_GENERIC_MT with openMP (but do not define MR_OPENMP_MT) + + Microsoft C++ compiler, VC2005 (for openMP support) + + Make sure to compile miracl modules with /openmp flag + + cl /O2 /GX /openmp threadmp.cpp big.cpp zzn.cpp miracl.lib + + Runs from the command prompt + + First thread factors one number, while second thread factors a second + Each thread is initialised differently + One outputs factors in decimal, the other in Hex + The work of the threads are inter-leaved. + + NOTE: You really need a multi-core processor to appreciate this.... + +*/ + +#include +#include +#include +#include "big.h" +#include "zzn.h" + +using namespace std; + +// Brents factoring algorithm + +#define mr_min(a,b) ((a) < (b)? (a) : (b)) + +int brent(int id,char * fred,int base) +{ /* factoring program using Brents method */ + long k,r,i,m,iter; + Big n,z; + + ZZn x,y,q,ys; + n=fred; + + cout << "thread "<< id << " factoring " << n << endl; + get_mip()->IOBASE=base; + m=10L; + r=1L; + iter=0L; + z=0; + do + { + modulo(n); // ZZn arithmetic done mod n + y=z; // convert back to ZZn (n has changed!) + + cout << "thread " << id << " iteration " << iter << endl; + q=1; + do + { + x=y; + for (i=1L;i<=r;i++) y=(y*y+3); + k=0; + do + { + iter++; + if (iter%10==0) cout << "thread " << id << " iteration " << iter << endl; + ys=y; + for (i=1L;i<=mr_min(m,r-k);i++) + { + y=(y*y+3); + q=((y-x)*q); + } + z=gcd(q,n); + k+=m; + } while (k +#include +#include +#include "big.h" +#include "zzn.h" + +using namespace std; + +// Brents factoring algorithm + +#define mr_min(a,b) ((a) < (b)? (a) : (b)) + +int brent(int id,char * fred,int base) +{ /* factoring program using Brents method */ + long k,r,i,m,iter; + Big n,z; + + ZZn x,y,q,ys; + n=fred; + + cout << "thread "<< id << " factoring " << n << endl; + get_mip()->IOBASE=base; + m=10L; + r=1L; + iter=0L; + z=0; + do + { + modulo(n); // ZZn arithmetic done mod n + y=z; // convert back to ZZn (n has changed!) + + cout << "thread " << id << " iteration " << iter << endl; + q=1; + do + { + x=y; + for (i=1L;i<=r;i++) y=(y*y+3); + k=0; + do + { + iter++; + if (iter%10==0) cout << "thread " << id << " iteration " << iter << endl; + ys=y; + for (i=1L;i<=mr_min(m,r-k);i++) + { + y=(y*y+3); + q=((y-x)*q); + } + z=gcd(q,n); + k+=m; + } while (k +#include +#include +#include +#include "big.h" +#include "zzn.h" + +using namespace std; + +// Brents factoring algorithm + +#define mr_min(a,b) ((a) < (b)? (a) : (b)) + +int brent(int id,char * fred,int base) +{ /* factoring program using Brents method */ + long k,r,i,m,iter; + Big n,z; + + ZZn x,y,q,ys; + n=fred; + + cout << "thread "<< id << " factoring " << n << endl; + get_mip()->IOBASE=base; + m=10L; + r=1L; + iter=0L; + z=0; + do + { + modulo(n); // ZZn arithmetic done mod n + y=z; // convert back to ZZn (n has changed!) + + cout << "thread " << id << " iteration " << iter << endl; + q=1; + do + { + x=y; + for (i=1L;i<=r;i++) y=(y*y+3); + k=0; + do + { + iter++; + if (iter%10==0) cout << "thread " << id << " iteration " << iter << endl; + ys=y; + for (i=1L;i<=mr_min(m,r-k);i++) + { + y=(y*y+3); + q=((y-x)*q); + } + z=gcd(q,n); + k+=m; + } while (k +#include "big.h" +#include "poly.h" +#include "polymod.h" + +using namespace std; + +Miracl precision=100; + + +// Code to parse formula in command line +// This code isn't mine, but its public domain +// Shamefully I forget the source +// +// NOTE: It may be necessary on some platforms to change the operators * and # + +#if defined(unix) +#define TIMES '.' +#define RAISE '^' +#else +#define TIMES '*' +#define RAISE '#' +#endif + +Big tt; +static char *ss; + +void eval_power (Big& oldn,Big& n,char op) +{ + if (op) n=pow(oldn,toint(n)); // power(oldn,size(n),n,n); +} + +void eval_product (Big& oldn,Big& n,char op) +{ + switch (op) + { + case TIMES: + n*=oldn; + break; + case '/': + n=oldn/n; + break; + case '%': + n=oldn%n; + } +} + +void eval_sum (Big& oldn,Big& n,char op) +{ + switch (op) + { + case '+': + n+=oldn; + break; + case '-': + n=oldn-n; + } +} + +void eval (void) +{ + Big oldn[3]; + Big n; + int i; + char oldop[3]; + char op; + char minus; + for (i=0;i<3;i++) + { + oldop[i]=0; + } +LOOP: + while (*ss==' ') + ss++; + if (*ss=='-') /* Unary minus */ + { + ss++; + minus=1; + } + else + minus=0; + while (*ss==' ') + ss++; + if (*ss=='(' || *ss=='[' || *ss=='{') /* Number is subexpression */ + { + ss++; + eval (); + n=tt; + } + else /* Number is decimal value */ + { + for (i=0;ss[i]>='0' && ss[i]<='9';i++) + ; + if (!i) /* No digits found */ + { + cout << "Error - invalid number" << endl; + exit (20); + } + op=ss[i]; + ss[i]=0; + n=atoi(ss); + ss+=i; + *ss=op; + } + if (minus) n=-n; + do + op=*ss++; + while (op==' '); + if (op==0 || op==')' || op==']' || op=='}') + { + eval_power (oldn[2],n,oldop[2]); + eval_product (oldn[1],n,oldop[1]); + eval_sum (oldn[0],n,oldop[0]); + tt=n; + return; + } + else + { + if (op==RAISE) + { + eval_power (oldn[2],n,oldop[2]); + oldn[2]=n; + oldop[2]=RAISE; + } + else + { + if (op==TIMES || op=='/' || op=='%') + { + eval_power (oldn[2],n,oldop[2]); + oldop[2]=0; + eval_product (oldn[1],n,oldop[1]); + oldn[1]=n; + oldop[1]=op; + } + else + { + if (op=='+' || op=='-') + { + eval_power (oldn[2],n,oldop[2]); + oldop[2]=0; + eval_product (oldn[1],n,oldop[1]); + oldop[1]=0; + eval_sum (oldn[0],n,oldop[0]); + oldn[0]=n; + oldop[0]=op; + } + else /* Error - invalid operator */ + { + cout << "Error - invalid operator" << endl; + exit (20); + } + } + } + } + goto LOOP; +} + +int main(int argc,char **argv) +{ + Big n; + int i,ip,r,Base; + BOOL gotN; + miracl*mip=&precision; + + argc--; argv++; + if (argc<1) + { + cout << "Incorrect Usage" << endl; + cout << "Program tests number for primality" << endl; + cout << "using AKS algorithm, conjecture 4" << endl; + cout << "tp " << endl; + cout << "OR" << endl; + cout << "tp -f " << endl; +#if defined(unix) + cout << "e.g. tp -f 2^192-2^64-1" << endl; +#else + cout << "e.g. tp -f 2#192-2#64-1" << endl; +#endif + cout << "To input N in Hex, precede with -h" << endl; + return 0; + } + + ip=0; + gotN=FALSE; + gprime(10000); + +// Interpret command line + Base=10; + while (ipIOBASE=Base; + n=argv[ip++]; + mip->IOBASE=10; + gotN=TRUE; + continue; + } + + cout << "Error in command line" << endl; + return 0; + } + + if (!gotN) + { + cout << "Error in command line" << endl; + return 0; + } + + if (n==2) + { + cout << "PRIME" << endl; + return 0; + } + if (small_factors(n)) + { + cout << "COMPOSITE - has small factors" << endl; + return 0; + } + + if (perfect_power(n)) + { + cout << "COMPOSITE - is a perfect power" << endl; + return 0; + } + + + for (i=0;;i++) + { + r=mip->PRIMES[i]; + if ((n*n-1)%r!=0) break; + } + + modulo(n); + + Variable x; + Poly M=pow(x,r)-1; // M=x^r-1 + + setmod(M); + + PolyMod lhs,rhs; + + lhs=x-1; // left-hand side + lhs=pow(lhs,n); // (x-1)^n mod M + + rhs=x; // right-hand side + rhs=pow(rhs,n)-1; // x^n-1 mod M + + if (lhs==rhs) cout << "PRIME" << endl; + else cout << "COMPOSITE" << endl; + + return 0; +} + diff --git a/miracl/source/williams.c b/miracl/source/williams.c new file mode 100644 index 0000000..460ade3 --- /dev/null +++ b/miracl/source/williams.c @@ -0,0 +1,187 @@ +/* + * Program to factor big numbers using Williams (p+1) method. + * Works when for some prime divisor p of n, p+1 has only + * small factors. + * See "Speeding the Pollard and Elliptic Curve Methods" + * by Peter Montgomery, Math. Comp. Vol. 48. Jan. 1987 pp243-264 + */ + +#include +#include +#include "miracl.h" + +#define LIMIT1 10000 /* must be int, and > MULT/2 */ +#define LIMIT2 500000L /* may be long */ +#define MULT 2310 /* must be int, product of small primes 2.3.. */ +#define NEXT 13 /* next small prime */ +#define NTRYS 3 /* number of attempts */ + +static BOOL plus[1+MULT/2],minus[1+MULT/2]; + +miracl *mip; + +void marks(long start) +{ /* mark non-primes in this interval. Note * + * that those < NEXT are dealt with already */ + int i,pr,j,k; + for (j=1;j<=MULT/2;j+=2) plus[j]=minus[j]=TRUE; + for (i=0;;i++) + { /* mark in both directions */ + pr=mip->PRIMES[i]; + if (prstart) break; + k=pr-start%pr; + for (j=k;j<=MULT/2;j+=pr) + plus[j]=FALSE; + k=start%pr; + for (j=k;j<=MULT/2;j+=pr) + minus[j]=FALSE; + } +} + +int main() +{ /* factoring program using Williams (p+1) method */ + int k,phase,m,nt,iv,pos,btch; + long i,p,pa,interval; + big b,q,n,fp,fvw,fd,fn,t; + static big fu[1+MULT/2]; + static BOOL cp[1+MULT/2]; + mip=mirsys(30,0); + b=mirvar(0); + q=mirvar(0); + n=mirvar(0); + t=mirvar(0); + fp=mirvar(0); + fvw=mirvar(0); + fd=mirvar(0); + fn=mirvar(0); + gprime(LIMIT1); + for (m=1;m<=MULT/2;m+=2) + if (igcd(MULT,m)==1) + { + fu[m]=mirvar(0); + cp[m]=TRUE; + } + else cp[m]=FALSE; + printf("input number to be factored\n"); + cinnum(n,stdin); + if (isprime(n)) + { + printf("this number is prime!\n"); + return 0; + } + for (nt=0,k=3;k<10;k++) + { /* try more than once for p+1 condition (may be p-1) */ + convert(k,b); /* try b=3,4,5.. */ + convert((k*k-4),t); + if (egcd(t,n,t)!=1) continue; /* check (b*b-4,n)!=0 */ + nt++; + phase=1; + p=0; + btch=50; + i=0; + printf("phase 1 - trying all primes less than %d\n",LIMIT1); + printf("prime= %8ld",p); + forever + { /* main loop */ + if (phase==1) + { /* looking for all factors of p+1 < LIMIT1 */ + p=mip->PRIMES[i]; + if (mip->PRIMES[i+1]==0) + { /* now change gear */ + phase=2; + printf("\nphase 2 - trying last prime less than %ld\n" + ,LIMIT2); + printf("prime= %8ld",p); + copy(b,fu[1]); + copy(b,fp); + mad(b,b,b,n,n,fd); + decr(fd,2,fd); + negify(b,t); + mad(fd,b,t,n,n,fn); + for (m=5;m<=MULT/2;m+=2) + { /* store fu[m] = Vm(b) */ + negify(fp,t); + mad(fn,fd,t,n,n,t); + copy(fn,fp); + copy(t,fn); + if (!cp[m]) continue; + copy(t,fu[m]); + } + convert(MULT,t); + lucas(b,t,n,fp,fd); + iv=(int)(p/MULT); + if (p%MULT>MULT/2) iv++; + interval=(long)iv*MULT; + p=interval+1; + convert(iv,t); + lucas(fd,t,n,fp,fvw); + negify(fp,fp); + subtract(fvw,fu[p%MULT],q); + marks(interval); + btch*=100; + i++; + continue; + } + pa=p; + while ((LIMIT1/p) > pa) pa*=p; + convert((int)pa,t); + lucas(b,t,n,fp,q); + copy(q,b); + decr(q,2,q); + } + else + { /* phase 2 - looking for last large prime factor of (p+1) */ + p+=2; + pos=(int)(p%MULT); + if (pos>MULT/2) + { /* increment giant step */ + iv++; + interval=(long)iv*MULT; + p=interval+1; + marks(interval); + pos=1; + copy(fvw,t); + mad(fvw,fd,fp,n,n,fvw); + negify(t,fp); + } + if (!cp[pos]) continue; + + /* if neither interval+/-pos is prime, don't bother */ + if (!plus[pos] && !minus[pos]) continue; + subtract(fvw,fu[pos],t); + mad(q,t,t,n,n,q); /* batching gcds */ + } + if (i++%btch==0) + { /* try for a solution */ + printf("\b\b\b\b\b\b\b\b%8ld",p); + fflush(stdout); + egcd(q,n,t); + if (size(t)==1) + { + if (p>LIMIT2) break; + else continue; + } + if (mr_compare(t,n)==0) + { + printf("\ndegenerate case"); + break; + } + printf("\nfactors are\n"); + if (isprime(t)) printf("prime factor "); + else printf("composite factor "); + cotnum(t,stdout); + divide(n,t,n); + if (isprime(n)) printf("prime factor "); + else printf("composite factor "); + cotnum(n,stdout); + return 0; + } + } + if (nt>=NTRYS) break; + printf("\ntrying again\n"); + } + printf("\nfailed to factor\n"); + return 0; +} + diff --git a/miracl/source/williams.cpp b/miracl/source/williams.cpp new file mode 100644 index 0000000..48ff24b --- /dev/null +++ b/miracl/source/williams.cpp @@ -0,0 +1,181 @@ +/* + * Program to factor big numbers using Williams (p+1) method. + * Works when for some prime divisor p of n, p+1 has only + * small factors. + * See "Speeding the Pollard and Elliptic Curve Methods" + * by Peter Montgomery, Math. Comp. Vol. 48. Jan. 1987 pp243-264 + * + * Requires: big.cpp zzn.cpp + * + */ + +#include +#include + +#include "zzn.h" + +using namespace std; + +#define LIMIT1 10000 /* must be int, and > MULT/2 */ +#define LIMIT2 500000L /* may be long */ +#define NEXT 13 /* next small prime */ +#define MULT 2310 /* must be int, product of small primes 2.3.. */ +#define NTRYS 3 /* number of attempts */ + +Miracl precision=50; /* number of ints per ZZn */ + +miracl *mip; +static long p; +static int iv; +static ZZn b,q,fvw,fd,fp,fn,fu[1+MULT/2]; +static BOOL cp[1+MULT/2],Plus[1+MULT/2],Minus[1+MULT/2]; + +void marks(long start) +{ /* mark non-primes in this interval. Note * + * that those < NEXT are dealt with already */ + int i,pr,j,k; + for (j=1;j<=MULT/2;j+=2) Plus[j]=Minus[j]=TRUE; + for (i=0;;i++) + { /* mark in both directions */ + pr=mip->PRIMES[i]; + if (prstart) break; + k=pr-start%pr; + for (j=k;j<=MULT/2;j+=pr) + Plus[j]=FALSE; + k=start%pr; + for (j=k;j<=MULT/2;j+=pr) + Minus[j]=FALSE; + } +} + +void next_phase() +{ /* now change gear */ + ZZn t; + long interval; + fp=fu[1]=b; + fd=b*b-2; + fn=fd*b-b; + for (int m=5;m<=MULT/2;m+=2) + { /* store fu[m] = Vm(b) */ + t=fn*fd-fp; + fp=fn; + fn=t; + if (!cp[m]) continue; + fu[m]=t; + } + fd=luc(b,MULT); + iv=p/MULT; + if (p%MULT>MULT/2) iv++; + interval=(long)iv*MULT; + p=interval+1; + marks(interval); + fvw=luc(fd,iv,&fp); + q=fvw-fu[p%MULT]; +} + +int giant_step() +{ /* increment giant step */ + long interval; + ZZn t; + iv++; + interval=(long)iv*MULT; + p=interval+1; + marks(interval); + t=fvw; + fvw=fvw*fd-fp; + fp=t; + return 1; +} + +int main() +{ /* factoring program using Williams (p+1) method */ + int k,phase,m,nt,pos,btch; + long i,pa; + Big n,t; + mip=&precision; + gprime(LIMIT1); + for (m=1;m<=MULT/2;m+=2) + if (igcd(MULT,m)==1) cp[m]=TRUE; + else cp[m]=FALSE; + cout << "input number to be factored\n"; + cin >> n; + if (prime(n)) + { + cout << "this number is prime!\n"; + return 0; + } + modulo(n); /* do all arithmetic mod n */ + for (nt=0,k=3;k<10;k++) + { /* try more than once for p+1 condition (may be p-1) */ + b=k; /* try b=3,4,5.. */ + nt++; + phase=1; + p=0; + btch=50; + i=0; + cout << "phase 1 - trying all primes less than " << LIMIT1; + cout << "\nprime= " << setw(8) << p; + forever + { /* main loop */ + if (phase==1) + { /* looking for all factors of p+1 < LIMIT1 */ + p=mip->PRIMES[i]; + if (mip->PRIMES[i+1]==0) + { /* now change gear */ + phase=2; + cout << "\nphase 2 - trying last prime less than "; + cout << LIMIT2 << "\nprime= " << setw(8) << p; + next_phase(); + btch*=100; + i++; + continue; + } + pa=p; + while ((LIMIT1/p) > pa) pa*=p; + q=luc(b,(int)pa); + b=q; + q-=2; + } + else + { /* looking for last large prime factor of (p+1) */ + p+=2; + pos=p%MULT; + if (pos>MULT/2) pos=giant_step(); + if (!cp[pos]) continue; + + /* if neither interval+/-pos is prime, don't bother */ + + if (!Plus[pos] && !Minus[pos]) continue; + q*=(fvw-fu[pos]); /* batching gcds */ + } + if (i++%btch==0) + { /* try for a solution */ + cout << "\b\b\b\b\b\b\b\b" << setw(8) << p << flush; + t=gcd(q,n); + if (t==1) + { + if (p>LIMIT2) break; + else continue; + } + if (t==n) + { + cout << "\ndegenerate case"; + break; + } + if (prime(t)) cout << "\nprime factor " << t; + else cout << "\ncomposite factor " << t; + n/=t; + if (prime(n)) cout << "\nprime factor " << n; + else cout << "\ncomposite factor " << n; + cout << endl; + return 0; + } + } + if (nt>=NTRYS) break; + cout << "\ntrying again\n"; + } + cout << "\nfailed to factor\n"; + return 0; +} + diff --git a/miracl/source/win64.mcs b/miracl/source/win64.mcs new file mode 100644 index 0000000..0caaf33 --- /dev/null +++ b/miracl/source/win64.mcs @@ -0,0 +1,305 @@ +; Comba/KCM Macros for 64-bit Windows +; +; Note that mr_small is 64-bit unsigned __int64 +; +; Triple register is extra|sumhi|sumlo +; +; See makemcs.txt for more information about this file +; +MACRO PMUL_START + carry=0; +ENDM +MACRO PMUL + su=_umul128(a[%d],sn,&v); + su+=carry; + v+=(sua[0]); + c[0]=u; +ENDM +; +; SUB macro - c[.]=a[.]-b[.] +; +MACRO SUB + ma=a[%d]; + mb=b[%d]; + u=ma-carry; + carry=(u>ma); + ma=u; + u=ma-mb; + carry+=(u>ma); + c[%d]=u; +ENDM +MACRO SUB_END +ENDM +; +; DEC_START macro +; +MACRO DEC_START + u=a[0]-b[0]; + carry=(u>a[0]); + a[0]=u; +ENDM +; +; DEC macro a[.]-=b[.] +; +MACRO DEC + ma=a[%d]; + mb=b[%d]; + u=ma-carry; + carry=(u>ma); + ma=u; + u=ma-mb; + carry+=(u>ma); + a[%d]=u; +ENDM +; +; DEC_END macro +; +MACRO DEC_END +ENDM +; +; KADD_START macro. Zero Carry +; +MACRO KADD_START + carry=0; + k%d: +ENDM +; +; KASL macro +; +MACRO KASL + n--; + if (n==0) goto k%d; + a+=%d; + b+=%d; + c+=%d; + goto k%d; + k%d: +ENDM +; +; KADD_END macro +; +MACRO KADD_END +ENDM +; +; KINC_START macro +; +MACRO KINC_START + carry=0; + k%d: +ENDM +; +; KIDL macro +; +MACRO KIDL + n--; + if (n==0) goto k%d; + a+=%d; + b+=%d; + goto k%d; + k%d: +ENDM +; +; KINC_END macro +; +MACRO KINC_END +ENDM +; +; KDEC_START macro. Zero carry +; +MACRO KDEC_START + carry=0; + k%d: +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END +ENDM diff --git a/miracl/source/zzn.cpp b/miracl/source/zzn.cpp new file mode 100644 index 0000000..09a69c7 --- /dev/null +++ b/miracl/source/zzn.cpp @@ -0,0 +1,192 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * + * MIRACL C++ functions zzn.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ZZn functions using Montgomery + * representation + * NOTE : Must be used in conjunction with big.h and big.cpp + * + */ + +#include "zzn.h" + +big ZZn::getzzn(void) const + { return fn;} + +ZZn& ZZn::operator/=(int i) +{ + if (i==1) return *this; + if (i==2) + { // make a special effort... modulus is odd + nres_div2(fn,fn); + return *this; + } + ZZn x=i; + nres_moddiv(fn,x.fn,fn); + return *this; +} + +BOOL ZZn::iszero() const +{ if (size(fn)==0) return TRUE; return FALSE;} + +ZZn operator-(const ZZn& b) +{ZZn x=b; nres_negate(x.fn,x.fn); return x;} + +ZZn operator+(const ZZn& b,int i) +{ZZn abi=b; abi+=i; return abi;} +ZZn operator+(int i, const ZZn& b) +{ZZn aib=b; aib+=i; return aib;} +ZZn operator+(const ZZn& b1, const ZZn& b2) +{ZZn abb=b1; abb+=b2; return abb;} + +ZZn operator-(const ZZn& b, int i) +{ZZn mbi=b; mbi-=i; return mbi;} +ZZn operator-(int i, const ZZn& b) +{ZZn mib=i; mib-=b; return mib;} +ZZn operator-(const ZZn& b1, const ZZn& b2) +{ZZn mbb=b1; mbb-=b2; return mbb;} + +ZZn operator*(const ZZn& b,int i) +{ZZn xbb=b; xbb*=i; return xbb;} +ZZn operator*(int i, const ZZn& b) +{ZZn xbb=b; xbb*=i; return xbb;} +ZZn operator*(const ZZn& b1, const ZZn& b2) +{ZZn xbb=b1; xbb*=b2; return xbb;} + +ZZn operator/(const ZZn& b1, int i) +{ZZn z=b1; z/=i; return z; } + +ZZn operator/(int i, const ZZn& b2) +{ZZn z=i; nres_moddiv(z.fn,b2.fn,z.fn); return z;} +ZZn operator/(const ZZn& b1, const ZZn& b2) +{ZZn z=b1; z/=b2; return z;} + +ZZn pow( const ZZn& b1, const Big& b2) +{ZZn z; nres_powmod(b1.fn,b2.getbig(),z.fn);return z;} + +ZZn pow( const ZZn& b,int i) +{ZZn z; Big ib=i; nres_powmod(b.fn,ib.getbig(),z.fn); return z;} + +ZZn pow( const ZZn& b1, const Big& b2, const ZZn& b3,const Big& b4) +{ZZn z; nres_powmod2(b1.fn,b2.getbig(),b3.fn,b4.getbig(),z.fn); return z;} + +int jacobi(const ZZn& x) +{redc(x.fn,get_mip()->w1); return jack(get_mip()->w1,get_mip()->modulus); } + +#ifndef MR_NO_RAND +ZZn randn(void) +{ZZn z; bigrand(get_mip()->modulus,z.fn); return z;} +#endif +BOOL qr(const ZZn& x) +{redc(x.fn,get_mip()->w1); if (jack(get_mip()->w1,get_mip()->modulus)==1) return TRUE; return FALSE; } + +BOOL qnr(const ZZn& x) +{redc(x.fn,get_mip()->w1); if (jack(get_mip()->w1,get_mip()->modulus)==-1) return TRUE; return FALSE;} + +ZZn one(void) +{ + ZZn w; + w=get_mip()->one; + return w; +} + +ZZn getA(void) +{ + ZZn w; + if (get_mip()->AsizeAsize; + else w=get_mip()->A; + return w; +} + +ZZn getB(void) +{ + ZZn w; + if (get_mip()->BsizeBsize; + else w=get_mip()->B; + return w; +} + +#ifndef MR_STATIC + +ZZn pow(int n,ZZn *a,Big *b) +{ + ZZn z; + int i; + big *x=(big *)mr_alloc(n,sizeof(big)); + big *y=(big *)mr_alloc(n,sizeof(big)); + for (i=0;ifn,z.fn); +// else nres_lucas(b1.fn,b2.getbig(),z.fn,z.fn); +// return z;} + + +ZZn sqrt(const ZZn& b) +{ZZn z; nres_sqroot(b.fn,z.fn); return z;} + +#ifndef MR_NO_STANDARD_IO + +ostream& operator<<(ostream& s,const ZZn& xx) +{ + ZZn b=xx; + Big x=(Big)b; + s << x; + return s; +} + +#endif diff --git a/miracl/sparc.txt b/miracl/sparc.txt new file mode 100644 index 0000000..6d254e9 --- /dev/null +++ b/miracl/sparc.txt @@ -0,0 +1,176 @@ + +NOTE: On Sparcs with hardware support for quad-precision long doubles, +it may be optimal to build a MIRACL library using a "double" underlying +type rather than use the approach described here. See double.txt + +************************************* + + +These comments apply to the standard 32-bit SPARC (Version 8) processor with +hardware 32-bit multiplication. For 64-bit SPARC (Version 9) see below. + + +************************************* + +If developing for the SPARC, or indeed any other new processor, you should +first build a C-only library. + +For the SPARC, this mirdef.h header would be appropriate for an integer- +only build of the library. + +-------------------------------------- + +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + + +#define MIRACL 32 +#define MR_BIG_ENDIAN +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_dltype long long +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned long long +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + + +#define MR_NOASM + +--------------------------------------------- + +Assuming that the mirdef.h, miracl.h and mr*.c files are all in the same +directory, then a suitable batch file for building a MIRACL library might +look like this:- + +------------------------------- + +gcc -I. -c -O2 mrcore.c +gcc -I. -c -O2 mrarth0.c +gcc -I. -c -O2 mrarth1.c +gcc -I. -c -O2 mrarth2.c +gcc -I. -c -O2 mralloc.c +gcc -I. -c -O2 mrsmall.c +gcc -I. -c -O2 mrio1.c +gcc -I. -c -O2 mrio2.c +gcc -I. -c -O2 mrgcd.c +gcc -I. -c -O2 mrjack.c +gcc -I. -c -O2 mrxgcd.c +gcc -I. -c -O2 mrarth3.c +gcc -I. -c -O2 mrbits.c +gcc -I. -c -O2 mrrand.c +gcc -I. -c -O2 mrprime.c +gcc -I. -c -O2 mrcrt.c +gcc -I. -c -O2 mrscrt.c +gcc -I. -c -O2 mrmonty.c +gcc -I. -c -O2 mrpower.c +gcc -I. -c -O2 mrsroot.c +gcc -I. -c -O2 mrcurve.c +gcc -I. -c -O2 mrfast.c +gcc -I. -c -O2 mrzzn2.c +gcc -I. -c -O2 mrzzn2b.c +gcc -I. -c -O2 mrzzn3.c +gcc -I. -c -O2 mrecn2.c +gcc -I. -c -O2 mrshs.c +gcc -I. -c -O2 mrshs256.c +gcc -I. -c -O2 mrshs512.c +gcc -I. -c -O2 mraes.c +gcc -I. -c -O2 mrlucas.c +gcc -I. -c -O2 mrstrong.c +gcc -I. -c -O2 mrbrick.c +gcc -I. -c -O2 mrebrick.c +gcc -I. -c -O2 mrec2m.c +gcc -I. -c -O2 mrgf2m.c +ar rc miracl.a mrcore.o mrarth0.o mrarth1.o mrarth2.o mralloc.o mrsmall.o +ar r miracl.a mrio1.o mrio2.o mrjack.o mrgcd.o mrxgcd.o mrarth3.o mrsroot.o +ar r miracl.a mrrand.o mrprime.o mrcrt.o mrscrt.o mrmonty.o mrcurve.o +ar r miracl.a mrfast.o mrshs.o mraes.o mrlucas.o mrstrong.o mrbrick.o +ar r miracl.a mrebrick.o mrgf2m.o mrec2m.o mrpower.o mrzzn2b.o +ar r miracl.a mrshs256.o mrshs512.o mrbits.o mrzzn2.o mrzzn3.o mrecn2.o +del mr*.o +gcc -I.-O2 pk-demo.c miracl.a -o pk-demo + +-------------------------------------------- + +This may be fast enough for you. If its not you can use the assembly language +macros provided in sparc32.mcs for greater speed. See kcmcomba.txt. + +For faster RSA and DH implementations replace the MR_NOASM definition with +MR_KCM n (where n is usually 4, 8 or 16 - experiment. n*MIRACL must divide the +modulus size in bits exactly, which it will for standard moduli of 1024 bit +for example). Compile and run the utility mex.c + +c:\miracl>mex n sparc32 mrkcm + +(Yes its the same n). Rebuild the MIRACL library, but this time include the +modules mrkcm.c and mrmuldv.c (you can find the latter as mrmuldv.ccc This +standard C version will do, although the SPARC asm versions from mrmuldv.any +are faster. These would need to be assembled rather than compiled) + +For fast GF(p) elliptic curves, replace MR_NOASM with MR_COMBA n. This time +32*n is exactly the size of p in bits (assuming 32-bit processor). + +c:\miracl>mex n sparc32 mrcomba + +Rebuild the MIRACL library, but this time include the modules mrcomba.c and +mrmuldv.c. + +Still not fast enough? If the prime p is of a "special" form, define in +mirdef.h MR_SPECIAL. Edit mrcomba.tpl to insert "special" code for modular +reduction - its quite easy and you will find examples there already. Run +mex as before, and rebuild MIRACL again. + +For processors other than the SPARC, the basic procedure is the same. A C-only +build is always possible. To go faster you will need to create a .mcs file +for your processor, and then you can proceed as above. + +An alternative is to do a C-only build and then go in and optimise the +generated assembly language. The time-critical routines are usually +multiply() and redc() which can be found in mrarth2.c and mrmonty.c + +This will probably not be as fast as the highly optimised approach outlined +above. + + +---------------------------------------------------------- + +64-bit SPARC (Version 9). Alas not a "real" 64-bit processor in the sense that +there is no 64x64=128 bit multiply instruction. + + +The standard C header files mirdef.h should in this case look like + + +-------------------------------------- + +/* + * MIRACL compiler/hardware definitions - mirdef.h + */ + + +#define MIRACL 32 +#define MR_BIG_ENDIAN +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_dltype long +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned long +#define MAXBASE ((mr_small)1<<(MIRACL-1)) + + +#define MR_NOASM + +--------------------------------------------- + + +Compile as above, but include compiler flag -m64. Also you may need to change +-O2 to -O1 - when I tried it -O2 optimization was broken. + + +For faster assembly language implementation proceed as above, but this time +use macros from sparc64.mcs + +____________________________________________ + diff --git a/miracl/sse2.txt b/miracl/sse2.txt new file mode 100644 index 0000000..6408d4f --- /dev/null +++ b/miracl/sse2.txt @@ -0,0 +1,82 @@ +If you have a Pentium 4 or clone processor that supports the SSE2 +extensions, then using these instructions can be faster. + +The file sse2.mcs is provided as a plug-in alternative for ms86.mcs, and +gccsse2.mcs is provided as an alternative for gcc386.mcs + +Using the COMBA or KCM methods and these provided macros, PCs will execute +big number code up to 60% faster. Ideal for a Pentium 4 based Crypto server. +See kcmcomba.txt + +It is the programmers responsibility to ensure that their hardware and their +compiler supports SSE2 extensions. + +Tested with latest Microsoft (use sse2.mcs) and GCC compilers (V3.3 or greater +- use gccsse2.mcs) + +The key instruction is PMULUDQ which multiplies two pairs of 32-bit numbers in +a single instruction. Unfortunately trying to exploit this capability is very +difficult. But even just using it for a single multiplication is faster than +the standard x386 MUL instruction. However SSE2 instructions do not support a +carry flag :(. But the PADDQ instruction adds 64-bit numbers. + +Consider the following trick:- + +The 64-bit result of a PMULUDQ is written to a 128-bit SSE2 register thus + +< 32 bits > + ++--------+---------+----------+-----------+ +| | | | | +|00000000|000000000| Hi | Lo | +| | | | | ++--------+---------+----------+-----------+ + +<---------------- 128 bits ---------------> + + +Now shuffle this (using PSHUFD) so it becomes + + ++--------+---------+----------+-----------+ +| | | | | +|00000000| Hi |0000000000| Lo | +| | | | | ++--------+---------+----------+-----------+ + + +Now accumulate (by simple addition) partial products like these +(see makemcs.txt) in an SSE2 register, using the PADDQ instruction + ++--------+---------+----------+-----------+ +| | | | | +|00000CHi| SumHi |0000000CLo| SumLo | +| | | | | ++--------+---------+----------+-----------+ + + +where CHi and CLo are accumulated carries from each half + +At the bottom of each column of partial products, the sum for the column is +SumLo, and the Carry for the next column is the sum of + + ++--------+---------+----------+-----------+ +| | | | | +| 0 | 0 |0000000CHi| SumHi | +| | | | | ++--------+---------+----------+-----------+ + +and + + ++--------+---------+----------+-----------+ +| | | | | +| 0 | 0 | 0 |00000000Clo| +| | | | | ++--------+---------+----------+-----------+ + + +This can easily be achieved using the available shift instructions and PADDQ. + + diff --git a/miracl/st22.txt b/miracl/st22.txt new file mode 100644 index 0000000..1c67880 --- /dev/null +++ b/miracl/st22.txt @@ -0,0 +1,100 @@ +ST22 32-bit smart-card processor + +Supported by the files + +mrmuldv.st2 +st22.mcs +st22_new.mcs +mrkcmx.tpl +mrcombax.tpl +mrcomb2x.tpl + +(To obtain these files, please contact us directly at mscott@indigo.ie) + +The Comba and KCM methods are fully supported. Also support for GF(2^m) +methods, so MR_COMBA2 can be defined. + +The alternative st22_new.mcs file implements the slightly faster hybrid method. + +The inline assembly feature in the compiler is not as powerful as the GCC +compilers, and so special template files are needed to support this +processor (the .tpl files above) + +Note the type "unsigned long long" does not work with the compiler. This +program outputs u=0 while the correct answer is u=0xfffffffe. + +#include + +int main() +{ + unsigned int a,b; + unsigned long long u; + + a=0xFFFFFFFF; b=0xFFFFFFFF; + + u=(unsigned long long)a*b; + printf("u= %x\n",(unsigned int)(u>>32)); + + return 0; +} + +This can be fixed by inserting asm("mov $dspmode,1") before the +multiplication. + + +For a quick-start example extract all the miracl files into +a single directory, and use this mirdef.h header file + +#define MR_BIG_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype long long +#define mr_unsign64 unsigned long long +#define MR_STATIC 6 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_SHORT_OF_MEMORY +#define MR_COMBA 6 +#define MR_SPECIAL + +Next compile the standalone utility mex.c + +Then build the miracl library using + +del miracl.a +mex 6 st22 mrcombax +copy mrmuldv.st2 mrmuldv.c +sjcc -c -O3 mrcore.c +sjcc -c -O3 mrarth0.c +sjcc -c -O3 mrarth1.c +sjcc -c -O3 mrarth2.c +sjcc -c -O3 mrio1.c +sjcc -c -O3 mrxgcd.c +sjcc -c -O3 mrbits.c +sjcc -c -O3 mrmonty.c +sjcc -c -O3 mrsroot.c +sjcc -c -O3 mrcurve.c +sjcc -c -O3 mrjack.c +sjcc -c -O3 mrlucas.c +sjcc -c -O3 mrebrick.c +sjcc -c -O3 mrsmall.c +sjcc -c -O3 mrmuldv.c +sjcc -c -O3 mrcombax.c + +sjar rc miracl.a mrcore.obj mrarth0.obj mrarth1.obj mrarth2.obj +sjar r miracl.a mrio1.obj mrxgcd.obj mrbits.obj mrjack.obj +sjar r miracl.a mrmonty.obj mrcurve.obj mrsroot.obj +sjar r miracl.a mrebrick.obj mrmuldv.obj mrlucas.obj +sjar r miracl.a mrcombax.obj mrsmall.obj +del mr*.obj + +Create a project using the program ecdhp.c, the above mirdef.h header, +the header miracl.h and the miracl.a library + + diff --git a/miracl/texasdsp.txt b/miracl/texasdsp.txt new file mode 100644 index 0000000..c1894d8 --- /dev/null +++ b/miracl/texasdsp.txt @@ -0,0 +1,220 @@ +Using Code Composer Studio V5 and TI cycle-accurate Simulator to build MIRACL +for Texas C6713 processor + +A quick "getting started" project. + +Use this as mirdef.h + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned long long +#define mr_dltype long long +#define MR_NOASM +#define MR_STRIPPED_DOWN +#define MR_ALWAYS_BINARY +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_NOKOBLITZ +#define MR_NO_SS + + +Note that for the C6713 the long integer type is a non-standard 40-bits, so +try to avoid it. + +Create a static library miracl.lib from these modules + +mirdef.h +miracl.h + +mrcore.c +mrarth0.c +mrarth1.c +mrarth2.c +mrsmall.c +mrio1.c +mrio2.c +mrgcd.c +mrjack.c +mrxgcd.c +mrarth3.c +mrbits.c +mrrand.c +mrprime.c +mrcrt.c +mrscrt.c +mrmonty.c +mrpower.c +mrsroot.c +mrlucas.c +mrshs.c +mrshs256.c +mraes.c +mrgcm.c +mrfpe.c +mrstrong.c +mrcurve.c +mrbrick.c +mrebrick.c +mrzzn2.c +mrzzn2b.c +mrzzn3.c +mrecn2.c +mrfast.c +mralloc.c +mrshs512.c +mrsha3.c +mrec2m.c +mrgf2m.c + +Then build the pk-demo project from pk-demo.c, miracl.h, mirdef.h and miracl.lib + +Set the stack size to 0x2000 and the Heap size to 0x6000. Set optimization to -O2 +Turn on and enable the Clock under the Run menu to count clock cycles. + +Build and run the project in the debugger. + + + +Now for a more ambitious project... + +Use this mirdef.h + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned long long +#define mr_dltype long long +#define MR_NOASM +#define MR_STRIPPED_DOWN +#define MR_ALWAYS_BINARY +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_NOKOBLITZ +#define MR_NO_SS +#define MR_STATIC 6 +#define MR_COMBA 6 +#define MR_GENERALIZED_MERSENNE +#define MR_SPECIAL +#define MR_SIMPLE_BASE +#define MR_SIMPLE_IO +#define MR_GENERIC_MT + +Then create mrcomba.c by executing (after compiling mex.c on any PC) + +mex -s 6 c mrcomba + +and create a static miracl.lib library from these components + +mirdef.h +miracl.h + +mrcore.c +mrarth0.c +mrarth1.c +mrarth2.c +mrio1.c +mrjack.c +mrxgcd.c +mrbits.c +mrmonty.c +mrsroot.c +mrlucas.c +mrcurve.c +mrebrick.c +mrcomba.c + +Finally build the ecdhp project from ecdhp.c, miracl.h, mirdef.h and miracl.lib + +Set the stack size to 0x1000 and the Heap size to 0x800 (apparently I/O uses the +heap - this MIRACL build does not - these numbers can be reduced experimentally). +Set optimization to -O2. Turn on and enable the Clock under the Run menu to count clock cycles. + +Build and run the project in the debugger. + +The C6713 is a VLIW processor, so assembly language would be difficult, and is +probably best avoided. +Also it does not support unsigned 32-bit multiplication instruction, which is not +ideal. + + +One more - testecc.c - which exercises Elliptic Curve Diffie-Hellman, Digital Signature and +Encryption using a typical MIRACL based API. MIRACL is basically hidden behind an API +which simply throws around octet strings. Thread-Safe/No-Heap. + +Use this mirdef.h + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define mr_dltype long long +#define mr_unsign64 unsigned long long +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define MR_ALWAYS_BINARY +#define MR_STATIC 8 +#define MR_GENERIC_MT +#define MR_STRIPPED_DOWN +#define MR_NOSUPPORT_COMPRESSION +#define MR_SIMPLE_BASE +#define MR_SIMPLE_IO +#define MR_NOASM +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_NOKOBLITZ +#define MR_NO_SS +#define MR_COMBA 8 +#define MR_GENERALIZED_MERSENNE +#define MR_SPECIAL + +and create mrcomba.c via + +mex -s 8 c mrcomba + +Build miracl.lib from + +mirdef.h +miracl.h + +mrcore.c +mrarth0.c +mrarth1.c +mrarth2.c +mrio1.c +mrgcd.c +mrxgcd.c +mrarth3.c +mrbits.c +mrmonty.c +mrcurve.c +mraes.c +mrshs256.c +mrstrong.c +mrcomba.c + +Build the testecc project from testecc.c, miracl.h, mirdef.h, ecdh.h, ecdh.c, octet.c, octet.h and miracl.lib + +Now we run into a problem. The C compiler does not like to initialise an octet structure like this + + char s0[32]; + octet S0={0,sizeof(s0),s0}; + +So this must be changed throughout to + + char s0[32]; + octet S0={0,sizeof(s0),NULL}; + .. + S0.val=s0; + +Annoying! + +Set the stack size to 0x2000 and the Heap size to 0x800. +Set optimization to -O2. Turn on and enable the Clock under the Run menu to count clock cycles. + diff --git a/miracl/update.txt b/miracl/update.txt new file mode 100644 index 0000000..6b63411 --- /dev/null +++ b/miracl/update.txt @@ -0,0 +1,453 @@ + +Version 4.0 + +The main changes from the earlier version 3.xx is the introduction of the +MIP, Miracl Instance Pointer. This is to facilitate the development of +multi-threaded applications. The manual has been updated, and a few small +bugs dealt with. + +From a programmers point of view, the main change is that previously Global +variables like IOBASE, must now be accessed via the MIP, so + + IOBASE=16; + +gets replaced by + + mip->IOBASE=16; + +The MIP itself is returned by mirsys(), so + + mirsys(200,256); + +now becomes + + miracl *mip=mirsys(200,256); + + +Version 4.01 + +New example programs pk-demo.c and pk-demo.cpp demonstrate popular public key +methods, viz. The Diffie-Hellman key exchange, and the RSA public key system + + +Version 4.1 + +Support for Elliptic Curve PK Crypto systems. New fast Elliptic Curve module +mrcurve.c. This will be very fast on an 32-bit Pentium+ if for example MR_COMBA +is defined as 5 in mirdef.h for 160-bit curve (5*32 = 160) + +Implementation of Elliptic Curve variant of the Digital Signature Standard. + +Montgomery arithmetic now used more extensively internally. + +pk-demo.c/cpp now also implements Elliptic Curve key exchange, and the El +Gamal PK method. + + +Version 4.1.1 + +In mrprime.c - +New trial_divison() function - dual purpose routine to quickly test primality +status of a big integer. +New nxsafeprime() function - speeds up search for so-called safe primes, +for example a prime p for which (p-1)/2 is also prime. + +New Lucus exponentiation module mrlucas.c + + +Version 4.1.2 + +Implementation of Complex Multiplication method for the generation of Elliptic +curves (the previously used method has been shown to generate weak curves). + +This was implemented from description in Annex to IEEE P1363 + +Note the free executable CM.EXE + +Version V4.1.3 + +Inline assembly support for DJGPP C/C++ Compiler. + + +Version V4.1.4 + +New module for implementing Brickell et al's method for exponentiation with +precomputation. + +New facility for user-specified function called periodically by time- +consuming MIRACL functions. Useful for doing a Windows message-pump, or +responding to real-time events. See set_user_function(). + + +Version V4.1.5 + +New multiple-exponentiation program powmodn(), calculates +a^b.c^d.e^f....x^y mod n. Also ecurve_multn() which does the same for +elliptic curves. + +Brickel et al method extended to Elliptic curves. + + +Version V4.2.0 + +C version of KCM method implemented. Might be advantageous for extreme RISC +processors with no integer multiply instruction. Ask for C only build in +config program (you will need to specify a double length type), and follow +instructions. + +Elliptic curve point multiplication speeded up a bit. + +C only code improved. Interesting to note that the 32-bit Microsoft C compiler +- using __int64 as a double length type - now generates code that is nearly as +fast as optimized assembly language (with /O2 flag). + +New low level routine muldvd2() introduced - speeds up time critical loops. +See mrmuldv.any + + + +Version V4.2.1 + +New bmark.c benchmarking program. Shows timings for typical public key crypto +methods. Useful for comparing MIRACL with other Libraries, and for determining +the optimal MIRACL build for a particular application. + +MIRACL routine entry and exit tidied up, and skipped if MR_STRIPPED_DOWN +is defined. + + +Version 4.2.2 + +Implementation of AES encryption algorithm (in fact RIJNDAEL). This is a +"place-holder" for now until actual AES winner is decided. + +Implementation of Cramer-Shoup PK algorithm - see files +crencode.cpp/crdecode.cpp/crsetup.cpp/crgen.cpp + +.. and Schoof's algorithm! Counts number of rational points +on an elliptic curve defined over the field GF(p). + +Note the free Windows Command Prompt executable SCHOOF.EXE, available from +download site + +Version 4.2.3 + +Implementation of Schoof-Elkies-Atkin algorithm , for more efficient +elliptic curve point-counting. Again free Windows Command Prompt executables +(MUELLER.EXE, PROCESS.EXE and SEA.EXE) are available for download. + +Version 4.2.4 + +Schoof and Schoof-Elkies-Atkin algorithm implementations greatly optimized. + + +Version 4.3.0 + +Support for Elliptic Curve Cryptography over GF(2^m). ECDSA implemented for +same - see ecsgen2.c ecsign2.c ecsver2.c. +The C++ class is implemented in ec2.h and ec2.cpp + +Also Schoof's algorithm for point-counting over GF(2^m) curves + + +Version 4.4.0 + +By popular demand! Multi-threaded support. Read the new section in the manual + + +Version 4.4.1 + +new routines bytes_to_big(), big_to_bytes() for easy conversion between pure +binary and bigs. Also strong_bigrand() for ease of access to cryptographically +strong big numbers + + +Version 4.4.2 + +New P1363 wrapper/DLL introduced. Lim-Lee prime generation. General tidy-up, +and more installation help. + + +Version 4.4.3 + +Fuller support for new AES (we were right - it was Rijndael). Also +implemenations of the Lim-Lee algorithm for generating primes, and +implementations of the new SHA-256, SHA-384 and SHA512 hashing algorithms. + + +Version 4.4.3a + +Maintainance release. A few bug fixes. Domain data in +common.dss/common.ecs/common2.ecs is now in Hex, as Hex is used in the +standards documents. Schoof fixed for anomalous curves. + +New section on error messages in the manual. I/O buffer size is now set +dynamically via set_io_buffer_size() routine - no longer fixed in mirdef.h + +Version 4.5 + +New mechanisms for implementing fastest embedded code. The Comba and KCM +methods have been extended and supported for more compiler/processor +combinations. Through the use of the Macro EXpansion program MEX.C macros +can be inserted into supplied templates. If your compiler supports in-line +assembly, this is probably the mechanism to use for best performance on +embedded processors. See kcmcomba.txt for more details. + +Version 4.6 + +Internal structure of big numbers changed, from an array to a simple +struct. Memory alignment problems solved. Support for use of floating-point +"double" type - see double.txt. More IEEE 1363 and P1363a support. + + +Version 4.6.1 + +Implementation of Boneh & Franklin's IBE Identity Based Encryption + + +Version 4.6.2 + +Extended GCD algorithm speeded by 70%. Some minor bugs dealt with. + + +Version 4.6.3 + +Jacobi symbol algorithm substantially speeded up. New program imratio.c +calculates S/M, I/M and J/M ratios + +Version 4.6.4 + +New fast method for assigning C++ Big objects from the stack + +Version 4.6.5 + +New alternative Comba/Kcm macros that "interleave" multiplication steps. This +should be faster on modern load/store architectures. See makemcs.txt +Complex Multiplication utility for counting points on elliptic curves greatly +improved. Comba/Kcm macros for 32-bit SPARC implemented - see sparc.txt and +sparc.mcs. Double base-type code debugged/optimized. Optimizer problem with +Gnu GCC solved. + + +Version 4.7 + +New improved and updated IEEE 1363 support. + +Version 4.7.1 + +New P1363a primitives and methods - DLPSP-NR2/PV, DLSP-NR2, DLVP-NR2, +DLSP-PV, DLVP-PV, ECPSP-NR2/PV, ECSP-NR2, ECVP-NR2, ECSP-PV, ECVP-PV, +EMSA4, EMSR1, EMSR2, EMSR3, DLSSR, DLSSR-PV, IFSSR + +New functions memalloc,memkill and mirvar_mem. When many big variables need to +be created in a C program multiple calls to mirvar can be slow. Better to +allocate space for all in one heap access. See brent.c and p1363.c for an +example of use. + + +Version 4.7.2 + +Cryptographically Strong Pseudo Random Number Generator interface improved. +See test1363.c and p1363.c for example of use. It is now possible to allocate +bigs in C programs from the stack - see brute.c for an example + + +Version 4.7.3 + +New style C++ I/O headers supported. C function "round" renamed to "mround", +"negate" to "negify", to avoid GCC 3.2 name clashes + +Version 4.7.4 + +Base64 I/O supported. Just set IOBASE=64 before input/output + +Version 4.7.5 + +config.c fixed for chars > 8 bits. Elliptic curve point comparison speeded up. +Minor bug fixes. GCC 3.3 support + +Version 4.8 + +Miracl header files now accessed via "*.h" rather than <*.h> (following +numerous complaints!) Very minor changes... Example implementation of Cock's +ID based PK scheme + +Version 4.8.1 + +New Floating Point class - see float.h and float.cpp, and read float.txt. Uses +asymptotically fast FFT methods, so efficient for very high precision +calculation. New CM program - see cm.cpp and cm.txt. Up to 50 times faster. + +Version 4.8.2 + +Full support for Itanium processor. + +Version 4.8.3 + +Support for AMD64 processor. Problem with GCC -O2 optimizer fixed. Some new +experimental code for pairings - see ake.txt + +Version 4.8.4 + +Support for SSE2 Pentium 4 extensions. Up to 60% faster on a PC! See sse2.txt +For example use sse2.mcs to create much faster CM.EXE utility - see cm.txt +New support for ARM using GCC compiler. + +Version 4.8.5 + +Faster C++ wrapper code. Compiler flags /DGF2MS=n and /DZZNS=n speed up +programs substantially by allocating from the stack. Some files renamed. + +Version 5.0.0 + +New support for very constrained environments. It is now possible to build +a miracl library which does not require a heap. Space for big variables can +now be claimed from the stack. Internal functions have been reorganised to +facilitate these changes. More #define options now allow for a smaller +library to be built. These changes apply to both C and C++ programs. See +section 2.4 of the manual for more details. + +Version 5.0.1 + +Minor bug fixes + +Version 5.0.2 + +Precomputation methods updated and improved. Now uses the standard Comb +method, as described in Handbook of Applied Cryptography. Much faster. +When using precomputation the user now specifies the window size - +which allows control over the time-space trade-off. + +Version 5.1.0 + +Support for Koblitz curves. This is completely transparent - the user does +nothing. See the output of bmark program to see speed-up acheived. Change +from IEEE to Lopez-Dahab coordinates for EC(F_2^m}. Significantly faster. + +Version 5.2.0 + +ZZn2 arithmetic now absorbed into MIRACL C library, resulting in faster +pairings. New Lazy reduction algorithm for ZZn2 multiplications, fully +supported by COMBA mechanisms. + +Version 5.2.1 + +Full support for PowerPC G5 64-bit processor + +Version 5.2.2 + +OpenMP supported for multi-core programming - see threadmp.cpp. New small, +fast ECDH example programs ecdh2m.c ecdhp.c (for 32-bit processors) and +ecdh2m16.c (for 16-bit processors). This last is ideal for low powered +wireless sensor networks. + +Version 5.3 + +New program irp.cpp to automatically generate optimal code for insertion +in the reduce2(.) function in mrecgf2m.c +The program findbase.cpp to find the "best" irreducible polynomial, has +been updated. +New program newbasis.cpp converts a value from one irreducible polynomial +representation to another. +New support for 8-bit MIRACL, and for tiny architectures like Atmel AVR +ATmega128. This Atmel device is commonly used in Wireless Sensor Networks. +See ecdh2m8.c and ecdhp8.c and avr.mcs +New mirdef.h option #define MR_SMALL_EWINDOW which if defined uses a +smaller sliding window for elliptic curve point multiplication, which is a +space-time trade off. Useful when RAM is under pressure.. +Also MR_SIMPLE_IO for simple input/output (no base changes, no file I/O, +only input from ROM, and I/O as binary bytes) +And MR_NO_RAND to disable and remove the built in random number generator. +MR_STATIC is now interpreted as a request for the minimum possible code +size, and if it is defined, many rarely used routines are removed. + +Version 5.3.1 + +Module mrecgf2m.c split into mrgf2m.c and mrec2m.c +New amd64.mcs file for very fast 64-bit performance on AMD and newer Intel +processors. See amd64.txt. New Hybrid method for multiplication - experimental. +See amd64.mcs, avr2.mcs and avr4.mcs for some example code. + +Version 5.3.2 + +Support for Pseudo Mersenne Prime moduli of the form 2^n-c, where n is a +multiple of the word length, and c is a small constant. See ecdhp32.c +for an example of use. Improved support for ARM processor. + +Version 5.3.3 + +Solinas's Joint Sparse Form now used for elliptic curve double addition. +New C support for E(Fp^2) elliptic curves. Implementation of the R-ate pairing. +New smaller/faster jacobi symbol code. New utilities romaker.c and romaker2.c +to automatically generate ROMs and precomputed values for elliptic curves. + +Version 5.4 + +Edwards Curves now supported - see edwards.txt +Full support for Win64 applications (64-bit windows) +Some minor improvements to pairings. Some new pairings supported. + +Version 5.4.1 + +New faster pairing implementations - using better extension field towerings. +Some bug fixes + +Version 5.4.2 + +New pairing implementation at high security levels (AES-192 -ake18kssx.cpp). +Some bug fixes. Support for .NET managed code - see managed.txt + +Version 5.4.3 + +Support for AES-GCM mode of operation. See aesgcm.txt and new module mrgcm.c +Precompiled libraries are no longer included in the distribution. + +Version 5.4.4 + +New pairing implementation at high security levels (AES-256 - ake24blsa.cpp). +Some bug fixes in pairing code. + +Version 5.5 + +New high level interface for implementing pairing-based protocols. +See pairings.txt +Protocols can be implemented very succinctly, at various security levels, +and with realistic timings. All known optimizations used. +Many example schemes from P1363.3 implemented. + +Version 5.5.1 + +Improved high-level pairing interface. More options + +Version 5.5.2 + +Support for Analog Devices Blackfin processor + +Version 5.5.3 + +Improved high level interface for pairing-based protocols, with new features. + +Version 5.5.4 + +More example pairings protocols - Attribute-Based, Predicate Based, HIBE +See pairings.txt. Support for Microchip PIC32, see pic32.txt + +Version 5.6 + +Some minor bug fixes. New licensing terms. + +Version 5.6.1 + +New MIRACL module mrzzn4.c + + +Version 7.0.0 + +New support for Format Preserving Encryption. See fpe.pdf and new module mrfpe.c +New support for SHA3 hash function (Keccak). See mrsha3.c +New Macros for MIPS - see mips.mcs + +Version 7.0.1 + +New advice om Texas DSP C6713 processor - see texasdsp.txt +New Typical Thread-Safe No-Heap API example code for ECC - see testecc.c diff --git a/miracl/vc2005.txt b/miracl/vc2005.txt new file mode 100644 index 0000000..d8dbf00 --- /dev/null +++ b/miracl/vc2005.txt @@ -0,0 +1,114 @@ +To build the MIRACL library with Visual C++ V8.0 + +Select New Project, Console Application + +Name: miracl +Location: d:\myprojects (for example) +Solution name: miracl + +Click OK + +Click Application settings +Click on Static library. +Disable precompiled headers +Click on Finish + +Click on Header Files in the left hand pane +Click on Project, and Add Existing Item +Add miracl.h and mirdef.h from wherever you have unzipped the miracl +distribution + +Click on Source Files in the left hand pane +Click on Project, and Add Existing Item +Add the following MIRACL source files from the miracl distribution +to the project + +mraes.c +mralloc.c +mrarth0.c +mrarth1.c +mrarth2.c +mrarth3.c +mrbits.c +mrbrick.c +mrbuild.c +mrcore.c +mrcrt.c +mrcurve.c +mrdouble.c +mrebrick.c +mrec2m.c +mrgf2m.c +mrfast.c +mrflash.c +mrflsh1.c +mrflsh2.c +mrflsh3.c +mrflsh4.c +mrfrnd.c +mrgcd.c +mrgcm.c +mrio1.c +mrio2.c +mrjack.c +mrlucas.c +mrmonty.c +mrmuldv.c +mrpi.c +mrpower.c +mrprime.c +mrrand.c +mrround.c +mrscrt.c +mrshs.c +mrshs256.c +mrshs512.c +mrsmall.c +mrsroot.c +mrstrong.c +mrxgcd.c +mrzzn2.c +mrzzn2b.c +mrzzn3.c +mrecn2.c + +Then Click on Build miracl. The library is created in directory +d:\myprojects\miracl\debug\miracl.lib + +Alternatively create a release version in the obvious way (if desired). +Close this project + +Again Select New Project, Win32 Console Application + +Name: brent +Location: d:\myprojects +Solution name: brent + +Click on OK, click on Application Settings, leave it as Console Application, +and again disable precompiled headers. +Click on Finish. + + +Click on Header Files in the left hand pane +Click on Project, and Add Existing Item +Add miracl.h and mirdef.h from wherever you have unzipped the miracl +distribution +Also add zzn.h and big.h (the files required here are indicated in the +comment /* Requires: big.cpp zzn.cpp */ at the start of brent.cpp) + +Click on Source Files in the left hand pane +Right click on the automatically generated file brent.cpp, and exclude it +from the project. +Click on Project, and Add Existing Item +Add the file brent.cpp from the miracl distribution +Add the files zzn.cpp and big.cpp from the miracl distribution + +Click on Project, and Add Existing Item. Navigate to where-ever the miracl +library has been created (d:\myprojects\miracl\debug\) and add miracl.lib +to the project. Answer No to the dialog that appears. + +Click on Build brent + +The source files are compiled and linked to the miracl library. To run the +program Click on Debug, and then on Start without Debugging. + diff --git a/miracl/win64.txt b/miracl/win64.txt new file mode 100644 index 0000000..ab9a9ed --- /dev/null +++ b/miracl/win64.txt @@ -0,0 +1,24 @@ + +Intel x86-64 now fully supported using Microsoft Visual C++ (Visual Studio) +Note that this environment does NOT support inline assembly, so built-in +intrinsics must be used instead, like umul128() + +Use a header file like + +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype __int64 +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned __int64 +#define MR_FLASH 52 +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define BITSINCHAR 8 + +and use the file mrmuldv.w64 as mrmuldv.c + +There is also a macro file win64.mcs - see kcmcomba.txt and makemcs.txt + +To build the windows x86-64 miracl library, execute the batch file ms64doit.bat + diff --git a/sign.cpp b/sign.cpp new file mode 100644 index 0000000..852ee76 --- /dev/null +++ b/sign.cpp @@ -0,0 +1,107 @@ + +#include +#include "sign.h" +#include "hash.h" +#include "utils.h" + +void getFullkey( + ECC_PARAMS *params, + char *ID, // 用户ID + big d, // 用户部分私钥 + big x, // 用户秘密值 + epoint *X, // 用户公钥 + big sa // 用户完整私钥 +) +{ + // 计算hash值H_2(ID, X) + big h_2_big = mirvar(0); + hash2(ID, X, (*params).p, h_2_big); + + // 计算sa = d + h_2*x mod p + big tmp = mirvar(0); + multiply(x, h_2_big, tmp); + add(d, tmp, sa); + power(sa, 1, (*params).p, sa); // mod p + + mirkill(h_2_big); + mirkill(tmp); +} + +void sign_Thumbur( + ECC_PARAMS *params, + char *ID, // 用户ID + char *msg, // 签名消息 + big sa, // 输入用户完整私钥 + epoint *Q, // 输入用户完整公钥 + epoint *U, // 输出签名的随机数变换 + epoint *PK_pub, //输入KGC的公钥 + big v // 输出签名的计算值 +) +{ + // 产生随机数u,计算U=uP + big u = mirvar(0); + bigrand((*params).p, u); + ecurve_mult(u, (*params).P, U); + + // 计算hash值H_3(ID, msg, Q, U, PK_pub) + big h_3_big = mirvar(0); + hash3(ID, msg, Q, U, PK_pub, (*params).p, h_3_big); + + // 计算签名值 v = u + h_3*sa + big tmp = mirvar(0); + multiply(sa, h_3_big, tmp); + add(u, tmp, v); + power(v, 1, (*params).p, v); // mod p + outbig(v, "v"); + + mirkill(u); + mirkill(h_3_big); + mirkill(tmp); +} + +bool verify_Thumbur( + ECC_PARAMS *params, + char *ID, + char *msg, + epoint *Q, + epoint *PK_pub, + epoint *U, + big v +) +{ + // 计算hash值H_1(ID, Q, PK_pub) + big h_1_big = mirvar(0); + hash1(ID, Q, PK_pub, (*params).p, h_1_big); + + // 计算hash值H_3(ID, msg, Q, U, PK_pub) + big h_3_big = mirvar(0); + hash3(ID, msg, Q, U, PK_pub, (*params).p, h_3_big); + + // 验签等式 v*P = U + h_3(Q + h_1*P_pub) + // 等式左边: + epoint *left = epoint_init(); + ecurve_mult(v, (*params).P, left); + + // 等式右边: + epoint *tmp_p = epoint_init(); + ecurve_mult(h_1_big, PK_pub, tmp_p); + ecurve_add(Q, tmp_p); + ecurve_mult(h_3_big, tmp_p, tmp_p); + ecurve_add(U, tmp_p); + + bool bRv = false; + if (epoint_comp(left, tmp_p)) + { + bRv = true; + } + else + { + bRv = false; + } + + mirkill(h_1_big); + mirkill(h_3_big); + epoint_free(left); + epoint_free(tmp_p); + return bRv; +} \ No newline at end of file diff --git a/sign.h b/sign.h new file mode 100644 index 0000000..839c9d5 --- /dev/null +++ b/sign.h @@ -0,0 +1,36 @@ +#ifndef __SIGN_H__ +#define __SIGN_H__ + +#include "ecurve.h" + +void getFullkey( + ECC_PARAMS *params, + char *ID, // 用户ID + big d, // 用户部分私钥 + big x, // 用户秘密值 + epoint *X, // 用户公钥 + big sa // 用户完整私钥 +); + +void sign_Thumbur( + ECC_PARAMS *params, + char *ID, // 用户ID + char *msg, // 签名消息 + big sa, // 用户完整私钥 + epoint *Q, // 用户完整公钥 + epoint *U, // 输出签名的随机数变换 + epoint *PK_pub, //kgc公钥 + big v // 输出签名的计算值 +); + +bool verify_Thumbur( + ECC_PARAMS *params, + char *ID, + char *msg, + epoint *Q, + epoint *PK_pub, + epoint *U, + big v +); + +#endif \ No newline at end of file diff --git a/utils.cpp b/utils.cpp new file mode 100644 index 0000000..394c78c --- /dev/null +++ b/utils.cpp @@ -0,0 +1,76 @@ +#include +#include +#include +#include "utils.h" +#include "ecurve.h" +#include "kgc.h" + +//将big大数类型转为char*类型 +void outbig(big num, char *val_name) +{ + char out_str[257] = {0}; + cotstr(num, out_str); + printf("\nchar str_%s[] = \"%s\";", val_name, out_str); +} + +//将big大数类型转为char*类型 +void outpoint(epoint *PO, char *val_name) +{ + char out_str[257] = {0}; + big PO_x = mirvar(0); + big PO_y = mirvar(0); + epoint_get(PO, PO_x, PO_y); + cotstr(PO_x, out_str); + printf("\nchar str_%s_x[]= \"%s\";", val_name, out_str); + cotstr(PO_y, out_str); + printf("\nchar str_%s_y[]= \"%s\";", val_name, out_str); +} + +// 设置随机数种子 +void setRandSeed() +{ + time_t seed; + time(&seed); // 用系统时间做种子 + irand((long)seed); + return; +} + +// +void sha256_update_string(sha256 sh, const char *data, long data_len) +{ + for (long i = 0; i < data_len; i++) + { + shs256_process(&sh, data[i]); + } +} + +void sha256_update_point(sha256 sh, epoint *point) +{ + big point_x = mirvar(0); + big point_y = mirvar(0); + char point_x_string[256] = {0}; + char point_y_string[256] = {0}; + epoint_get(point, point_x, point_y); + cotstr(point_x, point_x_string); + cotstr(point_y, point_y_string); + + for (unsigned int i = 0; i < strlen(point_x_string); i++) + { + shs256_process(&sh, point_x_string[i]); + } + + for (unsigned int i = 0; i < strlen(point_y_string); i++) + { + shs256_process(&sh, point_y_string[i]); + } + + mirkill(point_x); + mirkill(point_y); +} + +//用户产生秘密值x,以及与基点点乘后的X +void genSecret(ECC_PARAMS *params, big x, epoint *X) +{ + bigrand((*params).p, x); //产生小于阶p的big值 + ecurve_mult(x, (*params).P, X); +} diff --git a/utils.h b/utils.h new file mode 100644 index 0000000..10e70d6 --- /dev/null +++ b/utils.h @@ -0,0 +1,26 @@ +#ifndef __UNTILS_H__ +#define __UNTILS_H__ + +extern "C" +{ +#include "miracl.h" +#include "mirdef.h" +} +#include "ecurve.h" + +void outbig(big num, char *val_name); + +void outpoint(epoint *PO, char *val_name); + +void setRandSeed(); + +void sha256_update_string(sha256 sh, const char *data, long data_len); + +void sha256_update_point(sha256 sh, epoint *point); + +void genSecret(ECC_PARAMS *params, big x, epoint *X); + +bool Setup(); + + +#endif \ No newline at end of file

j;m--) l[m]=l[m-1]; + l[j]=p; // insert largest prime power in table + } + else + { + start_prime=i; + break; + } + } + +// table of primes and prime powers now looks like:- +// 2 3 5 7 9 11 13 16 17 19 .... +// S p p + +// where S is start_prime, and p marks the largest prime powers in the range +// CRT uses primes starting from S, but small primes are kept in anyway, +// as they allow quick abort if searching for prime NP. + +// Calculate Divisor Polynomials +// Set the first few by hand.... + + P[0]=0; P[1]=1; P[2]=0; P[3]=0; P[4]=0; + + P2[1]=1; P3[1]=1; + + P[2].addterm(1,1); + + P2[2]=P[2]*P[2]; + P3[2]=P2[2]*P[2]; + + P[3].addterm(B,0); + P[3].addterm(1,3); + P[3].addterm(1,4); + + P2[3]=P[3]*P[3]; + P3[3]=P2[3]*P[3]; + + P[4].addterm(B,2); + P[4].addterm(1,6); + + P2[4]=P[4]*P[4]; + P3[4]=P2[4]*P[4]; + + lower=5; // next one to be calculated + + t[0]=0; + + Poly2Mod zero,one,XT,XTy,YT,YTy,ZT,XL,YL,ZL,ZL2,ZT2; + one=1; // polynomial = 1 + zero=0; // polynomial = 0 + + Crt CRT(nl-start_prime,&l[start_prime]); // initialise for application of + // chinese remainder thereom + +// now look for trace%prime for prime=3,5,7,11 etc +// actual trace is found by combining these via CRT + + l[0]=4; + if (TR==0) l[0]=8; + + escape=FALSE; + for (i=0;ilower) lower=lp+2; + } + for (tau=0;tau<=lp/2;tau++) permisso[tau]=TRUE; + + eigen=FALSE; + if (lp%2==0) + { // its 2^c + Poly2 G,G2,PI; + GF2m S; + int t=lp,c=0; + while (t!=1) {t/=2; c++;} + +// +// When lp is a power of 2, we can construct a root of the Division Polynomial +// directly. See Menezes P.107. This is much quicker. Then the eigenvalue +// heuristic can be used. +// + + S=sqrt(sqrt((GF2m)B)); + G=X+S; + G2=G*G; + PI=1; + + for (jj=2;jjlow) low=tau+3; + + if (tau==1) + { // easy case + Ax=ZT2XP+XT; + Bx=XTy; + } + else + { + Pt=Pf[tau-1]*Pf[tau+1]; + Ax=ZT2*(XP*P2f[tau]+Pt)+P2f[tau]*XT; + Bx=P2f[tau]*XTy; + } + + Hx=Ax*Ax+XX*Ax*Bx+MFX*(Bx*Bx); + + if (iszero(Hx)) // NOTE: GCD not needed + { // found it. Now compare Y coordinates to determine sign + + if (tau==1) + { + Ax=YT+ZT3*YP; + Bx=YTy+ZT3*YPy; + } + else + { + Tx=XP*P2f[tau]*Pf[tau]; + Pt*=Pf[tau]; + Ax=YT*Tx+ZT3*(Tx*(XP+YP)+(XP2+XP+YP)*Pt+Pf[tau-2]*P2f[tau+1]); + Bx=YTy*Tx+ZT3*YPy*(Tx+Pt); + } + + Hx=Ax*Ax+XX*Ax*Bx+MFX*(Bx*Bx); // substitute into curve + if (!iszero(Hx)) + { // its the other one + tau=(lp-tau)%lp; + cout << "\b\b\b\b"; + cout << setw(4) << (p+1-tau)%lp << flush; + } + t[i]=tau; + if ((p+1-tau)%lp==0) + { + cout << " ***" << endl; + if (search) escape=TRUE; + } + else cout << endl; + break; + } + cout << "\b\b\b\b"; + } + + for (jj=0;jjIOBASE=16; + ofile << aa << endl; + ofile << bb << endl; + ofile << nrp << endl; + ofile << x << endl; + ofile << y << endl; + mip->IOBASE=10; + ofile << a << endl; + ofile << b << endl; + ofile << c << endl; + } + + if (p==nrp) + { + cout << "WARNING: Curve is anomalous" << endl; + return 0; + } + +// check MOV condition for curves of Cryptographic interest +// if (M<128) return 0; + + nrp/=2; + if (nrp%2==0) nrp/=2; + + d=1; + for (i=0;i<50;i++) + { + d=modmult(d,p,nrp); + if (d==1) + { + if (i==1 || prime(nrp)) cout << "WARNING: Curve fails MOV condition, k= " << i << endl; + else cout << "WARNING: Curve fails MOV condition, k<= " << i << endl; + return 0; + } + } + + return 0; +} + diff --git a/miracl/source/curve/schoof2.txt b/miracl/source/curve/schoof2.txt new file mode 100644 index 0000000..ff9a546 --- /dev/null +++ b/miracl/source/curve/schoof2.txt @@ -0,0 +1,34 @@ +To build the Schoof2 application, you must compile and link the modules +together, with MIRACL C++ classes, and with the MIRACL library. + +A precompiled Windows executable is available from +ftp://ftp.compapp.dcu.ie/pub/crypto/schoof2.exe + +So for Borland C++ (although MS C++ is a fair bit quicker) + +bcc32 schoof2.cpp poly2.cpp poly2mod.cpp ec2.cpp big.cpp gf2m.cpp crt.cpp +miracl.lib + +For MS C + +cl /O2 /GX schoof2.cpp poly2.cpp poly2mod.cpp ec2.cpp big.cpp gf2m.cpp crt.cpp +miracl.lib + +On UNIX using g++, something like + +g++ -I. -c poly2.cpp +g++ -I. -c poly2mod.cpp + + +g++ -I. schoof2.cpp poly2.o poly2mod.o big.o gf2m.o ec2.o crt.o +miracl.a /usr/lib/libm.a -o schoof2 + +should work + + +Note that the headers poly2.h and poly2mod.h are assumed to be in +the local directory. + +To find a suitable polynomial basis refer to the table providing in +IEEE-P1363 Annex A, or compile and run the example program findbase.cpp + diff --git a/miracl/source/curve/sea.cpp b/miracl/source/curve/sea.cpp new file mode 100644 index 0000000..64d6d7f --- /dev/null +++ b/miracl/source/curve/sea.cpp @@ -0,0 +1,1681 @@ +// Schoof-Elkies-Atkin Algorithm! +// Mike Scott August 1999 mike@compapp.dcu.ie +// Counts points on GF(p) Elliptic Curve, y^2=x^3+Ax+B a prerequisite +// for implemention of Elliptic Curve Cryptography +// This program is intended as an aid to Cryptographers in generating +// suitable curves (ideally with a prime number of points) with respect +// to prime moduli from 160 to 512 bits in length. This can be done with +// relatively modest computing facilities - the average home computer and +// a little patience will suffice. +// +// An "ideal" curve is defined as one with with prime number of points. +// +// First the credits +// +// Basic algorithm is due to Schoof +// 1. "Elliptic Curves Over Finite Fields and the Computation of Square Roots +// mod p", Rene Schoof, Math. Comp., Vol. 44 pp 483-494 +// +// Elkies-Atkin ideas are described in +// +// 2. "Counting points on Elliptic Curves over Finite Fields", Rene Schoof, +// Jl. de Theorie des Nombres de Bordeaux 7 (1995) pp 219-254 +// +// The particular variation implemented here is due to Mueller. See his thesis +// +// 3. "Ein Algorithmus zur Bestimmung der Punktanzahl elliptischer Kurven +// uber endlichen Korpern der Charakteristik grosser drei", +// available from Volker Mueller's home page +// www.informatik.th-darmstadt.de/TI/Mitarbeiter/vmueller.html +// +// Other useful English-language publications are available from this site. +// Strongly recommended is the recent book +// +// 4. "Elliptic Curves in Cryptography" +// by Blake, Seroussi and Smart, London Mathematical Society Lecture Note +// Series 265, Cambridge University Press. ISBN 0 521 65374 6 +// +// Another useful reference is +// 5. Elliptic Curve Public Key Cryptosystems", Menezes, +// Kluwer Academic Publishers, Chapter 7 +// +// The Kangaroo continuation is due to Pollard:- +// +// 6. "Monte Carlo Methods for Index Computation" +// by J.M. Pollard in Math. Comp. Vol. 32 1978 pp 918-924 +// +// Fast FFT methods are largely as described by Shoup +// +// 7. "A New Polynomial Factorisation Algorithm and its implementation", +// Victor Shoup, Jl. Symbolic Computation, 1996 +// +// A potentially more effective way of using Atkin primes is described in +// +// 8. "Remarks on the Schoof-Elkies-Atkin Algorithm", L. Dewaghe, Math. Comp. +// Vol. 67, 223, July 1998, pp 1247-1252 +// +// Thanks are due to Richard Crandall for his encouragment, and the idea of +// using projective co-ordinates. +// +// NOTE: Only for use on curves over large prime modulus P. +// For smaller P use schoof.exe utility available from the same source. +// +// This first version does not process so-called Atkin primes +// Schoof's original algorithm is used for primes 3, 5 and 7 (this facilitates +// "early abort" using the -s option). +// +// After that only Elkies primes are used. It is therefore not as fast as it +// could be, particularly for smaller values of the prime modulus P. +// However when the asymptotics kick-in, it starts to get competitive (when +// you need it to). Since the average Cryptographer will only wish to +// generate a few curves for practical use, this is deemed to be adequate. +// The final continuation uses Pollard's Lambda ("kangaroo") algorithm. +// +// It is envisaged that from time-to-time this program will be modified +// and hopefully improved - that is speeded up. +// In particular it is planned to exploit Atkin Primes to allow two herds of +// kangaroos complete the job more efficiently +// +// Asyptotically the algorithm should take time O(log(p)^5) +// However the Kangaroo continuation favours "smaller" curves, while +// the asymptotic behaviour is more accurate for "bigger" curves +// +// Timings in minutes:- random curves 180MHz Pentium Pro +// (ignoring time to generate Modular Polynomials) +// +// C1 C2 C3 Ave Asymptotic multiplier wrt 160 bits +// 160-bit 2.5 3.0 2.0 2.5 1 +// 192-bit 5.5 5.5 3.5 4.8 2.5 +// 224-bit 9 7.5 10 8.8 5.4 +// 256-bit 13.5 21.5 23 19.3 10.5 +// 384-bit 86 108 120 105 60 +// 512-bit 600 357 398 452 336 +// +// As can be seen the asymptotic behaviour of the program would appear to +// be about right. The wide variations in timing for the same size of curve +// is typical - it depends on how "lucky" you are finding Elkies Primes +// +// **************** +// Download Instructions +// +// To access the Windows 'NT/95/98 executables directly, point your +// browser at ftp://ftp.compapp.dcu.ie/pub/crypto, and download +// +// mueller.exe +// modpol.exe +// process.exe +// sea.exe +// +// The main program source file for these programs may be found in the +// same place, with .cpp extensions. +// +// To obtain the full source code first look at +// the README file on the ftp site, and then download +// +// ftp://ftp.compapp.dcu.ie/pub/crypto/miracl.zip +// To recompile, see the file sea.txt +// +// For more information:- +// +// http://indigo.ie/~mscott +// +// **************** +// Instructions for use +// +// First run the utility "mueller" to build up a collection of Modular +// Polynomials. Each modular polynomial is associated with a small odd prime. +// This needs to be done once only - ever, but you can from time +// to time augment your collection of Polynomials by running it again. +// Its quite time consuming, but in less than an hour you should have enough +// to get started. The more you have, the bigger the prime modulus that you +// can use. +// +// Then run the utility "process" to process the raw polynomial file with +// respect to your chosen prime modulus P. This need to be done just once for +// every prime modulus of interest to you. This takes only a few minutes at +// most. +// +// An alternative is to use instead the "modpol" application, which is a +// composite of "mueller" and "process". It directly generates the Modular +// Polynomials reduced wrt a pre-specified prime modulus, suitable for +// immediate use by "sea". If working with limited computing resources such +// that sufficient generic Modular Polynomials cannot be generated by +// "mueller", this may be your only alternative. +// +// Finally run this program "sea" specifying the A and B parameters of the +// particular curve. This program can also search through many curves for +// a curve ideal for cryptographic use (with a prime number of points). +// +// For example try:- +// +// mueller 0 120 -o mueller.raw +// process -f 65112*2#144-1 -i mueller.raw -o test160.pol +// sea -3 49 -i test160.pol +// +// Here the "mueller" program generates modular polynomials for all odd primes +// in the range 0 - 120 into the file mueller.raw. The "process" application +// reduces these 'raw' polynomials wrt the 160 bit prime modulus +// P = 65112*2^144-1 to a file test160.pol. The "sea" application uses this +// file to count the points on the curve Y^2 = X^3 - 3X + 49 mod P +// +// Alternatively:- +// +// modpol -f 65112*2#144-1 0 120 -o test160.pol +// sea -3 49 -i test160.pol +// +// The number of Modular Polynomials required depends on the size of the +// prime modulus P. It is also random in the sense that it depends on the +// probability of each small prime being an "Elkies" prime wrt the given curve. +// In the vast majority of cases the range suggested to "mueller" or "modpol" +// should be 0 to bits(P), where bits(P) is the number of bits in P. However +// you might get away with a much smaller value if you are lucky with your +// "Elkies" primes. If modular polynomials could not be generated for all +// primes in the range, due to the use of the -s2, -s3 or -s6 flag in +// "mueller" or "modpol" (see comments in mueller.cpp), then a somewhat +// larger range might be needed. +// +// When using the "sea" program, the -s option is particularly useful +// and allows automatic search for an "ideal" curve. If a curve order is +// exactly divisible by a small prime, that curve is immediately abandoned, +// and the program moves on to the next, incrementing the B parameter of +// the curve. This is a fairly arbitrary but simple way of moving on to +// the "next" curve. +// +// Note that if a prime q is an Atkin prime, then we know at least that q +// is not a factor of NP, in other words that NP mod q != 0. +// This can be easily proved. +// +// NOTE: The output file can be used directly with for example the ECDSA +// programs IF AND ONLY IF an ideal curve is found. If you wish to use +// a less-than-ideal curve, you will first have to factor NP completely, and +// find a random point of large prime order. +// +// **************** +// +// Rev. 1 September 1999 - Faster and more Kangaroos! +// Rev. 2 October 1999 - Poly class revamped. Faster search for tau mod lp +// Rev. 3 October 1999 - Eliminated calculation of X^P +// Rev. 4 December 1999 - Various optimizations +// +// This implementation is free. No terms, no conditions. It requires +// version 4.24 or greater of the MIRACL library (a Shareware, Commercial +// product, but free for non-profit making use), +// available from ftp://ftp.compapp.dcu.ie/pub/crypto/miracl.zip +// +// However this program may be freely used (unmodified!) to generate curves +// for commercial use. It may be recompiled for this purpose on any hardware. +// +// 32-bit build only +// +// Note that is a little faster to use an integer-only build of MIRACL. +// See mirdef.hio +// +// + +#include +#include +#include +#include +#include "ecn.h" // Elliptic Curve Class +#include "crt.h" // Chinese Remainder Theorem Class + +// +// poly.h implements polynomial arithmetic. FFT methods are used for maximum +// speed, as the polynomials can get very big. +// But all that gruesome detail is hidden away. +// +// polymod.h implements polynomial arithmetic wrt to a preset poynomial +// modulus. This looks a bit neater. Function setmod() sets the modulus +// to be used. Again fast FFT methods are used. +// +// polyxy.h implements a bivariate polynomial class +// + +#include "poly.h" +#include "polymod.h" +#include "polyxy.h" + +using namespace std; + +#ifndef MR_NOFULLWIDTH +Miracl precision=18; // max. 18x32 bits per big number +#else +Miracl precision(18,MAXBASE); +#endif + +PolyMod MY2,MY4; + +ZZn A,B; // Here ZZn are integers mod the prime p + // Montgomery representation is used internally + +BOOL Edwards=FALSE; + +// Elliptic curve Point duplication formula + +void elliptic_dup(PolyMod& X,PolyMod& Y,PolyMod& Z) +{ // (X,Y,Z)=2.(X,Y,Z) + PolyMod W1,W2,W3,W4; + + W2=Z*Z; // 1 + W3=A*(W2*W2); // 2 + W1=X*X; // 3 + W4=3*W1+W3; + Z*=(2*Y); // 4 Z has an implied y + W2=MY2*(Y*Y); // 5 + W3=4*X*W2; // 6 + W1=W4*W4; // 7 + X=W1-2*W3; + W2*=W2; + W2*=8; // 8 + W3-=X; + W3*=W4; // 9 polynomial multiplications + Y=W3-W2; + X*=MY2; // fix up - move implied y from Z to Y + Y*=MY2; + Z*=MY2; +} + +// +// This is addition formula for two distinct points on an elliptic curve +// Works with projective coordinates which are automatically reduced wrt a +// polynomial modulus +// Remember that the expression for the Y coordinate of each point +// (a function of X) is implicitly multiplied by Y. +// We know Y^2=X^3+AX+B, but we don't have an expression for Y +// So if Y^2 ever crops up - substitute for it +// + +void elliptic_add(PolyMod& XT,PolyMod& YT,PolyMod& ZT,PolyMod& X,PolyMod& Y) +{ // add (X,Y,1) to (XT,YT,ZT) + // on an elliptic curve + PolyMod W1,W2,W4,W5,W6; + + W1=XT; + W6=ZT*ZT; // 1 + W4=X*W6; // 2 * + W1-=W4; + + W2=YT; // W2 has an implied y + W6*=ZT; // 3 + W5=Y*W6; // 4 * W5 has an implied y + W2-=W5; + if (iszero(W1)) + { + if (iszero(W2)) + { // should have doubled + elliptic_dup(XT,YT,ZT); + return; + } + else + { // point at infinity + ZT.clear(); + return; + } + } + + W4=W1+2*W4; // W4=2*W4+W1 + W5=W2+2*W5; // W5=2*W5+W2 + + ZT*=W1; // 5 + + W6=W1*W1; // 6 + W1*=W6; // 7 + W6*=W4; // 8 + W4=MY2*(W2*W2); // 9 Substitute for Y^2 + + XT=W4-W6; + + W6=W6-2*XT; + W2*=W6; // 10 + W1*=W5; // 11 polynomial multiplications + W5=W2-W1; + + YT=W5/(ZZn)2; + + return; +} + +// +// Program to compute the order of a point on an elliptic curve +// using Pollard's lambda method for catching kangaroos. +// +// As a way of counting points on an elliptic curve, this +// has complexity O(p^(1/4)) +// +// However Schoof puts a spring in the step of the kangaroos +// allowing them to make bigger jumps, and lowering overall complexity +// to O(p^(1/4)/sqrt(L)) where L is the product of the Schoof primes +// +// See "Monte Carlo Methods for Index Computation" +// by J.M. Pollard in Math. Comp. Vol. 32 1978 pp 918-924 +// +// This code has been considerably speeded up using ideas from +// "Parallel Collision Search with Cryptographic Applications", van Oorchot +// and Wiener, J. Crypto., Vol. 12, 1-28, 1999 +// + +#define STORE 80 +#define HERD 5 + +ECn wild[STORE],tame[STORE]; +Big wdist[STORE],tdist[STORE]; +int wname[STORE],tname[STORE]; + +Big kangaroo(Big p,Big order,Big ordermod) +{ + ECn ZERO,K[2*HERD],TE[2*HERD],X,P,G,table[128],trap; + Big start[2*HERD],txc,wxc,mean,leaps,upper,lower,middle,a,b,x,y,n,w,t,nrp; + int i,jj,j,m,sp,nw,nt,cw,ct,k,distinguished,nbits; + Big D[2*HERD],s,distance[128],real_order; + BOOL bad,collision,abort; + forever + { +// find a random point on the curve + do + { + x=rand(p); + } while (!P.set(x,x)); + + lower=p+1-2*sqrt(p)-3; // lower limit of search + upper=p+1+2*sqrt(p)+3; // upper limit of search + + w=1+(upper-lower)/ordermod; + leaps=sqrt(w); + mean=HERD*leaps/2; // ideal mean for set S=1/2*w^(0.5) + nbits=bits(leaps/16); + if (nbits>30) nbits=30; + distinguished=1<mean) break; + } + table[0]=ordermod*P; + for (i=1;i1) + middle+=(ordermod+order-middle%ordermod); // middle must be + // order mod ordermod + + for (i=0;i=STORE) + { + abort=TRUE; + break; + } + cout << "." << flush; + tame[nt]=K[jj]; + tdist[nt]=D[jj]; + tname[nt]=jj; + for (k=0;k=STORE) + { + abort=TRUE; + break; + } + cout << "." << flush; + wild[nw]=K[jj]; + wdist[nw]=D[jj]; + wname[nw]=jj; + for (k=0;kPRIMES[i]; + if (sp==0) break; + if (real_order%sp==0) + { + G=P; + G*=(real_order/sp); + if (G==ZERO) + { + real_order/=sp; + continue; + } + } + i++; + } + if (real_order <= 4*sqrt(p)) + { + cout << "Low Order point used - trying again" << endl; + continue; + } + real_order=nrp; + for (i=0;(sp=get_mip()->PRIMES[i])!=0;i++) + while (real_order%sp==0) real_order/=sp; + if (real_order==1) + { // all factors of nrp were considered + cout << "NP= " << nrp << endl; + break; + } + if (prime(real_order)) + { // all factors of NP except for one last one.... + G=P; + G*=(nrp/real_order); + if (G==ZERO) + { + cout << "Failed - trying again" << endl; + continue; + } + else + { + cout << "NP= " << nrp << endl; + break; + } + } +// Couldn't be bothered factoring nrp completely +// Probably not an interesting curve for Cryptographic purposes anyway..... +// But if 10 random points are all "killed" by nrp, its almost +// certain to be the true NP, and not a multiple of a small order. + + bad=FALSE; + for (i=0;i<10;i++) + { + do + { + x=rand(p); + } while (!P.set(x,x)); + G=P; + G*=nrp; + if (G!=ZERO) + { + bad=TRUE; + break; + } + } + if (bad) + { + cout << "Failed - trying again" << endl; + continue; + } + cout << "NP is composite and not ideal for Cryptographic use" << endl; + cout << "NP= " << nrp << " (probably)" << endl; + break; + } + return nrp; +} + +// +// Coefficients Ck from Mueller's lemma 6.2 +// 3. page 90 +// 4. page 127-128 +// + +void get_ck(int terms,ZZn a,ZZn b,ZZn *c) +{ + int k,h; + if (terms==0) return; + c[1]=-a/5; + if (terms==1) return; + c[2]=-b/7; + for (k=3;k<=terms;k++) + { + c[k]=0; + for (h=1;h<=k-2;h++) c[k]+=c[h]*c[k-1-h]; + c[k]*=((ZZn)3/(ZZn)((k-2)*(2*k+3))); + } +} + +// +// quadratic field arithmetic +// needed for Atkin Primes +// + +void mulquad(int p,int qnr,int x,int y,int& a,int& b) +{ + int olda=a; + a=(a*x+b*y*qnr)%p; + b=(olda*y+b*x)%p; +} + +void powquad(int p,int qnr,int x,int y,int e,int& a,int& b) +{ + int k=e; + a=1; + b=0; + if (k==0) return; + + for(;;) + { + if (k%2!=0) + mulquad(p,qnr,x,y,a,b); + k/=2; + if (k==0) return; + mulquad(p,qnr,x,y,x,y); + } +} + +// +// Euler Totient function +// + +int phi(int n) +{ + int i,r=1; + for (i=2;i <-i file>" << endl; + cout << "where the input file contains pre-processed modular polynomials" << endl; + cout << "for a particular prime modulus P" << endl; + cout << "e.g. sea -3 35317045537 -i mueller.pol" << endl; + cout << "To input A and B in Hex, precede with -h" << endl; + cout << "To output to a file, use flag -o " << endl; + cout << "To observe Atkin prime processing, use flag -a" << endl; + cout << "NOTE: Atkin prime information is not currently used" << endl; + cout << "To search for NP prime, incrementing B, use flag -s" << endl; + cout << "(For Edwards curve the search is for NP=4*prime)" << endl; + cout << "\nFreeware from Certivox, Dublin, Ireland" << endl; + cout << "Full C++ source code and MIRACL multiprecision library available" << endl; + cout << "email mscott@indigo.ie" << endl; + return 0; + } + + ip=0; + gprime(10000); // generate small primes < 1000 + search=fout=gotI=gotA=gotB=atkin=FALSE; + a=0; b=0; + +// Interpret command line + Base=10; + while (ipIOBASE=Base; + a=argv[ip++]; + mip->IOBASE=10; + gotA=TRUE; + continue; + } + if (!gotB) + { + mip->IOBASE=Base; + b=argv[ip++]; + mip->IOBASE=10; + gotB=TRUE; + continue; + } + cout << "Error in command line" << endl; + return 0; + } + + if (!gotI || !gotA || !gotB) + { + cout << "Error in command line" << endl; + return 0; + } + +// get prime modulus from .pol file + + mueller >> p; + pbits=bits(p); + if (pbits<64) + { + cout << "Prime modulus too small for this program!" << endl; + cout << "Use SCHOOF program (ftp://ftp.compapp.dcu.ie/pub/crypto/schoof.exe)" << endl; + exit(0); + } + cout << "P= " << p << endl; + cout << "P mod 24 = " << p%24 << endl; + cout << "P is " << pbits << " bits long" << endl; + cout << "Reading in pre-processed Modular Polynomials... " << endl; +// +// read in all pre-processed bivariate modular polynomials +// + modulo(p); // set modulus + l[0]=2; + max=0; + for (i=1;;i++) + { + mueller >> lp; + if (mueller.eof()) break; + max=i; + l[i]=lp; + cout << setw(3) << lp << flush; + posXY=NULL; + Gl[i].clear(); + forever + { + mueller >> c >> nx >> ny; + posXY=Gl[i].addterm((ZZn)c,nx,ny,posXY); + if (nx==0 && ny==0) break; + } + cout << "\b\b\b" << flush; + } + + mueller.close(); + +// loop for "-s" search option + + forever { + + fft_reset(); // reset FFT tables + + if (Edwards) + { + modulo(p); + EB=b; + EA=a; + AZ=(ZZn)1/(EA-EB); + A2=2*(EA+EB)/(EA-EB); + A4=1; AW=1; + + AW*=AZ; A2*=AZ; A4*=AZ; + + A4*=AW; + + T=4*A2; + T1=3*T; + T3=18*36*(2*A4); + + A=T3-3*T1*T1; + B=-T1*T3+2*T1*T1*T1; + ecurve((Big)A,(Big)B,p,MR_AFFINE); // initialise Elliptic Curve + + } + else + { + ecurve(a,b,p,MR_AFFINE); // initialise Elliptic Curve + A=a; + B=b; + } + +// The elliptic curve as a Polynomial + + Y2=0; + Y2.addterm(B,0); + Y2.addterm(A,1); + Y2.addterm((ZZn)1,3); + Y4=Y2*Y2; + + cout << "Counting the number of points (NP) on the curve" << endl; + if (Edwards) + { + cout << "X^2+" << EA << "*Y^2=X^2*Y^2+" << EB << endl; + cout << "Equivalent to Weierstrass form" << endl; + } + cout << "y^2= " << Y2 << " mod " << p << endl; + + delta=-16*(4*A*A*A+27*B*B); + + if (delta==0) + { + cout << "Not Allowed! 4A^3+27B^2 = 0" << endl; + if (search) {b+=1; continue; } + else return 0; + } + + // Calculate j-invariant + + j=(-1728*64*A*A*A)/delta; + + if (j==0 || j==1728) + { + cout << "Not Allowed! j-invariant = 0 or 1728" << endl; + if (search) {b+=1; continue; } + else return 0; + } + + +// Finding the order modulo 2 +// If GCD(X^P-X,X^3+AX+B) == 1 , trace=1 mod 2, else trace=0 mod 2 + + XX=0; + XX.addterm((ZZn)1,1); + YY=0; + YY.addterm((ZZn)-1,0); // Point (X,-Y) + setmod(Y2); + + XP=pow(XX,p); + G=gcd(XP-XX); + parity=0; + if (isone(G)) parity=1; + cout << "NP mod 2 = " << (p+1-parity)%2; + if ((p+1-parity)%2==0) + { + cout << " ***" << endl; + if (search && !Edwards) {b+=1; continue; } + } + else cout << endl; + + nl=0; + accum=1; // accumulated product of good primes + + Poly zero; + PolyMod one,XT,YT,ZT,XL,YL,ZL,ZL2,ZT2; + one=1; // polynomial = 1 + zero=0; // polynomial = 0 + + PolyXY dGx,dGy,dGxx,dGxy,dGyy; + ZZn E0b,E0bd,E2bs,E4b,E6b,Dg,Dj,Dgd,Djd,Dgs,Djs,jl,jld,p1,jd; + ZZn E4bl,E6bl,deltal,atilde,btilde,gd,f,fd,s,Eg,Ej,Exy; + int r,v,ld,ld1,discrim; + ZZn M,cf[500],cft[500],ad,K,RF; + Poly Fl,T,WP[500],H,X,Y,R; + term *pos; + + E4b=-(A/3); + E6b=-(B/2); + delta=(E4b*E4b*E4b-E6b*E6b)/1728; + +// +// find out how many bits we are going to need +// before Kangaroos can take over +// + first=5; + sl[0]=3; sl[1]=5; sl[2]=7; sl[3]=8; sl[4]=9; sl[5]=0; // do low prime powers + SCHP=9; + + if (pbits<=256) d=pow((Big)2,64); + else d=pow((Big)2,72); // kangaroos do more work + + d=sqrt(p/d); + + escape=FALSE; + + +// Calculate Divisor Polynomials for small primes - Schoof 1985 p.485 +// Set the first few by hand.... + + + P[1]=1; P[2]=2; P[3]=0; P[4]=0; + + P2[1]=1; P3[1]=1; + + P2[2]=P[2]*P[2]; + P3[2]=P2[2]*P[2]; + + P[3].addterm(-(A*A),0); P[3].addterm(12*B,1); + P[3].addterm(6*A,2) ; P[3].addterm((ZZn)3,4); + + P2[3]=P[3]*P[3]; + P3[3]=P2[3]*P[3]; + + P[4].addterm((ZZn)(-4)*(8*B*B+A*A*A),0); + P[4].addterm((ZZn)(-16)*(A*B),1); + P[4].addterm((ZZn)(-20)*(A*A),2); + P[4].addterm((ZZn)80*B,3); + P[4].addterm((ZZn)20*A,4); + P[4].addterm((ZZn)4,6); + + P2[4]=P[4]*P[4]; + P3[4]=P2[4]*P[4]; + +// generation of Divisor polynomials +// See Schoof p. 485 + + for (jj=5;jj<=SCHP+1;jj++) + { // different for even and odd + if (jj%2==1) + { + n=(jj-1)/2; + if (n%2==0) + P[jj]=P[n+2]*P3[n]*Y4-P3[n+1]*P[n-1]; + else + P[jj]=P[n+2]*P3[n]-Y4*P3[n+1]*P[n-1]; + } + else + { + n=jj/2; + P[jj]=P[n]*(P[n+2]*P2[n-1]-P[n-2]*P2[n+1])/(ZZn)2; + + } + if (jj <= 1+(SCHP+1)/2) + { // precalculate for later + P2[jj]=P[jj]*P[jj]; + P3[jj]=P2[jj]*P[jj]; + } + } + +// +// Schoof's original method for small primes +// + + for (i=0;;i++) + { + lp=sl[i]; + if (lp==0) break; + + if (lp>=first) + { + good[nl]=lp; + accum*=lp; + } + k=p%lp; + + setmod(P[lp]); + MY2=Y2; +// These next are time-consuming calculations of X^P, X^(P*P), Y^P and Y^(P*P) + + cout << "X^P " << flush; + XP=pow(XX,p); + cout << "\b\b\b\bY^P " << flush; + YP=pow(MY2,(p-1)/2); + + cout << "\b\b\b\bX^PP" << flush; + XPP=compose(XP,XP); // this is faster + cout << "\b\b\b\bY^PP" << flush; + YPP=YP*compose(YP,XP); + cout << "\b\b\b\b"; + + PolyMod Pk,P2k,PkP1,PkM1,PkP2; + Pk=P[k]; PkP1=P[k+1]; PkM1=P[k-1]; PkP2=P[k+2]; + + P2k=(Pk*Pk); +// +// This is Schoof's algorithm, stripped to its bare essentials +// +// Now looking for the value of tau which satisfies +// (X^(P*P),Y^(P*P)) + k.(X,Y) = tau.(X^P,Y^P) +// +// Note that (X,Y) are rational polynomial expressions for points on +// an elliptic curve, so "+" means elliptic curve point addition +// +// k.(X,Y) can be found directly from Divisor polynomials +// Schoof Prop (2.2) +// +// Points are converted to projective (X,Y,Z) form +// This is faster (x2). Observe that (X/Z^2,Y/Z^3,1) is the same +// point in projective co-ordinates as (X,Y,Z) +// + + if (k%2==0) + { + XT=XX*MY2*P2k-PkM1*PkP1; + YT=(PkP2*PkM1*PkM1-P[k-2]*PkP1*PkP1)/4; + XT*=MY2; // fix up, so that Y has implicit y multiplier + YT*=MY2; // rather than Z + ZT=MY2*Pk; + } + else + { + XT=(XX*P2k-MY2*PkM1*PkP1); + if (k==1) YT=(PkP2*PkM1*PkM1+PkP1*PkP1)/4; + else YT=(PkP2*PkM1*PkM1-P[k-2]*PkP1*PkP1)/4; + ZT=Pk; + } + + elliptic_add(XT,YT,ZT,XPP,YPP); + +// +// Test for Schoof's case 1 - LHS (XT,YT,ZT) is point at infinity +// + + cout << "NP mod " << lp << " = " << flush; + if (iszero(ZT)) + { // Is it zero point? (XPP,YPP) = - K(X,Y) + if (lp>=first) t[nl++]=0; + cout << setw(3) << (p+1)%lp; + if ((p+1)%lp==0) + { + cout << " ***" << endl; + if (search && (!Edwards || lp!=4)) {escape=TRUE; break;} + } + else cout << endl; + continue; + } +// +// Now keep finding tau.(X^P,Y^P), until equality is detected +// This is very simple! +// + XL=XP; + YL=YP; + ZL=1; + ZT2=ZT*ZT; + for (tau=1;tau<=(lp/2);tau++) + { + cout << setw(3) << (p+1-tau)%lp << flush; + + ZL2=ZL*ZL; + if (iszero(XT*ZL2-ZT2*XL)) // LHS == RHS?? + { // LHS = RHS + if (!iszero(YT*ZL2*ZL-YL*ZT*ZT2)) + { // point doubled - change sign + tau=lp-tau; + cout << "\b\b\b"; + cout << setw(3) << (p+1-tau)%lp << flush; + } + if (lp>=first) t[nl++]=tau; + if ((p+1-tau)%lp==0) + { + cout << " ***" << endl; + if (search && (!Edwards || lp!=4)) escape=TRUE; + } + else cout << endl; + break; + } + elliptic_add(XL,YL,ZL,XP,YP); + cout << "\b\b\b"; + } + if (escape) break; + } + + if (!escape) for (i=1;accum<=d;i++) + { + if (i>max) + { + cout << "WARNING: Ran out of Modular Polynomials!" << endl; + break; + } + lp=l[i]; + + if (lp<=SCHP) continue; + + k=p%lp; + for (is=1;;is++) + if (is*(lp-1)%12==0) break; + + el=lp; + s=is; + +// Get next Modular Polynomial + + MP=Gl[i]; + +// Evaluate bivariate polynomial at Y=j-invariant +// and use as polynomial modulus + + F=MP.F(j); + setmod(F); + cout << setw(3) << lp << flush; + XP=pow(XX,p); +// +// Determine "Splitting type" +// + cout << "\b\b\bGCD" << flush; + G=gcd(XP-XX); + + if (degree(G)==lp+1) + { + cout << "\b\b\b" << flush; + continue; // pathological case + } + if (degree(G)==0) // Atkin Prime + { + if (!atkin && lp>100) // Don't process large Atkin Primes + { + cout << "\b\b\b" << flush; + continue; + } + BOOL useful=FALSE; + cout << "\b\b\b" << flush; + cout << "ATK" << flush; + + PolyMod u[20]; + int max_r,lim=1; + u[0]=XP; + u[1]=compose(u[0],u[0]); + +// +// The code for processing Atkin Primes is in here, but currently largely +// unused. However the simplest case is used, as it suggests only one +// value for NP mod lp, and so can be used just like an Elkies prime +// +// + if (atkin) max_r=lp+1; + else max_r=2; + for (r=2;r<=max_r;r++) + { + PolyMod C; + int kk,m; + BOOL first; + if ((lp+1)%r!=0) continue; // only keep good ones! + v=jac(k,lp); // check Schoof Prop. 6.3 + jj=(lp+1)/r; + if (jj%2==0 && v==(-1)) continue; + if (jj%2==1 && v==1) continue; + // if (phi(r)>8) continue; // > 8 candidates + // if (lp<30 && phi(r)>2) continue; + // if (lp<60 && phi(r)>4) continue; + kk=r; m=0; + first=TRUE; +// +// Right-to-Left Power Composition - find X^(P^r) +// + forever + { + if (kk%2!=0) + { + if (first) C=u[m]; + else C=compose(u[m],C); + first=FALSE; + } + kk/=2; + if (kk==0) break; + m++; + if (m>lim) + { // remember them for next time + u[m]=compose(u[m-1],u[m-1]); + lim=m; + } + } + + if (iszero(C-XX)) + { // found splitting type + useful=TRUE; + break; + } + } + cout << "\b\b\b" << flush; + if (!useful) continue; + + cout << "NP mod " << lp << " = " << flush; + + int a,b,candidates,gx,gy,ord,qnr=2; + BOOL gen; + while (jac(qnr,lp)!=(-1)) qnr++; + +// +// [4] Algorithm VII.4 - find a generator of F(lp^2) +// + ord=lp*lp-1; + gy=1; + for (gx=1;gx1 && igcd(jj,r)!=1) continue; + powquad(lp,qnr,gx,gy,jj*ord/r,a,b); + + tau=((a+1)*k*(int)invers(2,lp))%lp; + if (tau==0) + { // r must be 2 - I can make use of this! + // Its an Atkin prime, but only one possibility + candidates++; + cout << (p+1)%lp << flush; + if ((p+1)%lp==0) + { + cout << " ***" << endl; + if (search && (!Edwards || lp!=4)) escape=TRUE; + } + else cout << endl; + good[nl]=lp; + t[nl]=tau; + nl++; + accum*=lp; + break; + } + else if (jac(tau,lp)==1) + { + candidates+=2; + tau=sqrmp(tau,lp); + tau=(2*tau)%lp; + if (candidates==phi(r)) + { + cout << (p+1-tau)%lp << " or " << (p+1+tau)%lp << endl; + break; + } + else cout << (p+1-tau)%lp << "," << (p+1+tau)%lp << "," << flush; + } + } + if (escape) break; + continue; + } + +// +// Good Elkies prime - so use it! +// +// First solve quadratic for a root +// + if (degree(G)==1) + { + discrim=0; + g=-G.coeff(0); // Elkies Prime, one root, (2 possibilites) + } + else // degree(G)==2 + { // Elkies Prime, two roots + discrim=1; + qb=G.coeff(1); + qc=G.coeff(0); + g=sqrt(qb*qb-4*qc); + g=(-qb-g)/2; // pick either one + } + cout << "\b\b\bELK" << flush; +// +// Mueller's procedure for finding the atilde, btilde and p1 +// parameters of the isogenous curve +// 3. page 111 +// 4. page 131-133 +// First we need partial differentials of bivariate Modular Polynomial +// + + dGx=diff_dx(MP); + dGy=diff_dy(MP); + dGxx=diff_dx(dGx); + dGxy=diff_dx(dGy); + dGyy=diff_dy(dGy); + + Eg=dGx.F(g,j); // Evaluated at (g,j) + Ej=dGy.F(g,j); + Exy=dGxy.F(g,j); + + Dg=g*Eg; + Dj=j*Ej; + + deltal=delta*pow(g,12/is)/pow(el,12); + + if (Dj==0) + { + E4bl=E4b/(el*el); + atilde=-3*pow(el,4)*E4bl; + jl=pow(E4bl,3)/deltal; + btilde=2*pow(el,6)*sqrt((jl-1728)*deltal); + p1=0; + } + else + { + E2bs=(-12*E6b*Dj)/(s*E4b*Dg); + + gd=-(s/12)*E2bs*g; + jd=-E4b*E4b*E6b/delta; + E0b=E6b/(E4b*E2bs); + + Dgd=gd*Eg+g*(gd*dGxx.F(g,j)+jd*Exy); + Djd=jd*Ej+j*(jd*dGyy.F(g,j)+gd*Exy); + + E0bd=((-s*Dgd)/12-E0b*Djd)/Dj; + + E4bl=(E4b-E2bs*(12*E0bd/E0b+6*E4b*E4b/E6b-4*E6b/E4b)+E2bs*E2bs)/(el*el); + + jl=pow(E4bl,3)/deltal; + f=pow(el,is)/g; fd=s*E2bs*f/12; + + Dgs=dGx.F(f,jl); + Djs=dGy.F(f,jl); + + jld=-fd*Dgs/(el*Djs); + E6bl=-E4bl*jld/jl; + + atilde=-3*pow(el,4)*E4bl; + btilde=-2*pow(el,6)*E6bl; + p1=-el*E2bs/2; + } + +// +// Find factor of Division Polynomial from atilde, btilde and p1 +// Here we follow 3. p 116 +// Polynomials have been modified s.t x=z^2 +// +// Note that all Polynomials can be reduced mod x^(d+1), +// where d=(lp-1)/2, using modxn() function +// + + cout << "\b\b\bFAC" << flush; + ld=(lp-1)/2; + ld1=(lp-3)/2; + + get_ck(ld1,A,B,cf); + + WP[1]=1; + pos=NULL; + for (k=ld1;k>0;k--) + pos=WP[1].addterm(cf[k],k+1,pos); + for (v=2;v<=ld;v++) + WP[v]=modxn(WP[v-1]*WP[1],ld+1); +// +// WPv have understood multiplier x^-v +// + get_ck(ld1,atilde,btilde,cft); + + Y=0; + pos=NULL; + for (k=ld1;k>0;k--) + pos=Y.addterm((lp*cf[k]-cft[k])/(ZZn)((2*k+1)*(2*k+2)),k+1,pos); + Y.addterm(-p1,1,pos); + + RF=1; + H=1; + X=1; + for (r=1;r<=ld;r++) + { + X=modxn(X*Y,ld+1); + RF*=r; + H+=(X/RF); + } +// +// H has understood multiplier x^-d +// + ad=1; + Fl=0; + pos=Fl.addterm(ad,ld); + for (v=ld-1;v>=0;v--) + { + H-=ad*WP[v+1]; + H=divxn(H,1); + ad=H.min(); + pos=Fl.addterm(ad,v,pos); + } + + setmod(Fl); + MY2=Y2; + MY4=Y4; + +// +// Only the Y-coordinate is calculated. No need for X^P ! +// + cout << "\b\b\bY^P" << flush; + YP=pow(MY2,(p-1)/2); + cout << "\b\b\b"; + +// Calculate Divisor Polynomials for small primes - Schoof 1985 p.485 +// This time mod the new (small) modulus Fl +// Set the first few by hand.... + + PolyMod Pf[300],P2f[300],P3f[300]; + Pf[0]=0; Pf[1]=1; Pf[2]=2; Pf[3]=0; Pf[4]=0; + + P2f[1]=1; P3f[1]=1; + + P2f[2]=Pf[2]*Pf[2]; + P3f[2]=P2f[2]*Pf[2]; + + Pf[3].addterm(-(A*A),0); Pf[3].addterm(12*B,1); + Pf[3].addterm(6*A,2) ; Pf[3].addterm((ZZn)3,4); + + P2f[3]=Pf[3]*Pf[3]; + P3f[3]=P2f[3]*Pf[3]; + + Pf[4].addterm((ZZn)(-4)*(8*B*B+A*A*A),0); + Pf[4].addterm((ZZn)(-16)*(A*B),1); + Pf[4].addterm((ZZn)(-20)*(A*A),2); + Pf[4].addterm((ZZn)80*B,3); + Pf[4].addterm((ZZn)20*A,4); + Pf[4].addterm((ZZn)4,6); + + P2f[4]=Pf[4]*Pf[4]; + P3f[4]=P2f[4]*Pf[4]; + lower=5; + +// +// Now looking for value of lambda which satisfies +// (X^P,Y^P) = lambda.(XX,YY). +// 3. Page 118, Algorithm 7.9 +// +// Note that it appears to be sufficient to only compare the Y coordinates (!?) +// For a justification see page 120 of 3. +// Thank you SYSTRAN translation service! (www.altavista.com) +// + good[nl]=lp; + cout << "NP mod " << lp << " = " << flush; + for (lambda=1;lambda<=(lp-1)/2;lambda++) + { + int res=0; + PolyMod Ry,Ty; + tau=(lambda+invers(lambda,lp)*p)%lp; + + k=(lp+tau*tau-(4*p)%lp)%lp; + if (jac(k,lp)!=discrim) continue; +// +// Possible values of tau could be eliminated here by an application of +// Atkin's algorithm.... +// + cout << setw(3) << (p+1-tau)%lp << flush; + + // This "loop" is usually executed just once + for (jj=lower;jj<=lambda+2;jj++) + { // different for even and odd + if (jj%2==1) // 2 mod-muls + { + n=(jj-1)/2; + if (n%2==0) + Pf[jj]=Pf[n+2]*P3f[n]*MY4-P3f[n+1]*Pf[n-1]; + else + Pf[jj]=Pf[n+2]*P3f[n]-MY4*P3f[n+1]*Pf[n-1]; + } + else // 3 mod-muls + { + n=jj/2; + Pf[jj]=Pf[n]*(Pf[n+2]*P2f[n-1]-Pf[n-2]*P2f[n+1])/(ZZn)2; + } + P2f[jj]=Pf[jj]*Pf[jj]; // square + P3f[jj]=P2f[jj]*Pf[jj]; // cube + } + if (lambda+3>lower) lower=lambda+3; + + // compare Y-coordinates - 3 polynomial mod-muls required + + if (lambda%2==0) + { + Ry=(Pf[lambda+2]*P2f[lambda-1]-Pf[lambda-2]*P2f[lambda+1])/4; + Ty=MY4*YP*P3f[lambda]; + } + else + { + if (lambda==1) Ry=(Pf[lambda+2]*P2f[lambda-1]+P2f[lambda+1])/4; + else Ry=(Pf[lambda+2]*P2f[lambda-1]-Pf[lambda-2]*P2f[lambda+1])/4; + Ty=YP*P3f[lambda]; + } + if (iszero(Ty-Ry)) res=1; + if (iszero(Ty+Ry)) res=2; + + if (res!=0) + { // has it doubled, or become point at infinity? + if (res==2) + { // it doubled - wrong sign + tau=(lp-tau)%lp; + cout << "\b\b\b"; + cout << setw(3) << (p+1-tau)%lp << flush; + } + t[nl]=tau; + if ((p+1-tau)%lp==0) + { + cout << " ***" << endl; + if (search && (!Edwards || lp!=4)) escape=TRUE; + } + else cout << endl; + break; + } + cout << "\b\b\b"; + } + nl++; + accum*=lp; + if (escape) break; + } + Modulus.clear(); + + if (escape) {b+=1; continue;} + + Crt CRT(nl,good); + Big order,ordermod; + ordermod=accum; + order=(p+1-CRT.eval(t))%ordermod; // get order mod product of primes + + nrp=kangaroo(p,order,ordermod); + + if (Edwards) + { + if (!prime(nrp/4) && search) {b+=1; continue; } + else break; + } + else + { + if (!prime(nrp) && search) {b+=1; continue; } + else break; + } + } + + if (fout) + { + ECn P; + ofile << bits(p) << endl; + mip->IOBASE=16; + ofile << p << endl; + + ofile << a << endl; + ofile << b << endl; + + // generate a random point on the curve + // point will be of prime order for "ideal" curve, otherwise any point + if (!Edwards) + { + do { + x=rand(p); + } while (!P.set(x,x)); + P.get(x,y); + ofile << nrp << endl; + } + else + { + ZZn X,Y,Z,R,TA,TB,TC,TD,TE,TU; + forever + { + X=randn(); + R=(X*X-EB)/(X*X-EA); + if (!qr(R))continue; + Y=sqrt(R); + break; + } + Z=1; +// double point twice (4*P) + for (i=0;i<2;i++) + { + TA = X*X; + TB = Y*Y; + TU = EA*TB; + TC = TA+TU; + TD = TA-TU; + TE = (X+Y)*(X+Y)-TA-TB; + + X = TC*TD; + Y = TE*(TC-2*EB*Z*Z); + Z = TD*TE; + } + X/=Z; + Y/=Z; + x=X; + y=Y; + ofile << nrp/4 << endl; + } + ofile << x << endl; + ofile << y << endl; + mip->IOBASE=10; + } + if (p==nrp) + { + cout << "WARNING: Curve is anomalous" << endl; + return 0; + } +// check MOV condition for curves of Cryptographic interest + d=1; + for (i=0;i<50;i++) + { + d=modmult(d,p,nrp); + if (d==1) + { + cout << "WARNING: Curve fails MOV condition" << endl; + return 0; + } + } + + return 0; +} + diff --git a/miracl/source/curve/sea.cpp.bak b/miracl/source/curve/sea.cpp.bak new file mode 100644 index 0000000..968ff9f --- /dev/null +++ b/miracl/source/curve/sea.cpp.bak @@ -0,0 +1,1680 @@ +// Schoof-Elkies-Atkin Algorithm! +// Mike Scott August 1999 mike@compapp.dcu.ie +// Counts points on GF(p) Elliptic Curve, y^2=x^3+Ax+B a prerequisite +// for implemention of Elliptic Curve Cryptography +// This program is intended as an aid to Cryptographers in generating +// suitable curves (ideally with a prime number of points) with respect +// to prime moduli from 160 to 512 bits in length. This can be done with +// relatively modest computing facilities - the average home computer and +// a little patience will suffice. +// +// An "ideal" curve is defined as one with with prime number of points. +// +// First the credits +// +// Basic algorithm is due to Schoof +// 1. "Elliptic Curves Over Finite Fields and the Computation of Square Roots +// mod p", Rene Schoof, Math. Comp., Vol. 44 pp 483-494 +// +// Elkies-Atkin ideas are described in +// +// 2. "Counting points on Elliptic Curves over Finite Fields", Rene Schoof, +// Jl. de Theorie des Nombres de Bordeaux 7 (1995) pp 219-254 +// +// The particular variation implemented here is due to Mueller. See his thesis +// +// 3. "Ein Algorithmus zur Bestimmung der Punktanzahl elliptischer Kurven +// uber endlichen Korpern der Charakteristik grosser drei", +// available from Volker Mueller's home page +// www.informatik.th-darmstadt.de/TI/Mitarbeiter/vmueller.html +// +// Other useful English-language publications are available from this site. +// Strongly recommended is the recent book +// +// 4. "Elliptic Curves in Cryptography" +// by Blake, Seroussi and Smart, London Mathematical Society Lecture Note +// Series 265, Cambridge University Press. ISBN 0 521 65374 6 +// +// Another useful reference is +// 5. Elliptic Curve Public Key Cryptosystems", Menezes, +// Kluwer Academic Publishers, Chapter 7 +// +// The Kangaroo continuation is due to Pollard:- +// +// 6. "Monte Carlo Methods for Index Computation" +// by J.M. Pollard in Math. Comp. Vol. 32 1978 pp 918-924 +// +// Fast FFT methods are largely as described by Shoup +// +// 7. "A New Polynomial Factorisation Algorithm and its implementation", +// Victor Shoup, Jl. Symbolic Computation, 1996 +// +// A potentially more effective way of using Atkin primes is described in +// +// 8. "Remarks on the Schoof-Elkies-Atkin Algorithm", L. Dewaghe, Math. Comp. +// Vol. 67, 223, July 1998, pp 1247-1252 +// +// Thanks are due to Richard Crandall for his encouragment, and the idea of +// using projective co-ordinates. +// +// NOTE: Only for use on curves over large prime modulus P. +// For smaller P use schoof.exe utility available from the same source. +// +// This first version does not process so-called Atkin primes +// Schoof's original algorithm is used for primes 3, 5 and 7 (this facilitates +// "early abort" using the -s option). +// +// After that only Elkies primes are used. It is therefore not as fast as it +// could be, particularly for smaller values of the prime modulus P. +// However when the asymptotics kick-in, it starts to get competitive (when +// you need it to). Since the average Cryptographer will only wish to +// generate a few curves for practical use, this is deemed to be adequate. +// The final continuation uses Pollard's Lambda ("kangaroo") algorithm. +// +// It is envisaged that from time-to-time this program will be modified +// and hopefully improved - that is speeded up. +// In particular it is planned to exploit Atkin Primes to allow two herds of +// kangaroos complete the job more efficiently +// +// Asyptotically the algorithm should take time O(log(p)^5) +// However the Kangaroo continuation favours "smaller" curves, while +// the asymptotic behaviour is more accurate for "bigger" curves +// +// Timings in minutes:- random curves 180MHz Pentium Pro +// (ignoring time to generate Modular Polynomials) +// +// C1 C2 C3 Ave Asymptotic multiplier wrt 160 bits +// 160-bit 2.5 3.0 2.0 2.5 1 +// 192-bit 5.5 5.5 3.5 4.8 2.5 +// 224-bit 9 7.5 10 8.8 5.4 +// 256-bit 13.5 21.5 23 19.3 10.5 +// 384-bit 86 108 120 105 60 +// 512-bit 600 357 398 452 336 +// +// As can be seen the asymptotic behaviour of the program would appear to +// be about right. The wide variations in timing for the same size of curve +// is typical - it depends on how "lucky" you are finding Elkies Primes +// +// **************** +// Download Instructions +// +// To access the Windows 'NT/95/98 executables directly, point your +// browser at ftp://ftp.compapp.dcu.ie/pub/crypto, and download +// +// mueller.exe +// modpol.exe +// process.exe +// sea.exe +// +// The main program source file for these programs may be found in the +// same place, with .cpp extensions. +// +// To obtain the full source code first look at +// the README file on the ftp site, and then download +// +// ftp://ftp.compapp.dcu.ie/pub/crypto/miracl.zip +// To recompile, see the file sea.txt +// +// For more information:- +// +// http://indigo.ie/~mscott +// +// **************** +// Instructions for use +// +// First run the utility "mueller" to build up a collection of Modular +// Polynomials. Each modular polynomial is associated with a small odd prime. +// This needs to be done once only - ever, but you can from time +// to time augment your collection of Polynomials by running it again. +// Its quite time consuming, but in less than an hour you should have enough +// to get started. The more you have, the bigger the prime modulus that you +// can use. +// +// Then run the utility "process" to process the raw polynomial file with +// respect to your chosen prime modulus P. This need to be done just once for +// every prime modulus of interest to you. This takes only a few minutes at +// most. +// +// An alternative is to use instead the "modpol" application, which is a +// composite of "mueller" and "process". It directly generates the Modular +// Polynomials reduced wrt a pre-specified prime modulus, suitable for +// immediate use by "sea". If working with limited computing resources such +// that sufficient generic Modular Polynomials cannot be generated by +// "mueller", this may be your only alternative. +// +// Finally run this program "sea" specifying the A and B parameters of the +// particular curve. This program can also search through many curves for +// a curve ideal for cryptographic use (with a prime number of points). +// +// For example try:- +// +// mueller 0 120 -o mueller.raw +// process -f 65112*2#144-1 -i mueller.raw -o test160.pol +// sea -3 49 -i test160.pol +// +// Here the "mueller" program generates modular polynomials for all odd primes +// in the range 0 - 120 into the file mueller.raw. The "process" application +// reduces these 'raw' polynomials wrt the 160 bit prime modulus +// P = 65112*2^144-1 to a file test160.pol. The "sea" application uses this +// file to count the points on the curve Y^2 = X^3 - 3X + 49 mod P +// +// Alternatively:- +// +// modpol -f 65112*2#144-1 0 120 -o test160.pol +// sea -3 49 -i test160.pol +// +// The number of Modular Polynomials required depends on the size of the +// prime modulus P. It is also random in the sense that it depends on the +// probability of each small prime being an "Elkies" prime wrt the given curve. +// In the vast majority of cases the range suggested to "mueller" or "modpol" +// should be 0 to bits(P), where bits(P) is the number of bits in P. However +// you might get away with a much smaller value if you are lucky with your +// "Elkies" primes. If modular polynomials could not be generated for all +// primes in the range, due to the use of the -s2, -s3 or -s6 flag in +// "mueller" or "modpol" (see comments in mueller.cpp), then a somewhat +// larger range might be needed. +// +// When using the "sea" program, the -s option is particularly useful +// and allows automatic search for an "ideal" curve. If a curve order is +// exactly divisible by a small prime, that curve is immediately abandoned, +// and the program moves on to the next, incrementing the B parameter of +// the curve. This is a fairly arbitrary but simple way of moving on to +// the "next" curve. +// +// Note that if a prime q is an Atkin prime, then we know at least that q +// is not a factor of NP, in other words that NP mod q != 0. +// This can be easily proved. +// +// NOTE: The output file can be used directly with for example the ECDSA +// programs IF AND ONLY IF an ideal curve is found. If you wish to use +// a less-than-ideal curve, you will first have to factor NP completely, and +// find a random point of large prime order. +// +// **************** +// +// Rev. 1 September 1999 - Faster and more Kangaroos! +// Rev. 2 October 1999 - Poly class revamped. Faster search for tau mod lp +// Rev. 3 October 1999 - Eliminated calculation of X^P +// Rev. 4 December 1999 - Various optimizations +// +// This implementation is free. No terms, no conditions. It requires +// version 4.24 or greater of the MIRACL library (a Shareware, Commercial +// product, but free for non-profit making use), +// available from ftp://ftp.compapp.dcu.ie/pub/crypto/miracl.zip +// +// However this program may be freely used (unmodified!) to generate curves +// for commercial use. It may be recompiled for this purpose on any hardware. +// +// 32-bit build only +// +// Note that is a little faster to use an integer-only build of MIRACL. +// See mirdef.hio +// +// + +#include +#include +#include +#include +#include "ecn.h" // Elliptic Curve Class +#include "crt.h" // Chinese Remainder Theorem Class + +// +// poly.h implements polynomial arithmetic. FFT methods are used for maximum +// speed, as the polynomials can get very big. +// But all that gruesome detail is hidden away. +// +// polymod.h implements polynomial arithmetic wrt to a preset poynomial +// modulus. This looks a bit neater. Function setmod() sets the modulus +// to be used. Again fast FFT methods are used. +// +// polyxy.h implements a bivariate polynomial class +// + +#include "poly.h" +#include "polymod.h" +#include "polyxy.h" + +using namespace std; + +#ifndef MR_NOFULLWIDTH +Miracl precision=18; // max. 18x32 bits per big number +#else +Miracl precision(18,MAXBASE); +#endif + +PolyMod MY2,MY4; + +ZZn A,B; // Here ZZn are integers mod the prime p + // Montgomery representation is used internally + +BOOL Edwards=FALSE; + +// Elliptic curve Point duplication formula + +void elliptic_dup(PolyMod& X,PolyMod& Y,PolyMod& Z) +{ // (X,Y,Z)=2.(X,Y,Z) + PolyMod W1,W2,W3,W4; + + W2=Z*Z; // 1 + W3=A*(W2*W2); // 2 + W1=X*X; // 3 + W4=3*W1+W3; + Z*=(2*Y); // 4 Z has an implied y + W2=MY2*(Y*Y); // 5 + W3=4*X*W2; // 6 + W1=W4*W4; // 7 + X=W1-2*W3; + W2*=W2; + W2*=8; // 8 + W3-=X; + W3*=W4; // 9 polynomial multiplications + Y=W3-W2; + X*=MY2; // fix up - move implied y from Z to Y + Y*=MY2; + Z*=MY2; +} + +// +// This is addition formula for two distinct points on an elliptic curve +// Works with projective coordinates which are automatically reduced wrt a +// polynomial modulus +// Remember that the expression for the Y coordinate of each point +// (a function of X) is implicitly multiplied by Y. +// We know Y^2=X^3+AX+B, but we don't have an expression for Y +// So if Y^2 ever crops up - substitute for it +// + +void elliptic_add(PolyMod& XT,PolyMod& YT,PolyMod& ZT,PolyMod& X,PolyMod& Y) +{ // add (X,Y,1) to (XT,YT,ZT) + // on an elliptic curve + PolyMod W1,W2,W4,W5,W6; + + W1=XT; + W6=ZT*ZT; // 1 + W4=X*W6; // 2 * + W1-=W4; + + W2=YT; // W2 has an implied y + W6*=ZT; // 3 + W5=Y*W6; // 4 * W5 has an implied y + W2-=W5; + if (iszero(W1)) + { + if (iszero(W2)) + { // should have doubled + elliptic_dup(XT,YT,ZT); + return; + } + else + { // point at infinity + ZT.clear(); + return; + } + } + + W4=W1+2*W4; // W4=2*W4+W1 + W5=W2+2*W5; // W5=2*W5+W2 + + ZT*=W1; // 5 + + W6=W1*W1; // 6 + W1*=W6; // 7 + W6*=W4; // 8 + W4=MY2*(W2*W2); // 9 Substitute for Y^2 + + XT=W4-W6; + + W6=W6-2*XT; + W2*=W6; // 10 + W1*=W5; // 11 polynomial multiplications + W5=W2-W1; + + YT=W5/(ZZn)2; + + return; +} + +// +// Program to compute the order of a point on an elliptic curve +// using Pollard's lambda method for catching kangaroos. +// +// As a way of counting points on an elliptic curve, this +// has complexity O(p^(1/4)) +// +// However Schoof puts a spring in the step of the kangaroos +// allowing them to make bigger jumps, and lowering overall complexity +// to O(p^(1/4)/sqrt(L)) where L is the product of the Schoof primes +// +// See "Monte Carlo Methods for Index Computation" +// by J.M. Pollard in Math. Comp. Vol. 32 1978 pp 918-924 +// +// This code has been considerably speeded up using ideas from +// "Parallel Collision Search with Cryptographic Applications", van Oorchot +// and Wiener, J. Crypto., Vol. 12, 1-28, 1999 +// + +#define STORE 80 +#define HERD 5 + +ECn wild[STORE],tame[STORE]; +Big wdist[STORE],tdist[STORE]; +int wname[STORE],tname[STORE]; + +Big kangaroo(Big p,Big order,Big ordermod) +{ + ECn ZERO,K[2*HERD],TE[2*HERD],X,P,G,table[128],trap; + Big start[2*HERD],txc,wxc,mean,leaps,upper,lower,middle,a,b,x,y,n,w,t,nrp; + int i,jj,j,m,sp,nw,nt,cw,ct,k,distinguished,nbits; + Big D[2*HERD],s,distance[128],real_order; + BOOL bad,collision,abort; + forever + { +// find a random point on the curve + do + { + x=rand(p); + } while (!P.set(x,x)); + + lower=p+1-2*sqrt(p)-3; // lower limit of search + upper=p+1+2*sqrt(p)+3; // upper limit of search + + w=1+(upper-lower)/ordermod; + leaps=sqrt(w); + mean=HERD*leaps/2; // ideal mean for set S=1/2*w^(0.5) + nbits=bits(leaps/16); + if (nbits>30) nbits=30; + distinguished=1<mean) break; + } + table[0]=ordermod*P; + for (i=1;i1) + middle+=(ordermod+order-middle%ordermod); // middle must be + // order mod ordermod + + for (i=0;i=STORE) + { + abort=TRUE; + break; + } + cout << "." << flush; + tame[nt]=K[jj]; + tdist[nt]=D[jj]; + tname[nt]=jj; + for (k=0;k=STORE) + { + abort=TRUE; + break; + } + cout << "." << flush; + wild[nw]=K[jj]; + wdist[nw]=D[jj]; + wname[nw]=jj; + for (k=0;kPRIMES[i]; + if (sp==0) break; + if (real_order%sp==0) + { + G=P; + G*=(real_order/sp); + if (G==ZERO) + { + real_order/=sp; + continue; + } + } + i++; + } + if (real_order <= 4*sqrt(p)) + { + cout << "Low Order point used - trying again" << endl; + continue; + } + real_order=nrp; + for (i=0;(sp=get_mip()->PRIMES[i])!=0;i++) + while (real_order%sp==0) real_order/=sp; + if (real_order==1) + { // all factors of nrp were considered + cout << "NP= " << nrp << endl; + break; + } + if (prime(real_order)) + { // all factors of NP except for one last one.... + G=P; + G*=(nrp/real_order); + if (G==ZERO) + { + cout << "Failed - trying again" << endl; + continue; + } + else + { + cout << "NP= " << nrp << endl; + break; + } + } +// Couldn't be bothered factoring nrp completely +// Probably not an interesting curve for Cryptographic purposes anyway..... +// But if 10 random points are all "killed" by nrp, its almost +// certain to be the true NP, and not a multiple of a small order. + + bad=FALSE; + for (i=0;i<10;i++) + { + do + { + x=rand(p); + } while (!P.set(x,x)); + G=P; + G*=nrp; + if (G!=ZERO) + { + bad=TRUE; + break; + } + } + if (bad) + { + cout << "Failed - trying again" << endl; + continue; + } + cout << "NP is composite and not ideal for Cryptographic use" << endl; + cout << "NP= " << nrp << " (probably)" << endl; + break; + } + return nrp; +} + +// +// Coefficients Ck from Mueller's lemma 6.2 +// 3. page 90 +// 4. page 127-128 +// + +void get_ck(int terms,ZZn a,ZZn b,ZZn *c) +{ + int k,h; + if (terms==0) return; + c[1]=-a/5; + if (terms==1) return; + c[2]=-b/7; + for (k=3;k<=terms;k++) + { + c[k]=0; + for (h=1;h<=k-2;h++) c[k]+=c[h]*c[k-1-h]; + c[k]*=((ZZn)3/(ZZn)((k-2)*(2*k+3))); + } +} + +// +// quadratic field arithmetic +// needed for Atkin Primes +// + +void mulquad(int p,int qnr,int x,int y,int& a,int& b) +{ + int olda=a; + a=(a*x+b*y*qnr)%p; + b=(olda*y+b*x)%p; +} + +void powquad(int p,int qnr,int x,int y,int e,int& a,int& b) +{ + int k=e; + a=1; + b=0; + if (k==0) return; + + for(;;) + { + if (k%2!=0) + mulquad(p,qnr,x,y,a,b); + k/=2; + if (k==0) return; + mulquad(p,qnr,x,y,x,y); + } +} + +// +// Euler Totient function +// + +int phi(int n) +{ + int i,r=1; + for (i=2;i <-i file>" << endl; + cout << "where the input file contains pre-processed modular polynomials" << endl; + cout << "for a particular prime modulus P" << endl; + cout << "e.g. sea -3 35317045537 -i mueller.pol" << endl; + cout << "To input A and B in Hex, precede with -h" << endl; + cout << "To output to a file, use flag -o " << endl; + cout << "To observe Atkin prime processing, use flag -a" << endl; + cout << "NOTE: Atkin prime information is not currently used" << endl; + cout << "To search for NP prime, incrementing B, use flag -s" << endl; + cout << "(For Edwards curve the search is for NP=4*prime)" << endl; + cout << "\nFreeware from Certivox, Dublin, Ireland" << endl; + cout << "Full C++ source code and MIRACL multiprecision library available" << endl; + cout << "email mscott@indigo.ie" << endl; + return 0; + } + + ip=0; + gprime(10000); // generate small primes < 1000 + search=fout=gotI=gotA=gotB=atkin=FALSE; + a=0; b=0; + +// Interpret command line + Base=10; + while (ipIOBASE=Base; + a=argv[ip++]; + mip->IOBASE=10; + gotA=TRUE; + continue; + } + if (!gotB) + { + mip->IOBASE=Base; + b=argv[ip++]; + mip->IOBASE=10; + gotB=TRUE; + continue; + } + cout << "Error in command line" << endl; + return 0; + } + + if (!gotI || !gotA || !gotB) + { + cout << "Error in command line" << endl; + return 0; + } + +// get prime modulus from .pol file + + mueller >> p; + pbits=bits(p); + if (pbits<64) + { + cout << "Prime modulus too small for this program!" << endl; + cout << "Use SCHOOF program (ftp://ftp.compapp.dcu.ie/pub/crypto/schoof.exe)" << endl; + exit(0); + } + cout << "P= " << p << endl; + cout << "P mod 24 = " << p%24 << endl; + cout << "P is " << pbits << " bits long" << endl; + cout << "Reading in pre-processed Modular Polynomials... " << endl; +// +// read in all pre-processed bivariate modular polynomials +// + modulo(p); // set modulus + l[0]=2; + max=0; + for (i=1;;i++) + { + mueller >> lp; + if (mueller.eof()) break; + max=i; + l[i]=lp; + cout << setw(3) << lp << flush; + posXY=NULL; + Gl[i].clear(); + forever + { + mueller >> c >> nx >> ny; + posXY=Gl[i].addterm((ZZn)c,nx,ny,posXY); + if (nx==0 && ny==0) break; + } + cout << "\b\b\b" << flush; + } + + mueller.close(); + +// loop for "-s" search option + + forever { + + fft_reset(); // reset FFT tables + + if (Edwards) + { + modulo(p); + EB=b; + EA=a; + AZ=(ZZn)1/(EA-EB); + A2=2*(EA+EB)/(EA-EB); + A4=1; AW=1; + + AW*=AZ; A2*=AZ; A4*=AZ; + + A4*=AW; + + T=4*A2; + T1=3*T; + T3=18*36*(2*A4); + + A=T3-3*T1*T1; + B=-T1*T3+2*T1*T1*T1; + ecurve((Big)A,(Big)B,p,MR_AFFINE); // initialise Elliptic Curve + + } + else + { + ecurve(a,b,p,MR_AFFINE); // initialise Elliptic Curve + A=a; + B=b; + } + +// The elliptic curve as a Polynomial + + Y2=0; + Y2.addterm(B,0); + Y2.addterm(A,1); + Y2.addterm((ZZn)1,3); + Y4=Y2*Y2; + + cout << "Counting the number of points (NP) on the curve" << endl; + if (Edwards) + { + cout << "X^2+" << EA << "*Y^2=X^2*Y^2+" << EB << endl; + cout << "Equivalent to Weierstrass form" << endl; + } + cout << "y^2= " << Y2 << " mod " << p << endl; + + delta=-16*(4*A*A*A+27*B*B); + + if (delta==0) + { + cout << "Not Allowed! 4A^3+27B^2 = 0" << endl; + if (search) {b+=1; continue; } + else return 0; + } + + // Calculate j-invariant + + j=(-1728*64*A*A*A)/delta; + + if (j==0 || j==1728) + { + cout << "Not Allowed! j-invariant = 0 or 1728" << endl; + if (search) {b+=1; continue; } + else return 0; + } + + +// Finding the order modulo 2 +// If GCD(X^P-X,X^3+AX+B) == 1 , trace=1 mod 2, else trace=0 mod 2 + + XX=0; + XX.addterm((ZZn)1,1); + YY=0; + YY.addterm((ZZn)-1,0); // Point (X,-Y) + setmod(Y2); + + XP=pow(XX,p); + G=gcd(XP-XX); + parity=0; + if (isone(G)) parity=1; + cout << "NP mod 2 = " << (p+1-parity)%2; + if ((p+1-parity)%2==0) + { + cout << " ***" << endl; + if (search && !Edwards) {b+=1; continue; } + } + else cout << endl; + + nl=0; + accum=1; // accumulated product of good primes + + Poly zero; + PolyMod one,XT,YT,ZT,XL,YL,ZL,ZL2,ZT2; + one=1; // polynomial = 1 + zero=0; // polynomial = 0 + + PolyXY dGx,dGy,dGxx,dGxy,dGyy; + ZZn E0b,E0bd,E2bs,E4b,E6b,Dg,Dj,Dgd,Djd,Dgs,Djs,jl,jld,p1,jd; + ZZn E4bl,E6bl,deltal,atilde,btilde,gd,f,fd,s,Eg,Ej,Exy; + int r,v,ld,ld1,discrim; + ZZn M,cf[500],cft[500],ad,K,RF; + Poly Fl,T,WP[500],H,X,Y,R; + term *pos; + + E4b=-(A/3); + E6b=-(B/2); + delta=(E4b*E4b*E4b-E6b*E6b)/1728; + +// +// find out how many bits we are going to need +// before Kangaroos can take over +// + first=5; + sl[0]=3; sl[1]=5; sl[2]=7; sl[3]=8; sl[4]=9; sl[5]=0; // do low prime powers + SCHP=9; + + if (pbits<=256) d=pow((Big)2,64); + else d=pow((Big)2,72); // kangaroos do more work + + d=sqrt(p/d); + + escape=FALSE; + + +// Calculate Divisor Polynomials for small primes - Schoof 1985 p.485 +// Set the first few by hand.... + + + P[1]=1; P[2]=2; P[3]=0; P[4]=0; + + P2[1]=1; P3[1]=1; + + P2[2]=P[2]*P[2]; + P3[2]=P2[2]*P[2]; + + P[3].addterm(-(A*A),0); P[3].addterm(12*B,1); + P[3].addterm(6*A,2) ; P[3].addterm((ZZn)3,4); + + P2[3]=P[3]*P[3]; + P3[3]=P2[3]*P[3]; + + P[4].addterm((ZZn)(-4)*(8*B*B+A*A*A),0); + P[4].addterm((ZZn)(-16)*(A*B),1); + P[4].addterm((ZZn)(-20)*(A*A),2); + P[4].addterm((ZZn)80*B,3); + P[4].addterm((ZZn)20*A,4); + P[4].addterm((ZZn)4,6); + + P2[4]=P[4]*P[4]; + P3[4]=P2[4]*P[4]; + +// generation of Divisor polynomials +// See Schoof p. 485 + + for (jj=5;jj<=SCHP+1;jj++) + { // different for even and odd + if (jj%2==1) + { + n=(jj-1)/2; + if (n%2==0) + P[jj]=P[n+2]*P3[n]*Y4-P3[n+1]*P[n-1]; + else + P[jj]=P[n+2]*P3[n]-Y4*P3[n+1]*P[n-1]; + } + else + { + n=jj/2; + P[jj]=P[n]*(P[n+2]*P2[n-1]-P[n-2]*P2[n+1])/(ZZn)2; + + } + if (jj <= 1+(SCHP+1)/2) + { // precalculate for later + P2[jj]=P[jj]*P[jj]; + P3[jj]=P2[jj]*P[jj]; + } + } + +// +// Schoof's original method for small primes +// + + for (i=0;;i++) + { + lp=sl[i]; + if (lp==0) break; + + if (lp>=first) + { + good[nl]=lp; + accum*=lp; + } + k=p%lp; + + setmod(P[lp]); + MY2=Y2; +// These next are time-consuming calculations of X^P, X^(P*P), Y^P and Y^(P*P) + + cout << "X^P " << flush; + XP=pow(XX,p); + cout << "\b\b\b\bY^P " << flush; + YP=pow(MY2,(p-1)/2); + + cout << "\b\b\b\bX^PP" << flush; + XPP=compose(XP,XP); // this is faster + cout << "\b\b\b\bY^PP" << flush; + YPP=YP*compose(YP,XP); + cout << "\b\b\b\b"; + + PolyMod Pk,P2k,PkP1,PkM1,PkP2; + Pk=P[k]; PkP1=P[k+1]; PkM1=P[k-1]; PkP2=P[k+2]; + + P2k=(Pk*Pk); +// +// This is Schoof's algorithm, stripped to its bare essentials +// +// Now looking for the value of tau which satisfies +// (X^(P*P),Y^(P*P)) + k.(X,Y) = tau.(X^P,Y^P) +// +// Note that (X,Y) are rational polynomial expressions for points on +// an elliptic curve, so "+" means elliptic curve point addition +// +// k.(X,Y) can be found directly from Divisor polynomials +// Schoof Prop (2.2) +// +// Points are converted to projective (X,Y,Z) form +// This is faster (x2). Observe that (X/Z^2,Y/Z^3,1) is the same +// point in projective co-ordinates as (X,Y,Z) +// + + if (k%2==0) + { + XT=XX*MY2*P2k-PkM1*PkP1; + YT=(PkP2*PkM1*PkM1-P[k-2]*PkP1*PkP1)/4; + XT*=MY2; // fix up, so that Y has implicit y multiplier + YT*=MY2; // rather than Z + ZT=MY2*Pk; + } + else + { + XT=(XX*P2k-MY2*PkM1*PkP1); + if (k==1) YT=(PkP2*PkM1*PkM1+PkP1*PkP1)/4; + else YT=(PkP2*PkM1*PkM1-P[k-2]*PkP1*PkP1)/4; + ZT=Pk; + } + + elliptic_add(XT,YT,ZT,XPP,YPP); + +// +// Test for Schoof's case 1 - LHS (XT,YT,ZT) is point at infinity +// + + cout << "NP mod " << lp << " = " << flush; + if (iszero(ZT)) + { // Is it zero point? (XPP,YPP) = - K(X,Y) + if (lp>=first) t[nl++]=0; + cout << setw(3) << (p+1)%lp; + if ((p+1)%lp==0) + { + cout << " ***" << endl; + if (search && (!Edwards || lp!=4)) {escape=TRUE; break;} + } + else cout << endl; + continue; + } +// +// Now keep finding tau.(X^P,Y^P), until equality is detected +// This is very simple! +// + XL=XP; + YL=YP; + ZL=1; + ZT2=ZT*ZT; + for (tau=1;tau<=(lp/2);tau++) + { + cout << setw(3) << (p+1-tau)%lp << flush; + + ZL2=ZL*ZL; + if (iszero(XT*ZL2-ZT2*XL)) // LHS == RHS?? + { // LHS = RHS + if (!iszero(YT*ZL2*ZL-YL*ZT*ZT2)) + { // point doubled - change sign + tau=lp-tau; + cout << "\b\b\b"; + cout << setw(3) << (p+1-tau)%lp << flush; + } + if (lp>=first) t[nl++]=tau; + if ((p+1-tau)%lp==0) + { + cout << " ***" << endl; + if (search && (!Edwards || lp!=4)) escape=TRUE; + } + else cout << endl; + break; + } + elliptic_add(XL,YL,ZL,XP,YP); + cout << "\b\b\b"; + } + if (escape) break; + } + + if (!escape) for (i=1;accum<=d;i++) + { + if (i>max) + { + cout << "WARNING: Ran out of Modular Polynomials!" << endl; + break; + } + lp=l[i]; + + if (lp<=SCHP) continue; + + k=p%lp; + for (is=1;;is++) + if (is*(lp-1)%12==0) break; + + el=lp; + s=is; + +// Get next Modular Polynomial + + MP=Gl[i]; + +// Evaluate bivariate polynomial at Y=j-invariant +// and use as polynomial modulus + + F=MP.F(j); + setmod(F); + cout << setw(3) << lp << flush; + XP=pow(XX,p); +// +// Determine "Splitting type" +// + cout << "\b\b\bGCD" << flush; + G=gcd(XP-XX); + + if (degree(G)==lp+1) + { + cout << "\b\b\b" << flush; + continue; // pathological case + } + if (degree(G)==0) // Atkin Prime + { + if (!atkin && lp>100) // Don't process large Atkin Primes + { + cout << "\b\b\b" << flush; + continue; + } + BOOL useful=FALSE; + cout << "\b\b\b" << flush; + cout << "ATK" << flush; + + PolyMod u[20]; + int max_r,lim=1; + u[0]=XP; + u[1]=compose(u[0],u[0]); + +// +// The code for processing Atkin Primes is in here, but currently largely +// unused. However the simplest case is used, as it suggests only one +// value for NP mod lp, and so can be used just like an Elkies prime +// +// + if (atkin) max_r=lp+1; + else max_r=2; + for (r=2;r<=max_r;r++) + { + PolyMod C; + int kk,m; + BOOL first; + if ((lp+1)%r!=0) continue; // only keep good ones! + v=jac(k,lp); // check Schoof Prop. 6.3 + jj=(lp+1)/r; + if (jj%2==0 && v==(-1)) continue; + if (jj%2==1 && v==1) continue; + // if (phi(r)>8) continue; // > 8 candidates + // if (lp<30 && phi(r)>2) continue; + // if (lp<60 && phi(r)>4) continue; + kk=r; m=0; + first=TRUE; +// +// Right-to-Left Power Composition - find X^(P^r) +// + forever + { + if (kk%2!=0) + { + if (first) C=u[m]; + else C=compose(u[m],C); + first=FALSE; + } + kk/=2; + if (kk==0) break; + m++; + if (m>lim) + { // remember them for next time + u[m]=compose(u[m-1],u[m-1]); + lim=m; + } + } + + if (iszero(C-XX)) + { // found splitting type + useful=TRUE; + break; + } + } + cout << "\b\b\b" << flush; + if (!useful) continue; + + cout << "NP mod " << lp << " = " << flush; + + int a,b,candidates,gx,gy,ord,qnr=2; + BOOL gen; + while (jac(qnr,lp)!=(-1)) qnr++; + +// +// [4] Algorithm VII.4 - find a generator of F(lp^2) +// + ord=lp*lp-1; + gy=1; + for (gx=1;gx1 && igcd(jj,r)!=1) continue; + powquad(lp,qnr,gx,gy,jj*ord/r,a,b); + + tau=((a+1)*k*(int)invers(2,lp))%lp; + if (tau==0) + { // r must be 2 - I can make use of this! + // Its an Atkin prime, but only one possibility + candidates++; + cout << (p+1)%lp << flush; + if ((p+1)%lp==0) + { + cout << " ***" << endl; + if (search && (!Edwards || lp!=4)) escape=TRUE; + } + else cout << endl; + good[nl]=lp; + t[nl]=tau; + nl++; + accum*=lp; + break; + } + else if (jac(tau,lp)==1) + { + candidates+=2; + tau=sqrmp(tau,lp); + tau=(2*tau)%lp; + if (candidates==phi(r)) + { + cout << (p+1-tau)%lp << " or " << (p+1+tau)%lp << endl; + break; + } + else cout << (p+1-tau)%lp << "," << (p+1+tau)%lp << "," << flush; + } + } + if (escape) break; + continue; + } + +// +// Good Elkies prime - so use it! +// +// First solve quadratic for a root +// + if (degree(G)==1) + { + discrim=0; + g=-G.coeff(0); // Elkies Prime, one root, (2 possibilites) + } + else // degree(G)==2 + { // Elkies Prime, two roots + discrim=1; + qb=G.coeff(1); + qc=G.coeff(0); + g=sqrt(qb*qb-4*qc); + g=(-qb-g)/2; // pick either one + } + cout << "\b\b\bELK" << flush; +// +// Mueller's procedure for finding the atilde, btilde and p1 +// parameters of the isogenous curve +// 3. page 111 +// 4. page 131-133 +// First we need partial differentials of bivariate Modular Polynomial +// + + dGx=diff_dx(MP); + dGy=diff_dy(MP); + dGxx=diff_dx(dGx); + dGxy=diff_dx(dGy); + dGyy=diff_dy(dGy); + + Eg=dGx.F(g,j); // Evaluated at (g,j) + Ej=dGy.F(g,j); + Exy=dGxy.F(g,j); + + Dg=g*Eg; + Dj=j*Ej; + + deltal=delta*pow(g,12/is)/pow(el,12); + + if (Dj==0) + { + E4bl=E4b/(el*el); + atilde=-3*pow(el,4)*E4bl; + jl=pow(E4bl,3)/deltal; + btilde=2*pow(el,6)*sqrt((jl-1728)*deltal); + p1=0; + } + else + { + E2bs=(-12*E6b*Dj)/(s*E4b*Dg); + + gd=-(s/12)*E2bs*g; + jd=-E4b*E4b*E6b/delta; + E0b=E6b/(E4b*E2bs); + + Dgd=gd*Eg+g*(gd*dGxx.F(g,j)+jd*Exy); + Djd=jd*Ej+j*(jd*dGyy.F(g,j)+gd*Exy); + + E0bd=((-s*Dgd)/12-E0b*Djd)/Dj; + + E4bl=(E4b-E2bs*(12*E0bd/E0b+6*E4b*E4b/E6b-4*E6b/E4b)+E2bs*E2bs)/(el*el); + + jl=pow(E4bl,3)/deltal; + f=pow(el,is)/g; fd=s*E2bs*f/12; + + Dgs=dGx.F(f,jl); + Djs=dGy.F(f,jl); + + jld=-fd*Dgs/(el*Djs); + E6bl=-E4bl*jld/jl; + + atilde=-3*pow(el,4)*E4bl; + btilde=-2*pow(el,6)*E6bl; + p1=-el*E2bs/2; + } + +// +// Find factor of Division Polynomial from atilde, btilde and p1 +// Here we follow 3. p 116 +// Polynomials have been modified s.t x=z^2 +// +// Note that all Polynomials can be reduced mod x^(d+1), +// where d=(lp-1)/2, using modxn() function +// + + cout << "\b\b\bFAC" << flush; + ld=(lp-1)/2; + ld1=(lp-3)/2; + + get_ck(ld1,A,B,cf); + + WP[1]=1; + pos=NULL; + for (k=ld1;k>0;k--) + pos=WP[1].addterm(cf[k],k+1,pos); + for (v=2;v<=ld;v++) + WP[v]=modxn(WP[v-1]*WP[1],ld+1); +// +// WPv have understood multiplier x^-v +// + get_ck(ld1,atilde,btilde,cft); + + Y=0; + pos=NULL; + for (k=ld1;k>0;k--) + pos=Y.addterm((lp*cf[k]-cft[k])/(ZZn)((2*k+1)*(2*k+2)),k+1,pos); + Y.addterm(-p1,1,pos); + + RF=1; + H=1; + X=1; + for (r=1;r<=ld;r++) + { + X=modxn(X*Y,ld+1); + RF*=r; + H+=(X/RF); + } +// +// H has understood multiplier x^-d +// + ad=1; + Fl=0; + pos=Fl.addterm(ad,ld); + for (v=ld-1;v>=0;v--) + { + H-=ad*WP[v+1]; + H=divxn(H,1); + ad=H.min(); + pos=Fl.addterm(ad,v,pos); + } + + setmod(Fl); + MY2=Y2; + MY4=Y4; + +// +// Only the Y-coordinate is calculated. No need for X^P ! +// + cout << "\b\b\bY^P" << flush; + YP=pow(MY2,(p-1)/2); + cout << "\b\b\b"; + +// Calculate Divisor Polynomials for small primes - Schoof 1985 p.485 +// This time mod the new (small) modulus Fl +// Set the first few by hand.... + + PolyMod Pf[300],P2f[300],P3f[300]; + Pf[0]=0; Pf[1]=1; Pf[2]=2; Pf[3]=0; Pf[4]=0; + + P2f[1]=1; P3f[1]=1; + + P2f[2]=Pf[2]*Pf[2]; + P3f[2]=P2f[2]*Pf[2]; + + Pf[3].addterm(-(A*A),0); Pf[3].addterm(12*B,1); + Pf[3].addterm(6*A,2) ; Pf[3].addterm((ZZn)3,4); + + P2f[3]=Pf[3]*Pf[3]; + P3f[3]=P2f[3]*Pf[3]; + + Pf[4].addterm((ZZn)(-4)*(8*B*B+A*A*A),0); + Pf[4].addterm((ZZn)(-16)*(A*B),1); + Pf[4].addterm((ZZn)(-20)*(A*A),2); + Pf[4].addterm((ZZn)80*B,3); + Pf[4].addterm((ZZn)20*A,4); + Pf[4].addterm((ZZn)4,6); + + P2f[4]=Pf[4]*Pf[4]; + P3f[4]=P2f[4]*Pf[4]; + lower=5; + +// +// Now looking for value of lambda which satisfies +// (X^P,Y^P) = lambda.(XX,YY). +// 3. Page 118, Algorithm 7.9 +// +// Note that it appears to be sufficient to only compare the Y coordinates (!?) +// For a justification see page 120 of 3. +// Thank you SYSTRAN translation service! (www.altavista.com) +// + good[nl]=lp; + cout << "NP mod " << lp << " = " << flush; + for (lambda=1;lambda<=(lp-1)/2;lambda++) + { + int res=0; + PolyMod Ry,Ty; + tau=(lambda+invers(lambda,lp)*p)%lp; + + k=(lp+tau*tau-(4*p)%lp)%lp; + if (jac(k,lp)!=discrim) continue; +// +// Possible values of tau could be eliminated here by an application of +// Atkin's algorithm.... +// + cout << setw(3) << (p+1-tau)%lp << flush; + + // This "loop" is usually executed just once + for (jj=lower;jj<=lambda+2;jj++) + { // different for even and odd + if (jj%2==1) // 2 mod-muls + { + n=(jj-1)/2; + if (n%2==0) + Pf[jj]=Pf[n+2]*P3f[n]*MY4-P3f[n+1]*Pf[n-1]; + else + Pf[jj]=Pf[n+2]*P3f[n]-MY4*P3f[n+1]*Pf[n-1]; + } + else // 3 mod-muls + { + n=jj/2; + Pf[jj]=Pf[n]*(Pf[n+2]*P2f[n-1]-Pf[n-2]*P2f[n+1])/(ZZn)2; + } + P2f[jj]=Pf[jj]*Pf[jj]; // square + P3f[jj]=P2f[jj]*Pf[jj]; // cube + } + if (lambda+3>lower) lower=lambda+3; + + // compare Y-coordinates - 3 polynomial mod-muls required + + if (lambda%2==0) + { + Ry=(Pf[lambda+2]*P2f[lambda-1]-Pf[lambda-2]*P2f[lambda+1])/4; + Ty=MY4*YP*P3f[lambda]; + } + else + { + if (lambda==1) Ry=(Pf[lambda+2]*P2f[lambda-1]+P2f[lambda+1])/4; + else Ry=(Pf[lambda+2]*P2f[lambda-1]-Pf[lambda-2]*P2f[lambda+1])/4; + Ty=YP*P3f[lambda]; + } + if (iszero(Ty-Ry)) res=1; + if (iszero(Ty+Ry)) res=2; + + if (res!=0) + { // has it doubled, or become point at infinity? + if (res==2) + { // it doubled - wrong sign + tau=(lp-tau)%lp; + cout << "\b\b\b"; + cout << setw(3) << (p+1-tau)%lp << flush; + } + t[nl]=tau; + if ((p+1-tau)%lp==0) + { + cout << " ***" << endl; + if (search && (!Edwards || lp!=4)) escape=TRUE; + } + else cout << endl; + break; + } + cout << "\b\b\b"; + } + nl++; + accum*=lp; + if (escape) break; + } + Modulus.clear(); + + if (escape) {b+=1; continue;} + + Crt CRT(nl,good); + Big order,ordermod; + ordermod=accum; + order=(p+1-CRT.eval(t))%ordermod; // get order mod product of primes + + nrp=kangaroo(p,order,ordermod); + + if (Edwards) + { + if (!prime(nrp/4) && search) {b+=1; continue; } + else break; + } + else + { + if (!prime(nrp) && search) {b+=1; continue; } + else break; + } + } + + if (fout) + { + ECn P; + ofile << bits(p) << endl; + mip->IOBASE=16; + ofile << p << endl; + + ofile << a << endl; + ofile << b << endl; + + // generate a random point on the curve + // point will be of prime order for "ideal" curve, otherwise any point + if (!Edwards) + { + do { + x=rand(p); + } while (!P.set(x,x)); + P.get(x,y); + ofile << nrp << endl; + } + else + { + ZZn X,Y,Z,R,TA,TB,TC,TD,TE; + forever + { + X=randn(); + R=(X*X-EB)/(X*X-EA); + if (!qr(R))continue; + Y=sqrt(R); + break; + } + Z=1; +// double point twice (4*P) + for (i=0;i<2;i++) + { + TA = X*X; + TB = Y*Y; + TC = TA+TB; + TD = TA-TB; + TE = (X+Y)*(X+Y)-TC; + + X = TC*TD; + Y = TE*(TC-2*EB*Z*Z); + Z = TD*TE; + } + X/=Z; + Y/=Z; + x=X; + y=Y; + ofile << nrp/4 << endl; + } + ofile << x << endl; + ofile << y << endl; + mip->IOBASE=10; + } + if (p==nrp) + { + cout << "WARNING: Curve is anomalous" << endl; + return 0; + } +// check MOV condition for curves of Cryptographic interest + d=1; + for (i=0;i<50;i++) + { + d=modmult(d,p,nrp); + if (d==1) + { + cout << "WARNING: Curve fails MOV condition" << endl; + return 0; + } + } + + return 0; +} + diff --git a/miracl/source/curve/sea.txt b/miracl/source/curve/sea.txt new file mode 100644 index 0000000..ff62071 --- /dev/null +++ b/miracl/source/curve/sea.txt @@ -0,0 +1,88 @@ +Schoof-Elkies-Atkin-Mueller program for counting points on a GF(p) elliptic +curve y^2=x^3+Ax+B mod p. + +Precompiled Windows executables of these programs may be downloaded from +ftp://ftp.compapp.dcu.ie/pub/crypto + +To build the mueller/process/sea applications, you must compile and link the +modules together, with MIRACL C++ classes , and with the MIRACL library. + +So for MS C++ + +cl /c /O2 /GX ps_big.cpp +cl /c /O2 /GX big.cpp +cl /c /O2 /GX mueller.cpp +link mueller.obj ps_big.obj big.obj miracl.lib + +cl /c /O2 /GX process.cpp +link process.obj big.obj miracl.lib + +cl /c /O2 /GX modpol.cpp +cl /c /O2 /GX ps_zzn.cpp +cl /c /O2 /GX zzn.cpp +link modpol.obj ps_zzn.obj zzn.obj big.obj miracl.lib + +cl /c /O2 /GX sea.cpp +cl /c /O2 /GX poly.cpp +cl /c /O2 /GX polymod.cpp +cl /c /O2 /GX polyxy.cpp +cl /c /O2 /GX ecn.cpp +cl /c /O2 /GX crt.cpp +link sea.obj poly.obj polymod.obj polyxy.obj big.obj zzn.obj ecn.obj +crt.obj miracl.lib + +For Linux GCC + +g++ -I. -c -O2 ps_big.cpp +g++ -I. -c -O2 big.cpp +g++ -I. mueller.cpp ps_big.o big.o miracl.a -o mueller + +etc. + + +Note that the headers ps_big.h, ps_zzn.h, poly.h, polymod.h and polyxy.h are +assumed to be in the local directiory + + +Instructions for use + +First run the utility "mueller" to build up a collection of Modular +Polynomials. This needs to be done once only - ever, but you can from time +augment your collection of Polynomials by running it again. Its quite time +consuming, but in less than an hour you should have enough to get started. The +more you have, the bigger the prime modulus that you can use. + +Then run the utility "process" to process the raw polynomial file with +respect to your chosen prime modulus. This need to be done just once for +every prime modulus of interest to you. This takes only a few minutes at +most. + +Alternatively use "modpol", which is a composite of "mueller" and "process". +This may be better if you have difficulty running the memory hungry "mueller" + +Finally run this program "sea" specifying the A and B parameters of the +particular curve. This program can also search through many curves for +a curve ideal for cryptographic use (with a prime number of points). + +For example try:- + +mueller 0 120 -o mueller.raw +process -f 65112*2#144-1 -i mueller.raw -o test160.pol +sea -3 49 -i test160.pol + +or + +modpol -f 65112*2#144-1 0 120 -o test160.pol +sea -3 49 -i test160.pol + +(In Unix, use . and ^ instead of * and #) + +When using the "sea" program, the -s option is particularly useful +and allows automatic search for an "ideal" curve. If a curve order is +exactly divisible by a small prime, that curve is immediately abandoned, +and the program moves on to the next, incrementing the B parameter of +the curve. + + +For more information, see the comments at the head of the source file sea.cpp + diff --git a/miracl/source/curve/super2.cpp b/miracl/source/curve/super2.cpp new file mode 100644 index 0000000..27b69dc --- /dev/null +++ b/miracl/source/curve/super2.cpp @@ -0,0 +1,235 @@ +// +// Simple Program to find number of points on supersingular curves over GF(2^p) +// +// Either y^2+y=x^3+x +// or y^2+y=x^3+x+1 +// +// See "Elliptic Curve Public Key Cryptosystems", Menezes, +// Kluwer Academic Publishers, Chapter 3 +// +// Requires: big.cpp ec2.cpp +// +// + +#include +#include +#include +#include +#include "big.h" +#include "ec2.h" + +using namespace std; + +Miracl precision=50; // max. 50x32 bits per big number + +int main(int argc,char **argv) +{ + ofstream ofile; + int A,B,a,b,c,M,ip,m,i; + Big nrp,q,r2q,x,y,f,p,r,cof,d; + BOOL fout,gota,gotb,gotc,gotA,gotB,gotM,large; + miracl *mip=&precision; + EC2 P,Q,T,KP,KQ; + + gprime(100000); + + argv++; argc--; + if (argc<1) + { + cout << "Incorrect Usage" << endl; + cout << "Program finds the number of points (NP) on a Super-singular" << endl; + cout << "Elliptic curve which is defined over the Galois field GF(2^M)" << endl; + cout << "The Elliptic Curve has the equation Y^2 +Y = X^3 + AX + B " << endl; + cout << "(A,B) must be (1,0) or (1,1), M must be odd" << endl; + cout << "A suitable trinomial or Pentanomial basis must" << endl; + cout << "also be specified t^m+t^a+1 or t^m+t^a+t^b+t^c+1" << endl; + cout << "These can be found in e.g. the IEEE P1363 standard" << endl; + cout << "super2 " << endl << endl; + cout << "e.g. super2 1 1 191 9" << endl << endl; + cout << "To output to a file, use flag -o " << endl; + cout << "\nFreeware from Certivox, Dublin, Ireland" << endl; + cout << "Full C++ source code and MIRACL multiprecision library available" << endl; + cout << "email mscott@indigo.ie" << endl; + return 0; + } + + fout=gotM=gotA=gotB=gota=gotb=gotc=FALSE; + M=a=b=c=0; + + ip=0; +// Interpret command line + while (ip1 || M%2!=1) + { + cout << "Error in command line" << endl; + return 0; + } + + if (!ecurve2(-M,a,b,c,(Big)A,(Big)B,TRUE,MR_AFFINE)) + { + cout << "Illegal Curve Parameters" << endl; + return 0; + } + + m=M%8; + + q=pow((Big)2,M); + r2q=pow((Big)2,(M+1)/2); + + if (B==0) + { + if (m==1 || m==7) nrp=q+1+r2q; + else nrp=q+1-r2q; + } + else + { + if (m==1 || m==7) nrp=q+1-r2q; + else nrp=q+1+r2q; + } + + cout << "NP= " << nrp << endl; + cof=1; large=false; // indicates large prime factor found + + if (prime(nrp)) + { + cout << "NP is Prime!" << endl; + p=nrp; + large=TRUE; + } + else + { + cout << "NP= " ; + p=nrp; + for (i=0;;i++) + { + f=mip->PRIMES[i]; + if (f==0) break; + if (p%f==0) + { + cof*=f; + p/=f; + if (p==1) break; + cout << f << "." ; + continue; + } + if ((p/f)<=f) + { + cout << p << endl; + p=1; + break; + } + } + if (p>1) + { + if (prime(p)) + { + cout << "prime" << endl; + large=TRUE; + } + else cout << "composite" << endl; + } + } + do { + x=rand(q); + } while (!P.set(x,x)); + + T=P; + T*=nrp; + + if (!T.iszero()) + { + cout << "nrp*P!=O - something is wrong!" << endl; + return 0; + } + + P*=cof; + + if (large) + { // check MOV condition + d=1; + for (i=1;i<=4;i++) + { + d=modmult(d,q,p); + if (d==1) + { + cout << "Security Multiplier= " << i << endl; + break; + } + } + } + + if (fout && large) + { + + P.get(x,y); + ofile << -M << endl; + ofile << A << endl; + ofile << B << endl; + mip->IOBASE=16; + ofile << nrp << endl; + ofile << x << endl; + ofile << y << endl; + mip->IOBASE=10; + ofile << a << endl; + ofile << b << endl; + ofile << c << endl; + } + return 0; +} + diff --git a/miracl/source/curve/trans.cpp b/miracl/source/curve/trans.cpp new file mode 100644 index 0000000..5e4d89f --- /dev/null +++ b/miracl/source/curve/trans.cpp @@ -0,0 +1,157 @@ +// +// Simple Program to transform an elliptic curve +// to the simplified Weierstrass form. +// +// See "Elliptic Curve Public Key Cryptosystems", Menezes, +// Kluwer Academic Publishers, Chapter 3 +// +// Requires: big.cpp +// +// cl /O2 trans.cpp big.cpp miracl.lib +// g++ -O2 trans.cpp big.cpp miracl.a -o trans +// +// + + +#include +#include "big.h" + +using namespace std; + +Miracl precision=100; + +int main(int argc,char **argv) +{ + Big az,a1,a2,a3,a4,a6,aw; + Big t,t1,t2,t3,t4,a,b; + Big delta,j,g; + argc--; argv++; + + if (argc!=7) + { + cout << "Wrong number of parameters provided" << endl; + cout << "trans a b c d e f g" << endl; + cout << "Transforms elliptic curve from the general form" << endl; + cout << "ay^2+bxy+cy=dx^3+ex^2+fx+g" << endl; + cout << "to the simplified Weierstrass form" << endl; + cout << "Y^2=X^3+AX+B" << endl; + exit(0); + } + az=argv[0]; + a1=argv[1]; + a2=argv[4]; + a3=argv[2]; + a4=argv[5]; + a6=argv[6]; + aw=argv[3]; + + if (aw==0 || az==0) + { + cout << "This is not an elliptic curve" << endl; + return 0; + } + + cout << "Transforming elliptic curve" << endl; + if (az==1) cout << "y^2"; + else cout << az << ".y^2"; + if (a1!=0) + { + if (a1>0) cout << "+"; + if (a1==-1) cout << "-xy"; + if (a1==1) cout << "xy"; + if (a1!=-1 && a1!=1) cout << a1 << ".xy"; + } + if (a3!=0) + { + if (a3>0) cout << "+"; + if (a3==-1) cout << "-y"; + if (a3==1) cout << "y"; + if (a3!=-1 && a3!=1) cout << a3 << ".y"; + } + if (aw==1) cout << " = x^3"; + else cout << " = " << aw << ".x^3"; + + if (a2!=0) + { + if (a2>0) cout << "+"; + if (a2==-1) cout << "-x^2"; + if (a2==1) cout << "x^2"; + if (a2!=-1 && a2!=1) cout << a2 << ".x^2"; + } + if (a4!=0) + { + if (a4>0) cout << "+"; + if (a4==-1) cout << "-x"; + if (a4==1) cout << "x"; + if (a4!=-1 && a4!=1) cout << a4 << ".x"; + } + if (a6!=0) + { + if (a6>0) cout << "+"; + cout << a6; + } + cout << endl; + +/* transform az*y^2 to y^2 by simple substitution.... */ + + if (az!=1) + { + aw*=az; a2*=az; a4*=az; a6*=az; + } + +/* transform aw*x^3 to x^3 by simple substitution.... */ + + if (aw!=1) + { + a3*=aw; a4*=aw; a6*=(aw*aw); + } + + t=4*a2+a1*a1; + t1=3*t; + t3=18*36*(a1*a3+2*a4); + t4=9*36*36*(4*a6+a3*a3); + + a=t3-3*t1*t1; + b=t4-t1*t3+2*t1*t1*t1; + + if (a%16==0 && b%64==0) { a/=16; b/=64;} + if (a%81==0 && b%729==0) { a/=81; b/=729;} + if (a%625==0 && b%15625==0) { a/=625; b/=15625;} + if (a%2401==0 && b%117649==0) { a/=2401; b/=117649;} + + cout << ".. to the simplified Weierstrass form" << endl; + cout << "Y^2 = X^3"; + if (a!=0) + { + if (a>0) cout << "+"; + if (a==-1) cout << "-X"; + if (a==1) cout << "X"; + if (a!=-1 && a!=1) cout << a << ".X"; + } + if (b!=0) + { + if (b>0) cout << "+"; + cout << b; + } + cout << endl; + + delta=-16*(4*a*a*a+27*b*b); + + cout << "discriminant= " << delta << endl; + + if (delta==0) cout << "curve is singular" << endl; + else + { + j=-1728*(4*a)*(4*a)*(4*a); + g=gcd(j,delta); + j/=g; + delta/=g; + if (delta<0) + { + j=-j; delta=-delta; + } + if (delta>1) cout << "j-invariant = " << j << "/" << delta << endl; + else cout << "j-invariant = " << j << endl; + } +} + diff --git a/miracl/source/curve/variable.h b/miracl/source/curve/variable.h new file mode 100644 index 0000000..d5ed0be --- /dev/null +++ b/miracl/source/curve/variable.h @@ -0,0 +1,9 @@ +// Dummy Variable class +#ifndef VARIABLE_H +#define VARIABLE_H + +class Variable +{ +}; + +#endif diff --git a/miracl/source/curve/weil.cpp b/miracl/source/curve/weil.cpp new file mode 100644 index 0000000..6d1fb7c --- /dev/null +++ b/miracl/source/curve/weil.cpp @@ -0,0 +1,120 @@ +/* + * Weil's theorem + * + * Reads in details of an elliptic curve + * The curve is y^2=x^3+A.x+B mod p + * and finds the number of points on curve over the extension field p^k + * + * An input file supplies the domain information {p,A,B,q}, + * where A and B are curve parameters, This file can be created by + * the cm, schoof or sea applications. Here p is the prime modulus, and q + * is the number of points on the curve. + * + * Invoke as weil , for example + * prompt:>weil common.ecs 8 + * + * This program also calculates the number of points on the twisted + * extension curve. If this is prime, then this will be an ideal setting + * for elliptic curve cryptography over the extension field p^k using + * the curve y^2=x^3+A.(d^2)x+B.(d^3) where d is any quadratic non residue + * in F(p^k) + * + * Inspired by "Fast Generation of Elliptic Curves with prime order over + * F_p^{2c}", Nogami & Morikawa + * + * To get the results of their table 7 ... + * + * prompt:>schoof -f 2#24-3 3 10 -o example.ecs + * prompt:>weil example.ecs 8 + * + * It is easy to create a simple batch file to loop around these programs + * until a good curve is found. + * + * Requires: big.cpp ecn.cpp + */ + +#include +#include +#include "big.h" +#include "ecn.h" + +using namespace std; + +#ifndef MR_NOFULLWIDTH +Miracl precision=100; +#else +Miracl precision(100,MAXBASE); +#endif + +int main(int argc,char **argv) +{ + ifstream curve; /* construct file I/O streams */ + int k,bts; + Big p,a,b,q; + miracl *mip=&precision; + BOOL gotI=FALSE; + Big t[50],trace,np,npt; + + argv++; argc--; + if (argc!=2) + { + cout << "Wrong number of parameters" << endl; + return 1; + } + + + curve.open(argv[0],ios::in); + if (!curve) + { + cout << "Input file " << argv[0] << " could not be opened" << endl; + return 1; + } + + k=atoi(argv[1]); + + curve >> bts; + mip->IOBASE=16; + curve >> p >> a >> b >> q; + // mip->IOBASE=10; + + ecurve(a,b,p,MR_PROJECTIVE); + + cout << "base curve is y^2=x^3"; + if (a<0) cout << a << "x"; + if (a>0) cout << "+" << a << "x"; + + if (b<0) cout << b; + if (b>0) cout << "+" << b; + cout << " mod " << p << endl; + + if (k<2 || k>32) + { + cout << "Bad extension degree specified" << endl; + return 0; + } + trace=p+1-q; + t[0]=2; + t[1]=trace; + for (int i=1;i +#include "miracl.h" +#include +#include + +/* +#define RSA +*/ + +void strip(char *name) +{ /* strip extension off filename */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +int main() +{ /* decipher using private key */ + big x,y,ke,p,q,n,a,b,alpha,beta,t; + FILE *ifile; + FILE *ofile; + int ch; + long i,ipt; + char ifname[13],ofname[13]; + BOOL flo; + miracl *mip=mirsys(100,0); + x=mirvar(0); + ke=mirvar(0); + p=mirvar(0); + q=mirvar(0); + n=mirvar(0); + y=mirvar(0); + alpha=mirvar(0); + beta=mirvar(0); + a=mirvar(0); + b=mirvar(0); + t=mirvar(0); + mip->IOBASE=16; + if ((ifile=fopen("private.key","rt"))==NULL) + { + printf("Unable to open file private.key\n"); + return 0; + } + cinnum(p,ifile); + cinnum(q,ifile); + fclose(ifile); + multiply(p,q,ke); + do + { /* get input file */ + printf("file to be deciphered = "); + gets(ifname); + } while (strlen(ifname)==0); + strip(ifname); + strcat(ifname,".key"); + if ((ifile=fopen(ifname,"rt"))==NULL) + { + printf("Unable to open file %s\n",ifname); + return 0; + } + fscanf(ifile,"%ld\n",&ipt); + cinnum(x,ifile); + fclose(ifile); + strip(ifname); + strcat(ifname,".blg"); + printf("output filename = "); + gets(ofname); + flo=FALSE; + if (strlen(ofname)>0) + { /* set up output file */ + flo=TRUE; + ofile=fopen(ofname,"wt"); + } + else ofile=stdout; + printf("deciphering message\n"); + + xgcd(p,q,a,b,t); + lgconv(ipt,n); /* first recover "one-time pad" */ + +#ifdef RSA + decr(p,1,alpha); + premult(alpha,2,alpha); + incr(alpha,1,alpha); + subdiv(alpha,3,alpha); +#else + incr(p,1,alpha); + subdiv(alpha,4,alpha); +#endif + decr(p,1,y); + powmod(alpha,n,y,alpha); + + +#ifdef RSA + decr(q,1,beta); + premult(beta,2,beta); + incr(beta,1,beta); + subdiv(beta,3,beta); +#else + incr(q,1,beta); + subdiv(beta,4,beta); +#endif + decr(q,1,y); + powmod(beta,n,y,beta); + + copy(x,y); + divide(x,p,p); + divide(y,q,q); + powmod(x,alpha,p,x); /* using chinese remainder thereom */ + powmod(y,beta,q,y); + mad(x,q,q,ke,ke,t); + mad(t,b,b,ke,ke,t); + mad(y,p,p,ke,ke,x); + mad(x,a,a,ke,ke,x); + add(x,t,x); + divide(x,ke,ke); + if (size(x)<0) add(x,ke,x); + + if ((ifile=fopen(ifname,"rb"))==NULL) + { + printf("Unable to open file %s\n",ifname); + return 0; + } + for (i=0;iw[0]; /* XOR with last byte of x */ + fputc((char)ch,ofile); +#ifdef RSA + power(x,3,ke,x); +#else + mad(x,x,x,ke,ke,x); +#endif + } + fclose(ifile); + if (flo) fclose(ofile); + printf("\nmessage ends\n"); + return 0; +} + diff --git a/miracl/source/deciph.cpp b/miracl/source/deciph.cpp new file mode 100644 index 0000000..de10b7f --- /dev/null +++ b/miracl/source/deciph.cpp @@ -0,0 +1,112 @@ +/* + * Program to decipher message using Blum-Goldwasser probabalistic + * Public key method + * + * Define RSA to use cubing instead of squaring. This is no longer + * provably as difficult to break as factoring the modulus, its a bit + * slower, but it is resistant to chosen ciphertext attack. + * + * Requires: big.cpp crt.cpp + */ + +#include +#include +#include "big.h" /* include MIRACL system */ +#include "crt.h" +#include + +using namespace std; + +// #define RSA + +Miracl precision=100; + +void strip(char *name) +{ /* strip extension off filename */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +int main() +{ /* decipher using private key */ + Big x,t,ke,p[2],rem[2]; + ifstream private_key("private.key"); + ifstream input_file,key_file; + ofstream output_file; + int k; + char ch; + long i,ipt; + char ifname[13],ofname[13]; + BOOL flo; + miracl *mip=&precision; + + mip->IOBASE=16; + private_key >> p[0] >> p[1]; + ke=p[0]*p[1]; + cout << "file to be deciphered = "; + cin >> ifname; + strip(ifname); + strcat(ifname,".key"); + key_file.open(ifname,ios::in); + if (!key_file) + { + cout << "Unable to open file " << ifname << "\n"; + return 0; + } + key_file >> ipt >> x; + strip(ifname); + strcat(ifname,".blg"); + cout << "output filename = "; + cin.sync(); + cin.getline(ofname,13); + flo=FALSE; + if (strlen(ofname)>0) + { /* set up output file */ + flo=TRUE; + output_file.open(ofname); + } + cout << "deciphering message" << endl; + + Crt chinese(2,p); + +/* recover "one-time pad" */ + + for (k=0;k<2;k++) + { +#ifdef RSA + t=pow((2*(p[k]-1)+1)/3,(Big)ipt,p[k]-1); +#else + t=pow((p[k]+1)/4,(Big)ipt,p[k]-1); +#endif + rem[k]=pow(x%p[k],t,p[k]); + } + + x=chinese.eval(rem); /* using Chinese remainder thereom */ + + input_file.open(ifname,ios::binary|ios::in); + if (!input_file) + { + cout << "Unable to open file " << ifname << "\n"; + return 0; + } + for (i=0;i +#include "miracl.h" +#include +#include + +#define NP 2 /* two primes - could be used with more */ + +miracl *mip; + +void strip(char *name) +{ /* strip extension off filename */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +int main() +{ /* decode using private key */ + int i; + big e,ep[NP],m,ke,kd,p[NP],kp[NP],mn,mx; + FILE *ifile; + FILE *ofile; + char ifname[13],ofname[13]; + BOOL flo; + big_chinese ch; + mip=mirsys(100,0); + for (i=0;iIOBASE=16; + if ((ifile=fopen("private.key","rt"))==NULL) + { + printf("Unable to open file private.key\n"); + return 0; + } + for (i=0;iIOBASE=16; + cinnum(m,ifile); + if (size(m)==0) break; + for (i=0;i=0) divide(e,mn,mn); + mip->IOBASE=128; + if (flo) cotnum(e,ofile); + cotnum(e,stdout); + } + crt_end(&ch); + fclose(ifile); + if (flo) fclose(ofile); + printf("message ends\n"); + return 0; +} + diff --git a/miracl/source/decode.cpp b/miracl/source/decode.cpp new file mode 100644 index 0000000..f5ef11a --- /dev/null +++ b/miracl/source/decode.cpp @@ -0,0 +1,98 @@ +/* + * Program to decode message using RSA private key. + * + * Requires: big.cpp crt.cpp + */ + +#include +#include +#include +#include "big.h" /* include MIRACL system */ +#include "crt.h" /* chinese remainder thereom */ + +using namespace std; + +#define NP 2 /* two primes - could be used with more */ + +Miracl precision=100; + +void strip(char *name) +{ /* strip extension off filename */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +int main() +{ /* decode using private key */ + int i; + Big e,ep[NP],m,ke,p[NP],kp[NP],mn,mx; + ifstream private_key("private.key"); + ifstream input_file; + ofstream output_file; + char ifname[13],ofname[13]; + BOOL flo; + miracl *mip=&precision; + mip->IOBASE=16; + for (i=0;i> p[i]; + } + /* construct public and private keys */ + ke=1; + for (i=0;iIOBASE=16; + input_file >> m; + if (m==0) break; + for (i=0;i=mx) e%=mn; + mip->IOBASE=128; + if (flo) output_file << e; + cout << e << flush; + } + cout << "message ends\n"; + return 0; +} + diff --git a/miracl/source/dssetup.c b/miracl/source/dssetup.c new file mode 100644 index 0000000..d3d370e --- /dev/null +++ b/miracl/source/dssetup.c @@ -0,0 +1,91 @@ +/* + * Digital Signature Standard + * + * See Communications ACM July 1992, Vol. 35 No. 7 + * This new standard for digital signatures has been proposed by + * the American National Institute of Standards and Technology (NIST) + * under advisement from the National Security Agency (NSA). + * + * This program generates the common values p, q and g to a file + * common.dss + */ + +#include +#include "miracl.h" + +#define QBITS 160 +#define PBITS 1024 + +int main() +{ + FILE *fp; + big p,q,h,g,n,s,t; + long seed; + miracl *mip=mirsys(100,0); + p=mirvar(0); + q=mirvar(0); + h=mirvar(0); + g=mirvar(0); + n=mirvar(0); + s=mirvar(0); + t=mirvar(0); + +/* randomise */ + printf("Enter 9 digit random number seed = "); + scanf("%ld",&seed); + getchar(); + irand(seed); + +/* generate q */ + forever + { + bigbits(QBITS,q); + nxprime(q,q); + if (logb2(q)>QBITS) continue; + break; + } + printf("q= "); + cotnum(q,stdout); + +/* generate p */ + expb2(PBITS,t); + decr(t,1,t); + premult(q,2,n); + divide(t,n,t); + expb2(PBITS-1,s); + decr(s,1,s); + divide(s,n,s); + forever + { + bigrand(t,p); + if (mr_compare(p,s)<=0) continue; + premult(p,2,p); + multiply(p,q,p); + incr(p,1,p); + copy(p,n); + if (isprime(p)) break; + } + printf("p= "); + cotnum(p,stdout); + +/* generate g */ + do { + decr(p,1,t); + bigrand(t,h); + divide(t,q,t); + powmod(h,t,p,g); + } while (size(g)==1); + printf("g= "); + cotnum(g,stdout); + + + fp=fopen("common.dss","wt"); + fprintf(fp,"%d\n",PBITS); + mip->IOBASE=16; + cotnum(p,fp); + cotnum(q,fp); + cotnum(g,fp); + fclose(fp); + return 0; +} + diff --git a/miracl/source/dssetup.cpp b/miracl/source/dssetup.cpp new file mode 100644 index 0000000..1984aca --- /dev/null +++ b/miracl/source/dssetup.cpp @@ -0,0 +1,77 @@ +/* + * Digital Signature Standard + * + * See Communications ACM July 1992, Vol. 35 No. 7 + * This new standard for digital signatures has been proposed by + * the American National Institute of Standards and Technology (NIST) + * under advisement from the National Security Agency (NSA). + * + * This program generates the common values p, q and g to a file + * common.dss + * + * See "Applied Cryptography", by Bruce Schneier for a better way + * to generate trustworthy primes + * + * Requires: big.cpp + * + */ + +#include +#include +#include "big.h" + +using namespace std; + +#define QBITS 160 +#define PBITS 1024 + +Miracl precision=100; + +int main() +{ + ofstream common("common.dss"); /* construct file I/O streams */ + Big p,q,h,g,x,y,n,s,t; + long seed; + miracl *mip=&precision; + cout << "Enter 9 digit random number seed = "; + cin >> seed; + irand(seed); + +/* generate q */ + forever + { + n=rand(QBITS-1,2); /* 159 bit number, base 2 */ + q=2*n+1; + while (!prime(q)) q+=2; + if (bits(q)>QBITS) continue; + break; + } + cout << "q= " << q << endl; + +/* generate p */ + t=(pow((Big)2,PBITS)-1)/(2*q); + s=(pow((Big)2,PBITS-1)-1)/(2*q); + forever + { + n=rand(t); + if (n +#include +#include "big.h" + +using namespace std; + +Miracl precision=100; + +int main() +{ + ifstream common("common.dss"); /* construct file I/O streams */ + ofstream public_key("public.dss"); + ofstream private_key("private.dss"); + Big p,q,h,g,x,y,n,s,t; + long seed; + int bits; + miracl *mip=&precision; + + cout << "Enter 9 digit random number seed = "; + cin >> seed; + irand(seed); + +/* get common data */ + common >> bits; + mip->IOBASE=16; + common >> p >> q >> g; + mip->IOBASE=10; + + y=pow(g,q,p); + if (y!=1) + { + cout << "Problem - generator g is not of order q" << endl; + exit(0); + } + +/* generate public/private keys */ + x=rand(q); + y=pow(g,x,p); + cout << "public key = " << y << endl; + public_key << y << endl; + private_key << x << endl; + return 0; +} + diff --git a/miracl/source/dssign.c b/miracl/source/dssign.c new file mode 100644 index 0000000..2c5273b --- /dev/null +++ b/miracl/source/dssign.c @@ -0,0 +1,123 @@ +/* + * Digital Signature Algorithm (DSA) + * + * See Communications ACM July 1992, Vol. 35 No. 7 + * This new standard for digital signatures has been proposed by + * the American National Institute of Standards and Technology (NIST) + * under advisement from the National Security Agency (NSA). + * + * This program asks for the name of a , computes its message digest, + * signs it, and outputs the signature to a file .dss. It is assumed + * that the common values p, q and g, as well as the private key of the + * signer have been previously generated by the dssgen program + * + */ + +#include +#include "miracl.h" +#include +#include + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static void hashing(FILE *fp,big hash) +{ /* compute hash function */ + char h[20]; + int i,ch; + sha sh; + shs_init(&sh); + while ((ch=fgetc(fp))!=EOF) shs_process(&sh,ch); + shs_hash(&sh,h); + bytes_to_big(20,h,hash); +} + +int main() +{ + FILE *fp; + char ifname[50],ofname[50]; + big p,q,g,x,r,s,k,hash; + long seed; + int bits; + miracl *mip; + +/* get public data */ + fp=fopen("common.dss","rt"); + if (fp==NULL) + { + printf("file common.dss does not exist\n"); + return 0; + } + + fscanf(fp,"%d\n",&bits); + mip=mirsys(bits/4,16); /* use Hex internally */ + p=mirvar(0); + q=mirvar(0); + g=mirvar(0); + x=mirvar(0); + r=mirvar(0); + s=mirvar(0); + k=mirvar(0); + hash=mirvar(0); + + innum(p,fp); + innum(q,fp); + innum(g,fp); + fclose(fp); + +/* randomise */ + printf("Enter 9 digit random number seed = "); + scanf("%ld",&seed); + getchar(); + irand(seed); + +/* calculate r - this can be done offline, + and hence amortized to almost nothing */ + bigrand(q,k); + powmod(g,k,p,r); /* see brick.c for method to speed this up */ + divide(r,q,q); + +/* get private key of signer */ + fp=fopen("private.dss","rt"); + if (fp==NULL) + { + printf("file private.dss does not exist\n"); + return 0; + } + innum(x,fp); + fclose(fp); + +/* calculate message digest */ + printf("file to be signed = "); + gets(ifname); + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".dss"); + if ((fp=fopen(ifname,"rb"))==NULL) + { + printf("Unable to open file %s\n",ifname); + return 0; + } + hashing(fp,hash); + fclose(fp); + +/* calculate s */ + xgcd(k,q,k,k,k); + mad(x,r,hash,q,q,s); + mad(s,k,k,q,q,s); + fp=fopen(ofname,"wt"); + otnum(r,fp); + otnum(s,fp); + fclose(fp); + mirexit(); + return 0; +} + diff --git a/miracl/source/dssign.cpp b/miracl/source/dssign.cpp new file mode 100644 index 0000000..ce4f789 --- /dev/null +++ b/miracl/source/dssign.cpp @@ -0,0 +1,110 @@ +/* + * Digital Signature Algorithm (DSA) + * + * See Communications ACM July 1992, Vol. 35 No. 7 + * This new standard for digital signatures has been proposed by + * the American National Institute of Standards and Technology (NIST) + * under advisement from the National Security Agency (NSA). + * + * This program asks for the name of a , computes its message digest, + * signs it, and outputs the signature to a file .dss. It is assumed + * that the common values p, q and g, as well as the private key of the + * signer have been previously generated by the dssgen program + * + * Requires: big.cpp + */ + +#include +#include +#include +#include "big.h" + +using namespace std; + +Miracl precision(200,256); + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static Big hash(ifstream &fp) +{ /* compute hash function */ + char ch,s[20]; + int i; + Big h; + sha sh; + shs_init(&sh); + forever + { /* read in bytes from message file */ + fp.get(ch); + if (fp.eof()) break; + shs_process(&sh,ch); + } + shs_hash(&sh,s); + h=from_binary(20,s); + return h; +} + +int main() +{ + ifstream common("common.dss"); /* construct file I/O streams */ + ifstream private_key("private.dss"); + ifstream message; + ofstream signature; + char ifname[13],ofname[13]; + Big p,q,g,x,r,s,k,h; + long seed; + int bits; + miracl *mip=&precision; + +/* randomise */ + cout << "Enter 9 digit random number seed = "; + cin >> seed; + irand(seed); + +/* get common data */ + common >> bits; + mip->IOBASE=16; + common >> p >> q >> g; + mip->IOBASE=10; + +/* calculate r - this can be done off-line, + and hence amortized to almost nothing */ + k=rand(q); + r=pow(g,k,p); /* see brick.cpp for method to speed this up */ + r%=q; + +/* get private key of signer */ + private_key >> x; + +/* get message to be signed */ + cout << "file to be signed = " ; + cin >> ifname; + + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".dss"); + message.open(ifname,ios::binary|ios::in); + if (!message) + { + cout << "Unable to open file " << ifname << "\n"; + return 0; + } + h=hash(message); + +/* calculate s */ + k=inverse(k,q); + s=((h+x*r)*k)%q; + signature.open(ofname); + signature << r << endl; + signature << s << endl; + return 0; +} + diff --git a/miracl/source/dssver.c b/miracl/source/dssver.c new file mode 100644 index 0000000..77dd6d8 --- /dev/null +++ b/miracl/source/dssver.c @@ -0,0 +1,120 @@ +/* + * Digital Signature Algorithm (DSA) + * + * See Communications ACM July 1992, Vol. 35 No. 7 + * This new standard for digital signatures has been proposed by + * the American National Institute of Standards and Technology (NIST) + * under advisement from the National Security Agency (NSA). + * + * This program verifies a the signature given to a in + * .dss generated by program dssign.c + * + */ + +#include +#include "miracl.h" +#include +#include + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static void hashing(FILE *fp,big hash) +{ /* compute hash function */ + char h[20]; + sha sh; + int i,ch; + shs_init(&sh); + while ((ch=fgetc(fp))!=EOF) shs_process(&sh,ch); + shs_hash(&sh,h); + bytes_to_big(20,h,hash); +} + +int main() +{ + FILE *fp; + char ifname[50],ofname[50]; + big p,q,g,y,v,u1,u2,r,s,hash; + int bits; + miracl *mip; +/* get public data */ + fp=fopen("common.dss","rt"); + if (fp==NULL) + { + printf("file common.dss does not exist\n"); + return 0; + } + + fscanf(fp,"%d\n",&bits); + mip=mirsys(bits/4,16); /* Use Hex Internally */ + p=mirvar(0); + q=mirvar(0); + g=mirvar(0); + y=mirvar(0); + v=mirvar(0); + u1=mirvar(0); + u2=mirvar(0); + s=mirvar(0); + r=mirvar(0); + hash=mirvar(0); + + innum(p,fp); + innum(q,fp); + innum(g,fp); + fclose(fp); + +/* get public key of signer */ + fp=fopen("public.dss","rt"); + if (fp==NULL) + { + printf("file public.dss does not exist\n"); + return 0; + } + innum(y,fp); + fclose(fp); +/* get message */ + printf("signed file = "); + gets(ifname); + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".dss"); + if ((fp=fopen(ifname,"rb"))==NULL) + { /* no message */ + printf("Unable to open file %s\n",ifname); + return 0; + } + + hashing(fp,hash); + fclose(fp); + fp=fopen(ofname,"rt"); + if (fp==NULL) + { /* no signature */ + printf("signature file %s does not exist\n",ofname); + return 0; + } + innum(r,fp); + innum(s,fp); + fclose(fp); + if (mr_compare(r,q)>=0 || mr_compare(s,q)>=0) + { + printf("Signature is NOT verified\n"); + return 0; + } + xgcd(s,q,s,s,s); + mad(hash,s,s,q,q,u1); + mad(r,s,s,q,q,u2); + powmod2(g,u1,y,u2,p,v); + divide(v,q,q); + if (mr_compare(v,r)==0) printf("Signature is verified\n"); + else printf("Signature is NOT verified\n"); + return 0; +} + diff --git a/miracl/source/dssver.cpp b/miracl/source/dssver.cpp new file mode 100644 index 0000000..f33f5a5 --- /dev/null +++ b/miracl/source/dssver.cpp @@ -0,0 +1,109 @@ +/* + * Digital Signature Algorithm (DSA) + * + * See Communications ACM July 1992, Vol. 35 No. 7 + * This new standard for digital signatures has been proposed by + * the American National Institute of Standards and Technology (NIST) + * under advisement from the National Security Agency (NSA). + * + * This program verifies a the signature given to a in + * .dss generated by program dssign.c + * + * Requires: big.cpp + * + */ + +#include +#include +#include +#include "big.h" + +using namespace std; + +Miracl precision(200,256); + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static Big hash(ifstream &fp) +{ /* compute hash function */ + char ch,s[20]; + int i; + Big h; + sha sh; + shs_init(&sh); + forever + { /* read in bytes from message file */ + fp.get(ch); + if (fp.eof()) break; + shs_process(&sh,ch); + } + shs_hash(&sh,s); + h=from_binary(20,s); + return h; +} + +int main() +{ + ifstream common("common.dss"); /* construct file I/O streams */ + ifstream public_key("public.dss"); + ifstream message; + ifstream signature; + Big p,q,g,y,v,u1,u2,r,s,h; + char ifname[13],ofname[13]; + int bits; + miracl *mip=&precision; + +/* get public data */ + common >> bits; + mip->IOBASE=16; + common >> p >> q >> g; + mip->IOBASE=10; +/* get public key of signer */ + public_key >> y; +/* get message */ + cout << "signed file = " ; + cin.sync(); + cin.getline(ifname,13); + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".dss"); + message.open(ifname,ios::binary|ios::in); + if (!message) + { /* no message */ + cout << "Unable to open file " << ifname << "\n"; + return 0; + } + h=hash(message); + + signature.open(ofname,ios::in); + if (!signature) + { /* no signature */ + cout << "signature file " << ofname << " does not exist\n"; + return 0; + } + signature >> r >> s; + if (r>=q || s>=q) + { + cout << "Signature is NOT verified\n"; + return 0; + } + s=inverse(s,q); + u1=(h*s)%q; + u2=(r*s)%q; + v=pow(g,u1,y,u2,p); /* v=g^u1.y^u2 mod p */ + + v%=q; + if (v==r) cout << "Signature is verified\n"; + else cout << "Signature is NOT verified\n"; + return 0; +} + diff --git a/miracl/source/ebrick.c b/miracl/source/ebrick.c new file mode 100644 index 0000000..5162d2b --- /dev/null +++ b/miracl/source/ebrick.c @@ -0,0 +1,95 @@ +/* + * Test program for fast computation of xG for fixed G using precomputation. + * This idea can be used to substantially speed up certain phases + * of the EC Digital Signature Standard (ECDSA). + * + * See "Handbook of Applied Cryptography" + * + */ + +#include +#include "miracl.h" + +int main() +{ + FILE *fp; + big e,n,a,b,x,y,r; + epoint *g; + ebrick binst; + int nb,bits,window,len,bptr,m,i,j; + miracl *mip=mirsys(50,0); + n=mirvar(0); + e=mirvar(0); + a=mirvar(0); + b=mirvar(0); + x=mirvar(0); + y=mirvar(0); + r=mirvar(0); +#ifndef MR_EDWARDS + fp=fopen("common.ecs","rt"); +#else + fp=fopen("edwards.ecs","rt"); +#endif + fscanf(fp,"%d\n",&bits); + mip->IOBASE=16; + cinnum(n,fp); + cinnum(a,fp); + cinnum(b,fp); + cinnum(r,fp); + cinnum(x,fp); + cinnum(y,fp); + mip->IOBASE=10; + + printf("modulus is %d bits in length\n",logb2(n)); + printf("Enter max. size of exponent in bits = "); + scanf("%d",&nb); + getchar(); + printf("Enter window size in bits (1-10)= "); + scanf("%d",&window); + getchar(); + + ebrick_init(&binst,x,y,a,b,n,window,nb); + +/* Print out the precomputed table (for use in ecdhp.c ?) + In which case make sure that MR_SPECIAL is defined and + active in the build of this program, so MR_COMBA must + also be defined as the number of words in the modulus * + +len=MR_ROUNDUP(bits,MIRACL); +bptr=0; +for (i=0;i<2*(1< +#include +#include "ecn.h" +#include "ebrick.h" /* include MIRACL system */ + +using namespace std; + +Miracl precision=50; + +int main() +{ + ifstream common("common.ecs"); + Big a,b,x,y,e,n,r; + int bits,nb,w; + miracl *mip=&precision; + common >> bits; + mip->IOBASE=16; + common >> n >> a >> b >> r >> x >> y; + mip->IOBASE=10; + + w=8; // window size + + cout << "Enter size of exponent in bits = "; + cin >> nb; + + EBrick B(x,y,a,b,n,w,nb); + + e=rand(nb,2); /* random exponent */ + + cout << "naive method" << endl; + ecurve(a,b,n,MR_PROJECTIVE); + ECn G(x,y); + G*=e; + G.get(x,y); + cout << x << endl; + + x=0; + cout << "Comb method" << endl; + + B.mul(e,x,y); + + cout << x << endl; + return 0; +} + diff --git a/miracl/source/ebrick2.c b/miracl/source/ebrick2.c new file mode 100644 index 0000000..d60be88 --- /dev/null +++ b/miracl/source/ebrick2.c @@ -0,0 +1,96 @@ +/* + * Test program to implement Comb method for fast + * computation of x*G, for fixed G, using precomputation. + * This idea can be used to substantially speed up certain phases + * of the Elliptic Curve Digital Signature Standard (DSS). + * + * See "Handbook of Applied Cryptography" + * + */ + +#include +#include "miracl.h" + +int main() +{ + FILE *fp; + int m,a,b,c; + big e,a2,a6,x,y,r; + epoint *g; + ebrick2 binst; + int i,j,len,bptr,nb,window; + miracl *mip=mirsys(50,0); + e=mirvar(0); + a2=mirvar(0); + a6=mirvar(0); + x=mirvar(0); + y=mirvar(0); + r=mirvar(0); + + fp=fopen("common2.ecs","rt"); + fscanf(fp,"%d\n",&m); + mip->IOBASE=16; + cinnum(a2,fp); + cinnum(a6,fp); + cinnum(r,fp); + cinnum(x,fp); + cinnum(y,fp); + mip->IOBASE=10; + + fscanf(fp,"%d\n",&a); + fscanf(fp,"%d\n",&b); + fscanf(fp,"%d\n",&c); + + printf("modulus is %d bits in length\n",m); + printf("Enter size of exponent in bits = "); + scanf("%d",&nb); + getchar(); + printf("Enter window size in bits (1-10)= "); + scanf("%d",&window); + getchar(); + + + if (!ebrick2_init(&binst,x,y,a2,a6,m,a,b,c,window,nb)) + { + printf("Failed to Initialize\n"); + return 0; + } +/* Print out the precomputed table (for use in ecdh2m.c ?) + +len=MR_ROUNDUP(m,MIRACL); +bptr=0; +for (i=0;i<2*(1< +#include +#include "ec2.h" +#include "ebrick2.h" /* include MIRACL system */ + +using namespace std; + +Miracl precision=50; + +int main() +{ + ifstream common("common2.ecs"); + int m,a,b,c,w; + Big a2,a6,x,y,e,r; + int nb; + miracl *mip=&precision; + + common >> m; + mip->IOBASE=16; + common >> a2 >> a6 >> r >> x >> y; + mip->IOBASE=10; + common >> a >> b >> c; + + w=8; // window size + + cout << "Enter size of exponent in bits = "; + cin >> nb; + + EBrick2 B(x,y,a2,a6,m,a,b,c,w,nb); + + e=rand(nb,2); /* random exponent */ + + cout << "naive method" << endl; + ecurve2(m,a,b,c,a2,a6,FALSE,MR_PROJECTIVE); + EC2 G(x,y); + G*=e; + G.get(x,y); + cout << x << endl; + + x=0; + cout << "Comb method" << endl; + + B.mul(e,x,y); + + cout << x << endl; + return 0; +} + diff --git a/miracl/source/ec2.cpp b/miracl/source/ec2.cpp new file mode 100644 index 0000000..efe2a89 --- /dev/null +++ b/miracl/source/ec2.cpp @@ -0,0 +1,141 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ functions ec2.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class EC2 functions + * NOTE : Must be used in conjunction with big.h and big.cpp + * + */ + +#include "ec2.h" + +int EC2::get(Big& x,Big& y) const + {return epoint2_get(p,x.getbig(),y.getbig());} +int EC2::get(Big& x) const + {return epoint2_get(p,x.getbig(),x.getbig());} +#ifndef MR_STATIC +void EC2::getx(Big& x) const + {epoint2_getxyz(p,x.getbig(),NULL,NULL);} +void EC2::getxy(Big& x,Big &y) const + {epoint2_getxyz(p,x.getbig(),y.getbig(),NULL);} +void EC2::getxyz(Big& x,Big &y,Big &z) const + {epoint2_getxyz(p,x.getbig(),y.getbig(),z.getbig());} +#endif + +BOOL EC2::iszero() const + {if (p->marker==MR_EPOINT_INFINITY) return TRUE; return FALSE;} + +epoint * EC2::get_point() const +{ return p; } + +EC2 operator-(const EC2& e) +{ EC2 t=e; epoint2_negate(t.p); return t;} + + +#ifndef MR_NO_ECC_MULTIADD +EC2 mul(const Big& e1,const EC2& p1,const Big& e2,const EC2& p2) +{ + EC2 t; + ecurve2_mult2(e1.getbig(),p1.get_point(),e2.getbig(),p2.get_point(),t.get_point()); + return t; +} +#endif + +EC2 operator*(const Big& e,const EC2& b) +{ + EC2 t; + ecurve2_mult(e.getbig(),b.p,t.p); + return t; +} + +#ifndef MR_STATIC +#ifndef MR_NO_ECC_MULTIADD + +EC2 mul(int n,const Big *y,EC2 *x) +{ + EC2 w; + int i; + big *a=(big *)mr_alloc(n,sizeof(big)); + epoint **b=(epoint **)mr_alloc(n,sizeof(epoint *)); + for (i=0;i +#include +#include "miracl.h" + +#define HEXDIGS (MIRACL/4) + +/* !!!!!! THIS CODE AND THESE ROMS ARE NOW CREATED AUTOMATICALLY USING THE ROMAKER2.C APPLICATION !!!!!!!! */ +/* !!!!!! READ COMMENTS IN ROMAKER2.C !!!!!! */ + + +#define CURVE_M 163 +#define CURVE_A 7 +#define CURVE_B 6 +#define CURVE_C 3 + +/* NIST b163 bit elliptic curve Y^2+XY=X^3+A.X^2+B (from nist163.ecs). Irreducible polynomial + is x^163+x^7+x^6+x^3+1. Here is stored B, the group order q, and the generator G(x,y) */ + +static const mr_small rom[]= +{0x4A3205FD,0x512F7874,0x1481EB10,0xB8C953CA,0x0A601907,2, + 0xA4234C33,0x77E70C12,0x000292FE,0,0,4, + 0xE8343E36,0xD4994637,0xA0991168,0x86A2D57E,0xF0EBA162,3, + 0x797324F1,0xB11C5C0C,0xA2CDD545,0x71A0094F,0xD51FBC6C,0}; + +#define WINDOW 4 + +/* 2^4 =16 precomputed points based on fixed generator G(x,y) */ +/* (created using romaker2.c program with window size of 4) */ + +static const mr_small prom[]= +{0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0, +0xe8343e36,0xd4994637,0xa0991168,0x86a2d57e,0xf0eba162,0x3, +0x797324f1,0xb11c5c0c,0xa2cdd545,0x71a0094f,0xd51fbc6c,0x0, +0x5fd9372,0xaa17fdf2,0x6648e974,0x31dd5c03,0x75f1f527,0x2, +0xdcf990e0,0x79117c6a,0x5d2ff662,0x9865bdb2,0xb0914960,0x0, +0x78a887a6,0xe478fe58,0x3d3d2364,0x3b85b263,0x34c6885e,0x5, +0xef273598,0xa6d7e436,0x53001bd9,0x75cc731c,0xbf414f74,0x3, +0x4f685f08,0x6f8daf88,0xd1c71b1f,0x6f4913ff,0xbaa8682a,0x2, +0xd5301336,0xb4f6dd1e,0x6454423b,0x4ebaf45,0x65c6e401,0x2, +0xa700c73d,0x6f842a26,0xe8f5f5fd,0x4db6da9,0x48fcdc95,0x6, +0x1db757cb,0xb5bf42ba,0xabfd25b4,0x466e5be3,0x2cf27012,0x7, +0xeb7ad12e,0x47e38e87,0x5f9c4ef1,0x2fcd5483,0x3893822e,0x0, +0x7c98bf09,0xa41f9589,0x680ca2a3,0xdfa83842,0xedd41659,0x1, +0xa3463d19,0xaf8c4bb0,0x2288658a,0x84b3c40d,0x90cd449b,0x2, +0x6bb4bf11,0x5e996afa,0x9b2ae97a,0xff211307,0xfbf58239,0x5, +0x4ab8c649,0x2fcf02ee,0x3c7efb85,0x76f09ad9,0xdbca45da,0x7, +0xeeba93af,0x59adf276,0xd25e3760,0x3292b2c1,0x271d1b84,0x4, +0x37f9391c,0xf423fd60,0xbf079624,0x4c9036e0,0x63075e19,0x4, +0xb726dfb5,0x38c349b3,0x6e0988b7,0x87b54141,0xcb8d73b,0x2, +0xd1acdb88,0x64ca1fcc,0x690dfa73,0xc6708b6f,0xb44b3919,0x2, +0x2b3f67d9,0xc01ccb1e,0x5311dcc8,0xdb9fdd9a,0x9118031e,0x0, +0x9a5c0d6e,0x4e99152f,0xaf853232,0x8db0dccc,0xef0f58d7,0x5, +0x6db63148,0xefdd7e0a,0xcc819e67,0x56a979bc,0x8d1169b4,0x3, +0x8670b917,0x3d61a2ac,0x6ed8588a,0x5cc94655,0x8096413e,0x2, +0xd8715f72,0xc2ce06e6,0xd50c5c77,0x1553a69b,0x8a20fadc,0x2, +0x9dd077b2,0xb2978893,0x7aa617bb,0xadbac172,0xf57da9a2,0x1, +0x6800bbe2,0x837ad74e,0xdac7cd95,0x1082c382,0xb5ec04b2,0x0, +0x43835328,0xa986d58b,0x8d7f7c4e,0xfd642a8d,0x6d4462d4,0x3, +0xf19901e9,0x60993930,0x67c98e9b,0x1ab9c90d,0x5d7f4593,0x6, +0x39e10752,0xde366730,0xa867db73,0x5bcb53b5,0x6b5e56c0,0x3, +0xaf59dcaa,0x8bdbf9ff,0x2221c861,0x52b45c1a,0x221a9b1f,0x6}; + +#define WORDS 6 /* Number of words per big variable 6*32 > 163 */ + +/* Note that in a real application a source of real random numbers would be required, to + replace those generated by MIRACL's internal pseudo-random generator "bigbits" + Alternatively from a truly random and unguessable seed, use MIRACL's strong random + number generator */ + +/* Elliptic Curve Diffie-Hellman, using point compression to minimize bandwidth, + and precomputation to speed up off-line calculation */ + +int main() +{ + int promptr; + epoint *PA,*PB; + big A,B,a,b,q,pa,pb,key,x,y; + ebrick2 binst; + miracl instance; /* create miracl workspace on the stack */ + +/* Specify base 16 here so that HEX can be read in directly without a base-change */ + + miracl *mip=mirsys(&instance,WORDS*HEXDIGS,16); /* size of bigs is fixed */ + char mem_big[MR_BIG_RESERVE(9)]; /* we need 9 bigs... */ + char mem_ecp[MR_ECP_RESERVE(2)]; /* ..and two elliptic curve points */ + memset(mem_big, 0, MR_BIG_RESERVE(9)); /* clear the memory */ + memset(mem_ecp, 0, MR_ECP_RESERVE(2)); + + A=mirvar_mem(mip, mem_big, 0); /* Initialise big numbers */ + B=mirvar_mem(mip, mem_big, 1); + pa=mirvar_mem(mip, mem_big, 2); + pb=mirvar_mem(mip, mem_big, 3); + key=mirvar_mem(mip, mem_big, 4); + x=mirvar_mem(mip, mem_big, 5); + y=mirvar_mem(mip, mem_big, 6); + a=mirvar_mem(mip, mem_big, 7); + b=mirvar_mem(mip, mem_big, 8); + + PA=epoint_init_mem(mip, mem_ecp, 0); /* initialise Elliptic Curve points */ + PB=epoint_init_mem(mip, mem_ecp, 1); + + irand(mip, 3L); /* change parameter for different random numbers */ + promptr=0; + init_big_from_rom(B,WORDS,rom,WORDS*4,&promptr); /* Read in curve parameter B from ROM */ + /* don't need q or G(x,y) (we have precomputed table from it) */ + + convert(mip,1,A); /* set A=1 */ + +/* Create precomputation instance from precomputed table in ROM */ + + ebrick2_init(&binst,prom,A,B,CURVE_M,CURVE_A,CURVE_B,CURVE_C,WINDOW,CURVE_M); + +/* offline calculations */ + + bigbits(mip,CURVE_M,a); /* A's random number */ + mul2_brick(mip,&binst,a,pa,pa); /* a*G =(pa,ya) */ + + bigbits(mip,CURVE_M,b); /* B's random number */ + mul2_brick(mip,&binst,b,pb,pb); /* b*G =(pb,yb) */ + +/* Swap X values */ + +/* online calculations */ + ecurve2_init(mip,CURVE_M,CURVE_A,CURVE_B,CURVE_C,A,B,FALSE,MR_PROJECTIVE); + epoint2_set(mip,pb,pb,0,PB); /* decompress PB */ + ecurve2_mult(mip,a,PB,PB); + epoint2_get(mip,PB,key,key); + +/* since internal base is HEX, can use otnum instead of cotnum - avoiding a base change */ + +#ifndef MR_NO_STANDARD_IO +printf("Alice's Key= "); +otnum(mip,key,stdout); +#endif + + epoint2_set(mip,pa,pa,0,PB); /* decompress PA */ + ecurve2_mult(mip,b,PB,PB); + epoint2_get(mip,PB,key,key); + +#ifndef MR_NO_STANDARD_IO +printf("Bob's Key= "); +otnum(mip,key,stdout); +#endif + +/* clear the memory */ + + memset(mem_big, 0, MR_BIG_RESERVE(9)); + memset(mem_ecp, 0, MR_ECP_RESERVE(2)); + + return 0; +} diff --git a/miracl/source/ecdh2m16.c b/miracl/source/ecdh2m16.c new file mode 100644 index 0000000..f33f745 --- /dev/null +++ b/miracl/source/ecdh2m16.c @@ -0,0 +1,284 @@ +/* + +Example GF(2^m) Elliptic Curve Diffie-Hellman program for very constrained environments. Uses point compression. +Stack-only memory allocation. 16-bit version. The Koblitz curve variant is ideal for wireless sensor networks. + +Use with this mirdef.h header (for a PC using MS C) + +#define MR_LITTLE_ENDIAN +#define MIRACL 16 +#define mr_utype short +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype int +#define MR_DLTYPE_IS_INT +#define MR_STATIC 11 +#define MR_ALWAYS_BINARY +#define MR_NOASM +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_NO_SS +#define MR_SIMPLE_BASE +#define MR_SIMPLE_IO + +and also possibly + +#define MR_NO_FILE_IO +#define MR_NO_STANDARD_IO + +Build the library from these modules (Example using MS C compiler) + +-------------------------------- + +cl /c /O2 /W3 mrcore.c +cl /c /O2 /W3 mrarth0.c +cl /c /O2 /W3 mrarth1.c +cl /c /O2 /W3 mrio1.c +cl /c /O2 /W3 mrbits.c +cl /c /O2 /W3 mrec2m.c +cl /c /O2 /W3 mrgf2m.c + +rem +rem Create library 'miracl.lib' +del miracl.lib + +lib /OUT:miracl.lib mrbits.obj mrio1.obj +lib /OUT:miracl.lib miracl.lib mrarth0.obj mrarth1.obj mrcore.obj +lib /OUT:miracl.lib miracl.lib mrec2m.obj mrgf2m.obj +del mr*.obj + +rem Create the program + +cl /O2 ecdh2m16.c miracl.lib + +------------------------------- + +On an msp430, try using this mirdef.h + +#define MIRACL 16 +#define MR_LITTLE_ENDIAN +#define mr_utype int +#define mr_unsign32 unsigned long +#define mr_dltype long +#define mr_unsign64 unsigned long long +#define MR_IBITS 16 +#define MR_LBITS 32 +#define MR_NOASM +#define MR_NO_FILE_IO +#define MR_STATIC 11 +#define MR_ALWAYS_BINARY +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_GENERIC_MT +#define MR_STRIPPED_DOWN +#define MR_SIMPLE_IO +#define MR_SIMPLE_BASE +#define MR_NO_SS +#define MR_SMALL_EWINDOW +#define MR_NO_STANDARD_IO + +*/ + +#include +#include +#include "miracl.h" + +#define HEXDIGS (MIRACL/4) + +/* !!!!!! THIS CODE AND THESE ROMS ARE NOW CREATED AUTOMATICALLY USING THE ROMAKER2.C APPLICATION !!!!!!!! */ +/* !!!!!! READ COMMENTS IN ROMAKER2.C !!!!!! */ + +#define CURVE_M 163 +#define CURVE_A 7 +#define CURVE_B 6 +#define CURVE_C 3 + + +/* NIST b163 elliptic curve Y^2+XY=X^3+A.X^2+B (from nist163.ecs). Irreducible polynomial + is x^163+x^7+x^6+x^3+1. Here is stored B, the group order q, and the generator G(x,y) */ +/* +static const mr_small rom[]= +{0x05FD,0x4A32,0x7874,0x512F,0xEB10,0x1481,0x53CA,0xB8C9,0x1907,0x0A60,2, + 0x4C33,0xA423,0x0C12,0x77E7,0x92FE,0x0002,0,0,0,0,4, + 0x3E36,0xE834,0x4637,0xD499,0x1168,0xA099,0xD57E,0x86A2,0xA162,0xF0EB,3, + 0x24F1,0x7973,0x5C0C,0xB11C,0xD545,0xA2CD,0x094F,0x71A0,0xBC6C,0xD51F,0}; +*/ + +/* NIST k163 Koblitz curve */ +static const mr_small rom[]= +{ +0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0xA5EF,0x99F8,0xCC0D,0xA2E0,0x0108,0x2,0x0,0x0,0x0,0x0,0x4, +0xA80F,0x109C,0xE90E,0x272D,0x911D,0x37CA,0x7A2B,0x5EF8,0x0B47,0x96C3,0x3, +0x6391,0xD6E7,0xA253,0x2923,0x142D,0xBABB,0x1DC3,0x8BB4,0x0E4C,0x947D,0x3}; + +#define WINDOW 4 + +/* 2^4 =16 precomputed points based on fixed generator G(x,y) */ +/* (created using romaker2.c program with window size of 4) */ + +/* standard curve +static const mr_small prom[]= +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x3e36,0xe834,0x4637,0xd499,0x1168,0xa099,0xd57e,0x86a2,0xa162,0xf0eb,0x3, +0x24f1,0x7973,0x5c0c,0xb11c,0xd545,0xa2cd,0x94f,0x71a0,0xbc6c,0xd51f,0x0, +0x9372,0x5fd,0xfdf2,0xaa17,0xe974,0x6648,0x5c03,0x31dd,0xf527,0x75f1,0x2, +0x90e0,0xdcf9,0x7c6a,0x7911,0xf662,0x5d2f,0xbdb2,0x9865,0x4960,0xb091,0x0, +0x87a6,0x78a8,0xfe58,0xe478,0x2364,0x3d3d,0xb263,0x3b85,0x885e,0x34c6,0x5, +0x3598,0xef27,0xe436,0xa6d7,0x1bd9,0x5300,0x731c,0x75cc,0x4f74,0xbf41,0x3, +0x5f08,0x4f68,0xaf88,0x6f8d,0x1b1f,0xd1c7,0x13ff,0x6f49,0x682a,0xbaa8,0x2, +0x1336,0xd530,0xdd1e,0xb4f6,0x423b,0x6454,0xaf45,0x4eb,0xe401,0x65c6,0x2, +0xc73d,0xa700,0x2a26,0x6f84,0xf5fd,0xe8f5,0x6da9,0x4db,0xdc95,0x48fc,0x6, +0x57cb,0x1db7,0x42ba,0xb5bf,0x25b4,0xabfd,0x5be3,0x466e,0x7012,0x2cf2,0x7, +0xd12e,0xeb7a,0x8e87,0x47e3,0x4ef1,0x5f9c,0x5483,0x2fcd,0x822e,0x3893,0x0, +0xbf09,0x7c98,0x9589,0xa41f,0xa2a3,0x680c,0x3842,0xdfa8,0x1659,0xedd4,0x1, +0x3d19,0xa346,0x4bb0,0xaf8c,0x658a,0x2288,0xc40d,0x84b3,0x449b,0x90cd,0x2, +0xbf11,0x6bb4,0x6afa,0x5e99,0xe97a,0x9b2a,0x1307,0xff21,0x8239,0xfbf5,0x5, +0xc649,0x4ab8,0x2ee,0x2fcf,0xfb85,0x3c7e,0x9ad9,0x76f0,0x45da,0xdbca,0x7, +0x93af,0xeeba,0xf276,0x59ad,0x3760,0xd25e,0xb2c1,0x3292,0x1b84,0x271d,0x4, +0x391c,0x37f9,0xfd60,0xf423,0x9624,0xbf07,0x36e0,0x4c90,0x5e19,0x6307,0x4, +0xdfb5,0xb726,0x49b3,0x38c3,0x88b7,0x6e09,0x4141,0x87b5,0xd73b,0xcb8,0x2, +0xdb88,0xd1ac,0x1fcc,0x64ca,0xfa73,0x690d,0x8b6f,0xc670,0x3919,0xb44b,0x2, +0x67d9,0x2b3f,0xcb1e,0xc01c,0xdcc8,0x5311,0xdd9a,0xdb9f,0x31e,0x9118,0x0, +0xd6e,0x9a5c,0x152f,0x4e99,0x3232,0xaf85,0xdccc,0x8db0,0x58d7,0xef0f,0x5, +0x3148,0x6db6,0x7e0a,0xefdd,0x9e67,0xcc81,0x79bc,0x56a9,0x69b4,0x8d11,0x3, +0xb917,0x8670,0xa2ac,0x3d61,0x588a,0x6ed8,0x4655,0x5cc9,0x413e,0x8096,0x2, +0x5f72,0xd871,0x6e6,0xc2ce,0x5c77,0xd50c,0xa69b,0x1553,0xfadc,0x8a20,0x2, +0x77b2,0x9dd0,0x8893,0xb297,0x17bb,0x7aa6,0xc172,0xadba,0xa9a2,0xf57d,0x1, +0xbbe2,0x6800,0xd74e,0x837a,0xcd95,0xdac7,0xc382,0x1082,0x4b2,0xb5ec,0x0, +0x5328,0x4383,0xd58b,0xa986,0x7c4e,0x8d7f,0x2a8d,0xfd64,0x62d4,0x6d44,0x3, +0x1e9,0xf199,0x3930,0x6099,0x8e9b,0x67c9,0xc90d,0x1ab9,0x4593,0x5d7f,0x6, +0x752,0x39e1,0x6730,0xde36,0xdb73,0xa867,0x53b5,0x5bcb,0x56c0,0x6b5e,0x3, +0xdcaa,0xaf59,0xf9ff,0x8bdb,0xc861,0x2221,0x5c1a,0x52b4,0x9b1f,0x221a,0x6}; + +*/ + +/* Koblitz curve */ +static const mr_small prom[]= +{ +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0xa80f,0x109c,0xe90e,0x272d,0x911d,0x37ca,0x7a2b,0x5ef8,0xb47,0x96c3,0x3, +0x6391,0xd6e7,0xa253,0x2923,0x142d,0xbabb,0x1dc3,0x8bb4,0xe4c,0x947d,0x3, +0x995f,0xc028,0xc193,0x2522,0xd939,0x5e65,0xa7b2,0xb529,0xbfa7,0xcf3b,0x3, +0x8b9b,0x15a9,0x596,0x8dc,0xf769,0xb43,0x9dbe,0xf449,0xd1b5,0x469e,0x3, +0x6d58,0x8430,0x716f,0x9e47,0xa1e1,0xb642,0xc627,0x42a3,0xc42d,0x3bc0,0x4, +0x22c5,0x4777,0x1328,0x7d37,0xccee,0xf2aa,0x48da,0xb649,0x1975,0x3258,0x4, +0xf8ec,0x9f6f,0x657a,0x5407,0x6dd,0x64b6,0xd3c4,0x2ed2,0xb3ce,0xb359,0x2, +0xc1bc,0xe161,0x2aaf,0xa168,0xe151,0xb399,0xe43e,0x50e2,0x3d25,0x36f5,0x2, +0x1b3d,0xe2e5,0x6c41,0xfcb6,0x9a93,0xb168,0xb6a5,0xdb00,0x8b24,0x8b07,0x6, +0x986d,0x487e,0xb259,0x6e67,0xd461,0xa44b,0xdbb8,0xc3a4,0x1cb9,0x2c36,0x5, +0x16a6,0x69cf,0x1b27,0x95d6,0xae2f,0xa0e9,0x6e40,0x8aa0,0x1992,0x7663,0x0, +0x5bb6,0xd3db,0xe73e,0x9ba7,0x2a49,0xedfb,0x54c8,0xbd03,0xaa14,0x5776,0x4, +0x6cea,0x7952,0x9495,0x17d0,0x9857,0xc8ab,0x28e9,0x9918,0xbd1b,0x7088,0x4, +0x84c8,0xca42,0xbcd9,0x86b,0x5933,0x2169,0x3751,0x69cf,0x8eb1,0x6614,0x0, +0x443c,0xbaf9,0xd850,0x5c37,0x8c1d,0x102,0xc5ae,0x48dc,0x8924,0xbdf7,0x7, +0xae90,0x64f0,0x1c0a,0x2b1d,0x39ae,0xe292,0x6898,0x385,0x5c3c,0x7ea9,0x5, +0xe7d5,0x13c1,0xd193,0xaf75,0x7253,0xa5b4,0xff4,0x8ba0,0x6942,0x8ba5,0x5, +0x2a8,0xd2e8,0x2bd2,0xc23e,0xb5a9,0xbdbf,0x9b7b,0xf181,0x68b7,0xb5fc,0x1, +0xf539,0xef19,0xca18,0xcaf,0x47bd,0x53a,0xc744,0x6158,0x86eb,0x8a62,0x1, +0x1827,0x8c84,0x237f,0x8533,0xf9ad,0xcb90,0xff83,0x3e5b,0x5350,0x34b0,0x2, +0x7391,0x8ea3,0xb6d3,0xa2c2,0x99b4,0xf3db,0x1a6b,0x8f68,0xb788,0xca6d,0x7, +0x107a,0x10e9,0xdde2,0xfc4c,0x338,0xf2d9,0xd6d8,0xf4cf,0xffe0,0x28b5,0x7, +0xee97,0x44d7,0x81c2,0xb22,0xdcfa,0xcfc9,0xcf8,0x9ad9,0x21d3,0xc84b,0x7, +0x1333,0x4bd5,0xe63d,0xb9a2,0x6fe,0x695a,0xc8d8,0x78ed,0xcba4,0x9b42,0x7, +0xfb03,0xb995,0xba77,0x8c0a,0xc44c,0x6503,0x3b5a,0xaac6,0x816d,0x5822,0x6, +0x3659,0xef07,0x6e3f,0xd368,0x597f,0xde09,0xb5dc,0x1c4c,0x322d,0x8080,0x7, +0x8101,0x22b0,0x40d8,0x8ffd,0xff52,0x96fa,0x9d69,0x8858,0x9fc2,0x187b,0x4, +0x5955,0xf979,0xad7b,0x805b,0x8673,0x8e4,0x4f73,0x891e,0xdac6,0x7c21,0x3, +0xd66d,0xd03c,0xc732,0x2b2,0xad5c,0x60b8,0x6b89,0x1ac2,0x99bc,0x18d3,0x3, +0x8b4,0xa252,0xe5d,0x543a,0xe178,0x81,0x439,0x5ead,0xf33b,0x1d22,0x4}; + +#define WORDS 11 /* Number of words per big variable 11*16 > 163 */ + +/* Note that in a real application a source of real random numbers would be required, to + replace those generated by MIRACL's internal pseudo-random generator "bigbits" + Alternatively from a truly random and unguessable seed, use MIRACL's strong random + number generator */ + +/* Elliptic Curve Diffie-Hellman, using point compression to minimize bandwidth, + and precomputation to speed up off-line calculation */ + +int main() +{ + int promptr; + epoint *PB; + big A,B,a,b,q,pa,pb,key,x,y; + ebrick2 binst; + miracl instance; /* create miracl workspace on the stack */ + +/* Specify base 16 here so that HEX can be read in directly without a base-change */ + + miracl *mip=mirsys(&instance,WORDS*HEXDIGS,16); /* size of bigs is fixed */ + char mem_big[MR_BIG_RESERVE(10)]; /* we need 10 bigs... */ + char mem_ecp[MR_ECP_RESERVE(1)]; /* ..and two elliptic curve points */ + memset(mem_big, 0, MR_BIG_RESERVE(10)); /* clear the memory */ + memset(mem_ecp, 0, MR_ECP_RESERVE(1)); + + A=mirvar_mem(mip, mem_big, 0); /* Initialise big numbers */ + B=mirvar_mem(mip, mem_big, 1); + pa=mirvar_mem(mip, mem_big, 2); + pb=mirvar_mem(mip, mem_big, 3); + key=mirvar_mem(mip, mem_big, 4); + x=mirvar_mem(mip, mem_big, 5); + y=mirvar_mem(mip, mem_big, 6); + q=mirvar_mem(mip,mem_big,7); + a=mirvar_mem(mip, mem_big, 8); + b=mirvar_mem(mip, mem_big, 9); + + PB=epoint_init_mem(mip, mem_ecp, 0); /* initialise Elliptic Curve point */ + + irand(mip, 3L); /* change parameter for different random numbers */ + promptr=0; + init_big_from_rom(B,WORDS,rom,WORDS*4,&promptr); /* Read in curve parameter B from ROM */ + /* don't need q or G(x,y) (we have precomputed table from it) */ + init_big_from_rom(q,WORDS,rom,WORDS*4,&promptr); + init_big_from_rom(x,WORDS,rom,WORDS*4,&promptr); + init_big_from_rom(y,WORDS,rom,WORDS*4,&promptr); + + convert(mip,1,A); /* set A=1 */ + +/* Create precomputation instance from precomputed table in ROM */ + + ebrick2_init(&binst,prom,A,B,CURVE_M,CURVE_A,CURVE_B,CURVE_C,WINDOW,CURVE_M); + +/* offline calculations */ + + bigbits(mip,CURVE_M,a); /* A's random number */ + + mul2_brick(mip,&binst,a,pa,pa); /* a*G =(pa,ya) */ + + bigbits(mip,CURVE_M,b); /* B's random number */ + mul2_brick(mip,&binst,b,pb,pb); /* b*G =(pb,yb) */ + +/* online calculations */ + ecurve2_init(mip,CURVE_M,CURVE_A,CURVE_B,CURVE_C,A,B,FALSE,MR_PROJECTIVE); + + epoint2_set(mip,pb,pb,0,PB); /* decompress PB */ + ecurve2_mult(mip,a,PB,PB); + + epoint2_get(mip,PB,key,key); + +/* since internal base is HEX, can use otnum instead of cotnum - avoiding a base change */ + +printf("Alice's Key= "); +otnum(mip,key,stdout); + + epoint2_set(mip,pa,pa,0,PB); /* decompress PA */ + ecurve2_mult(mip,b,PB,PB); + epoint2_get(mip,PB,key,key); + +printf("Bob's Key= "); +otnum(mip,key,stdout); + +/* clear the memory */ + + memset(mem_big, 0, MR_BIG_RESERVE(10)); + memset(mem_ecp, 0, MR_ECP_RESERVE(1)); + + return 0; +} diff --git a/miracl/source/ecdh2m8.c b/miracl/source/ecdh2m8.c new file mode 100644 index 0000000..ae8fd5c --- /dev/null +++ b/miracl/source/ecdh2m8.c @@ -0,0 +1,254 @@ +/* + +Example GF(2^m) Elliptic Curve Diffie-Hellman program for very constrained environments. Uses point compression. +Stack-only memory allocation. 8-bit version. The Koblitz curve variant is ideal for wireless sensor networks. + +Note that using a Koblitz curve, precomputation may be inefficient, so either just use +regular point multiplication, or use a larger precomputed table. But the code is left in for illustration +purposes. + +This has been tested on an Atmel Atmeg128 8-bit processor using this mirdef.h file with avr-gcc, and a general +point multiplication takes 3 seconds at 4MHz, without any assembly language used. + +#define MR_LITTLE_ENDIAN +#define MIRACL 8 +#define mr_utype char +#define MR_IBITS 16 +#define MR_LBITS 32 +#define mr_unsign32 unsigned long +#define mr_dltype short +#define MR_STATIC 21 +#define MR_ALWAYS_BINARY +#define MR_NOASM +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_SMALL_EWINDOW +#define MR_NO_STANDARD_IO +#define MR_NO_FILE_IO +#define MR_NO_ECC_MULTIADD +#define MR_SIMPLE_BASE +#define MR_SIMPLE_IO +#define MR_NO_SS +#define MR_AVR + +Use with this mirdef.h header (for a PC using MS C) + +#define MR_LITTLE_ENDIAN +#define MIRACL 8 +#define mr_utype char +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype short +#define MR_STATIC 21 +#define MR_ALWAYS_BINARY +#define MR_NOASM +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_SMALL_EWINDOW +#define MR_NO_SS +#define MR_SIMPLE_BASE +#define MR_SIMPLE_IO + +In an embedded environment perhaps these should be defined as well.. + +#define MR_NO_STANDARD_IO +#define MR_NO_FILE_IO + +Build the library from these modules (Example using MS C compiler) + +cl /c /O2 /W3 mrcore.c +cl /c /O2 /W3 mrarth0.c +cl /c /O2 /W3 mrarth1.c +cl /c /O2 /W3 mrio1.c +cl /c /O2 /W3 mrbits.c +cl /c /O2 /W3 mrgf2m.c +cl /c /O2 /W3 mrec2m.c + +rem +rem Create library 'miracl.lib' +del miracl.lib + +lib /OUT:miracl.lib mrbits.obj mrio1.obj +lib /OUT:miracl.lib miracl.lib mrarth0.obj mrarth1.obj mrcore.obj +lib /OUT:miracl.lib miracl.lib mrec2m.obj mrgf2m.obj +del mr*.obj + +rem Create the program + +cl /O2 ecdh2m8.c miracl.lib + +*/ + +#include +#include +#include "miracl.h" + + +#define HEXDIGS (MIRACL/4) + +/* !!!!!! THIS CODE AND THESE ROMS ARE NOW CREATED AUTOMATICALLY USING THE ROMAKER2.C APPLICATION !!!!!!!! */ +/* !!!!!! READ COMMENTS IN ROMAKER2.C !!!!!! */ + +#define CURVE_M 163 +#define CURVE_A 7 +#define CURVE_B 6 +#define CURVE_C 3 + +/* NIST k163 Koblitz curve */ +#ifdef MR_AVR +__attribute__((__progmem__)) +#endif +static const mr_small rom[]= +{ +0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0xEF,0xA5,0x58,0x99,0x0D,0xCC,0xE0,0x8A,0x10,0x20,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4, +0x0F,0xA8,0x9C,0x10,0x0E,0xE9,0x2D,0x27,0x1D,0x91,0xCA,0x37,0x2B,0x7A,0xF8,0x5E,0x47,0x0B,0xC3,0x96,0x3, +0x91,0x63,0xE7,0xD6,0x53,0xA2,0x23,0x29,0x2D,0x14,0xBB,0xBA,0xC3,0x1D,0xB4,0x8B,0x4C,0x0E,0x7D,0x94,0x3}; + +#define WINDOW 4 + +/* 2^4 =16 precomputed points based on fixed generator G(x,y) */ +/* (created using romaker2.c program with window size of 4) */ + + +/* Koblitz curve - precomputed data based on fixed generator G */ +#ifdef MR_AVR +__attribute__((__progmem__)) +#endif +static const mr_small prom[]= +{ +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0xf,0xa8,0x9c,0x10,0xe,0xe9,0x2d,0x27,0x1d,0x91,0xca,0x37,0x2b,0x7a,0xf8,0x5e,0x47,0xb,0xc3,0x96,0x3, +0x91,0x63,0xe7,0xd6,0x53,0xa2,0x23,0x29,0x2d,0x14,0xbb,0xba,0xc3,0x1d,0xb4,0x8b,0x4c,0xe,0x7d,0x94,0x3, +0x5f,0x99,0x28,0xc0,0x93,0xc1,0x22,0x25,0x39,0xd9,0x65,0x5e,0xb2,0xa7,0x29,0xb5,0xa7,0xbf,0x3b,0xcf,0x3, +0x9b,0x8b,0xa9,0x15,0x96,0x5,0xdc,0x8,0x69,0xf7,0x43,0xb,0xbe,0x9d,0x49,0xf4,0xb5,0xd1,0x9e,0x46,0x3, +0x58,0x6d,0x30,0x84,0x6f,0x71,0x47,0x9e,0xe1,0xa1,0x42,0xb6,0x27,0xc6,0xa3,0x42,0x2d,0xc4,0xc0,0x3b,0x4, +0xc5,0x22,0x77,0x47,0x28,0x13,0x37,0x7d,0xee,0xcc,0xaa,0xf2,0xda,0x48,0x49,0xb6,0x75,0x19,0x58,0x32,0x4, +0xec,0xf8,0x6f,0x9f,0x7a,0x65,0x7,0x54,0xdd,0x6,0xb6,0x64,0xc4,0xd3,0xd2,0x2e,0xce,0xb3,0x59,0xb3,0x2, +0xbc,0xc1,0x61,0xe1,0xaf,0x2a,0x68,0xa1,0x51,0xe1,0x99,0xb3,0x3e,0xe4,0xe2,0x50,0x25,0x3d,0xf5,0x36,0x2, +0x3d,0x1b,0xe5,0xe2,0x41,0x6c,0xb6,0xfc,0x93,0x9a,0x68,0xb1,0xa5,0xb6,0x0,0xdb,0x24,0x8b,0x7,0x8b,0x6, +0x6d,0x98,0x7e,0x48,0x59,0xb2,0x67,0x6e,0x61,0xd4,0x4b,0xa4,0xb8,0xdb,0xa4,0xc3,0xb9,0x1c,0x36,0x2c,0x5, +0xa6,0x16,0xcf,0x69,0x27,0x1b,0xd6,0x95,0x2f,0xae,0xe9,0xa0,0x40,0x6e,0xa0,0x8a,0x92,0x19,0x63,0x76,0x0, +0xb6,0x5b,0xdb,0xd3,0x3e,0xe7,0xa7,0x9b,0x49,0x2a,0xfb,0xed,0xc8,0x54,0x3,0xbd,0x14,0xaa,0x76,0x57,0x4, +0xea,0x6c,0x52,0x79,0x95,0x94,0xd0,0x17,0x57,0x98,0xab,0xc8,0xe9,0x28,0x18,0x99,0x1b,0xbd,0x88,0x70,0x4, +0xc8,0x84,0x42,0xca,0xd9,0xbc,0x6b,0x8,0x33,0x59,0x69,0x21,0x51,0x37,0xcf,0x69,0xb1,0x8e,0x14,0x66,0x0, +0x3c,0x44,0xf9,0xba,0x50,0xd8,0x37,0x5c,0x1d,0x8c,0x2,0x1,0xae,0xc5,0xdc,0x48,0x24,0x89,0xf7,0xbd,0x7, +0x90,0xae,0xf0,0x64,0xa,0x1c,0x1d,0x2b,0xae,0x39,0x92,0xe2,0x98,0x68,0x85,0x3,0x3c,0x5c,0xa9,0x7e,0x5, +0xd5,0xe7,0xc1,0x13,0x93,0xd1,0x75,0xaf,0x53,0x72,0xb4,0xa5,0xf4,0xf,0xa0,0x8b,0x42,0x69,0xa5,0x8b,0x5, +0xa8,0x2,0xe8,0xd2,0xd2,0x2b,0x3e,0xc2,0xa9,0xb5,0xbf,0xbd,0x7b,0x9b,0x81,0xf1,0xb7,0x68,0xfc,0xb5,0x1, +0x39,0xf5,0x19,0xef,0x18,0xca,0xaf,0xc,0xbd,0x47,0x3a,0x5,0x44,0xc7,0x58,0x61,0xeb,0x86,0x62,0x8a,0x1, +0x27,0x18,0x84,0x8c,0x7f,0x23,0x33,0x85,0xad,0xf9,0x90,0xcb,0x83,0xff,0x5b,0x3e,0x50,0x53,0xb0,0x34,0x2, +0x91,0x73,0xa3,0x8e,0xd3,0xb6,0xc2,0xa2,0xb4,0x99,0xdb,0xf3,0x6b,0x1a,0x68,0x8f,0x88,0xb7,0x6d,0xca,0x7, +0x7a,0x10,0xe9,0x10,0xe2,0xdd,0x4c,0xfc,0x38,0x3,0xd9,0xf2,0xd8,0xd6,0xcf,0xf4,0xe0,0xff,0xb5,0x28,0x7, +0x97,0xee,0xd7,0x44,0xc2,0x81,0x22,0xb,0xfa,0xdc,0xc9,0xcf,0xf8,0xc,0xd9,0x9a,0xd3,0x21,0x4b,0xc8,0x7, +0x33,0x13,0xd5,0x4b,0x3d,0xe6,0xa2,0xb9,0xfe,0x6,0x5a,0x69,0xd8,0xc8,0xed,0x78,0xa4,0xcb,0x42,0x9b,0x7, +0x3,0xfb,0x95,0xb9,0x77,0xba,0xa,0x8c,0x4c,0xc4,0x3,0x65,0x5a,0x3b,0xc6,0xaa,0x6d,0x81,0x22,0x58,0x6, +0x59,0x36,0x7,0xef,0x3f,0x6e,0x68,0xd3,0x7f,0x59,0x9,0xde,0xdc,0xb5,0x4c,0x1c,0x2d,0x32,0x80,0x80,0x7, +0x1,0x81,0xb0,0x22,0xd8,0x40,0xfd,0x8f,0x52,0xff,0xfa,0x96,0x69,0x9d,0x58,0x88,0xc2,0x9f,0x7b,0x18,0x4, +0x55,0x59,0x79,0xf9,0x7b,0xad,0x5b,0x80,0x73,0x86,0xe4,0x8,0x73,0x4f,0x1e,0x89,0xc6,0xda,0x21,0x7c,0x3, +0x6d,0xd6,0x3c,0xd0,0x32,0xc7,0xb2,0x2,0x5c,0xad,0xb8,0x60,0x89,0x6b,0xc2,0x1a,0xbc,0x99,0xd3,0x18,0x3, +0xb4,0x8,0x52,0xa2,0x5d,0xe,0x3a,0x54,0x78,0xe1,0x81,0x0,0x39,0x4,0xad,0x5e,0x3b,0xf3,0x22,0x1d,0x4}; + +#define WORDS 21 /* Number of words per big variable 21*8 > 163 */ + +/* Note that in a real application a source of real random numbers would be required, to + replace those generated by MIRACL's internal pseudo-random generator "bigbits" + Alternatively from a truly random and unguessable seed, use MIRACL's strong random + number generator */ + +/* Elliptic Curve Diffie-Hellman, using point compression to minimize bandwidth, + and precomputation to speed up off-line calculation */ + +int main() +{ + int promptr; + epoint *PA,*PB; + big A,B,a,b,q,pa,pb,key,x,y; + ebrick2 binst; + miracl instance; /* create miracl workspace on the stack */ + +/* Specify base 16 here so that HEX can be read in directly without a base-change */ + + miracl *mip=mirsys(&instance,WORDS*HEXDIGS,16); /* size of bigs is fixed */ + char mem_big[MR_BIG_RESERVE(10)]; /* we need 10 bigs... */ + char mem_ecp[MR_ECP_RESERVE(2)]; /* ..and two elliptic curve points */ + memset(mem_big, 0, MR_BIG_RESERVE(10)); /* clear the memory */ + memset(mem_ecp, 0, MR_ECP_RESERVE(2)); + +/* printf("sizeof(miracl)= %d\n",sizeof(miracl)); */ + + A=mirvar_mem(mip, mem_big, 0); /* Initialise big numbers */ + B=mirvar_mem(mip, mem_big, 1); + pa=mirvar_mem(mip, mem_big, 2); + pb=mirvar_mem(mip, mem_big, 3); + key=mirvar_mem(mip, mem_big, 4); + x=mirvar_mem(mip, mem_big, 5); + y=mirvar_mem(mip, mem_big, 6); + q=mirvar_mem(mip,mem_big,7); + a=mirvar_mem(mip, mem_big, 8); + b=mirvar_mem(mip, mem_big, 9); + + PA=epoint_init_mem(mip, mem_ecp, 0); /* initialise Elliptic Curve points */ + PB=epoint_init_mem(mip, mem_ecp, 1); + + irand(mip, 3L); /* change parameter for different random numbers */ + promptr=0; + init_big_from_rom(B,WORDS,rom,WORDS*4,&promptr); /* Read in curve parameter B from ROM */ + /* don't need q or G(x,y) (we have precomputed table from it) */ + init_big_from_rom(q,WORDS,rom,WORDS*4,&promptr); + init_big_from_rom(x,WORDS,rom,WORDS*4,&promptr); + init_big_from_rom(y,WORDS,rom,WORDS*4,&promptr); + + convert(mip,1,A); /* set A=1 */ + +/* Create precomputation instance from precomputed table in ROM */ + + ebrick2_init(&binst,prom,A,B,CURVE_M,CURVE_A,CURVE_B,CURVE_C,WINDOW,CURVE_M); + +/* offline calculations */ + + bigbits(mip,CURVE_M,a); /* A's random number */ + + mul2_brick(mip,&binst,a,pa,pa); /* a*G =(pa,ya) */ + + bigbits(mip,CURVE_M,b); /* B's random number */ + mul2_brick(mip,&binst,b,pb,pb); /* b*G =(pb,yb) */ + +/* Swap X values */ + +/* online calculations */ + ecurve2_init(mip,CURVE_M,CURVE_A,CURVE_B,CURVE_C,A,B,FALSE,MR_PROJECTIVE); + + epoint2_set(mip,pb,pb,0,PB); /* decompress PB */ + ecurve2_mult(mip,a,PB,PB); + epoint2_get(mip,PB,key,key); + +/* since internal base is HEX, can use otnum instead of cotnum - avoiding a base change */ + +#ifndef MR_NO_STANDARD_IO +printf("Alice's Key= "); +otnum(mip,key,stdout); +#endif + + epoint2_set(mip,pa,pa,0,PB); /* decompress PA */ + ecurve2_mult(mip,b,PB,PB); + epoint2_get(mip,PB,key,key); + +#ifndef MR_NO_STANDARD_IO +printf("Bob's Key= "); +otnum(mip,key,stdout); +#endif + +/* clear the memory - good security measure */ + + memset(mem_big, 0, MR_BIG_RESERVE(10)); + memset(mem_ecp, 0, MR_ECP_RESERVE(2)); + + return 0; +} diff --git a/miracl/source/ecdhp.c b/miracl/source/ecdhp.c new file mode 100644 index 0000000..6afaf85 --- /dev/null +++ b/miracl/source/ecdhp.c @@ -0,0 +1,218 @@ +/* + +Example Elliptic Curve Diffie-Hellman program for 32-bit constrained environments. Uses point compression. +Stack-only memory allocation + +Use with this mirdef.h header (for a PC using MS C) + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype __int64 +#define mr_unsign64 unsigned __int64 +#define MR_STATIC 6 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_COMBA 6 +#define MR_GENERALIZED_MERSENNE +#define MR_SPECIAL +#define MR_SIMPLE_BASE +#define MR_SIMPLE_IO + +In an embedded environment perhaps these should be defined as well.. + +#define MR_NO_STANDARD_IO +#define MR_NO_FILE_IO + +Build the library from these modules (Example using MS C compiler) + +mex 6 ms86 mrcomba +rem (mex 6 sse2 mrcomba) will be faster on most PCs that support SSE2 +cl /c /O2 /W3 mrcore.c +cl /c /O2 /W3 mrarth0.c +cl /c /O2 /W3 mrarth1.c +cl /c /O2 /W3 mrio1.c +cl /c /O2 /W3 mrbits.c +cl /c /O2 /W3 mrcurve.c +cl /c /O2 /W3 mrsroot.c +cl /c /O2 /W3 mrjack.c +cl /c /O2 /W3 mrlucas.c +cl /c /O2 /W3 mrarth2.c +cl /c /O2 /W3 mrmonty.c +cl /c /O2 /W3 mrcomba.c +cl /c /O2 /W3 mrxgcd.c +cl /c /O2 /W3 mrmuldv.c +cl /c /O2 /W3 mrebrick.c + +rem +rem Create library 'miracl.lib' +del miracl.lib + +lib /OUT:miracl.lib mrio1.obj mrmonty.obj mrcomba.obj mrxgcd.obj mrmuldv.obj +lib /OUT:miracl.lib miracl.lib mrbits.obj mrarth2.obj mrlucas.obj mrjack.obj +lib /OUT:miracl.lib miracl.lib mrarth0.obj mrarth1.obj mrcore.obj mrebrick.obj +lib /OUT:miracl.lib miracl.lib mrcurve.obj mrsroot.obj +del mr*.obj + +rem Create the program + +cl /O2 ecdhp.c miracl.lib + +*/ + +#include +#include +#include "miracl.h" + +/* !!!!!! THIS CODE AND THESE ROMS ARE NOW CREATED AUTOMATICALLY USING THE ROMAKER.C APPLICATION !!!!!!!! */ +/* !!!!!! READ COMMENTS IN ROMAKER.C !!!!!! */ + +#define HEXDIGS (MIRACL/4) +#define CURVE_BITS 192 + +/* NIST p192 bit elliptic curve Y^2=X^3-3X+B (from secp192.ecs). + Here is stored P, B, the group order q, and the generator G(x,y) */ + +static const mr_small rom[]= +{0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFE,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +0xC146B9B1,0xFEB8DEEC,0x72243049,0x0FA7E9AB,0xE59C80E7,0x64210519, +0xB4D22831,0x146BC9B1,0x99DEF836,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +0x82FF1012,0xF4FF0AFD,0x43A18800,0x7CBF20EB,0xB03090F6,0x188DA80E, +0x1E794811,0x73F977A1,0x6B24CDD5,0x631011ED,0xFFC8DA78,0x07192B95}; + +#define WINDOW 4 + +/* 32 precomputed points based on fixed generator G(x,y) */ +/* (created using romaker.c program with window size of 4) */ + +/* These values are only correct if MR_SPECIAL is defined! */ + +static const mr_small prom[]= +{0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0, +0x82ff1012,0xf4ff0afd,0x43a18800,0x7cbf20eb,0xb03090f6,0x188da80e, +0x1e794811,0x73f977a1,0x6b24cdd5,0x631011ed,0xffc8da78,0x7192b95, +0x5d7c48d8,0xc39649c5,0x5a927c35,0xeb2cdfae,0xcba671fb,0x67e30cbd, +0xecbfbe7d,0x7a83cee1,0x6301577,0xce32d03c,0x5810f5c3,0xa93549c4, +0x66e3ead3,0x6f5ef889,0xdfc9bf1a,0xf29e6fea,0x452006e0,0xce216bb8, +0x927b3779,0x46b9092d,0xb5b80a20,0x1d0aeb4b,0x5aaec958,0xd98a2ee2, +0xc0a1e340,0xb19963d8,0x80d1090b,0x4730d4f4,0x184ac737,0x51a581d9, +0xe69912a5,0xecc56731,0x2f683f16,0x7cdfcea0,0xe0bb9f6e,0x5bd81ee2, +0xd4f43374,0xe4b15a2d,0xf292c341,0x757eea7,0xd0f8dc24,0xc730691, +0xbbf45e00,0xdf797890,0xe9de8708,0x8a9e83,0x9354de3e,0x31b24c31, +0xddf63aba,0xcb5ec043,0xf84f41e1,0xc94c21d9,0x61d24416,0xf0f40883, +0x406495f7,0xf37585b0,0x16bcd0ca,0xe5de3b5b,0xe13ea488,0x27853c1a, +0x8e8ae68f,0xd074232a,0xee29f7a9,0x749e528e,0x9716469f,0x611dea3, +0xd8043cc,0x66b867dd,0x3a727de6,0x6a654654,0x8338bdc9,0xf9546052, +0xc5d8f50,0xb6eb7193,0xb904b596,0x1c245c02,0x951f7513,0x4bc1f71, +0xbe34803d,0xa4d0916e,0x8c21962a,0x8bec948a,0xfd69f8d0,0x150096e7, +0xe71aac0c,0xbd44ffe8,0x4322d065,0x7d69a0b0,0xeca3ba2a,0x9f56d96c, +0x25a59dce,0xee59f0d1,0xc3f4575a,0x837d62dd,0x35de73d9,0xa4e07fb3, +0x1cf46ae2,0xec76760c,0xa33d44b0,0xff549832,0xf3185c11,0xe95ad210, +0x38ed372e,0x273e5ec5,0xb0ab1169,0x51d39136,0x8f3a27c8,0xa5ea86f6, +0x74d2d7d5,0x291237ea,0x56338e9b,0x953636ee,0x285c120c,0xda65e86, +0xf13c3233,0x1302f04c,0x978391b2,0xfc898ab9,0x3aa06272,0x26d65c2e, +0x18c5efe6,0xd50947a8,0xfe113c6c,0x45db23ae,0xe5bbe86d,0x91f199f2, +0x60fec064,0x376881b6,0x475daea4,0x387343e9,0xac8d8a19,0xeccd57e8, +0x5b510228,0xc9fef5b9,0x192ebcd6,0x374c0a4c,0xce6a83f9,0x2298f204, +0xf4c574d0,0x46e4b820,0xefeb2cc0,0x6d58644,0x10c3c949,0xe713a400, +0x2d64eedf,0x6178cb0e,0xb85e1f99,0x27af7d5e,0x6cb7be1f,0xd873ced7, +0x52a67f9c,0xefc9129c,0x6004d9ad,0xa3d7b957,0xdc41f8e2,0xfc599808, +0x7fdf928a,0xbb6c6b59,0xd7f93bf4,0xad167ef0,0x154e061c,0xfaa9e432, +0xd52c8f3f,0xc3d0d63,0xd5f7e08f,0x6101b2be,0xd6ae3cf3,0xd877cddd}; + + +#define WORDS 6 /* Number of words per big variable 6*32 = 192 */ + +/* Note that in a real application a source of real random numbers would be required, to + replace those generated by MIRACL's internal pseudo-random generator "bigbits" + Alternatively from a truly random and unguessable seed, use MIRACL's strong random + number generator */ + +/* Elliptic Curve Diffie-Hellman, using point compression to minimize bandwidth, + and precomputation to speed up off-line calculation */ + +int main() +{ + int promptr; + epoint *PB; + big A,B,p,a,b,pa,pb,key; + ebrick binst; + miracl instance; /* create miracl workspace on the stack */ + +/* Specify base 16 here so that HEX can be read in directly without a base-change */ + + miracl *mip=mirsys(&instance,WORDS*HEXDIGS,16); /* size of bigs is fixed */ + char mem_big[MR_BIG_RESERVE(8)]; /* we need 8 bigs... */ + char mem_ecp[MR_ECP_RESERVE(1)]; /* ..and 1 elliptic curve points */ + memset(mem_big, 0, MR_BIG_RESERVE(8)); /* clear the memory */ + memset(mem_ecp, 0, MR_ECP_RESERVE(1)); + + A=mirvar_mem(mip, mem_big, 0); /* Initialise big numbers */ + B=mirvar_mem(mip, mem_big, 1); + pa=mirvar_mem(mip, mem_big, 2); + pb=mirvar_mem(mip, mem_big, 3); + key=mirvar_mem(mip, mem_big, 4); + a=mirvar_mem(mip, mem_big, 5); + b=mirvar_mem(mip, mem_big, 6); + p=mirvar_mem(mip, mem_big, 7); + + PB=epoint_init_mem(mip, mem_ecp, 0); /* initialise Elliptic Curve points */ + + irand(mip, 3L); /* change parameter for different random numbers */ + + promptr=0; + init_big_from_rom(p,WORDS,rom,WORDS*5,&promptr); /* Read in prime modulus p from ROM */ + init_big_from_rom(B,WORDS,rom,WORDS*5,&promptr); /* Read in curve parameter B from ROM */ + /* don't need q or G(x,y) (we have precomputed table from it) */ + + convert(mip,-3,A); /* set A=-3 */ + +/* Create precomputation instance from precomputed table in ROM */ + + ebrick_init(&binst,prom,A,B,p,WINDOW,CURVE_BITS); + +/* offline calculations */ + + bigbits(mip,CURVE_BITS,a); /* A's random number */ + mul_brick(mip,&binst,a,pa,pa); /* a*G =(pa,ya) */ + + bigbits(mip,CURVE_BITS,b); /* B's random number */ + mul_brick(mip,&binst,b,pb,pb); /* b*G =(pb,yb) */ + +/* swap X values of point */ + +/* online calculations */ + ecurve_init(mip,A,B,p,MR_PROJECTIVE); + epoint_set(mip,pb,pb,0,PB); /* decompress PB */ + ecurve_mult(mip,a,PB,PB); + epoint_get(mip,PB,key,key); + +/* since internal base is HEX, can use otnum instead of cotnum - avoiding a base change */ +#ifndef MR_NO_STANDARD_IO +printf("Alice's Key= "); +otnum(mip,key,stdout); +#endif + + epoint_set(mip,pa,pa,0,PB); /* decompress PA */ + ecurve_mult(mip,b,PB,PB); + epoint_get(mip,PB,key,key); + +#ifndef MR_NO_STANDARD_IO +printf("Bob's Key= "); +otnum(mip,key,stdout); +#endif + +/* clear the memory */ + + memset(mem_big, 0, MR_BIG_RESERVE(8)); + memset(mem_ecp, 0, MR_ECP_RESERVE(1)); + + return 0; +} diff --git a/miracl/source/ecdhp16.c b/miracl/source/ecdhp16.c new file mode 100644 index 0000000..5b35944 --- /dev/null +++ b/miracl/source/ecdhp16.c @@ -0,0 +1,330 @@ +/* + +Example Elliptic Curve Diffie-Hellman program for 16-bit constrained environments. Uses point compression. +Stack-only memory allocation + +Use with this mirdef.h header (for a PC using MS C) + +(Use this header also with Blackfin processor, and +mex 10 blackfin mrcomba) + +#define MR_LITTLE_ENDIAN +#define MIRACL 16 +#define mr_utype short +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype int +#define MR_DLTYPE_IS_INT +#define MR_STATIC 10 +#define MR_ALWAYS_BINARY +#define MR_NOASM +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 10 +#define MR_GENERALIZED_MERSENNE +#define MR_SPECIAL +#define MR_BITSINCHAR 8 +#define MR_SIMPLE_BASE +#define MR_SIMPLE_IO + + +Build the library from these modules (Example using MS C compiler) + +mex 10 c mrcomba +rem In a real 16-bit setting, a suitable assembly language .mcs file would be used. Here we use C. +cl /c /O2 /W3 mrcore.c +cl /c /O2 /W3 mrarth0.c +cl /c /O2 /W3 mrarth1.c +cl /c /O2 /W3 mrio1.c +cl /c /O2 /W3 mrbits.c +cl /c /O2 /W3 mrcurve.c +cl /c /O2 /W3 mrsroot.c +cl /c /O2 /W3 mrjack.c +cl /c /O2 /W3 mrlucas.c +cl /c /O2 /W3 mrarth2.c +cl /c /O2 /W3 mrmonty.c +cl /c /O2 /W3 mrcomba.c +cl /c /O2 /W3 mrxgcd.c +cl /c /O2 /W3 mrebrick.c + +rem +rem Create library 'miracl.lib' +del miracl.lib + +lib /OUT:miracl.lib mrio1.obj mrmonty.obj mrcomba.obj mrxgcd.obj +lib /OUT:miracl.lib miracl.lib mrbits.obj mrarth2.obj mrlucas.obj mrjack.obj +lib /OUT:miracl.lib miracl.lib mrarth0.obj mrarth1.obj mrcore.obj mrebrick.obj +lib /OUT:miracl.lib miracl.lib mrcurve.obj mrsroot.obj +del mr*.obj + +rem Create the program + +cl /O2 ecdhp16.c miracl.lib + + +******************************************************************************************** + + +Using the Turbo C 16-bit compiler use this header + +#define MR_LITTLE_ENDIAN +#define MIRACL 16 +#define mr_utype short +#define MR_IBITS 16 +#define MR_LBITS 32 +#define mr_unsign32 unsigned long +#define mr_dltype long +#define MR_STATIC 10 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 10 +#define MR_GENERALIZED_MERSENNE +#define MR_SPECIAL +#define MR_BITSINCHAR 8 +#define MR_NOKOBLITZ + +Extract the Turbo C small model version of mrmuldv.c from mrmuldv.any +and execute + +mex 10 tc86 mrcomba +tcc -c -ms mrcore.c +tcc -c -ms mrarth0.c +tcc -c -ms mrarth1.c +tcc -c -ms mrarth2.c +tcc -c -ms mrio1.c +tcc -c -ms mrjack.c +tcc -c -ms mrxgcd.c +tcc -c -ms mrbits.c +tcc -c -ms mrmonty.c +tcc -c -ms mrsroot.c +tcc -c -ms mrcurve.c +tcc -c -ms mrlucas.c +tcc -c -ms mrsmall.c +tcc -c -ms mrebrick.c +tcc -c -ms mrcomba.c +tcc -c -ms mrmuldv.c + +rem +rem Create library 'miracl.lib' +del miracl.lib + +tlib miracl +tlib miracl +mrio1 +tlib miracl +mrjack+mrxgcd+mrarth2+mrsroot+mrbits +tlib miracl +mrmonty+mrarth1+mrarth0+mrsmall+mrcore +tlib miracl +mrcurve+mrlucas+mrebrick+mrcomba+mrmuldv +del mr*.obj + +tcc -ms ecdhp16.c miracl.lib + +This assumes that the tasm assembler is available + +******************************************************** + +For the msp430 processor use this header + +#define MIRACL 16 +#define MR_LITTLE_ENDIAN +#define mr_utype int +#define mr_unsign32 unsigned long +#define mr_dltype long +#define mr_unsign64 unsigned long long +#define MR_IBITS 16 +#define MR_LBITS 32 +#define MR_NO_FILE_IO +#define MR_STATIC 10 +#define MR_COMBA 10 +#define MR_ALWAYS_BINARY +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_GENERIC_MT +#define MR_STRIPPED_DOWN +#define MR_SIMPLE_IO +#define MR_SIMPLE_BASE +#define MR_SPECIAL +#define MR_GENERALIZED_MERSENNE +#define MR_SMALL_EWINDOW +#define MR_NO_STANDARD_IO +#define MR_NOASM + +mex 10 msp430 mrcomba + +But read the comments at the start of msp430.mcs + +Then add these files to the project, along with this file + +mrcore.c +mrarth0.c +mrarth1.c +mrarth2.c +mrio1.c +mrjack.c +mrxgcd.c +mrbits.c +mrmonty.c +mrsroot.c +mrcurve.c +mrlucas.c +mrsmall.c +mrebrick.c +mrcomba.c + +*/ + +#include +#include +#include "miracl.h" + +/* !!!!!! THIS CODE AND THESE ROMS ARE NOW CREATED AUTOMATICALLY USING THE ROMAKER.C APPLICATION !!!!!!!! */ +/* !!!!!! READ COMMENTS IN ROMAKER.C !!!!!! */ + + +#define HEXDIGS (MIRACL/4) +#define CURVE_BITS 160 + +/* SCOTT p160 bit elliptic curve Y^2=X^3-3X+157 modulo 2^160-2^112+2^64+1 + Here is stored P, B, the group order q, and the generator G(x,y) */ + +static const mr_small rom[]= +{0x0001, 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, +0x9D,0,0,0,0,0,0,0,0,0, +0x35C3, 0xC739, 0xA36F, 0x36C9, 0x593A, 0xFFFE, 0xFFFF, 0xFFFE, 0xFFFF, 0xFFFF, +0xA11E, 0x4E35, 0x6AAD, 0x373E, 0x87AD, 0xAC67, 0xE14C, 0xEF68, 0x0583, 0xE116, +0x8460, 0xF29E, 0xCE44, 0x63F0, 0x5E8B, 0x761E, 0xE48A, 0x6D02, 0x7574, 0x5707}; + +#define WINDOW 4 + +/* 32 precomputed points based on fixed generator G(x,y) */ +/* (created using romaker.c program with window size of 4) */ + +/* These values are only correct if MR_SPECIAL is defined! */ + +static const mr_small prom[]= +{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0xa11e,0x4e35,0x6aad,0x373e,0x87ad,0xac67,0xe14c,0xef68,0x583,0xe116, +0x8460,0xf29e,0xce44,0x63f0,0x5e8b,0x761e,0xe48a,0x6d02,0x7574,0x5707, +0x6772,0x397f,0x9767,0xf0ed,0xf5ea,0xf954,0x38f4,0x2928,0x7b45,0x2f0a, +0x6448,0xaeb8,0x22d7,0x7e28,0x1d6a,0x3509,0x7ea7,0xa3cd,0x9c3a,0xf99b, +0x544,0xd389,0x55a6,0xa7d5,0xb755,0xe532,0x77a2,0x6c83,0xc3b6,0xae04, +0x5eca,0xfa9,0x8852,0xf64f,0x40d6,0x5b02,0x8960,0xd05c,0xa31f,0x1675, +0x9873,0x5ab3,0xcfa1,0xcd39,0xf19a,0x5a4c,0xea04,0x23b5,0xc579,0xcb53, +0x8bf1,0x3d76,0x85c8,0x123d,0x445b,0x30,0x2cef,0xb240,0x69c9,0x4367, +0x43ee,0xa57f,0xb704,0xdf9e,0x6410,0x359c,0x8e20,0xf1f5,0x1711,0x52d4, +0x5cf1,0x3481,0xa1ea,0x432c,0xd516,0xb073,0x9ba8,0xc4a3,0x9cc7,0x6c19, +0x601b,0xb7f7,0x9a94,0x8011,0x50d,0xe1b5,0x34db,0x98a5,0xb4cb,0xf354, +0xd8f3,0x8b08,0x1176,0xa270,0xeda6,0x6d69,0xd305,0x6c9a,0xab0a,0x561d, +0xa57a,0xe3ad,0x6d98,0x45a2,0xfa02,0x9930,0x744a,0x7fb,0x263b,0xeca9, +0x230c,0x39f9,0xac8a,0x113e,0x2fd1,0x17cb,0x18bf,0xed10,0xd225,0xda56, +0x7ad3,0x6d66,0x9fed,0x13cf,0xed86,0xe288,0x55eb,0x61a1,0xc92d,0xa067, +0x8ef8,0x6b8d,0x67a,0xa091,0xef31,0x948a,0x553e,0x7280,0xe632,0x45a8, +0x4fc8,0x62c2,0xd82f,0x36b2,0x5143,0x836d,0xb073,0xc6fc,0xf900,0x5505, +0xeff8,0x2835,0xfbb,0x9523,0x8f5,0xfe1c,0xb10e,0x94e5,0x35ea,0xe75b, +0x43c7,0x1dfd,0xe2c8,0x5ed1,0x2cd1,0xcb7e,0x210,0x32ea,0x16d7,0x764b, +0xaf27,0x1721,0x37ac,0xe1f4,0xab94,0xb2f5,0xb1dc,0x7a94,0x611,0x42e, +0xc781,0x54c5,0x5784,0xa020,0xd723,0xdf6d,0x76b9,0xfbc9,0xb44e,0x9ffb, +0x9cd4,0x1bea,0x818b,0x7045,0xad2d,0xbeaa,0x505b,0xc778,0x5361,0x15c2, +0x6b66,0x81a5,0xdf67,0xadfe,0xe2fa,0xbdc5,0xef77,0x5eeb,0x60a5,0x9037, +0xa1cc,0x997,0xb8df,0xfc09,0x49e0,0x918a,0x2993,0x4f18,0xf876,0x9680, +0x694b,0x37d,0xbbce,0x3d9f,0x5494,0x9b16,0x25fb,0x760b,0xc6c3,0x9b41, +0x1bda,0x2fa5,0x45ce,0x3da9,0x4810,0x23b8,0xa722,0xceb9,0xc045,0x3366, +0xe65e,0x62ba,0x675a,0xfdf5,0xc814,0x23fd,0x33c9,0x4c06,0xe787,0xa06d, +0x7358,0x6132,0xf731,0xf884,0xe4d3,0x9f3b,0x9fcc,0x458c,0xfb96,0x58c5, +0x6fb1,0xe7f,0x240,0x8adb,0x9095,0xe4dc,0xe662,0x54b8,0x1716,0x8ae4, +0x9c38,0x8a61,0xfcad,0x78ef,0x2029,0x3c0c,0xed18,0x19af,0xd4fb,0xfbf5}; + + +#define WORDS 10 /* Number of words per big variable 10*16 = 160 */ + +/* Note that in a real application a source of real random numbers would be required, to + replace those generated by MIRACL's internal pseudo-random generator "bigbits" + Alternatively from a truly random and unguessable seed, use MIRACL's strong random + number generator */ + +/* Elliptic Curve Diffie-Hellman, using point compression to minimize bandwidth, + and precomputation to speed up off-line calculation */ + +int main() +{ + int promptr; + epoint *PB; + big A,B,p,a,b,q,pa,pb,key,x,y; + ebrick binst; + miracl instance; /* create miracl workspace on the stack */ + +/* Specify base 16 here so that HEX can be read in directly without a base-change */ + + miracl *mip=mirsys(&instance,WORDS*HEXDIGS,16); /* size of bigs is fixed */ + char mem_big[MR_BIG_RESERVE(10)]; /* we need 10 bigs... */ + char mem_ecp[MR_ECP_RESERVE(1)]; /* ..and two elliptic curve points */ + memset(mem_big, 0, MR_BIG_RESERVE(10)); /* clear the memory */ + memset(mem_ecp, 0, MR_ECP_RESERVE(1)); + + A=mirvar_mem(mip, mem_big, 0); /* Initialise big numbers */ + B=mirvar_mem(mip, mem_big, 1); + pa=mirvar_mem(mip, mem_big, 2); + pb=mirvar_mem(mip, mem_big, 3); + key=mirvar_mem(mip, mem_big, 4); + x=mirvar_mem(mip, mem_big, 5); + y=mirvar_mem(mip, mem_big, 6); + a=mirvar_mem(mip, mem_big, 7); + b=mirvar_mem(mip, mem_big, 8); + p=mirvar_mem(mip, mem_big, 9); + + PB=epoint_init_mem(mip, mem_ecp, 0); /* initialise Elliptic Curve points */ + + irand(mip, 3L); /* change parameter for different random numbers */ + + promptr=0; + init_big_from_rom(p,WORDS,rom,WORDS*5,&promptr); /* Read in prime modulus p from ROM */ + init_big_from_rom(B,WORDS,rom,WORDS*5,&promptr); /* Read in curve parameter B from ROM */ + /* don't need q or G(x,y) (we have precomputed table from it) */ + + convert(mip,-3,A); /* set A=-3 */ + +/* Create precomputation instance from precomputed table in ROM */ + + ebrick_init(&binst,prom,A,B,p,WINDOW,CURVE_BITS); + +/* offline calculations */ + + bigbits(mip,CURVE_BITS,a); /* A's random number */ + mul_brick(mip,&binst,a,pa,pa); /* a*G =(pa,ya) */ + bigbits(mip,CURVE_BITS,b); /* B's random number */ + mul_brick(mip,&binst,b,pb,pb); /* b*G =(pb,yb) */ + +/* swap X values of point */ + +/* online calculations */ + ecurve_init(mip,A,B,p,MR_PROJECTIVE); + epoint_set(mip,pb,pb,0,PB); /* decompress PB */ + ecurve_mult(mip,a,PB,PB); + epoint_get(mip,PB,key,key); + +/* since internal base is HEX, can use otnum instead of cotnum - avoiding a base change */ + +#ifndef MR_NO_STANDARD_IO +printf("Alice's Key= "); +otnum(mip,key,stdout); +#endif + + epoint_set(mip,pa,pa,0,PB); /* decompress PA */ + ecurve_mult(mip,b,PB,PB); + epoint_get(mip,PB,key,key); + +#ifndef MR_NO_STANDARD_IO +printf("Bob's Key= "); +otnum(mip,key,stdout); +#endif + +/* clear the memory */ + + memset(mem_big, 0, MR_BIG_RESERVE(10)); + memset(mem_ecp, 0, MR_ECP_RESERVE(1)); + + return 0; +} diff --git a/miracl/source/ecdhp32.c b/miracl/source/ecdhp32.c new file mode 100644 index 0000000..011b3fd --- /dev/null +++ b/miracl/source/ecdhp32.c @@ -0,0 +1,258 @@ +/* + +Example Elliptic Curve Diffie-Hellman program for 32-bit constrained environments. Uses point compression. +Stack-only memory allocation + +Use with this mirdef.h header (for a PC using MS C) + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype __int64 +#define mr_unsign64 unsigned __int64 +#define MR_STATIC 5 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +#define MR_COMBA 5 +#define MR_PSEUDO_MERSENNE +#define MR_SPECIAL +#define MR_SIMPLE_BASE +#define MR_SIMPLE_IO + +Build the library from these modules (Example using MS C compiler) + +mex 5 ms86 mrcomba +rem (mex 5 sse2 mrcomba) will be faster on most PCs that support SSE2 +cl /c /O2 /W3 mrcore.c +cl /c /O2 /W3 mrarth0.c +cl /c /O2 /W3 mrarth1.c +cl /c /O2 /W3 mrio1.c +cl /c /O2 /W3 mrbits.c +cl /c /O2 /W3 mrcurve.c +cl /c /O2 /W3 mrsroot.c +cl /c /O2 /W3 mrjack.c +cl /c /O2 /W3 mrlucas.c +cl /c /O2 /W3 mrarth2.c +cl /c /O2 /W3 mrmonty.c +cl /c /O2 /W3 mrcomba.c +cl /c /O2 /W3 mrxgcd.c +cl /c /O2 /W3 mrmuldv.c +cl /c /O2 /W3 mrebrick.c + +rem +rem Create library 'miracl.lib' +del miracl.lib + +lib /OUT:miracl.lib mrio1.obj mrmonty.obj mrcomba.obj mrxgcd.obj mrmuldv.obj +lib /OUT:miracl.lib miracl.lib mrbits.obj mrarth2.obj mrlucas.obj mrjack.obj +lib /OUT:miracl.lib miracl.lib mrarth0.obj mrarth1.obj mrcore.obj mrebrick.obj +lib /OUT:miracl.lib miracl.lib mrcurve.obj mrsroot.obj +del mr*.obj + +rem Create the program + +cl /O2 ecdhp32.c miracl.lib + +For the ARM processor use + +#define MIRACL 32 +#define MR_LITTLE_ENDIAN +#define mr_utype int +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_dltype long long +#define mr_unsign32 unsigned int +#define mr_unsign64 unsigned long long +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 5 +#define MR_STATIC 5 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MR_PSEUDO_MERSENNE +#define MR_SPECIAL + +and + +mex 5 arm mrcomba +armcc -I. -c -O2 mrcore.c +armcc -I. -c -O2 mrarth0.c +armcc -I. -c -O2 mrarth1.c +armcc -I. -c -O2 mrarth2.c +armcc -I. -c -O2 mrsmall.c +armcc -I. -c -O2 mrio1.c +armcc -I. -c -O2 mrjack.c +armcc -I. -c -O2 mrbits.c +armcc -I. -c -O2 mrxgcd.c +armcc -I. -c -O2 mrmonty.c +armcc -I. -c -O2 mrsroot.c +armcc -I. -c -O2 mrcurve.c +armcc -I. -c -O2 mrlucas.c +armcc -I. -c -O2 mrebrick.c + +armcc -I. -c -O2 mrcomba.c +armcc -I. -c -O2 mrmuldv.c +armar -rc miracl.a mrcore.o mrarth0.o mrarth1.o mrarth2.o mrsmall.o +armar -r miracl.a mrio1.o mrjack.o mrxgcd.o +armar -r miracl.a mrmonty.o mrcurve.o +armar -r miracl.a mrebrick.o mrsroot.o mrlucas.o +armar -r miracl.a mrbits.o mrcomba.o mrmuldv.o +del mr*.o +armcc -I. --debug -c -O2 ecdhp32.c +armlink ecdhp32.o miracl.a -o ecdhp32.axf + +*/ + +#include +#include +#include "miracl.h" + +/* !!!!!! THIS CODE AND THESE ROMS ARE NOW CREATED AUTOMATICALLY USING THE ROMAKER.C APPLICATION !!!!!!!! */ +/* !!!!!! READ COMMENTS IN ROMAKER.C !!!!!! */ + +#define HEXDIGS (MIRACL/4) +#define CURVE_BITS 160 + +/* Pseudo Mersenne 160 bit elliptic curve Y^2=X^3-3X+383 modulo 2^160-57 + Here is stored P, B, the group order q, and the generator G(x,y) */ + +static const mr_small rom[]= +{0xFFFFFFC7,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF, +0x17F,0x0,0x0,0x0,0x0, +0x717F3225,0x01A04F4B,0xFFFF0E3F,0xFFFFFFFF,0xFFFFFFFF, +0xB75666F1,0xD027BFEE,0x09B7D04A,0xED594E20,0x0A8ADC5E, +0x5545C9DA,0x111C6CCC,0xAC4D389F,0xAF7643D3,0x20FB2D5C}; + +#define WINDOW 4 + +/* 32 precomputed points based on fixed generator G(x,y) */ +/* (created using romaker.c program with window size of 4) */ + +/* These values are only correct if MR_SPECIAL is defined! */ + +static const mr_small prom[]= +{0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0, +0xb75666f1,0xd027bfee,0x9b7d04a,0xed594e20,0xa8adc5e, +0x5545c9da,0x111c6ccc,0xac4d389f,0xaf7643d3,0x20fb2d5c, +0xe5dcf80a,0xada27b96,0x19f2a789,0xa0cbd6fe,0xc6af4491, +0xa4c1ee35,0x91dabe76,0xd96fa35c,0x4f41e824,0x670a00e7, +0x30b19d16,0x479afa2d,0xbb823930,0x9e787e39,0x31a5c91d, +0x9b03e364,0x3f51de4f,0x689f02b5,0x2f3a650e,0x79e94aae, +0x3f8666bf,0xc77f5da0,0x75852755,0x97589faa,0xabe6ec1f, +0xf7323692,0xdf9d2073,0x6d298478,0xe792453f,0x2e642dd0, +0x15dd462,0xca2673e0,0x87e7cbaa,0xfea4ddf5,0xc7bfc7d1, +0xea471875,0xd904cb19,0x8bc54f99,0xec0f657,0x8499af11, +0x31493bdc,0xdc55770b,0x7c56aa97,0x2c277035,0xc8eeb5d7, +0xfe43174d,0x30478f80,0x949183c2,0xfd0a6517,0x324aa528, +0xb8ef76b2,0xb00adb49,0xef5f1ab6,0x379f6247,0x980c0c7f, +0x6b6834e1,0x6c07e146,0x5dba824f,0x69ebeaf9,0xa0ac2a9, +0xb0da9c9e,0xd183ecfa,0x7851c738,0x5d4e69d,0x1e56de83, +0x14ce58f9,0xa563c779,0x31f5109b,0x8b1c9c26,0xcc2b7bba, +0xc7f770dc,0xc8f03ab5,0xc1275f7d,0x84267b4f,0x9d88c48d, +0x3eee917d,0x22afc820,0x4c584705,0x76aec683,0xd44b436e, +0xa2dff854,0x83f54fb9,0xd7bd8efd,0xac4af0f8,0xd0a713fa, +0x4f6125f3,0xdf13ec6b,0x7e354de1,0xa3d9f4ba,0xb2826e0c, +0x6df1f4f9,0x7c6372ce,0x42af4b81,0xaba985d8,0x531dc9ea, +0xd5f9ceb2,0x5ac87241,0xbc750c8f,0xe593f7a9,0xd276be6e, +0x15c9546f,0x99e64886,0x1a75ccdc,0x8cd0d6fd,0x39a708cd, +0xc2d64d0,0x5ddaa2f3,0x31f47696,0xe7740a86,0xb2296006, +0x5608debb,0xff3f8b9f,0x32dc4b30,0x630b8f4c,0xb3f47d5, +0x84771cda,0x2faa9d5b,0x1de86f77,0x8f06694e,0x7af7c3d, +0x2ae42a1,0x3153a324,0x5643e61f,0x1f6e7021,0xe417b332, +0xd1c04a51,0xd6eeb7d1,0x9a3ba8c6,0x8c11b8e2,0xdf9bae00, +0x782cbc03,0xba24cf5f,0x4c09607f,0x11dd868c,0xf5e13ffe, +0xb630b0a0,0xb4d880b7,0x432ebc6a,0x28043baa,0x47a1ef13}; + +#define WORDS 5 /* Number of words per big variable 5*32 = 160 */ + +/* Note that in a real application a source of real random numbers would be required, to + replace those generated by MIRACL's internal pseudo-random generator "bigbits" + Alternatively from a truly random and unguessable seed, use MIRACL's strong random + number generator */ + +/* Elliptic Curve Diffie-Hellman, using point compression to minimize bandwidth, + and precomputation to speed up off-line calculation */ + +int main() +{ + int promptr; + epoint *PB; + big A,B,p,a,b,pa,pb,key; + ebrick binst; + miracl instance; /* create miracl workspace on the stack */ + +/* Specify base 16 here so that HEX can be read in directly without a base-change */ + + miracl *mip=mirsys(&instance,WORDS*HEXDIGS,16); /* size of bigs is fixed */ + char mem_big[MR_BIG_RESERVE(8)]; /* we need 8 bigs... */ + char mem_ecp[MR_ECP_RESERVE(1)]; /* ..and one elliptic curve point */ + memset(mem_big, 0, MR_BIG_RESERVE(8)); /* clear the memory */ + memset(mem_ecp, 0, MR_ECP_RESERVE(1)); + + A=mirvar_mem(mip, mem_big, 0); /* Initialise big numbers */ + B=mirvar_mem(mip, mem_big, 1); + pa=mirvar_mem(mip, mem_big, 2); + pb=mirvar_mem(mip, mem_big, 3); + key=mirvar_mem(mip, mem_big, 4); + a=mirvar_mem(mip, mem_big, 5); + b=mirvar_mem(mip, mem_big, 6); + p=mirvar_mem(mip, mem_big, 7); + + PB=epoint_init_mem(mip, mem_ecp, 0); /* initialise Elliptic Curve points */ + + irand(mip, 6L); /* change parameter for different random numbers */ + + promptr=0; + init_big_from_rom(p,WORDS,rom,WORDS*5,&promptr); /* Read in prime modulus p from ROM */ + /*init_big_from_rom(A,WORDS,rom,WORDS*5,&promptr);*/ + convert(mip,-3,A); /* fix A=-3 */ + init_big_from_rom(B,WORDS,rom,WORDS*5,&promptr); /* Read in curve parameter B from ROM */ + /* don't need q or G(x,y) (we have precomputed table from it) */ + convert(mip,-3,A); /* set A=-3 */ + +/* Create precomputation instance from precomputed table in ROM */ + + ebrick_init(&binst,prom,A,B,p,WINDOW,CURVE_BITS); + +/* offline calculations */ + + bigbits(mip,CURVE_BITS,a); /* A's random number */ + mul_brick(mip,&binst,a,pa,pa); /* a*G =(pa,ya) */ + bigbits(mip,CURVE_BITS,b); /* B's random number */ + mul_brick(mip,&binst,b,pb,pb); /* b*G =(pb,yb) */ + +/* swap X values of point */ + +/* online calculations */ + + ecurve_init(mip,A,B,p,MR_PROJECTIVE); + epoint_set(mip,pb,pb,0,PB); /* decompress PB */ + ecurve_mult(mip,a,PB,PB); + epoint_get(mip,PB,key,key); + +/* since internal base is HEX, can use otnum instead of cotnum - avoiding a base change */ + +printf("Alice's Key= "); +otnum(mip,key,stdout); + + epoint_set(mip,pa,pa,0,PB); /* decompress PA */ + ecurve_mult(mip,b,PB,PB); + epoint_get(mip,PB,key,key); + +printf("Bob's Key= "); +otnum(mip,key,stdout); + +/* clear the memory */ + + memset(mem_big, 0, MR_BIG_RESERVE(8)); + memset(mem_ecp, 0, MR_ECP_RESERVE(1)); + + return 0; +} diff --git a/miracl/source/ecdhp8.c b/miracl/source/ecdhp8.c new file mode 100644 index 0000000..5e07869 --- /dev/null +++ b/miracl/source/ecdhp8.c @@ -0,0 +1,261 @@ +/* + +Example Elliptic Curve Diffie-Hellman program for 8-bit constrained environments. Uses point compression. +Stack-only memory allocation + +Use with this mirdef.h header (for a PC using MS C) + +#define MR_LITTLE_ENDIAN +#define MIRACL 8 +#define mr_utype char +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define mr_dltype short +#define MR_STATIC 20 +#define MR_ALWAYS_BINARY +#define MR_NOASM +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 20 +#define MR_SPECIAL +#define MR_PSEUDO_MERSENNE +#define MR_BITSINCHAR 8 +#define MR_SMALL_EWINDOW +#define MR_NO_ECC_MULTIADD +#define MR_NO_LAZY_REDUCTION +#define MR_SIMPLE_BASE +#define MR_SIMPLE_IO + +Build the library from these modules (Example using MS C compiler) + +mex 20 c mrcomba +rem In a real 8-bit setting, a suitable assembly language .mcs file would be used. Here we use C. +cl /c /O2 /W3 mrcore.c +cl /c /O2 /W3 mrarth0.c +cl /c /O2 /W3 mrarth1.c +cl /c /O2 /W3 mrio1.c +cl /c /O2 /W3 mrbits.c +cl /c /O2 /W3 mrcurve.c +cl /c /O2 /W3 mrsroot.c +cl /c /O2 /W3 mrjack.c +cl /c /O2 /W3 mrlucas.c +cl /c /O2 /W3 mrarth2.c +cl /c /O2 /W3 mrmonty.c +cl /c /O2 /W3 mrcomba.c +cl /c /O2 /W3 mrxgcd.c +cl /c /O2 /W3 mrebrick.c + +rem +rem Create library 'miracl.lib' +del miracl.lib + +lib /OUT:miracl.lib mrio1.obj mrmonty.obj mrcomba.obj mrxgcd.obj +lib /OUT:miracl.lib miracl.lib mrbits.obj mrarth2.obj mrlucas.obj mrjack.obj +lib /OUT:miracl.lib miracl.lib mrarth0.obj mrarth1.obj mrcore.obj mrebrick.obj +lib /OUT:miracl.lib miracl.lib mrcurve.obj mrsroot.obj +del mr*.obj + +rem Create the program + +cl /O2 ecdhp8.c miracl.lib + +For Atmel AVR (atmega128) use + +#define MR_LITTLE_ENDIAN +#define MIRACL 8 +#define mr_utype char +#define MR_IBITS 16 +#define MR_LBITS 32 +#define mr_unsign32 unsigned long +#define mr_dltype int +#define mr_qltype long +#define MR_STATIC 20 +#define MR_ALWAYS_BINARY +#define MR_STRIPPED_DOWN +#define MR_GENERIC_MT +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_COMBA 20 +#define MR_SPECIAL +#define MR_PSEUDO_MERSENNE +#define MR_NOASM +#define MR_BITSINCHAR 8 +#define MR_NO_STANDARD_IO +#define MR_NO_FILE_IO +#define MR_NO_LAZY_REDUCTION +#define MR_NO_ECC_MULTIADD +#define MR_SIMPLE_BASE +#define MR_SIMPLE_IO +#define MR_SMALL_EWINDOW +#define MR_AVR + +Note this last line is added manually - it will not be added by config + +and execute + +mex 20 avr4 mrcomba + +Note that reading data from program memory (NVM) is a little complex on the AVR! + +*/ + +#include +#include +#include "miracl.h" + +/* !!!!!! THIS CODE AND THESE ROMS ARE NOW CREATED AUTOMATICALLY USING THE ROMAKER.C APPLICATION !!!!!!!! */ +/* !!!!!! READ COMMENTS IN ROMAKER.C !!!!!! */ + +#define HEXDIGS (MIRACL/4) +#define CURVE_BITS 160 + +/* Pseudo Mersenne 160 bit elliptic curve Y^2=X^3-3X+383 modulo 2^160-57 + Here is stored P, B, the group order q, and the generator G(x,y) */ + + +#ifdef MR_AVR +__attribute__((__progmem__)) +#endif + +static const mr_small rom[]= +{ +0xC7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, +0x7F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +0x25,0x32,0x7F,0x71,0x4B,0x4F,0xA0,0x01,0x3F,0x0E,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF, +0xf1,0x66,0x56,0xb7,0xee,0xbf,0x27,0xd0,0x4a,0xd0,0xb7,0x9,0x20,0x4e,0x59,0xed,0x5e,0xdc,0x8a,0xa, +0xda,0xc9,0x45,0x55,0xcc,0x6c,0x1c,0x11,0x9f,0x38,0x4d,0xac,0xd3,0x43,0x76,0xaf,0x5c,0x2d,0xfb,0x20}; + +#define WINDOW 4 + +/* 16 precomputed points based on fixed generator G(x,y) */ +/* (created using romaker.c program with window size of 4) */ + +/* These values are only correct if MR_SPECIAL is defined! */ + +#ifdef MR_AVR +__attribute__((__progmem__)) +#endif +static const mr_small prom[]= +{ +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, +0xf1,0x66,0x56,0xb7,0xee,0xbf,0x27,0xd0,0x4a,0xd0,0xb7,0x9,0x20,0x4e,0x59,0xed,0x5e,0xdc,0x8a,0xa, +0xda,0xc9,0x45,0x55,0xcc,0x6c,0x1c,0x11,0x9f,0x38,0x4d,0xac,0xd3,0x43,0x76,0xaf,0x5c,0x2d,0xfb,0x20, +0xa,0xf8,0xdc,0xe5,0x96,0x7b,0xa2,0xad,0x89,0xa7,0xf2,0x19,0xfe,0xd6,0xcb,0xa0,0x91,0x44,0xaf,0xc6, +0x35,0xee,0xc1,0xa4,0x76,0xbe,0xda,0x91,0x5c,0xa3,0x6f,0xd9,0x24,0xe8,0x41,0x4f,0xe7,0x0,0xa,0x67, +0x16,0x9d,0xb1,0x30,0x2d,0xfa,0x9a,0x47,0x30,0x39,0x82,0xbb,0x39,0x7e,0x78,0x9e,0x1d,0xc9,0xa5,0x31, +0x64,0xe3,0x3,0x9b,0x4f,0xde,0x51,0x3f,0xb5,0x2,0x9f,0x68,0xe,0x65,0x3a,0x2f,0xae,0x4a,0xe9,0x79, +0xbf,0x66,0x86,0x3f,0xa0,0x5d,0x7f,0xc7,0x55,0x27,0x85,0x75,0xaa,0x9f,0x58,0x97,0x1f,0xec,0xe6,0xab, +0x92,0x36,0x32,0xf7,0x73,0x20,0x9d,0xdf,0x78,0x84,0x29,0x6d,0x3f,0x45,0x92,0xe7,0xd0,0x2d,0x64,0x2e, +0x62,0xd4,0x5d,0x1,0xe0,0x73,0x26,0xca,0xaa,0xcb,0xe7,0x87,0xf5,0xdd,0xa4,0xfe,0xd1,0xc7,0xbf,0xc7, +0x75,0x18,0x47,0xea,0x19,0xcb,0x4,0xd9,0x99,0x4f,0xc5,0x8b,0x57,0xf6,0xc0,0xe,0x11,0xaf,0x99,0x84, +0xdc,0x3b,0x49,0x31,0xb,0x77,0x55,0xdc,0x97,0xaa,0x56,0x7c,0x35,0x70,0x27,0x2c,0xd7,0xb5,0xee,0xc8, +0x4d,0x17,0x43,0xfe,0x80,0x8f,0x47,0x30,0xc2,0x83,0x91,0x94,0x17,0x65,0xa,0xfd,0x28,0xa5,0x4a,0x32, +0xb2,0x76,0xef,0xb8,0x49,0xdb,0xa,0xb0,0xb6,0x1a,0x5f,0xef,0x47,0x62,0x9f,0x37,0x7f,0xc,0xc,0x98, +0xe1,0x34,0x68,0x6b,0x46,0xe1,0x7,0x6c,0x4f,0x82,0xba,0x5d,0xf9,0xea,0xeb,0x69,0xa9,0xc2,0xa,0xa, +0x9e,0x9c,0xda,0xb0,0xfa,0xec,0x83,0xd1,0x38,0xc7,0x51,0x78,0x9d,0xe6,0xd4,0x5,0x83,0xde,0x56,0x1e, +0xf9,0x58,0xce,0x14,0x79,0xc7,0x63,0xa5,0x9b,0x10,0xf5,0x31,0x26,0x9c,0x1c,0x8b,0xba,0x7b,0x2b,0xcc, +0xdc,0x70,0xf7,0xc7,0xb5,0x3a,0xf0,0xc8,0x7d,0x5f,0x27,0xc1,0x4f,0x7b,0x26,0x84,0x8d,0xc4,0x88,0x9d, +0x7d,0x91,0xee,0x3e,0x20,0xc8,0xaf,0x22,0x5,0x47,0x58,0x4c,0x83,0xc6,0xae,0x76,0x6e,0x43,0x4b,0xd4, +0x54,0xf8,0xdf,0xa2,0xb9,0x4f,0xf5,0x83,0xfd,0x8e,0xbd,0xd7,0xf8,0xf0,0x4a,0xac,0xfa,0x13,0xa7,0xd0, +0xf3,0x25,0x61,0x4f,0x6b,0xec,0x13,0xdf,0xe1,0x4d,0x35,0x7e,0xba,0xf4,0xd9,0xa3,0xc,0x6e,0x82,0xb2, +0xf9,0xf4,0xf1,0x6d,0xce,0x72,0x63,0x7c,0x81,0x4b,0xaf,0x42,0xd8,0x85,0xa9,0xab,0xea,0xc9,0x1d,0x53, +0xb2,0xce,0xf9,0xd5,0x41,0x72,0xc8,0x5a,0x8f,0xc,0x75,0xbc,0xa9,0xf7,0x93,0xe5,0x6e,0xbe,0x76,0xd2, +0x6f,0x54,0xc9,0x15,0x86,0x48,0xe6,0x99,0xdc,0xcc,0x75,0x1a,0xfd,0xd6,0xd0,0x8c,0xcd,0x8,0xa7,0x39, +0xd0,0x64,0x2d,0xc,0xf3,0xa2,0xda,0x5d,0x96,0x76,0xf4,0x31,0x86,0xa,0x74,0xe7,0x6,0x60,0x29,0xb2, +0xbb,0xde,0x8,0x56,0x9f,0x8b,0x3f,0xff,0x30,0x4b,0xdc,0x32,0x4c,0x8f,0xb,0x63,0xd5,0x47,0x3f,0xb, +0xda,0x1c,0x77,0x84,0x5b,0x9d,0xaa,0x2f,0x77,0x6f,0xe8,0x1d,0x4e,0x69,0x6,0x8f,0x3d,0x7c,0xaf,0x7, +0xa1,0x42,0xae,0x2,0x24,0xa3,0x53,0x31,0x1f,0xe6,0x43,0x56,0x21,0x70,0x6e,0x1f,0x32,0xb3,0x17,0xe4, +0x51,0x4a,0xc0,0xd1,0xd1,0xb7,0xee,0xd6,0xc6,0xa8,0x3b,0x9a,0xe2,0xb8,0x11,0x8c,0x0,0xae,0x9b,0xdf, +0x3,0xbc,0x2c,0x78,0x5f,0xcf,0x24,0xba,0x7f,0x60,0x9,0x4c,0x8c,0x86,0xdd,0x11,0xfe,0x3f,0xe1,0xf5, +0xa0,0xb0,0x30,0xb6,0xb7,0x80,0xd8,0xb4,0x6a,0xbc,0x2e,0x43,0xaa,0x3b,0x4,0x28,0x13,0xef,0xa1,0x47}; + +#define WORDS 20 /* Number of words per big variable 20*8 = 160 */ + +/* Note that in a real application a source of real random numbers would be required, to + replace those generated by MIRACL's internal pseudo-random generator "bigbits" + Alternatively from a truly random and unguessable seed, use MIRACL's strong random + number generator */ + +/* Elliptic Curve Diffie-Hellman, using point compression to minimize bandwidth, + and precomputation to speed up off-line calculation */ + + +int main() +{ + int promptr; + epoint *PA,*PB; + big A,B,p,a,b,pa,pb,key,x,y; + ebrick binst; + miracl instance; /* create miracl workspace on the stack */ + +/* Specify base 16 here so that HEX can be read in directly without a base-change */ + + miracl *mip=mirsys(&instance,WORDS*HEXDIGS,16); /* size of bigs is fixed */ + char mem_big[MR_BIG_RESERVE(10)]; /* we need 10 bigs... */ + char mem_ecp[MR_ECP_RESERVE(2)]; /* ..and two elliptic curve points */ + memset(mem_big, 0, MR_BIG_RESERVE(10)); /* clear the memory */ + memset(mem_ecp, 0, MR_ECP_RESERVE(2)); + + A=mirvar_mem(mip, mem_big, 0); /* Initialise big numbers */ + B=mirvar_mem(mip, mem_big, 1); + pa=mirvar_mem(mip, mem_big, 2); + pb=mirvar_mem(mip, mem_big, 3); + key=mirvar_mem(mip, mem_big, 4); + x=mirvar_mem(mip, mem_big, 5); + y=mirvar_mem(mip, mem_big, 6); + a=mirvar_mem(mip, mem_big, 7); + b=mirvar_mem(mip, mem_big, 8); + p=mirvar_mem(mip, mem_big, 9); + + PA=epoint_init_mem(mip, mem_ecp, 0); /* initialise Elliptic Curve points */ + PB=epoint_init_mem(mip, mem_ecp, 1); + + irand(mip, 3L); /* change parameter for different random numbers */ + + promptr=0; + init_big_from_rom(p,WORDS,rom,WORDS*5,&promptr); /* Read in prime modulus p from ROM */ + init_big_from_rom(B,WORDS,rom,WORDS*5,&promptr); /* Read in curve parameter B from ROM */ + /* don't need q or G(x,y) (we have precomputed table from it) */ + + convert(mip,-3,A); /* set A=-3 */ + +/* Create precomputation instance from precomputed table in ROM */ + + ebrick_init(&binst,prom,A,B,p,WINDOW,CURVE_BITS); + +/* offline calculations */ + + bigbits(mip,CURVE_BITS,a); /* A's random number */ + mul_brick(mip,&binst,a,pa,pa); /* a*G =(pa,ya) */ + bigbits(mip,CURVE_BITS,b); /* B's random number */ + mul_brick(mip,&binst,b,pb,pb); /* b*G =(pb,yb) */ + +/* swap X values of point */ + +/* online calculations */ + ecurve_init(mip,A,B,p,MR_PROJECTIVE); + epoint_set(mip,pb,pb,0,PB); /* decompress PB */ + ecurve_mult(mip,a,PB,PB); + epoint_get(mip,PB,key,key); + +/* since internal base is HEX, can use otnum instead of cotnum - avoiding a base change */ +#ifndef MR_NO_STANDARD_IO +printf("Alice's Key= "); +otnum(mip,key,stdout); +#endif + epoint_set(mip,pa,pa,0,PB); /* decompress PA */ + ecurve_mult(mip,b,PB,PB); + epoint_get(mip,PB,key,key); +#ifndef MR_NO_STANDARD_IO +printf("Bob's Key= "); +otnum(mip,key,stdout); +#endif +/* clear the memory */ + + memset(mem_big, 0, MR_BIG_RESERVE(10)); + memset(mem_ecp, 0, MR_ECP_RESERVE(2)); + + return 0; +} diff --git a/miracl/source/ecn.cpp b/miracl/source/ecn.cpp new file mode 100644 index 0000000..fc2b069 --- /dev/null +++ b/miracl/source/ecn.cpp @@ -0,0 +1,194 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * + * MIRACL C++ functions ecn.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class ECn functions using Montgomery + * representation + * NOTE : Must be used in conjunction with big.h and big.cpp + */ + +#include "ecn.h" + +int ECn::get(Big& x,Big& y) const + {return epoint_get(p,x.getbig(),y.getbig());} +int ECn::get(Big& x) const + {return epoint_get(p,x.getbig(),x.getbig());} + +#ifndef MR_STATIC +void ECn::getx(Big &x) const + {epoint_getxyz(p,x.getbig(),NULL,NULL);} +void ECn::getxy(Big &x,Big &y) const + {epoint_getxyz(p,x.getbig(),y.getbig(),NULL);} +void ECn::getxyz(Big &x,Big &y, Big &z) const + {epoint_getxyz(p,x.getbig(),y.getbig(),z.getbig());} +#endif + +// ecurve_add leaves some "goodies" in w6,w7 and w8 +// Note if A=0 for the elliptic curve, ex1 doesn't return anything useful +// ex2=Z*Z, ex1=2Y^2, lam = line slope + +int ECn::add(const ECn& b,big *lam,big *ex1,big *ex2) const +{ + int r=ecurve_add(b.p,p); *lam=get_mip()->w8; + if (ex1!=NULL) *ex1=get_mip()->w7; + if (ex2!=NULL) *ex2=get_mip()->w6; + return r; +} + +int ECn::sub(const ECn& b,big *lam,big *ex1,big *ex2) const +{ + int r=ecurve_sub(b.p,p); *lam=get_mip()->w8; + if (ex1!=NULL) *ex1=get_mip()->w7; + if (ex2!=NULL) *ex2=get_mip()->w6; + return r; +} + +BOOL ECn::iszero() const + {if (p->marker==MR_EPOINT_INFINITY) return TRUE; return FALSE;} + +epoint * ECn::get_point() const +{ return p; } + +ECn operator-(const ECn& e) +{ ECn t=e; epoint_negate(t.p); return t;} + +ECn operator*(const Big& e,const ECn& b) +{ + ECn t; + ecurve_mult(e.getbig(),b.p,t.p); + return t; +} + +#ifndef MR_NO_ECC_MULTIADD + +ECn mul(const Big& e1,const ECn& p1,const Big& e2,const ECn& p2) +{ + ECn t; + ecurve_mult2(e1.getbig(),p1.get_point(),e2.getbig(),p2.get_point(),t.get_point()); + return t; +} + +#ifndef MR_STATIC + +ECn mul(int n,const Big *y,ECn *x) +{ + ECn w; + int i; + big *a=(big *)mr_alloc(n,sizeof(big)); + epoint **b=(epoint **)mr_alloc(n,sizeof(epoint *)); + for (i=0;i +#include "miracl.h" +#ifdef MR_STATIC +#include +#endif + +static inline void zzn2_div2_i(zzn2 *w) +{ + moddiv2(w->a->w); + w->a->len=2; + moddiv2(w->b->w); + w->b->len=2; +} + +static inline void zzn2_tim2_i(zzn2 *w) +{ +#ifdef MR_COUNT_OPS +fpa+=2; +#endif + + modtim2(w->a->w); + modtim2(w->b->w); + w->a->len=2; + w->b->len=2; +} + +static inline void zzn2_tim3_i(zzn2 *w) +{ +#ifdef MR_COUNT_OPS +fpa+=4; +#endif + + modtim3(w->a->w); + modtim3(w->b->w); + w->a->len=2; + w->b->len=2; +} + +static inline void zzn2_copy_i(zzn2 *x,zzn2 *w) +{ + if (x==w) return; + + w->a->len=x->a->len; + w->a->w[0]=x->a->w[0]; + w->a->w[1]=x->a->w[1]; + w->b->len=x->b->len; + w->b->w[0]=x->b->w[0]; + w->b->w[1]=x->b->w[1]; + +} + +static inline void zzn2_add_i(zzn2 *x,zzn2 *y,zzn2 *w) +{ + +#ifdef MR_COUNT_OPS +fpa+=2; +#endif + + modadd(x->a->w,y->a->w,w->a->w); + modadd(x->b->w,y->b->w,w->b->w); + w->a->len=2; + w->b->len=2; +} + +static inline void zzn2_sub_i(zzn2 *x,zzn2 *y,zzn2 *w) +{ +#ifdef MR_COUNT_OPS +fpa+=2; +#endif + modsub(x->a->w,y->a->w,w->a->w); + modsub(x->b->w,y->b->w,w->b->w); + w->a->len=2; + w->b->len=2; +} + +static inline void zzn2_timesi_i(zzn2 *u) +{ + mr_small w1[2]; + w1[0]=u->a->w[0]; + w1[1]=u->a->w[1]; + + u->a->w[0]=u->b->w[0]; + u->a->w[1]=u->b->w[1]; + + modneg(u->a->w); + + u->b->w[0]=w1[0]; + u->b->w[1]=w1[1]; +} + +static inline void zzn2_txx_i(zzn2 *u) +{ + /* multiply w by t^2 where x^2-t is irreducible polynomial for ZZn4 + + for p=5 mod 8 t=sqrt(sqrt(-2)), qnr=-2 + for p=3 mod 8 t=sqrt(1+sqrt(-1)), qnr=-1 + for p=7 mod 8 and p=2,3 mod 5 t=sqrt(2+sqrt(-1)), qnr=-1 */ + zzn2 t; + struct bigtype aa,bb; + big a,b; + mr_small w3[2],w4[2]; + a=&aa; + b=&bb; + a->len=2; + b->len=2; + a->w=w3; + b->w=w4; + t.a=a; + t.b=b; + zzn2_copy_i(u,&t); + zzn2_timesi_i(u); + zzn2_add_i(u,&t,u); + zzn2_add_i(u,&t,u); + u->a->len=2; + u->b->len=2; +} + +static inline void zzn2_pmul_i(int i,zzn2 *x) +{ + modpmul(i,x->a->w); + modpmul(i,x->b->w); +} + +static inline void zzn2_sqr_i(zzn2 *x,zzn2 *w) +{ + static mr_small w1[2],w2[2]; +#ifdef MR_COUNT_OPS +fpa+=3; +fpc+=2; +#endif + modadd(x->a->w,x->b->w,w1); + modsub(x->a->w,x->b->w,w2); + modmult(x->a->w,x->b->w,w->b->w); + modmult(w1,w2,w->a->w); // routine that calculates (a+b)(a-b) ?? + modtim2(w->b->w); + w->a->len=2; + w->b->len=2; +} + +static inline void zzn2_dblsub_i(zzn2 *x,zzn2 *y,zzn2 *w) +{ +#ifdef MR_COUNT_OPS +fpa+=4; +#endif + moddblsub(w->a->w,x->a->w,y->a->w); + moddblsub(w->b->w,x->b->w,y->b->w); + w->a->len=2; + w->b->len=2; +} + +static inline void zzn2_mul_i(zzn2 *x,zzn2 *y,zzn2 *w) +{ + static mr_small w1[2],w2[2],w5[2]; +#ifdef MR_COUNT_OPS +fpa+=5; +fpc+=3; +#endif +/*#pragma omp parallel sections +{ + #pragma omp section */ + modmult(x->a->w,y->a->w,w1); +/* #pragma omp section */ + modmult(x->b->w,y->b->w,w2); +/*}*/ + + modadd(x->a->w,x->b->w,w5); + modadd(y->a->w,y->b->w,w->b->w); + modmult(w->b->w,w5,w->b->w); + moddblsub(w->b->w,w1,w2); /* w->b->w - w1 -w2 */ + + modsub(w1,w2,w->a->w); + + w->a->len=2; + w->b->len=2; +} + +void zzn2_inv_i(_MIPD_ zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return; +#ifdef MR_COUNT_OPS +fpc+=4; +fpa+=1; +#endif + MR_IN(163) + modsqr(w->a->w,mr_mip->w1->w); + modsqr(w->b->w,mr_mip->w2->w); + modadd(mr_mip->w1->w,mr_mip->w2->w,mr_mip->w1->w); + mr_mip->w1->len=2; + + /* redc(_MIPP_ mr_mip->w1,mr_mip->w6); */ + copy(mr_mip->w1,mr_mip->w6); + + xgcd(_MIPP_ mr_mip->w6,mr_mip->modulus,mr_mip->w6,mr_mip->w6,mr_mip->w6); + +/* nres(_MIPP_ mr_mip->w6,mr_mip->w6); */ + + modmult(w->a->w,mr_mip->w6->w,w->a->w); + modneg(mr_mip->w6->w); + modmult(w->b->w,mr_mip->w6->w,w->b->w); + MR_OUT +} + +BOOL nres_sqroot(_MIPD_ big x,big w) +{ /* w=sqrt(x) mod p. This depends on p being prime! */ + int i,t,js; +#ifdef MR_COUNT_OPS +fpc+=125; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + copy(x,w); + if (size(w)==0) return TRUE; + + + copy(w,mr_mip->w1); + for (i=0;i<25;i++) + { + modsqr(w->w,w->w); + modsqr(w->w,w->w); + modsqr(w->w,w->w); + modsqr(w->w,w->w); + modsqr(w->w,w->w); + } + w->len=2; + + modsqr(w->w,mr_mip->w2->w); + mr_mip->w2->len=2; + if (mr_compare(mr_mip->w1,mr_mip->w2)!=0) {zero(w);return FALSE;} + + + return TRUE; + +} + +BOOL zzn2_sqrt(_MIPD_ zzn2 *u,zzn2 *w) +{ /* sqrt(a+ib) = sqrt(a+sqrt(a*a-n*b*b)/2)+ib/(2*sqrt(a+sqrt(a*a-n*b*b)/2)) + where i*i=n */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_COUNT_OPS +fpc+=2; +fpa+=1; +#endif + if (mr_mip->ERNUM) return FALSE; + + zzn2_copy(u,w); + if (zzn2_iszero(w)) return TRUE; + + MR_IN(204) + + modsqr(w->b->w,mr_mip->w7->w); + modsqr(w->a->w,mr_mip->w1->w); + modadd(mr_mip->w1->w,mr_mip->w7->w,mr_mip->w7->w); + mr_mip->w7->len=2; + +// nres_modmult(_MIPP_ w->b,w->b,mr_mip->w7); +// nres_modmult(_MIPP_ w->a,w->a,mr_mip->w1); +// nres_modadd(_MIPP_ mr_mip->w7,mr_mip->w1,mr_mip->w7); + + if (!nres_sqroot(_MIPP_ mr_mip->w7,mr_mip->w7)) /* s=w7 */ + { + zzn2_zero(w); + MR_OUT + return FALSE; + } +#ifdef MR_COUNT_OPS +fpa+=1; +#endif + modadd(w->a->w,mr_mip->w7->w,mr_mip->w15->w); + moddiv2(mr_mip->w15->w); + mr_mip->w15->len=2; + +// nres_modadd(_MIPP_ w->a,mr_mip->w7,mr_mip->w15); +// nres_div2(_MIPP_ mr_mip->w15,mr_mip->w15); + + if (!nres_sqroot(_MIPP_ mr_mip->w15,mr_mip->w15)) + { +#ifdef MR_COUNT_OPS +fpa+=1; +#endif + modsub(w->a->w,mr_mip->w7->w,mr_mip->w15->w); + moddiv2(mr_mip->w15->w); + mr_mip->w15->len=2; + + + // nres_modsub(_MIPP_ w->a,mr_mip->w7,mr_mip->w15); + // nres_div2(_MIPP_ mr_mip->w15,mr_mip->w15); + if (!nres_sqroot(_MIPP_ mr_mip->w15,mr_mip->w15)) + { + zzn2_zero(w); + MR_OUT + return FALSE; + } +// else printf("BBBBBBBBBBBBBBBBBB\n"); + } +// else printf("AAAAAAAAAAAAAAAAAAA\n"); +#ifdef MR_COUNT_OPS +fpa+=1; +#endif + copy(mr_mip->w15,w->a); + modadd(mr_mip->w15->w,mr_mip->w15->w,mr_mip->w15->w); + nres_moddiv(_MIPP_ w->b,mr_mip->w15,w->b); + + MR_OUT + return TRUE; +} + +/* +BOOL zzn2_multi_inverse(_MIPD_ int m,zzn2 *x,zzn2 *w) +{ + int i; + zzn2 t1,t2; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (m==0) return TRUE; + if (m<0) return FALSE; + MR_IN(214) + + if (x==w) + { + mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + MR_OUT + return FALSE; + } + + if (m==1) + { + zzn2_copy_i(&x[0],&w[0]); + zzn2_inv_i(_MIPP_ &w[0]); + + MR_OUT + return TRUE; + } + + zzn2_from_int(_MIPP_ 1,&w[0]); + zzn2_copy_i(&x[0],&w[1]); + + for (i=2;iw8; + t1.b=mr_mip->w9; + t2.a=mr_mip->w10; + t2.b=mr_mip->w11; + + zzn2_mul_i(&w[m-1],&x[m-1],&t1); + if (zzn2_iszero(&t1)) + { + mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); + MR_OUT + return FALSE; + } + + zzn2_inv_i(_MIPP_ &t1); + + zzn2_copy_i(&x[m-1],&t2); + zzn2_mul_i(&w[m-1],&t1,&w[m-1]); + + for (i=m-2;;i--) + { + if (i==0) + { + zzn2_mul_i(&t2,&t1,&w[0]); + break; + } + zzn2_mul_i(&w[i],&t2,&w[i]); + zzn2_mul_i(&w[i],&t1,&w[i]); + if (!zzn2_isunity(_MIPP_ &x[i])) zzn2_mul_i(&t2,&x[i],&t2); + } + + MR_OUT + return TRUE; +} + +*/ + +BOOL ecn2_iszero(ecn2 *a) +{ + if (a->marker==MR_EPOINT_INFINITY) return TRUE; + return FALSE; +} + +void ecn2_copy(ecn2 *a,ecn2 *b) +{ + zzn2_copy_i(&(a->x),&(b->x)); + zzn2_copy_i(&(a->y),&(b->y)); +#ifndef MR_AFFINE_ONLY + if (a->marker==MR_EPOINT_GENERAL) zzn2_copy_i(&(a->z),&(b->z)); +#endif + b->marker=a->marker; +} + +void ecn2_zero(ecn2 *a) +{ + zzn2_zero(&(a->x)); zzn2_zero(&(a->y)); +#ifndef MR_AFFINE_ONLY + if (a->marker==MR_EPOINT_GENERAL) zzn2_zero(&(a->z)); +#endif + a->marker=MR_EPOINT_INFINITY; +} + +BOOL ecn2_compare(_MIPD_ ecn2 *a,ecn2 *b) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(193) + ecn2_norm(_MIPP_ a); + ecn2_norm(_MIPP_ b); + MR_OUT + if (zzn2_compare(&(a->x),&(b->x)) && zzn2_compare(&(a->y),&(b->y)) && a->marker==b->marker) return TRUE; + return FALSE; +} + +void ecn2_norm(_MIPD_ ecn2 *a) +{ + zzn2 t; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifndef MR_AFFINE_ONLY + if (mr_mip->ERNUM) return; + if (a->marker!=MR_EPOINT_GENERAL) return; + + MR_IN(194) + + zzn2_inv_i(_MIPP_ &(a->z)); + + t.a=mr_mip->w3; + t.b=mr_mip->w4; + zzn2_copy_i(&(a->z),&t); + + zzn2_sqr_i( &(a->z),&(a->z)); + zzn2_mul_i( &(a->x),&(a->z),&(a->x)); + zzn2_mul_i( &(a->z),&t,&(a->z)); + zzn2_mul_i( &(a->y),&(a->z),&(a->y)); + zzn2_from_int(_MIPP_ 1,&(a->z)); + a->marker=MR_EPOINT_NORMALIZED; + + MR_OUT +#endif +} + +void ecn2_get(_MIPD_ ecn2 *e,zzn2 *x,zzn2 *y,zzn2 *z) +{ + zzn2_copy_i(&(e->x),x); + zzn2_copy_i(&(e->y),y); +#ifndef MR_AFFINE_ONLY + if (e->marker==MR_EPOINT_GENERAL) zzn2_copy_i(&(e->z),z); + else zzn2_from_zzn(mr_mip->one,z); +#endif +} + +void ecn2_getxy(ecn2 *e,zzn2 *x,zzn2 *y) +{ + zzn2_copy_i(&(e->x),x); + zzn2_copy_i(&(e->y),y); +} + +void ecn2_getx(ecn2 *e,zzn2 *x) +{ + zzn2_copy_i(&(e->x),x); +} + +inline void zzn2_conj_i(zzn2 *x,zzn2 *w) +{ + zzn2_copy_i(x,w); + modneg(w->b->w); +} + +void ecn2_psi(_MIPD_ zzn2 *psi,ecn2 *P) +{ + ecn2_norm(_MIPP_ P); + zzn2_conj_i(&(P->x),&(P->x)); + zzn2_conj_i(&(P->y),&(P->y)); + zzn2_mul_i(&(P->x),&psi[0],&(P->x)); + zzn2_mul_i(&(P->y),&psi[1],&(P->y)); + +} + +#ifndef MR_AFFINE_ONLY +void ecn2_getz(_MIPD_ ecn2 *e,zzn2 *z) +{ + if (e->marker==MR_EPOINT_GENERAL) zzn2_copy_i(&(e->z),z); + else zzn2_from_zzn(mr_mip->one,z); +} +#endif + +void ecn2_rhs(_MIPD_ zzn2 *x,zzn2 *rhs) +{ /* calculate RHS of elliptic curve equation */ + BOOL twist; + zzn2 A,B; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + twist=mr_mip->TWIST; + + MR_IN(202) + + A.a=mr_mip->w10; + A.b=mr_mip->w11; + B.a=mr_mip->w12; + B.b=mr_mip->w13; + + if (mr_abs(mr_mip->Asize)Asize,&A); + else zzn2_from_zzn(mr_mip->A,&A); + + if (mr_abs(mr_mip->Bsize)Bsize,&B); + else zzn2_from_zzn(mr_mip->B,&B); + + if (twist) + { + if (mr_mip->Asize==0 || mr_mip->Bsize==0) + { + if (mr_mip->Asize==0) + { + zzn2_txd(_MIPP_ &B); + } + if (mr_mip->Bsize==0) + { + zzn2_mul_i( &A,x,&B); + zzn2_txd(_MIPP_ &B); + } + zzn2_negate(_MIPP_ &B,&B); + } + else + { + zzn2_txx_i(&B); + zzn2_txx_i(&B); + zzn2_txx_i(&B); + zzn2_mul_i( &A,x,&A); + zzn2_txx_i(&A); + zzn2_txx_i(&A); + zzn2_add_i(&B,&A,&B); + } + } + else + { + zzn2_mul_i( &A,x,&A); + zzn2_add_i(&B,&A,&B); + } + + zzn2_sqr_i( x,&A); + zzn2_mul_i( &A,x,&A); + zzn2_add_i(&B,&A,rhs); + + MR_OUT +} + +BOOL ecn2_set(_MIPD_ zzn2 *x,zzn2 *y,ecn2 *e) +{ + zzn2 lhs,rhs; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(195) + + lhs.a=mr_mip->w10; + lhs.b=mr_mip->w11; + rhs.a=mr_mip->w12; + rhs.b=mr_mip->w13; + + ecn2_rhs(_MIPP_ x,&rhs); + + zzn2_sqr_i( y,&lhs); + + if (!zzn2_compare(&lhs,&rhs)) + { + MR_OUT + return FALSE; + } + + zzn2_copy_i(x,&(e->x)); + zzn2_copy_i(y,&(e->y)); + + e->marker=MR_EPOINT_NORMALIZED; + + MR_OUT + return TRUE; +} + +#ifndef MR_NOSUPPORT_COMPRESSION + +BOOL ecn2_setx(_MIPD_ zzn2 *x,ecn2 *e) +{ + zzn2 rhs; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(201) + + rhs.a=mr_mip->w12; + rhs.b=mr_mip->w13; + + ecn2_rhs(_MIPP_ x,&rhs); + + if (!zzn2_iszero(&rhs)) + { + if (!zzn2_sqrt(_MIPP_ &rhs,&rhs)) + { + MR_OUT + return FALSE; + } + } + + zzn2_copy_i(x,&(e->x)); + zzn2_copy_i(&rhs,&(e->y)); + + e->marker=MR_EPOINT_NORMALIZED; + + MR_OUT + return TRUE; +} + +#endif + +#ifndef MR_AFFINE_ONLY +void ecn2_setxyz(zzn2 *x,zzn2 *y,zzn2 *z,ecn2 *e) +{ + zzn2_copy_i(x,&(e->x)); + zzn2_copy_i(y,&(e->y)); + zzn2_copy_i(z,&(e->z)); + e->marker=MR_EPOINT_GENERAL; +} +#endif + +void ecn2_negate(_MIPD_ ecn2 *u,ecn2 *w) +{ + ecn2_copy(u,w); + if (!w->marker!=MR_EPOINT_INFINITY) + zzn2_negate(_MIPP_ &(w->y),&(w->y)); +} +/* +BOOL ecn2_add2(_MIPD_ ecn2 *Q,ecn2 *P,zzn2 *lam,zzn2 *ex1) +{ + BOOL Doubling; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + Doubling=ecn2_add3(_MIPP_ Q,P,lam,ex1,NULL); + + return Doubling; +} + +BOOL ecn2_add1(_MIPD_ ecn2 *Q,ecn2 *P,zzn2 *lam) +{ + BOOL Doubling; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + Doubling=ecn2_add3(_MIPP_ Q,P,lam,NULL,NULL); + + return Doubling; +} +*/ + +BOOL ecn2_sub(_MIPD_ ecn2 *Q,ecn2 *P) +{ + BOOL Doubling; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + ecn2_negate(_MIPP_ Q,Q); + + Doubling=ecn2_add(_MIPP_ Q,P); + + ecn2_negate(_MIPP_ Q,Q); + + return Doubling; +} + +/* +static void zzn2_print(_MIPD_ char *label, zzn2 *x) +{ + char s1[1024], s2[1024]; + big a, b; + +#ifdef MR_STATIC + char mem_big[MR_BIG_RESERVE(2)]; + memset(mem_big, 0, MR_BIG_RESERVE(2)); + a=mirvar_mem(_MIPP_ mem_big,0); + b=mirvar_mem(_MIPP_ mem_big,1); +#else + a = mirvar(_MIPP_ 0); + b = mirvar(_MIPP_ 0); +#endif + redc(_MIPP_ x->a, a); otstr(_MIPP_ a, s1); + redc(_MIPP_ x->b, b); otstr(_MIPP_ b, s2); + + printf("%s: [%s,%s]\n", label, s1, s2); +#ifndef MR_STATIC + mr_free(a); mr_free(b); +#endif +} + +static void nres_print(_MIPD_ char *label, big x) +{ + char s[1024]; + big a; + + a = mirvar(_MIPP_ 0); + + redc(_MIPP_ x, a); + otstr(_MIPP_ a, s); + + printf("%s: %s\n", label, s); + + mr_free(a); +} +*/ + +BOOL ecn2_add_sub(_MIPD_ ecn2 *P,ecn2 *Q,ecn2 *PP,ecn2 *PM) +{ /* PP=P+Q, PM=P-Q. Assumes P and Q are both normalized, and P!=Q */ + #ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zzn2 t1,t2,lam; + + if (mr_mip->ERNUM) return FALSE; + + MR_IN(211) + + if (P->marker==MR_EPOINT_GENERAL || P->marker==MR_EPOINT_GENERAL) + { /* Sorry, some restrictions.. */ + mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + MR_OUT + return FALSE; + } + + if (zzn2_compare(&(P->x),&(Q->x))) + { /* P=Q or P=-Q - shouldn't happen */ + ecn2_copy(P,PP); + ecn2_add(_MIPP_ Q,PP); + ecn2_copy(P,PM); + ecn2_sub(_MIPP_ Q,PM); + + MR_OUT + return TRUE; + } + + t1.a = mr_mip->w8; + t1.b = mr_mip->w9; + t2.a = mr_mip->w10; + t2.b = mr_mip->w11; + lam.a = mr_mip->w12; + lam.b = mr_mip->w13; + + zzn2_copy_i(&(P->x),&t2); + zzn2_sub_i(&t2,&(Q->x),&t2); + zzn2_inv_i(_MIPP_ &t2); /* only one inverse required */ + zzn2_add_i(&(P->x),&(Q->x),&(PP->x)); + zzn2_copy_i(&(PP->x),&(PM->x)); + + zzn2_copy_i(&(P->y),&t1); + zzn2_sub_i(&t1,&(Q->y),&t1); + zzn2_copy_i(&t1,&lam); + zzn2_mul_i( &lam,&t2,&lam); + zzn2_copy_i(&lam,&t1); + zzn2_sqr_i( &t1,&t1); + zzn2_sub_i(&t1,&(PP->x),&(PP->x)); + zzn2_copy_i(&(Q->x),&(PP->y)); + zzn2_sub_i(&(PP->y),&(PP->x),&(PP->y)); + zzn2_mul_i( &(PP->y),&lam,&(PP->y)); + zzn2_sub_i(&(PP->y),&(Q->y),&(PP->y)); + + zzn2_copy_i(&(P->y),&t1); + zzn2_add_i(&t1,&(Q->y),&t1); + zzn2_copy_i(&t1,&lam); + zzn2_mul_i( &lam,&t2,&lam); + zzn2_copy_i(&lam,&t1); + zzn2_sqr_i( &t1,&t1); + zzn2_sub_i(&t1,&(PM->x),&(PM->x)); + zzn2_copy_i(&(Q->x),&(PM->y)); + zzn2_sub_i(&(PM->y),&(PM->x),&(PM->y)); + zzn2_mul_i( &(PM->y),&lam,&(PM->y)); + zzn2_add_i(&(PM->y),&(Q->y),&(PM->y)); + + PP->marker=MR_EPOINT_NORMALIZED; + PM->marker=MR_EPOINT_NORMALIZED; + + MR_OUT + return TRUE; +} + +BOOL ecn2_add(_MIPD_ ecn2 *Q,ecn2 *P) +{ /* P+=Q */ + BOOL Doubling=FALSE; + BOOL twist; + int iA; + zzn2 t1,t2,t3,lam; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + t1.a = mr_mip->w8; + t1.b = mr_mip->w9; + t2.a = mr_mip->w10; + t2.b = mr_mip->w11; + t3.a = mr_mip->w12; + t3.b = mr_mip->w13; + lam.a = mr_mip->w14; + lam.b = mr_mip->w15; + + + twist=mr_mip->TWIST; + if (mr_mip->ERNUM) return FALSE; + + if (P->marker==MR_EPOINT_INFINITY) + { + ecn2_copy(Q,P); + return Doubling; + } + if (Q->marker==MR_EPOINT_INFINITY) return Doubling; + + MR_IN(205) + + if (Q!=P && Q->marker==MR_EPOINT_GENERAL) + { /* Sorry, this code is optimized for mixed addition only */ + mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + MR_OUT + return Doubling; + } +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { +#endif + if (!zzn2_compare(&(P->x),&(Q->x))) + { + zzn2_copy_i(&(P->y),&t1); + zzn2_sub_i(&t1,&(Q->y),&t1); + zzn2_copy_i(&(P->x),&t2); + zzn2_sub_i(&t2,&(Q->x),&t2); + zzn2_copy_i(&t1,&lam); + zzn2_inv_i(_MIPP_ &t2); + zzn2_mul_i( &lam,&t2,&lam); + + zzn2_add_i(&(P->x),&(Q->x),&(P->x)); + zzn2_copy_i(&lam,&t1); + zzn2_sqr_i( &t1,&t1); + zzn2_sub_i(&t1,&(P->x),&(P->x)); + + zzn2_copy_i(&(Q->x),&(P->y)); + zzn2_sub_i(&(P->y),&(P->x),&(P->y)); + zzn2_mul_i( &(P->y),&lam,&(P->y)); + zzn2_sub_i(&(P->y),&(Q->y),&(P->y)); + } + else + { + if (!zzn2_compare(&(P->y),&(Q->y)) || zzn2_iszero(&(P->y))) + { + ecn2_zero(P); + zzn2_from_int(_MIPP_ 1,&lam); + MR_OUT + return Doubling; + } + zzn2_copy_i(&(P->x),&t1); + zzn2_copy_i(&(P->x),&t2); + zzn2_copy_i(&(P->x),&lam); + zzn2_sqr_i( &lam,&lam); + + zzn2_copy_i(&lam,&t3); + zzn2_tim2_i(&t3); + zzn2_add_i(&lam,&t3,&lam); + + if (mr_abs(mr_mip->Asize)Asize,&t3); + else zzn2_from_zzn(mr_mip->A,&t3); + + if (twist) + { + zzn2_txx_i(&t3); + zzn2_txx_i(&t3); + } + zzn2_add_i(&lam,&t3,&lam); + zzn2_copy_i(&(P->y),&t3); + zzn2_tim2_i(&t3); + zzn2_inv_i(_MIPP_ &t3); + zzn2_mul_i( &lam,&t3,&lam); + + zzn2_add_i(&t2,&(P->x),&t2); + zzn2_copy_i(&lam,&(P->x)); + zzn2_sqr_i( &(P->x),&(P->x)); + zzn2_sub_i(&(P->x),&t2,&(P->x)); + zzn2_sub_i(&t1,&(P->x),&t1); + zzn2_mul_i( &t1,&lam,&t1); + zzn2_sub_i(&t1,&(P->y),&(P->y)); + } +#ifndef MR_AFFINE_ONLY + zzn2_from_int(_MIPP_ 1,&(P->z)); +#endif + P->marker=MR_EPOINT_NORMALIZED; + MR_OUT + return Doubling; +#ifndef MR_AFFINE_ONLY + } + + if (Q==P) Doubling=TRUE; + + if (!Doubling) + { + if (P->marker!=MR_EPOINT_NORMALIZED) + { + zzn2_sqr_i(&(P->z),&t1); + zzn2_mul_i(&t1,&(P->z),&t2); + zzn2_mul_i(&t1,&(Q->x),&t1); + zzn2_mul_i(&t2,&(Q->y),&t2); + // zzn2_sqr_i( &(P->z),&t1); /* 1S */ + // zzn2_mul_i( &t3,&t1,&t3); /* 1M */ + // zzn2_mul_i( &t1,&(P->z),&t1); /* 1M */ + // zzn2_mul_i( &Yzzz,&t1,&Yzzz); /* 1M */ + } + else + { + zzn2_copy(&(Q->x),&t1); + zzn2_copy(&(Q->y),&t2); + } + if (zzn2_compare(&t1,&(P->x))) /*?*/ + { + if (!zzn2_compare(&t2,&(P->y)) || zzn2_iszero(&(P->y))) + { + ecn2_zero(P); + zzn2_from_int(_MIPP_ 1,&lam); + MR_OUT + return Doubling; + } + else Doubling=TRUE; + } + } + + if (!Doubling) + { /* Addition */ + zzn2_sub_i(&t1,&(P->x),&t1); + zzn2_sub_i(&t2,&(P->y),&t2); + if (P->marker==MR_EPOINT_NORMALIZED) zzn2_copy_i(&t1,&(P->z)); + else zzn2_mul_i(&(P->z),&t1,&(P->z)); + zzn2_sqr_i(&t1,&t3); + zzn2_mul_i(&t3,&t1,&lam); + zzn2_mul_i(&t3,&(P->x),&t3); + zzn2_copy_i(&t3,&t1); + zzn2_tim2_i(&t1); + zzn2_sqr_i(&t2,&(P->x)); + zzn2_dblsub_i(&t1,&lam,&(P->x)); + zzn2_sub_i(&t3,&(P->x),&t3); + zzn2_mul_i(&t3,&t2,&t3); + zzn2_mul_i(&lam,&(P->y),&lam); + zzn2_sub_i(&t3,&lam,&(P->y)); + } + else + { /* doubling */ + if (P->marker==MR_EPOINT_NORMALIZED) zzn2_from_int(_MIPP_ 1,&t1); + else zzn2_sqr_i(&(P->z),&t1); + if (twist) zzn2_txx_i(&t1); + zzn2_sub_i(&(P->x),&t1,&t2); + zzn2_add_i(&t1,&(P->x),&t1); + zzn2_mul_i(&t2,&t1,&t2); + zzn2_tim3_i(&t2); + + zzn2_tim2_i(&(P->y)); + if (P->marker==MR_EPOINT_NORMALIZED) zzn2_copy_i(&(P->y),&(P->z)); + else zzn2_mul_i(&(P->z),&(P->y),&(P->z)); + zzn2_sqr_i(&(P->y),&(P->y)); + zzn2_mul_i(&(P->y),&(P->x),&t3); + zzn2_sqr_i(&(P->y),&(P->y)); + zzn2_div2_i(&(P->y)); + zzn2_sqr_i(&t2,&(P->x)); + zzn2_copy_i(&t3,&t1); + zzn2_tim2_i(&t1); + zzn2_sub_i(&(P->x),&t1,&(P->x)); + zzn2_sub_i(&t3,&(P->x),&t1); + zzn2_mul_i(&t1,&t2,&t1); + zzn2_sub_i(&t1,&(P->y),&(P->y)); + } + + P->marker=MR_EPOINT_GENERAL; + MR_OUT + return Doubling; +#endif +} + +static int calc_n(int w) +{ /* number of precomputed values needed for given window size */ + if (w==3) return 3; + if (w==4) return 5; + if (w==5) return 11; + if (w==6) return 41; + return 0; +} + +/* Dahmen, Okeya and Schepers "Affine Precomputation with Sole Inversion in Elliptic Curve Cryptography" */ +/* Precomputes table into T. Assumes first P has been copied to P[0], then calculates 3P, 5P, 7P etc. into T */ + +#define MR_DOS_2 (14+4*MR_STR_SZ_2P) + +static void ecn2_dos(_MIPD_ int win,ecn2 *PT) +{ + BOOL twist; + int i,j,sz; + zzn2 A,B,C,D,E,T,W,d[MR_STR_SZ_2P],e[MR_STR_SZ_2P]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + +#ifndef MR_STATIC + char *mem = memalloc(_MIPP_ MR_DOS_2); +#else + char mem[MR_BIG_RESERVE(MR_DOS_2)]; + memset(mem, 0, MR_BIG_RESERVE(MR_DOS_2)); +#endif + + twist=mr_mip->TWIST; + j=0; + sz=calc_n(win); + + A.a= mirvar_mem(_MIPP_ mem, j++); + A.b= mirvar_mem(_MIPP_ mem, j++); + B.a= mirvar_mem(_MIPP_ mem, j++); + B.b= mirvar_mem(_MIPP_ mem, j++); + C.a= mirvar_mem(_MIPP_ mem, j++); + C.b= mirvar_mem(_MIPP_ mem, j++); + D.a= mirvar_mem(_MIPP_ mem, j++); + D.b= mirvar_mem(_MIPP_ mem, j++); + E.a= mirvar_mem(_MIPP_ mem, j++); + E.b= mirvar_mem(_MIPP_ mem, j++); + T.a= mirvar_mem(_MIPP_ mem, j++); + T.b= mirvar_mem(_MIPP_ mem, j++); + W.a= mirvar_mem(_MIPP_ mem, j++); + W.b= mirvar_mem(_MIPP_ mem, j++); + + for (i=0;iAsize)Asize,&A); + else zzn2_from_zzn(mr_mip->A,&A); + + if (twist) + { + zzn2_txx_i(&A); + zzn2_txx_i(&A); + } + zzn2_add_i(&A,&T,&A); /* 3. A=3x^2+a */ + zzn2_copy_i(&A,&W); + + zzn2_add_i(&C,&C,&B); + zzn2_add_i(&B,&C,&B); + zzn2_mul_i(&B,&(PT[0].x),&B); /* 4. B=3C.x */ + + zzn2_sqr_i(&A,&d[1]); + zzn2_sub_i(&d[1],&B,&d[1]); /* 5. d_1=A^2-B */ + + zzn2_sqr_i(&d[1],&E); /* 6. E=d_1^2 */ + + zzn2_mul_i(&B,&E,&B); /* 7. B=E.B */ + + zzn2_sqr_i(&C,&C); /* 8. C=C^2 */ + + zzn2_mul_i(&E,&d[1],&D); /* 9. D=E.d_1 */ + + zzn2_mul_i(&A,&d[1],&A); + zzn2_add_i(&A,&C,&A); + zzn2_negate(_MIPP_ &A,&A); /* 10. A=-d_1*A-C */ + + zzn2_add_i(&D,&D,&T); + zzn2_sqr_i(&A,&d[2]); + zzn2_sub_i(&d[2],&T,&d[2]); + zzn2_sub_i(&d[2],&B,&d[2]); /* 11. d_2=A^2-2D-B */ + + if (sz>3) + { + zzn2_sqr_i(&d[2],&E); /* 12. E=d_2^2 */ + + zzn2_add_i(&T,&D,&T); + zzn2_add_i(&T,&B,&T); + zzn2_mul_i(&T,&E,&B); /* 13. B=E(B+3D) */ + + zzn2_add_i(&A,&A,&T); + zzn2_add_i(&C,&T,&C); + zzn2_mul_i(&C,&D,&C); /* 14. C=D(2A+C) */ + + zzn2_mul_i(&d[2],&E,&D); /* 15. D=E.d_2 */ + + zzn2_mul_i(&A,&d[2],&A); + zzn2_add_i(&A,&C,&A); + zzn2_negate(_MIPP_ &A,&A); /* 16. A=-d_2*A-C */ + + + zzn2_sqr_i(&A,&d[3]); + zzn2_sub_i(&d[3],&D,&d[3]); + zzn2_sub_i(&d[3],&B,&d[3]); /* 17. d_3=A^2-D-B */ + + for (i=4;i0;i--) + { + zzn2_copy_i(&d[i],&B); + zzn2_mul_i(&e[i-1],&A,&d[i]); + zzn2_mul_i(&A,&B,&A); + } + zzn2_copy_i(&A,&d[0]); + + for (i=1;i=1;) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + n=mr_naf_window(_MIPP_ k,h,i,&nbs,&nzs,MR_WIN_SZ_2); + + for (j=0;j0) {nadds++; ecn2_add(_MIPP_ &T[n/2],P);} + if (n<0) {nadds++; ecn2_sub(_MIPP_ &T[(-n)/2],P);} + i-=nbs; + if (nzs) + { + for (j=0;j0) bb=logb2(_MIPP_ e)-1; + else bb=logb2(_MIPP_ f)-1; + + ecn2_add_sub(_MIPP_ &P1,&P2,&PS,&PD); + ecn2_zero(R); + nadds=0; + while (bb>=0) + { /* add/subtract method */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + ecn2_add(_MIPP_ R,R); + e1=h1=e2=h2=0; + + if (mr_testbit(_MIPP_ d,bb)) e2=1; + if (mr_testbit(_MIPP_ e,bb)) h2=1; + if (mr_testbit(_MIPP_ c,bb)) e1=1; + if (mr_testbit(_MIPP_ f,bb)) h1=1; + + if (e1!=h1) + { + if (e2==h2) + { + if (h1==1) {ecn2_add(_MIPP_ &P1,R); nadds++;} + else {ecn2_sub(_MIPP_ &P1,R); nadds++;} + } + else + { + if (h1==1) + { + if (h2==1) {ecn2_add(_MIPP_ &PS,R); nadds++;} + else {ecn2_add(_MIPP_ &PD,R); nadds++;} + } + else + { + if (h2==1) {ecn2_sub(_MIPP_ &PD,R); nadds++;} + else {ecn2_sub(_MIPP_ &PS,R); nadds++;} + } + } + } + else if (e2!=h2) + { + if (h2==1) {ecn2_add(_MIPP_ &P2,R); nadds++;} + else {ecn2_sub(_MIPP_ &P2,R); nadds++;} + } + bb-=1; + } + ecn2_norm(_MIPP_ R); + + MR_OUT +#ifndef MR_STATIC + memkill(_MIPP_ mem, MR_MUL2_JSF_RESERVE); +#else + memset(mem, 0, MR_BIG_RESERVE(MR_MUL2_JSF_RESERVE)); +#endif + return nadds; + +} + +/* General purpose multi-exponentiation engine, using inter-leaving algorithm. Calculate aP+bQ+cR+dS... + Inputs are divided into two groups of sizes wa<4 and wb<4. For the first group if the points are fixed the + first precomputed Table Ta[] may be taken from ROM. For the second group if the points are variable Tb[j] will + have to computed online. Each group has its own window size, wina (=5?) and winb (=4?) respectively. The values + a,b,c.. are provided in ma[] and mb[], and 3.a,3.b,3.c (as required by the NAF) are provided in ma3[] and + mb3[]. If only one group is required, set wb=0 and pass NULL pointers. + */ + +int ecn2_muln_engine(_MIPD_ int wa,int wina,int wb,int winb,big *ma,big *ma3,big *mb,big *mb3,ecn2 *Ta,ecn2 *Tb,ecn2 *R) +{ /* general purpose interleaving algorithm engine for multi-exp */ + int i,j,tba[4],pba[4],na[4],sa[4],tbb[4],pbb[4],nb[4],sb[4],nbits,nbs,nzs; + int sza,szb,nadds; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + sza=calc_n(wina); + szb=calc_n(winb); + + ecn2_zero(R); + + nbits=0; + for (i=0;inbits) nbits=j; } + for (i=0;inbits) nbits=j; } + + nadds=0; + for (i=nbits-1;i>=1;i--) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + if (R->marker!=MR_EPOINT_INFINITY) ecn2_add(_MIPP_ R,R); + for (j=0;j0) {ecn2_add(_MIPP_ &Ta[j*sza+na[j]/2],R); nadds++;} + if (na[j]<0) {ecn2_sub(_MIPP_ &Ta[j*sza+(-na[j])/2],R); nadds++;} + } + else + { + if (na[j]>0) {ecn2_sub(_MIPP_ &Ta[j*sza+na[j]/2],R); nadds++;} + if (na[j]<0) {ecn2_add(_MIPP_ &Ta[j*sza+(-na[j])/2],R); nadds++;} + } + } + } + for (j=0;j0) {ecn2_add(_MIPP_ &Tb[j*szb+nb[j]/2],R); nadds++;} + if (nb[j]<0) {ecn2_sub(_MIPP_ &Tb[j*szb+(-nb[j])/2],R); nadds++;} + } + else + { + if (nb[j]>0) {ecn2_sub(_MIPP_ &Tb[j*szb+nb[j]/2],R); nadds++;} + if (nb[j]<0) {ecn2_add(_MIPP_ &Tb[j*szb+(-nb[j])/2],R); nadds++;} + } + } + } + } + ecn2_norm(_MIPP_ R); + return nadds; +} + +/* Routines to support Galbraith, Lin, Scott (GLS) method for ECC */ +/* requires an endomorphism psi */ + +/* *********************** */ + +/* Precompute T - first half from i.P, second half from i.psi(P) */ + +void ecn2_precomp_gls(_MIPD_ int win,ecn2 *P,zzn2 *psi,ecn2 *T) +{ + int i,j,sz; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + j=0; + sz=calc_n(win); + + MR_IN(219) + + ecn2_norm(_MIPP_ P); + ecn2_copy(P,&T[0]); + + ecn2_dos(_MIPP_ win,T); /* precompute table */ + + for (i=sz;inb || mr_mip->ERNUM) return FALSE; + + t=MR_ROUNDUP(nb,window); + + if (t<2) return FALSE; + + MR_IN(221) + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base != mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return FALSE; + } +#endif + + B->window=window; + B->max=nb; + table=mr_alloc(_MIPP_ (1<a=mirvar(_MIPP_ 0); + B->b=mirvar(_MIPP_ 0); + B->n=mirvar(_MIPP_ 0); + copy(a,B->a); + copy(b,B->b); + copy(n,B->n); + + ecurve_init(_MIPP_ a,b,n,MR_AFFINE); + mr_mip->TWIST=TRUE; + + w.x.a=mirvar(_MIPP_ 0); + w.x.b=mirvar(_MIPP_ 0); + w.y.a=mirvar(_MIPP_ 0); + w.y.b=mirvar(_MIPP_ 0); + w.marker=MR_EPOINT_INFINITY; + ecn2_set(_MIPP_ x,y,&w); + + table[0].x.a=mirvar(_MIPP_ 0); + table[0].x.b=mirvar(_MIPP_ 0); + table[0].y.a=mirvar(_MIPP_ 0); + table[0].y.b=mirvar(_MIPP_ 0); + table[0].marker=MR_EPOINT_INFINITY; + table[1].x.a=mirvar(_MIPP_ 0); + table[1].x.b=mirvar(_MIPP_ 0); + table[1].y.a=mirvar(_MIPP_ 0); + table[1].y.b=mirvar(_MIPP_ 0); + table[1].marker=MR_EPOINT_INFINITY; + + ecn2_copy(&w,&table[1]); + for (j=0;jlen; + bptr=0; + B->table=mr_alloc(_MIPP_ 4*len*(1<table[bptr++]=table[i].x.a->w[j]; + for (j=0;jtable[bptr++]=table[i].x.b->w[j]; + + for (j=0;jtable[bptr++]=table[i].y.a->w[j]; + for (j=0;jtable[bptr++]=table[i].y.b->w[j]; + + mr_free(table[i].x.a); + mr_free(table[i].x.b); + mr_free(table[i].y.a); + mr_free(table[i].y.b); + } + + mr_free(table); + + MR_OUT + return TRUE; +} + +void ecn2_brick_end(ebrick *B) +{ + mirkill(B->n); + mirkill(B->b); + mirkill(B->a); + mr_free(B->table); +} + +#else + +/* use precomputated table in ROM */ + +void ecn2_brick_init(ebrick *B,const mr_small* rom,big a,big b,big n,int window,int nb) +{ + B->table=rom; + B->a=a; /* just pass a pointer */ + B->b=b; + B->n=n; + B->window=window; /* 2^4=16 stored values */ + B->max=nb; +} + +#endif + +/* +void ecn2_mul_brick(_MIPD_ ebrick *B,big e,zzn2 *x,zzn2 *y) +{ + int i,j,t,len,maxsize,promptr; + ecn2 w,z; + +#ifdef MR_STATIC + char mem[MR_BIG_RESERVE(10)]; +#else + char *mem; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (size(e)<0) mr_berror(_MIPP_ MR_ERR_NEG_POWER); + t=MR_ROUNDUP(B->max,B->window); + + MR_IN(116) + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base != mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return; + } +#endif + + if (logb2(_MIPP_ e) > B->max) + { + mr_berror(_MIPP_ MR_ERR_EXP_TOO_BIG); + MR_OUT + return; + } + + ecurve_init(_MIPP_ B->a,B->b,B->n,MR_BEST); + mr_mip->TWIST=TRUE; + +#ifdef MR_STATIC + memset(mem,0,MR_BIG_RESERVE(10)); +#else + mem=memalloc(_MIPP_ 10); +#endif + + w.x.a=mirvar_mem(_MIPP_ mem, 0); + w.x.b=mirvar_mem(_MIPP_ mem, 1); + w.y.a=mirvar_mem(_MIPP_ mem, 2); + w.y.b=mirvar_mem(_MIPP_ mem, 3); + w.z.a=mirvar_mem(_MIPP_ mem, 4); + w.z.b=mirvar_mem(_MIPP_ mem, 5); + w.marker=MR_EPOINT_INFINITY; + z.x.a=mirvar_mem(_MIPP_ mem, 6); + z.x.b=mirvar_mem(_MIPP_ mem, 7); + z.y.a=mirvar_mem(_MIPP_ mem, 8); + z.y.b=mirvar_mem(_MIPP_ mem, 9); + z.marker=MR_EPOINT_INFINITY; + + len=B->n->len; + maxsize=4*(1<window)*len; + + for (i=t-1;i>=0;i--) + { + j=recode(_MIPP_ e,t,B->window,i); + ecn2_add(_MIPP_ &w,&w); + if (j>0) + { + promptr=4*j*len; + init_big_from_rom(z.x.a,len,B->table,maxsize,&promptr); + init_big_from_rom(z.x.b,len,B->table,maxsize,&promptr); + init_big_from_rom(z.y.a,len,B->table,maxsize,&promptr); + init_big_from_rom(z.y.b,len,B->table,maxsize,&promptr); + z.marker=MR_EPOINT_NORMALIZED; + ecn2_add(_MIPP_ &z,&w); + } + } + ecn2_norm(_MIPP_ &w); + ecn2_getxy(&w,x,y); +#ifndef MR_STATIC + memkill(_MIPP_ mem,10); +#else + memset(mem,0,MR_BIG_RESERVE(10)); +#endif + MR_OUT +} +*/ + +void ecn2_mul_brick_gls(_MIPD_ ebrick *B,big *e,zzn2 *psi,zzn2 *x,zzn2 *y) +{ + int i,j,k,t,len,maxsize,promptr,se[2]; + ecn2 w,z; + +#ifdef MR_STATIC + char mem[MR_BIG_RESERVE(10)]; +#else + char *mem; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + for (k=0;k<2;k++) se[k]=exsign(e[k]); + + t=MR_ROUNDUP(B->max,B->window); + + MR_IN(222) + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base != mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return; + } +#endif + + if (logb2(_MIPP_ e[0])>B->max || logb2(_MIPP_ e[1])>B->max) + { + mr_berror(_MIPP_ MR_ERR_EXP_TOO_BIG); + MR_OUT + return; + } + + ecurve_init(_MIPP_ B->a,B->b,B->n,MR_BEST); + mr_mip->TWIST=TRUE; + +#ifdef MR_STATIC + memset(mem,0,MR_BIG_RESERVE(10)); +#else + mem=memalloc(_MIPP_ 10); +#endif + + z.x.a=mirvar_mem(_MIPP_ mem, 0); + z.x.b=mirvar_mem(_MIPP_ mem, 1); + z.y.a=mirvar_mem(_MIPP_ mem, 2); + z.y.b=mirvar_mem(_MIPP_ mem, 3); + z.marker=MR_EPOINT_INFINITY; + + w.x.a=mirvar_mem(_MIPP_ mem, 4); + w.x.b=mirvar_mem(_MIPP_ mem, 5); + w.y.a=mirvar_mem(_MIPP_ mem, 6); + w.y.b=mirvar_mem(_MIPP_ mem, 7); +#ifndef MR_AFFINE_ONLY + w.z.a=mirvar_mem(_MIPP_ mem, 8); + w.z.b=mirvar_mem(_MIPP_ mem, 9); +#endif + w.marker=MR_EPOINT_INFINITY; + + len=B->n->len; + maxsize=4*(1<window)*len; + + for (i=t-1;i>=0;i--) + { + ecn2_add(_MIPP_ &w,&w); + for (k=0;k<2;k++) + { + j=recode(_MIPP_ e[k],t,B->window,i); + if (j>0) + { + promptr=4*j*len; + init_big_from_rom(z.x.a,len,B->table,maxsize,&promptr); + init_big_from_rom(z.x.b,len,B->table,maxsize,&promptr); + init_big_from_rom(z.y.a,len,B->table,maxsize,&promptr); + init_big_from_rom(z.y.b,len,B->table,maxsize,&promptr); + z.marker=MR_EPOINT_NORMALIZED; + if (k==1) ecn2_psi(_MIPP_ psi,&z); + if (se[k]==PLUS) ecn2_add(_MIPP_ &z,&w); + else ecn2_sub(_MIPP_ &z,&w); + } + } + } + ecn2_norm(_MIPP_ &w); + ecn2_getxy(&w,x,y); +#ifndef MR_STATIC + memkill(_MIPP_ mem,10); +#else + memset(mem,0,MR_BIG_RESERVE(10)); +#endif + MR_OUT +} + diff --git a/miracl/source/ecnzzn.cpp b/miracl/source/ecnzzn.cpp new file mode 100644 index 0000000..674b3be --- /dev/null +++ b/miracl/source/ecnzzn.cpp @@ -0,0 +1,41 @@ +// +// Utility functions to force an ECn to be created from 2 or 3 ZZn +// And to extract an ECn into ZZns +// + +#include "ecnzzn.h" + +#ifndef MR_AFFINE_ONLY + +void force(ZZn& x,ZZn& y,ZZn& z,ECn& A) +{ // A=(x,y,z) + copy(getbig(x),A.get_point()->X); + copy(getbig(y),A.get_point()->Y); + copy(getbig(z),A.get_point()->Z); + A.get_point()->marker=MR_EPOINT_GENERAL; +} + +void extract(ECn &A, ZZn& x,ZZn& y,ZZn& z) +{ // (x,y,z) <- A + big t; + x=(A.get_point())->X; + y=(A.get_point())->Y; + t=(A.get_point())->Z; + if (A.get_status()!=MR_EPOINT_GENERAL) z=1; + else z=t; +} + +#endif + +void force(ZZn& x,ZZn& y,ECn& A) +{ // A=(x,y) + copy(getbig(x),A.get_point()->X); + copy(getbig(y),A.get_point()->Y); + A.get_point()->marker=MR_EPOINT_NORMALIZED; +} + +void extract(ECn& A,ZZn& x,ZZn& y) +{ // (x,y) <- A + x=(A.get_point())->X; + y=(A.get_point())->Y; +} diff --git a/miracl/source/ecsgen.c b/miracl/source/ecsgen.c new file mode 100644 index 0000000..98e1c51 --- /dev/null +++ b/miracl/source/ecsgen.c @@ -0,0 +1,112 @@ +/* + * Elliptic Curve Digital Signature Algorithm (ECDSA) + * + * + * This program generates one set of public and private keys in files + * public.ecs and private.ecs respectively. Notice that the public key + * can be much shorter in this scheme, for the same security level. + * + * It is assumed that Curve parameters are to be found in file common.ecs + * + * The curve is y^2=x^3+Ax+b mod p + * + * The file common.ecs is presumed to exist, and to contain the domain + * information {p,A,B,q,x,y}, where A and B are curve parameters, (x,y) are + * a point of order q, p is the prime modulus, and q is the order of the + * point (x,y). In fact normally q is the prime number of points counted + * on the curve. + */ + +#include +#include +#include "miracl.h" + +int main() +{ + FILE *fp; + int ep,bits; + epoint *g,*w; + big a,b,p,q,x,y,d; + long seed; + miracl *mip; + +#ifndef MR_EDWARDS + fp=fopen("common.ecs","rt"); + if (fp==NULL) + { + printf("file common.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&bits); +#else + fp=fopen("edwards.ecs","rt"); + if (fp==NULL) + { + printf("file edwards.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&bits); +#endif + mip=mirsys(bits/4,16); /* Use Hex internally */ + a=mirvar(0); + b=mirvar(0); + p=mirvar(0); + q=mirvar(0); + x=mirvar(0); + y=mirvar(0); + d=mirvar(0); + + innum(p,fp); + innum(a,fp); + innum(b,fp); + innum(q,fp); + innum(x,fp); + innum(y,fp); + + fclose(fp); + +/* randomise */ + printf("Enter 9 digit random number seed = "); + scanf("%ld",&seed); + getchar(); + irand(seed); + + ecurve_init(a,b,p,MR_PROJECTIVE); /* initialise curve */ + + g=epoint_init(); + w=epoint_init(); + + if (!epoint_set(x,y,0,g)) /* initialise point of order q */ + { + printf("1. Problem - point (x,y) is not on the curve\n"); + exit(0); + } + + ecurve_mult(q,g,w); + if (!point_at_infinity(w)) + { + printf("2. Problem - point (x,y) is not of order q\n"); + exit(0); + } + +/* generate public/private keys */ + + bigrand(q,d); + ecurve_mult(d,g,g); + + ep=epoint_get(g,x,x); /* compress point */ + + printf("public key = %d ",ep); + otnum(x,stdout); + + fp=fopen("public.ecs","wt"); + fprintf(fp,"%d ",ep); + otnum(x,fp); + fclose(fp); + + fp=fopen("private.ecs","wt"); + otnum(d,fp); + fclose(fp); + return 0; +} + diff --git a/miracl/source/ecsgen.cpp b/miracl/source/ecsgen.cpp new file mode 100644 index 0000000..9d9f72c --- /dev/null +++ b/miracl/source/ecsgen.cpp @@ -0,0 +1,85 @@ +/* + * Elliptic Curve Digital Signature Algorithm (ECDSA) + * + * + * This program generates one set of public and private keys in files + * public.ecs and private.ecs respectively. Notice that the public key + * can be much shorter in this scheme, for the same security level. + * + * It is assumed that Curve parameters are to be found in file common.ecs + * + * The curve is y^2=x^3+Ax+B mod p + * + * The file common.ecs is presumed to exist, and to contain the domain + * information {p,A,B,q,x,y}, where A and B are curve parameters, (x,y) are + * a point of order q, p is the prime modulus, and q is the order of the + * point (x,y). In fact normally q is the prime number of points counted + * on the curve. + * + * Requires: big.cpp ecn.cpp + */ + +#include +#include +#include "ecn.h" + +using namespace std; + +// if MR_STATIC defined, it should be 20 + +#ifndef MR_NOFULLWIDTH +Miracl precision=20; +#else +Miracl precision(20,MAXBASE); +#endif + +int main() +{ + ifstream common("common.ecs"); /* construct file I/O streams */ + ofstream public_key("public.ecs"); + ofstream private_key("private.ecs"); + int bits,ep; + miracl *mip=&precision; + + ECn G,W; + Big a,b,p,q,x,y,d; + long seed; + + cout << "Enter 9 digit random number seed = "; + cin >> seed; + irand(seed); + + common >> bits; + mip->IOBASE=16; + common >> p >> a >> b >> q >> x >> y; + mip->IOBASE=10; + + ecurve(a,b,p,MR_PROJECTIVE); + + if (!G.set(x,y)) + { + cout << "Problem - point (x,y) is not on the curve" << endl; + return 0; + } + + W=G; + W*=q; + + if (!W.iszero()) + { + cout << "Problem - point (x,y) is not of order q" << endl; + return 0; + } + +/* generate public/private keys */ + + d=rand(q); + // for (int i=0;i<=10000;i++) + G*=d; + ep=G.get(x); + cout << "public key = " << ep << " " << x << endl; + public_key << ep << " " << x << endl; + private_key << d << endl; + return 0; +} + diff --git a/miracl/source/ecsgen2.c b/miracl/source/ecsgen2.c new file mode 100644 index 0000000..bad3ec3 --- /dev/null +++ b/miracl/source/ecsgen2.c @@ -0,0 +1,127 @@ +/* + * Proposed Digital Signature Standard + * + * Elliptic Curve Variation GF(2^m) - See Dr. Dobbs Journal April 1997 + * + * This program generates one set of public and private keys in files + * public.ecs and private.ecs respectively. Notice that the public key + * can be much shorter in this scheme, for the same security level. + * + * It is assumed that Curve parameters are to be found in file common2.ecs + * + * The curve is y^2+xy = x^3+Ax^2+B over GF(2^m) using a trinomial or + * pentanomial basis (t^m+t^a+1 or t^m+t^a+t^b+t^c+1). These parameters + * can be generated using the findbase.cpp example program, or taken from tables + * provided, for example in IEEE-P1363 Annex A + * + * The file common2.ecs is presumed to exist and contain + * {m,A,B,q,x,y,a,b,c} where A and B are parameters of the equation + * above, (x,y) is an initial point on the curve, {m,a,b,c} are the field + * parameters, (b is zero for a trinomial) and q is the order of the + * (x,y) point, itself a large prime. The number of points on the curve is + * cf.q where cf is the "co-factor", normally 2 or 4. + * + */ + +#include +#include "miracl.h" + +#ifdef MR_COUNT_OPS +int fpm2,fpi2,lpz; +#endif + +int main() +{ + FILE *fp; + int i,ep,m,a,b,c; + miracl *mip; + epoint *g,*w; + big a2,a6,q,x,y,d; + long seed; + fp=fopen("common2.ecs","rt"); + if (fp==NULL) + { + printf("file common2.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&m); + + mip=mirsys(MR_ROUNDUP(mr_abs(m),4),16); /* MR_ROUNDUP rounds up m/MIRACL */ + a2=mirvar(0); + a6=mirvar(0); + q=mirvar(0); + x=mirvar(0); + y=mirvar(0); + d=mirvar(0); + + innum(a2,fp); + innum(a6,fp); + innum(q,fp); + innum(x,fp); + innum(y,fp); + + fscanf(fp,"%d\n",&a); + fscanf(fp,"%d\n",&b); + fscanf(fp,"%d\n",&c); + fclose(fp); + +/* randomise */ + printf("Enter 9 digit random number seed = "); + scanf("%ld",&seed); + getchar(); + + mip->IOBASE=16; + irand(seed); + ecurve2_init(m,a,b,c,a2,a6,FALSE,MR_BEST); /* initialise curve */ + + g=epoint_init(); + w=epoint_init(); + + if (!epoint2_set(x,y,0,g)) /* initialise point of order q */ + { + printf("Problem - point (x,y) is not on the curve\n"); + return 0; + } + + ecurve2_mult(q,g,w); + + if (!point_at_infinity(w)) + { + printf("Problem - point (x,y) is not of order q\n"); + return 0; + } + +/* generate public/private keys */ + + bigrand(q,d); +#ifdef MR_COUNT_OPS +fpm2=fpi2=0; lpz=1000; +for (i=0;i +#include +#include "ec2.h" + +using namespace std; + +Miracl precision=20; + +int main() +{ + ifstream common("common2.ecs"); /* construct file I/O streams */ + ofstream public_key("public.ecs"); + ofstream private_key("private.ecs"); + int ep,m,a,b,c; + EC2 G,W; + Big a2,a6,q,x,y,d; + long seed; + miracl *mip=&precision; + + cout << "Enter 9 digit random number seed = "; + cin >> seed; + irand(seed); + + common >> m; + mip->IOBASE=16; + common >> a2 >> a6 >> q >> x >> y; + mip->IOBASE=10; + common >> a >> b >> c; + + ecurve2(m,a,b,c,a2,a6,FALSE,MR_PROJECTIVE); + + if (!G.set(x,y)) + { + cout << "Problem - point (x,y) is not on the curve" << endl; + return 0; + } + + W=G; + W*=q; + if (!W.iszero()) + { + cout << "Problem - point (x,y) is not of order q" << endl; + return 0; + } + +/* generate public/private keys */ + + d=rand(q); + G*=d; + ep=G.get(x); + cout << "public key = " << ep << " " << x << endl; + public_key << ep << " " << x << endl; + private_key << d << endl; + return 0; +} + diff --git a/miracl/source/ecsgen2s.c b/miracl/source/ecsgen2s.c new file mode 100644 index 0000000..bb62537 --- /dev/null +++ b/miracl/source/ecsgen2s.c @@ -0,0 +1,123 @@ +/* + * Proposed Digital Signature Standard + * + * Elliptic Curve Variation GF(2^m) - See Dr. Dobbs Journal April 1997 + * + * This program generates one set of public and private keys in files + * public.ecs and private.ecs respectively. Notice that the public key + * can be much shorter in this scheme, for the same security level. + * + * It is assumed that Curve parameters are to be found in file common2.ecs + * + * The curve is y^2+xy = x^3+Ax^2+B over GF(2^m) using a trinomial or + * pentanomial basis (t^m+t^a+1 or t^m+t^a+t^b+t^c+1). These parameters + * can be generated using the findbase.cpp example program, or taken from tables + * provided, for example in IEEE-P1363 Annex A + * + * The file common2.ecs is presumed to exist and contain + * {m,A,B,q,x,y,a,b,c} where A and B are parameters of the equation + * above, (x,y) is an initial point on the curve, {m,a,b,c} are the field + * parameters, (b is zero for a trinomial) and q is the order of the + * (x,y) point, itself a large prime. The number of points on the curve is + * cf.q where cf is the "co-factor", normally 2 or 4. + * + * This program is written for static mode. + * For a 163-bit modulus p, MR_STATIC could be defined as 6 in mirdef.h + * for a 32-bit processor, or 11 for a 16-bit processor (11*16 > 163). + * The system parameters can be found in the file common2.ecs + * Assumes MR_GENERIC_MT is defined in mirdef.h + * + */ + +#include +#include "miracl.h" + +int main() +{ + FILE *fp; + int ep,m,a,b,c; + epoint *g,*w; + big a2,a6,q,x,y,d; + long seed; + miracl instance; + miracl *mip=&instance; + char mem[MR_BIG_RESERVE(6)]; /* reserve space on the stack for 6 bigs */ + char mem1[MR_ECP_RESERVE(2)]; /* and two elliptic curve points */ + memset(mem,0,MR_BIG_RESERVE(6)); + memset(mem1,0,MR_ECP_RESERVE(2)); + + fp=fopen("common2.ecs","rt"); + if (fp==NULL) + { + printf("file common2.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&m); + + mip=mirsys(mip,MR_ROUNDUP(abs(m),4),16); /* MR_ROUNDUP(a/b) rounds up a/b */ + a2=mirvar_mem(mip,mem,0); + a6=mirvar_mem(mip,mem,1); + q=mirvar_mem(mip,mem,2); + x=mirvar_mem(mip,mem,3); + y=mirvar_mem(mip,mem,4); + d=mirvar_mem(mip,mem,5); + + innum(mip,a2,fp); + innum(mip,a6,fp); + innum(mip,q,fp); + innum(mip,x,fp); + innum(mip,y,fp); + + fscanf(fp,"%d\n",&a); + fscanf(fp,"%d\n",&b); + fscanf(fp,"%d\n",&c); + fclose(fp); + +/* randomise */ + printf("Enter 9 digit random number seed = "); + scanf("%ld",&seed); + getchar(); + irand(mip,seed); + ecurve2_init(mip,m,a,b,c,a2,a6,FALSE,MR_PROJECTIVE); /* initialise curve */ + + g=epoint_init_mem(mip,mem1,0); + w=epoint_init_mem(mip,mem1,1); + + if (!epoint2_set(mip,x,y,0,g)) /* initialise point of order q */ + { + printf("Problem - point (x,y) is not on the curve\n"); + return 0; + } + + ecurve2_mult(mip,q,g,w); + if (!point_at_infinity(w)) + { + printf("Problem - point (x,y) is not of order q\n"); + return 0; + } + +/* generate public/private keys */ + + bigrand(mip,q,d); + ecurve2_mult(mip,d,g,g); + + ep=epoint2_get(mip,g,x,x); /* compress point */ + + printf("public key = %d ",ep); + otnum(mip,x,stdout); + + fp=fopen("public.ecs","wt"); + fprintf(fp,"%d ",ep); + otnum(mip,x,fp); + fclose(fp); + + fp=fopen("private.ecs","wt"); + otnum(mip,d,fp); + fclose(fp); +/* clear all memory used */ + memset(mem,0,MR_BIG_RESERVE(7)); + memset(mem1,0,MR_ECP_RESERVE(2)); + + return 0; +} + diff --git a/miracl/source/ecsgen_s.c b/miracl/source/ecsgen_s.c new file mode 100644 index 0000000..739c599 --- /dev/null +++ b/miracl/source/ecsgen_s.c @@ -0,0 +1,128 @@ +/* + * Elliptic Curve Digital Signature Algorithm (ECDSA) + * + * + * This program generates one set of public and private keys in files + * public.ecs and private.ecs respectively. Notice that the public key + * can be much shorter in this scheme, for the same security level. + * + * It is assumed that Curve parameters are to be found in file common.ecs + * + * The curve is y^2=x^3+Ax+b mod p + * + * The file common.ecs is presumed to exist, and to contain the domain + * information {p,A,B,q,x,y}, where A and B are curve parameters, (x,y) are + * a point of order q, p is the prime modulus, and q is the order of the + * point (x,y). In fact normally q is the prime number of points counted + * on the curve. + * + * This program is written for static mode. + * For a 160-bit modulus p, MR_STATIC could be defined as 5 in mirdef.h + * for a 32-bit processor, or 10 for a 16-bit processor. + * The system parameters can be found in the file common.ecs + * Assumes MR_GENERIC_MT is defined in mirdef.h + * + */ + +#include +#include "miracl.h" + +int main() +{ + FILE *fp; + int ep,bits; + epoint *g,*w; + big a,b,p,q,x,y,d; + long seed; + miracl instance; + miracl *mip=&instance; + char mem[MR_BIG_RESERVE(7)]; /* reserve space on the stack for 7 bigs */ + char mem1[MR_ECP_RESERVE(2)]; /* and two elliptic curve points */ + memset(mem,0,MR_BIG_RESERVE(7)); + memset(mem1,0,MR_ECP_RESERVE(2)); + +#ifndef MR_EDWARDS + fp=fopen("common.ecs","rt"); + if (fp==NULL) + { + printf("file common.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&bits); +#else + fp=fopen("edwards.ecs","rt"); + if (fp==NULL) + { + printf("file edwards.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&bits); +#endif + + mirsys(mip,bits/4,16); /* Use Hex internally */ + a=mirvar_mem(mip,mem,0); + b=mirvar_mem(mip,mem,1); + p=mirvar_mem(mip,mem,2); + q=mirvar_mem(mip,mem,3); + x=mirvar_mem(mip,mem,4); + y=mirvar_mem(mip,mem,5); + d=mirvar_mem(mip,mem,6); + + innum(mip,p,fp); + innum(mip,a,fp); + innum(mip,b,fp); + innum(mip,q,fp); + innum(mip,x,fp); + innum(mip,y,fp); + + fclose(fp); + +/* randomise */ + printf("Enter 9 digit random number seed = "); + scanf("%ld",&seed); + getchar(); + irand(mip,seed); + + ecurve_init(mip,a,b,p,MR_PROJECTIVE); /* initialise curve */ + + g=epoint_init_mem(mip,mem1,0); + w=epoint_init_mem(mip,mem1,1); + + if (!epoint_set(mip,x,y,0,g)) /* initialise point of order q */ + { + printf("Problem - point (x,y) is not on the curve\n"); + exit(0); + } + + ecurve_mult(mip,q,g,w); + if (!point_at_infinity(w)) + { + printf("Problem - point (x,y) is not of order q\n"); + exit(0); + } + +/* generate public/private keys */ + + bigrand(mip,q,d); + ecurve_mult(mip,d,g,g); + + ep=epoint_get(mip,g,x,x); /* compress point */ + + printf("public key = %d ",ep); + otnum(mip,x,stdout); + + fp=fopen("public.ecs","wt"); + fprintf(fp,"%d ",ep); + otnum(mip,x,fp); + fclose(fp); + + fp=fopen("private.ecs","wt"); + otnum(mip,d,fp); + fclose(fp); +/* clear all memory used */ + memset(mem,0,MR_BIG_RESERVE(7)); + memset(mem1,0,MR_ECP_RESERVE(2)); + + return 0; +} + diff --git a/miracl/source/ecsign.c b/miracl/source/ecsign.c new file mode 100644 index 0000000..ce160d5 --- /dev/null +++ b/miracl/source/ecsign.c @@ -0,0 +1,162 @@ +/* + * Elliptic Curve Digital Signature Algorithm (ECDSA) + * + * + * This program asks for the name of a , computes its message digest, + * signs it, and outputs the signature to a file .ecs. It is assumed + * that curve parameters are available from a file common.ecs, as well as + * the private key of the signer previously generated by the ecsgen program + * + * The curve is y^2=x^3+Ax+B mod p + * + * The file common.ecs is presumed to exist, and to contain the domain + * information {p,A,B,q,x,y}, where A and B are curve parameters, (x,y) are + * a point of order q, p is the prime modulus, and q is the order of the + * point (x,y). In fact normally q is the prime number of points counted + * on the curve. + * + */ + +#include +#include "miracl.h" +#include +#include + +#ifdef MR_COUNT_OPS +int fpm2,fpi2,fpc,fpa,fpx; +#endif + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static void hashing(FILE *fp,big hash) +{ /* compute hash function */ + char h[20]; + int ch; + sha sh; + shs_init(&sh); + while ((ch=fgetc(fp))!=EOF) shs_process(&sh,ch); + shs_hash(&sh,h); + bytes_to_big(20,h,hash); +} + +int main() +{ + FILE *fp; + char ifname[50],ofname[50]; + big a,b,p,q,x,y,d,r,s,k,hash; + epoint *g; + long seed; + int bits; + miracl *mip; +/* get public data */ +#ifndef MR_EDWARDS + fp=fopen("common.ecs","rt"); + if (fp==NULL) + { + printf("file common.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&bits); +#else + fp=fopen("edwards.ecs","rt"); + if (fp==NULL) + { + printf("file edwards.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&bits); +#endif + mip=mirsys(bits/4,16); /* Use Hex internally */ + a=mirvar(0); + b=mirvar(0); + p=mirvar(0); + q=mirvar(0); + x=mirvar(0); + y=mirvar(0); + d=mirvar(0); + r=mirvar(0); + s=mirvar(0); + k=mirvar(0); + hash=mirvar(0); + + innum(p,fp); /* modulus */ + innum(a,fp); /* curve parameters */ + innum(b,fp); + innum(q,fp); /* order of (x,y) */ + innum(x,fp); /* (x,y) point on curve of order q */ + innum(y,fp); + fclose(fp); + +/* randomise */ + printf("Enter 9 digit random number seed = "); + scanf("%ld",&seed); + getchar(); + irand(seed); + + ecurve_init(a,b,p,MR_PROJECTIVE); /* initialise curve */ + g=epoint_init(); + + if (!epoint_set(x,y,0,g)) /* initialise point of order q */ + { + printf("1. Problem - point (x,y) is not on the curve\n"); + exit(0); + } + +/* calculate r - this can be done offline, + and hence amortized to almost nothing */ + bigrand(q,k); +#ifdef MR_COUNT_OPS +fpm2=fpi2=fpc=fpa=fpx=0; +#endif + ecurve_mult(k,g,g); /* see ebrick.c for method to speed this up */ +#ifdef MR_COUNT_OPS +printf("Number of modmuls= %d, inverses= %d\n",fpc,fpx); +#endif + epoint_get(g,r,r); + divide(r,q,q); + +/* get private key of signer */ + fp=fopen("private.ecs","rt"); + if (fp==NULL) + { + printf("file private.ecs does not exist\n"); + return 0; + } + innum(d,fp); + fclose(fp); + +/* calculate message digest */ + printf("file to be signed = "); + gets(ifname); + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".ecs"); + if ((fp=fopen(ifname,"rb"))==NULL) + { + printf("Unable to open file %s\n",ifname); + return 0; + } + hashing(fp,hash); + fclose(fp); + +/* calculate s */ + xgcd(k,q,k,k,k); + + mad(d,r,hash,q,q,s); + mad(s,k,k,q,q,s); + fp=fopen(ofname,"wt"); + otnum(r,fp); + otnum(s,fp); + fclose(fp); + return 0; +} + diff --git a/miracl/source/ecsign.cpp b/miracl/source/ecsign.cpp new file mode 100644 index 0000000..7c2b441 --- /dev/null +++ b/miracl/source/ecsign.cpp @@ -0,0 +1,120 @@ +/* + * Elliptic Curve Digital Signature Algorithm (ECDSA) + * + * + * This program asks for the name of a , computes its message digest, + * signs it, and outputs the signature to a file .ecs. It is assumed + * that curve parameters are available from a file common.ecs, as well as + * the private key of the signer previously generated by the ecsgen program + * + * The curve is y^2=x^3+Ax+B mod p + * + * The file common.ecs is presumed to exist, and to contain the domain + * information {p,A,B,q,x,y}, where A and B are curve parameters, (x,y) are + * a point of order q, p is the prime modulus, and q is the order of the + * point (x,y). In fact normally q is the prime number of points counted + * on the curve. + * + * Requires: big.cpp ecn.cpp + */ + +#include +#include +#include +#include "ecn.h" + +using namespace std; + +#ifndef MR_NOFULLWIDTH +Miracl precision(200,256); +#else +Miracl precision(50,MAXBASE); +#endif + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static Big Hash(ifstream &fp) +{ /* compute hash function */ + char ch,s[20]; + Big h; + sha sh; + shs_init(&sh); + forever + { /* read in bytes from message file */ + fp.get(ch); + if (fp.eof()) break; + shs_process(&sh,ch); + } + shs_hash(&sh,s); + h=from_binary(20,s); + return h; +} + +int main() +{ + ifstream common("common.ecs"); /* construct file I/O streams */ + ifstream private_key("private.ecs"); + ifstream message; + ofstream signature; + char ifname[50],ofname[50]; + ECn G; + Big a,b,p,q,x,y,h,r,s,d,k; + long seed; + int bits; + miracl *mip=&precision; + +/* randomise */ + cout << "Enter 9 digit random number seed = "; + cin >> seed; + irand(seed); + +/* get common data */ + common >> bits; + mip->IOBASE=16; + common >> p >> a >> b >> q >> x >> y; + mip->IOBASE=10; + +/* calculate r - this can be done off-line, + and hence amortized to almost nothing */ + ecurve(a,b,p,MR_PROJECTIVE); + G=ECn(x,y); + k=rand(q); + G*=k; /* see ebrick.cpp for technique to speed this up */ + G.get(r); + r%=q; + +/* get private key of recipient */ + private_key >> d; + +/* get message */ + cout << "file to be signed = " ; + cin >> ifname; + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".ecs"); + message.open(ifname,ios::binary|ios::in); + if (!message) + { + cout << "Unable to open file " << ifname << "\n"; + return 0; + } + h=Hash(message); + +/* calculate s */ + k=inverse(k,q); + s=((h+d*r)*k)%q; + signature.open(ofname); + signature << r << endl; + signature << s << endl; + return 0; +} + diff --git a/miracl/source/ecsign2.c b/miracl/source/ecsign2.c new file mode 100644 index 0000000..f0b3299 --- /dev/null +++ b/miracl/source/ecsign2.c @@ -0,0 +1,158 @@ +/* + * Digital Signature Standard (DSS) + * + * Elliptic Curve variation GF(2^m) - See Dr. Dobbs Journal, April 1997 + * + * This program asks for the name of a , computes its message digest, + * signs it, and outputs the signature to a file .ecs. It is assumed + * that curve parameters are available from a file common2.ecs, as well as + * the private key of the signer previously generated by the ecsgen2 program + * + * The curve is y^2+xy = x^3+Ax^2+B over GF(2^m) using a trinomial or + * pentanomial basis (t^m+t^a+1 or t^m+t^a+t^b+t^c+1), These parameters + * can be generated using the findbase.cpp example program, or taken from tables + * provided, for example in IEEE-P1363 Annex A + * + * The file common2.ecs is presumed to exist and contain + * {m,A,B,q,x,y,a,b,c} where A and B are parameters of the equation + * above, (x,y) is an initial point on the curve, {m,a,b,c} are the field + * parameters, (b is zero for a trinomial) and q is the order of the + * (x,y) point, itself a large prime. The number of points on the curve is + * cf.q where cf is the "co-factor", normally 2 or 4. + * + */ + +#include +#include "miracl.h" +#include +#include + +#ifdef MR_COUNT_OPS +int fpm2,fpi2,fpc,fpa,fpx; +#endif + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static void hashing(FILE *fp,big hash) +{ /* compute hash function */ + char h[20]; + int i,ch; + sha sh; + shs_init(&sh); + while ((ch=fgetc(fp))!=EOF) shs_process(&sh,ch); + shs_hash(&sh,h); + bytes_to_big(20,h,hash); +} + +int main() +{ + FILE *fp; + int m,a,b,c; + miracl *mip; + char ifname[50],ofname[50]; + big a2,a6,q,x,y,d,r,s,k,hash; + epoint *g; + long seed; +/* get public data */ + fp=fopen("common2.ecs","rt"); + if (fp==NULL) + { + printf("file common2.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&m); + + mip=mirsys(MR_ROUNDUP(abs(m),4),16); + a2=mirvar(0); + a6=mirvar(0); + q=mirvar(0); + x=mirvar(0); + y=mirvar(0); + d=mirvar(0); + r=mirvar(0); + s=mirvar(0); + k=mirvar(0); + hash=mirvar(0); + + innum(a2,fp); /* curve parameters */ + innum(a6,fp); /* curve parameters */ + + innum(q,fp); /* order of (x,y) */ + innum(x,fp); /* (x,y) point on curve of order q */ + innum(y,fp); + + fscanf(fp,"%d\n",&a); + fscanf(fp,"%d\n",&b); + fscanf(fp,"%d\n",&c); + fclose(fp); + +/* randomise */ + printf("Enter 9 digit random number seed = "); + scanf("%ld",&seed); + getchar(); + irand(seed); + + ecurve2_init(m,a,b,c,a2,a6,FALSE,MR_BEST); /* initialise curve */ + + g=epoint_init(); + epoint2_set(x,y,0,g); /* set point of order q */ + +/* calculate r - this can be done offline, + and hence amortized to almost nothing */ + bigrand(q,k); + +#ifdef MR_COUNT_OPS +fpm2=fpi2=fpc=fpa=fpx=0; +#endif + ecurve2_mult(k,g,g); /* see ebrick2.c for method to speed this up */ +#ifdef MR_COUNT_OPS +printf("Number of modmuls= %d, inverses= %d\n",fpm2,fpi2); +#endif + epoint2_get(g,r,r); + divide(r,q,q); + +/* get private key of signer */ + fp=fopen("private.ecs","rt"); + if (fp==NULL) + { + printf("file private.ecs does not exist\n"); + return 0; + } + innum(d,fp); + fclose(fp); + +/* calculate message digest */ + printf("file to be signed = "); + gets(ifname); + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".ecs"); + if ((fp=fopen(ifname,"rb"))==NULL) + { + printf("Unable to open file %s\n",ifname); + return 0; + } + hashing(fp,hash); + fclose(fp); + +/* calculate s */ + xgcd(k,q,k,k,k); + + mad(d,r,hash,q,q,s); + mad(s,k,k,q,q,s); + fp=fopen(ofname,"wt"); + otnum(r,fp); + otnum(s,fp); + fclose(fp); + return 0; +} + diff --git a/miracl/source/ecsign2.cpp b/miracl/source/ecsign2.cpp new file mode 100644 index 0000000..c70995f --- /dev/null +++ b/miracl/source/ecsign2.cpp @@ -0,0 +1,125 @@ +/* + * Digital Signature Standard (DSS) + * + * Elliptic Curve variation GF(2^m) - See Dr. Dobbs Journal, April 1997 + * + * This program asks for the name of a , computes its message digest, + * signs it, and outputs the signature to a file .ecs. It is assumed + * that curve parameters are available from a file common.ecs, as well as + * the private key of the signer previously generated by the ecsgen program + * + * The curve is y^2+xy = x^3+Ax^2+B over GF(2^m) using a trinomial or + * pentanomial basis (t^m+t^a+1 or t^m+t^a+t^b+t^c+1). These parameters + * can be generated using the findbase.cpp example program, or taken from tables + * provided, for example in IEEE-P1363 Annex A + * + * The file common2.ecs is presumed to exist and contain + * {m,A,B,q,x,y,a,b,c} where A and B are parameters of the equation + * above, (x,y) is an initial point on the curve, {m,a,b,c} are the field + * parameters, (b is zero for a trinomial) and q is the order of the + * (x,y) point, itself a large prime. The number of points on the curve is + * cf.q where cf is the "co-factor", normally 2 or 4. + * + * Requires: big.cpp ec2.cpp + */ + + +#include +#include +#include +#include "ec2.h" + +using namespace std; + +Miracl precision(200,256); + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static Big Hash(ifstream &fp) +{ /* compute hash function */ + char ch,s[20]; + Big h; + sha sh; + shs_init(&sh); + forever + { /* read in bytes from message file */ + fp.get(ch); + if (fp.eof()) break; + shs_process(&sh,ch); + } + shs_hash(&sh,s); + h=from_binary(20,s); + return h; +} + +int main() +{ + ifstream common("common2.ecs"); /* construct file I/O streams */ + ifstream private_key("private.ecs"); + ifstream message; + ofstream signature; + char ifname[50],ofname[50]; + EC2 G; + Big a2,a6,q,x,y,h,r,s,d,k; + long seed; + int m,a,b,c; + miracl *mip=&precision; + +/* randomise */ + cout << "Enter 9 digit random number seed = "; + cin >> seed; + irand(seed); + +/* get common data */ + + common >> m; + mip->IOBASE=16; + common >> a2 >> a6 >> q >> x >> y; + mip->IOBASE=10; + common >> a >> b >> c; + +/* calculate r - this can be done off-line, + and hence amortized to almost nothing */ + ecurve2(m,a,b,c,a2,a6,FALSE,MR_PROJECTIVE); + G=EC2(x,y); + k=rand(q); + G*=k; /* see ebrick2.cpp for technique to speed this up */ + G.get(r); + r%=q; + +/* get private key of recipient */ + private_key >> d; + +/* get message */ + cout << "file to be signed = " ; + cin >> ifname; + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".ecs"); + message.open(ifname,ios::binary|ios::in); + if (!message) + { + cout << "Unable to open file " << ifname << "\n"; + return 0; + } + h=Hash(message); + +/* calculate s */ + k=inverse(k,q); + s=((h+d*r)*k)%q; + signature.open(ofname); + mip->IOBASE=10; + signature << r << endl; + signature << s << endl; + return 0; +} + diff --git a/miracl/source/ecsign2s.c b/miracl/source/ecsign2s.c new file mode 100644 index 0000000..1154342 --- /dev/null +++ b/miracl/source/ecsign2s.c @@ -0,0 +1,161 @@ +/* + * Digital Signature Standard (DSS) + * + * Elliptic Curve variation GF(2^m) - See Dr. Dobbs Journal, April 1997 + * + * This program asks for the name of a , computes its message digest, + * signs it, and outputs the signature to a file .ecs. It is assumed + * that curve parameters are available from a file common2.ecs, as well as + * the private key of the signer previously generated by the ecsgen2 program + * + * The curve is y^2+xy = x^3+Ax^2+B over GF(2^m) using a trinomial or + * pentanomial basis (t^m+t^a+1 or t^m+t^a+t^b+t^c+1), These parameters + * can be generated using the findbase.cpp example program, or taken from tables + * provided, for example in IEEE-P1363 Annex A + * + * The file common2.ecs is presumed to exist and contain + * {m,A,B,q,x,y,a,b,c} where A and B are parameters of the equation + * above, (x,y) is an initial point on the curve, {m,a,b,c} are the field + * parameters, (b is zero for a trinomial) and q is the order of the + * (x,y) point, itself a large prime. The number of points on the curve is + * cf.q where cf is the "co-factor", normally 2 or 4. + * + * This program is written for static mode. + * For a 163-bit modulus p, MR_STATIC could be defined as 6 in mirdef.h + * for a 32-bit processor, or 11 for a 16-bit processor (11*16 > 163). + * The system parameters can be found in the file common2.ecs + * Assumes MR_GENERIC_MT is defined in mirdef.h + */ + +#include +#include "miracl.h" +#include +#include + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static void hashing(miracl *mip,FILE *fp,big hash) +{ /* compute hash function */ + char h[20]; + int i,ch; + sha sh; + shs_init(&sh); + while ((ch=fgetc(fp))!=EOF) shs_process(&sh,ch); + shs_hash(&sh,h); + bytes_to_big(mip,20,h,hash); +} + +int main() +{ + FILE *fp; + int m,a,b,c; + char ifname[50],ofname[50]; + big a2,a6,q,x,y,d,r,s,k,hash; + epoint *g; + long seed; + miracl instance; + miracl *mip=&instance; + char mem[MR_BIG_RESERVE(10)]; /* reserve space on the stack for 10 bigs */ + char mem1[MR_ECP_RESERVE(1)]; /* and one elliptic curve points */ + memset(mem,0,MR_BIG_RESERVE(10)); + memset(mem1,0,MR_ECP_RESERVE(1)); + +/* get public data */ + fp=fopen("common2.ecs","rt"); + if (fp==NULL) + { + printf("file common2.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&m); + + mip=mirsys(mip,MR_ROUNDUP(abs(m),4),16); + a2=mirvar_mem(mip,mem,0); + a6=mirvar_mem(mip,mem,1); + q=mirvar_mem(mip,mem,2); + x=mirvar_mem(mip,mem,3); + y=mirvar_mem(mip,mem,4); + d=mirvar_mem(mip,mem,5); + r=mirvar_mem(mip,mem,6); + s=mirvar_mem(mip,mem,7); + k=mirvar_mem(mip,mem,8); + hash=mirvar_mem(mip,mem,9); + + innum(mip,a2,fp); /* curve parameters */ + innum(mip,a6,fp); /* curve parameters */ + innum(mip,q,fp); /* order of (x,y) */ + innum(mip,x,fp); /* (x,y) point on curve of order q */ + innum(mip,y,fp); + + fscanf(fp,"%d\n",&a); + fscanf(fp,"%d\n",&b); + fscanf(fp,"%d\n",&c); + fclose(fp); + +/* randomise */ + printf("Enter 9 digit random number seed = "); + scanf("%ld",&seed); + getchar(); + irand(mip,seed); + + ecurve2_init(mip,m,a,b,c,a2,a6,FALSE,MR_PROJECTIVE); /* initialise curve */ + + g=epoint_init_mem(mip,mem1,0); + epoint2_set(mip,x,y,0,g); /* set point of order q */ + +/* calculate r - this can be done offline, + and hence amortized to almost nothing */ + bigrand(mip,q,k); + ecurve2_mult(mip,k,g,g); /* see ebrick2.c for method to speed this up */ + epoint2_get(mip,g,r,r); + divide(mip,r,q,q); + +/* get private key of signer */ + fp=fopen("private.ecs","rt"); + if (fp==NULL) + { + printf("file private.ecs does not exist\n"); + return 0; + } + innum(mip,d,fp); + fclose(fp); + +/* calculate message digest */ + printf("file to be signed = "); + gets(ifname); + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".ecs"); + if ((fp=fopen(ifname,"rb"))==NULL) + { + printf("Unable to open file %s\n",ifname); + return 0; + } + hashing(mip,fp,hash); + fclose(fp); + +/* calculate s */ + xgcd(mip,k,q,k,k,k); + + mad(mip,d,r,hash,q,q,s); + mad(mip,s,k,k,q,q,s); + fp=fopen(ofname,"wt"); + otnum(mip,r,fp); + otnum(mip,s,fp); + fclose(fp); +/* clear all memory used */ + memset(mem,0,MR_BIG_RESERVE(10)); + memset(mem1,0,MR_ECP_RESERVE(1)); + + return 0; +} + diff --git a/miracl/source/ecsign_s.c b/miracl/source/ecsign_s.c new file mode 100644 index 0000000..6ea97b9 --- /dev/null +++ b/miracl/source/ecsign_s.c @@ -0,0 +1,170 @@ +/* + * Elliptic Curve Digital Signature Algorithm (ECDSA) + * + * + * This program asks for the name of a , computes its message digest, + * signs it, and outputs the signature to a file .ecs. It is assumed + * that curve parameters are available from a file common.ecs, as well as + * the private key of the signer previously generated by the ecsgen program + * + * The curve is y^2=x^3+Ax+B mod p + * + * The file common.ecs is presumed to exist, and to contain the domain + * information {p,A,B,q,x,y}, where A and B are curve parameters, (x,y) are + * a point of order q, p is the prime modulus, and q is the order of the + * point (x,y). In fact normally q is the prime number of points counted + * on the curve. + * + * This program is written for static mode. + * For a 160-bit modulus p, MR_STATIC could be defined as 5 in mirdef.h + * for a 32-bit processor, or 10 for a 16-bit processor. + * The system parameters can be found in the file common.ecs + * Assumes MR_GENERIC_MT is defined in mirdef.h + * + */ + +#include +#include "miracl.h" +#include +#include + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static void hashing(miracl *mip,FILE *fp,big hash) +{ /* compute hash function */ + char h[20]; + int len,ch; + sha sh; + shs_init(&sh); + while ((ch=fgetc(fp))!=EOF) shs_process(&sh,ch); + shs_hash(&sh,h); + len=(MIRACL*MR_STATIC)/8; + if (len>20) len=20; + bytes_to_big(mip,len,h,hash); +} + +int main() +{ + FILE *fp; + char ifname[50],ofname[50]; + big a,b,p,q,x,y,d,r,s,k,hash; + epoint *g; + long seed; + int bits; + miracl instance; + miracl *mip=&instance; + char mem[MR_BIG_RESERVE(11)]; /* reserve space on the stack for 11 bigs */ + char mem1[MR_ECP_RESERVE(1)]; /* and one elliptic curve points */ + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(1)); + + +/* get public data */ + +#ifndef MR_EDWARDS + fp=fopen("common.ecs","rt"); + if (fp==NULL) + { + printf("file common.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&bits); +#else + fp=fopen("edwards.ecs","rt"); + if (fp==NULL) + { + printf("file edwards.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&bits); +#endif + + + mirsys(mip,bits/4,16); /* Use Hex internally */ + + a=mirvar_mem(mip,mem,0); + b=mirvar_mem(mip,mem,1); + p=mirvar_mem(mip,mem,2); + q=mirvar_mem(mip,mem,3); + x=mirvar_mem(mip,mem,4); + y=mirvar_mem(mip,mem,5); + d=mirvar_mem(mip,mem,6); + r=mirvar_mem(mip,mem,7); + s=mirvar_mem(mip,mem,8); + k=mirvar_mem(mip,mem,9); + hash=mirvar_mem(mip,mem,10); + + innum(mip,p,fp); /* modulus */ + innum(mip,a,fp); /* curve parameters */ + innum(mip,b,fp); + innum(mip,q,fp); /* order of (x,y) */ + innum(mip,x,fp); /* (x,y) point on curve of order q */ + innum(mip,y,fp); + fclose(fp); + +/* randomise */ + printf("Enter 9 digit random number seed = "); + scanf("%ld",&seed); + getchar(); + irand(mip,seed); + + ecurve_init(mip,a,b,p,MR_PROJECTIVE); /* initialise curve */ + g=epoint_init_mem(mip,mem1,0); + epoint_set(mip,x,y,0,g); /* initialise point of order q */ + +/* calculate r - this can be done offline, + and hence amortized to almost nothing */ + bigrand(mip,q,k); + ecurve_mult(mip,k,g,g); /* see ebrick.c for method to speed this up */ + epoint_get(mip,g,r,r); + divide(mip,r,q,q); + +/* get private key of signer */ + fp=fopen("private.ecs","rt"); + if (fp==NULL) + { + printf("file private.ecs does not exist\n"); + return 0; + } + innum(mip,d,fp); + fclose(fp); + +/* calculate message digest */ + printf("file to be signed = "); + gets(ifname); + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".ecs"); + if ((fp=fopen(ifname,"rb"))==NULL) + { + printf("Unable to open file %s\n",ifname); + return 0; + } + + hashing(mip,fp,hash); + fclose(fp); +/* calculate s */ + xgcd(mip,k,q,k,k,k); + + mad(mip,d,r,hash,q,q,s); + mad(mip,s,k,k,q,q,s); + fp=fopen(ofname,"wt"); + otnum(mip,r,fp); + otnum(mip,s,fp); + fclose(fp); + + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(1)); + + return 0; +} + diff --git a/miracl/source/ecsver.c b/miracl/source/ecsver.c new file mode 100644 index 0000000..1fe2c18 --- /dev/null +++ b/miracl/source/ecsver.c @@ -0,0 +1,170 @@ +/* + * Elliptic Curve Digital Signature Algorithm (ECDSA) + * + * + * This program verifies the signature given to a in + * .ecs generated by program ecsign + * + * The curve is y^2=x^3+Ax+B mod p + * + * The file common.ecs is presumed to exist, and to contain the domain + * information {p,A,B,q,x,y}, where A and B are curve parameters, (x,y) are + * a point of order q, p is the prime modulus, and q is the order of the + * point (x,y). In fact normally q is the prime number of points counted + * on the curve. + * + */ + +#include +#include "miracl.h" +#include +#include + +#ifdef MR_COUNT_OPS +int fpm2,fpi2,fpc,fpa,fpx; +#endif + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static void hashing(FILE *fp,big hash) +{ /* compute hash function */ + char h[20]; + sha sh; + int ch; + shs_init(&sh); + while ((ch=fgetc(fp))!=EOF) shs_process(&sh,ch); + shs_hash(&sh,h); + bytes_to_big(20,h,hash); +} + +int main() +{ + FILE *fp; + int bits,ep; + epoint *g,*publc; + char ifname[50],ofname[50]; + big a,b,p,q,x,y,v,u1,u2,r,s,hash; + miracl *mip; + +/* get public data */ +#ifndef MR_EDWARDS + fp=fopen("common.ecs","rt"); + if (fp==NULL) + { + printf("file common.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&bits); +#else + fp=fopen("edwards.ecs","rt"); + if (fp==NULL) + { + printf("file edwards.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&bits); +#endif + + mip=mirsys(bits/4,16); /* Use Hex Internally */ + a=mirvar(0); + b=mirvar(0); + p=mirvar(0); + q=mirvar(0); + x=mirvar(0); + y=mirvar(0); + v=mirvar(0); + u1=mirvar(0); + u2=mirvar(0); + s=mirvar(0); + r=mirvar(0); + hash=mirvar(0); + + innum(p,fp); + innum(a,fp); + innum(b,fp); + innum(q,fp); + innum(x,fp); + innum(y,fp); + + fclose(fp); + + ecurve_init(a,b,p,MR_PROJECTIVE); /* initialise curve */ + g=epoint_init(); + epoint_set(x,y,0,g); + if (!epoint_set(x,y,0,g)) /* initialise point of order q */ + { + printf("1. Problem - point (x,y) is not on the curve\n"); + exit(0); + } + +/* get public key of signer */ + fp=fopen("public.ecs","rt"); + if (fp==NULL) + { + printf("file public.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d",&ep); + innum(x,fp); + fclose(fp); + + publc=epoint_init(); + if (!epoint_set(x,x,ep,publc)) /* decompress */ + { + printf("1. Not a point on the curve\n"); + return 0; + } + +/* get message */ + printf("signed file = "); + gets(ifname); + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".ecs"); + if ((fp=fopen(ifname,"rb"))==NULL) + { /* no message */ + printf("Unable to open file %s\n",ifname); + return 0; + } + hashing(fp,hash); + fclose(fp); + fp=fopen(ofname,"rt"); + if (fp==NULL) + { /* no signature */ + printf("signature file %s does not exist\n",ofname); + return 0; + } + innum(r,fp); + innum(s,fp); + fclose(fp); + if (mr_compare(r,q)>=0 || mr_compare(s,q)>=0) + { + printf("Signature is NOT verified\n"); + return 0; + } + xgcd(s,q,s,s,s); + mad(hash,s,s,q,q,u1); + mad(r,s,s,q,q,u2); +#ifdef MR_COUNT_OPS +fpm2=fpi2=fpc=fpa=fpx=0; +#endif + ecurve_mult2(u2,publc,u1,g,g); +#ifdef MR_COUNT_OPS +printf("Number of modmuls= %d, inverses= %d\n",fpc,fpx); +#endif + epoint_get(g,v,v); + divide(v,q,q); + if (mr_compare(v,r)==0) printf("Signature is verified\n"); + else printf("Signature is NOT verified\n"); + return 0; +} + diff --git a/miracl/source/ecsver.cpp b/miracl/source/ecsver.cpp new file mode 100644 index 0000000..5e3cca1 --- /dev/null +++ b/miracl/source/ecsver.cpp @@ -0,0 +1,121 @@ +/* + * Elliptic Curve Digital Signature Algorithm (ECDSA) + * + * + * This program verifies the signature given to a in + * .ecs generated by program ecsign + * + * The curve is y^2=x^3+Ax+B mod p + * + * The file common.ecs is presumed to exist, and to contain the domain + * information {p,A,B,q,x,y}, where A and B are curve parameters, (x,y) are + * a point of order q, p is the prime modulus, and q is the order of the + * point (x,y). In fact normally q is the prime number of points counted + * on the curve. + * + * Requires: big.cpp ecn.cpp + * + */ + +#include +#include +#include +#include "ecn.h" + +using namespace std; + +#ifndef MR_NOFULLWIDTH +Miracl precision(200,256); +#else +Miracl precision(50,MAXBASE); +#endif + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static Big Hash(ifstream &fp) +{ /* compute hash function */ + char ch,s[20]; + Big h; + sha sh; + shs_init(&sh); + forever + { /* read in bytes from message file */ + fp.get(ch); + if (fp.eof()) break; + shs_process(&sh,ch); + } + shs_hash(&sh,s); + h=from_binary(20,s); + return h; +} + +int main() +{ + ifstream common("common.ecs"); /* construct file I/O streams */ + ifstream public_key("public.ecs"); + ifstream message; + ifstream signature; + ECn G,Pub; + int bits,ep; + Big a,b,p,q,x,y,v,u1,u2,r,s,h; + char ifname[50],ofname[50]; + miracl *mip=&precision; + +/* get public data */ + common >> bits; + mip->IOBASE=16; + common >> p >> a >> b >> q >> x >> y; + mip->IOBASE=10; + ecurve(a,b,p,MR_PROJECTIVE); + G=ECn(x,y); +/* get public key of signer */ + public_key >> ep >> x; + Pub=ECn(x,ep); // decompress +/* get message */ + cout << "signed file = " ; + cin.sync(); + cin.getline(ifname,13); + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".ecs"); + message.open(ifname,ios::binary|ios::in); + if (!message) + { /* no message */ + cout << "Unable to open file " << ifname << "\n"; + return 0; + } + h=Hash(message); + + signature.open(ofname,ios::in); + if (!signature) + { /* no signature */ + cout << "signature file " << ofname << " does not exist\n"; + return 0; + } + signature >> r >> s; + if (r>=q || s>=q) + { + cout << "Signature is NOT verified\n"; + return 0; + } + s=inverse(s,q); + u1=(h*s)%q; + u2=(r*s)%q; + + G=mul(u2,Pub,u1,G); + G.get(v); + v%=q; + if (v==r) cout << "Signature is verified\n"; + else cout << "Signature is NOT verified\n"; + return 0; +} + diff --git a/miracl/source/ecsver2.c b/miracl/source/ecsver2.c new file mode 100644 index 0000000..2949636 --- /dev/null +++ b/miracl/source/ecsver2.c @@ -0,0 +1,161 @@ +/* + * Proposed Digital Signature Standard (DSS) + * + * Elliptic Curve Variation GF(2^m) - See Dr. Dobbs Journal April 1997 + * + * This program verifies the signature given to a in + * .ecs generated by program ecsign2 + * + * The curve is y^2+xy = x^3+Ax^2+B over GF(2^m) using a trinomial or + * pentanomial basis (t^m+t^a+1 or t^m+t^a+t^b+t^c+1), These parameters + * can be generated using the findbase.cpp example program, or taken from tables + * provided, for example in IEEE-P1363 Annex A + * + * The file common2.ecs is presumed to exist and contain + * {m,A,B,q,x,y,a,b,c} where A and B are parameters of the equation + * above, (x,y) is an initial point on the curve, {m,a,b,c} are the field + * parameters, (b is zero for a trinomial) and q is the order of the + * (x,y) point, itself a large prime. The number of points on the curve is + * cf.q where cf is the "co-factor", normally 2 or 4. + * + */ + +#include +#include "miracl.h" +#include +#include + +#ifdef MR_COUNT_OPS +int fpm2; +int fpi2; +int fpc; +int fpa; +int fpx; +#endif + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static void hashing(FILE *fp,big hash) +{ /* compute hash function */ + char h[20]; + sha sh; + int i,ch; + shs_init(&sh); + while ((ch=fgetc(fp))!=EOF) shs_process(&sh,ch); + shs_hash(&sh,h); + bytes_to_big(20,h,hash); +} + +int main() +{ + FILE *fp; + int ep,m,a,b,c; + miracl *mip; + epoint *g,*public; + char ifname[50],ofname[50]; + big a2,a6,q,x,y,v,u1,u2,r,s,hash; +/* get public data */ + fp=fopen("common2.ecs","rt"); + if (fp==NULL) + { + printf("file common2.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&m); + + mip=mirsys(MR_ROUNDUP(abs(m),4),16); + a2=mirvar(0); + a6=mirvar(0); + q=mirvar(0); + x=mirvar(0); + y=mirvar(0); + v=mirvar(0); + u1=mirvar(0); + u2=mirvar(0); + s=mirvar(0); + r=mirvar(0); + hash=mirvar(0); + + innum(a2,fp); + innum(a6,fp); + innum(q,fp); + innum(x,fp); + innum(y,fp); + + fscanf(fp,"%d\n",&a); + fscanf(fp,"%d\n",&b); + fscanf(fp,"%d\n",&c); + + fclose(fp); + + ecurve2_init(m,a,b,c,a2,a6,FALSE,MR_BEST); /* initialise curve */ + g=epoint_init(); + epoint2_set(x,y,0,g); /* initialise point of order q */ + +/* get public key of signer */ + fp=fopen("public.ecs","rt"); + if (fp==NULL) + { + printf("file public.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d",&ep); + innum(x,fp); + fclose(fp); + + public=epoint_init(); + epoint2_set(x,x,ep,public); /* decompress */ + +/* get message */ + printf("signed file = "); + gets(ifname); + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".ecs"); + if ((fp=fopen(ifname,"rb"))==NULL) + { /* no message */ + printf("Unable to open file %s\n",ifname); + return 0; + } + hashing(fp,hash); + fclose(fp); + fp=fopen(ofname,"rt"); + if (fp==NULL) + { /* no signature */ + printf("signature file %s does not exist\n",ofname); + return 0; + } + innum(r,fp); + innum(s,fp); + fclose(fp); + if (mr_compare(r,q)>=0 || mr_compare(s,q)>=0) + { + printf("Signature is NOT verified\n"); + return 0; + } + xgcd(s,q,s,s,s); + mad(hash,s,s,q,q,u1); + mad(r,s,s,q,q,u2); +#ifdef MR_COUNT_OPS +fpm2=fpi2=0; +#endif + ecurve2_mult2(u2,public,u1,g,g); +#ifdef MR_COUNT_OPS +printf("Number of modmuls= %d, inverses= %d\n",fpm2,fpi2); +#endif + epoint2_get(g,v,v); + divide(v,q,q); + if (mr_compare(v,r)==0) printf("Signature is verified\n"); + else printf("Signature is NOT verified\n"); + return 0; +} + diff --git a/miracl/source/ecsver2.cpp b/miracl/source/ecsver2.cpp new file mode 100644 index 0000000..d272914 --- /dev/null +++ b/miracl/source/ecsver2.cpp @@ -0,0 +1,126 @@ +/* + * Proposed Digital Signature Standard (DSS) + * + * Elliptic Curve Variation GF(2^m) - See Dr. Dobbs Journal April 1997 + * + * This program verifies the signature given to a in + * .ecs generated by program ecsign + * + * The curve is y^2+xy = x^3+Ax^2+B over GF(2^m) using a trinomial or + * pentanomial basis (t^m+t^a+1 or t^m+t^a+t^b+t^c+1). These parameters + * can be generated using the findbase.cpp example program, or taken from tables + * provided, for example in IEEE-P1363 Annex A + * + * The file common2.ecs is presumed to exist and contain + * {m,A,B,q,x,y,a,b,c,q} where A and B are parameters of the equation + * above, (x,y) is an initial point on the curve, {m,a,b,c} are the field + * parameters, (b is zero for a trinomial) and q is the order of the + * (x,y) point, itself a large prime. The number of points on the curve is + * cf.q where cf is the "co-factor", normally 2 or 4. + * + * Requires: big.cpp ec2.cpp + * + */ + +#include +#include +#include +#include "ec2.h" + +using namespace std; + +Miracl precision(200,256); + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static Big Hash(ifstream &fp) +{ /* compute hash function */ + char ch,s[20]; + Big h; + sha sh; + shs_init(&sh); + forever + { /* read in bytes from message file */ + fp.get(ch); + if (fp.eof()) break; + shs_process(&sh,ch); + } + shs_hash(&sh,s); + h=from_binary(20,s); + return h; +} + +int main() +{ + ifstream common("common2.ecs"); /* construct file I/O streams */ + ifstream public_key("public.ecs"); + ifstream message; + ifstream signature; + EC2 G,Pub; + int ep,m,a,b,c; + Big a2,a6,q,x,y,v,u1,u2,r,s,h; + char ifname[50],ofname[50]; + miracl *mip=&precision; + +/* get public data */ + + common >> m; + mip->IOBASE=16; + common >> a2 >> a6 >> q >> x >> y; + mip->IOBASE=10; + common >> a >> b >> c; + + ecurve2(m,a,b,c,a2,a6,FALSE,MR_PROJECTIVE); + G=EC2(x,y); +/* get public key of signer */ + public_key >> ep >> x; + Pub=EC2(x,ep); // decompress +/* get message */ + cout << "signed file = " ; + cin.sync(); + cin.getline(ifname,13); + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".ecs"); + message.open(ifname,ios::binary|ios::in); + if (!message) + { /* no message */ + cout << "Unable to open file " << ifname << "\n"; + return 0; + } + h=Hash(message); + + mip->IOBASE=10; + signature.open(ofname,ios::in); + if (!signature) + { /* no signature */ + cout << "signature file " << ofname << " does not exist\n"; + return 0; + } + signature >> r >> s; + if (r>=q || s>=q) + { + cout << "Signature is NOT verified\n"; + return 0; + } + s=inverse(s,q); + u1=(h*s)%q; + u2=(r*s)%q; + + G=mul(u2,Pub,u1,G); + G.get(v); + v%=q; + if (v==r) cout << "Signature is verified\n"; + else cout << "Signature is NOT verified\n"; + return 0; +} + diff --git a/miracl/source/ecsver2s.c b/miracl/source/ecsver2s.c new file mode 100644 index 0000000..f9cea2a --- /dev/null +++ b/miracl/source/ecsver2s.c @@ -0,0 +1,163 @@ +/* + * Digital Signature Standard (DSS) + * + * Elliptic Curve Variation GF(2^m) - See Dr. Dobbs Journal April 1997 + * + * This program verifies the signature given to a in + * .ecs generated by program ecsign2 + * + * The curve is y^2+xy = x^3+Ax^2+B over GF(2^m) using a trinomial or + * pentanomial basis (t^m+t^a+1 or t^m+t^a+t^b+t^c+1), These parameters + * can be generated using the findbase.cpp example program, or taken from tables + * provided, for example in IEEE-P1363 Annex A + * + * The file common2.ecs is presumed to exist and contain + * {m,A,B,q,x,y,a,b,c} where A and B are parameters of the equation + * above, (x,y) is an initial point on the curve, {m,a,b,c} are the field + * parameters, (b is zero for a trinomial) and q is the order of the + * (x,y) point, itself a large prime. The number of points on the curve is + * cf.q where cf is the "co-factor", normally 2 or 4. + * + * This program is written for static mode. + * For a 163-bit modulus p, MR_STATIC could be defined as 6 in mirdef.h + * for a 32-bit processor, or 11 for a 16-bit processor (11*16 > 163). + * The system parameters can be found in the file common2.ecs + * Assumes MR_GENERIC_MT is defined in mirdef.h + */ + +#include +#include "miracl.h" +#include +#include + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static void hashing(miracl *mip,FILE *fp,big hash) +{ /* compute hash function */ + char h[20]; + sha sh; + int i,ch; + shs_init(&sh); + while ((ch=fgetc(fp))!=EOF) shs_process(&sh,ch); + shs_hash(&sh,h); + bytes_to_big(mip,20,h,hash); +} + +int main() +{ + FILE *fp; + int ep,m,a,b,c; + epoint *g,*public; + char ifname[50],ofname[50]; + big a2,a6,q,x,y,v,u1,u2,r,s,hash; + miracl instance; + miracl *mip=&instance; + char mem[MR_BIG_RESERVE(11)]; /* reserve space on the stack for 11 bigs */ + char mem1[MR_ECP_RESERVE(2)]; /* and two elliptic curve points */ + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(2)); + +/* get public data */ + fp=fopen("common2.ecs","rt"); + if (fp==NULL) + { + printf("file common2.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&m); + + mip=mirsys(mip,MR_ROUNDUP(abs(m),4),16); + a2=mirvar_mem(mip,mem,0); + a6=mirvar_mem(mip,mem,1); + q=mirvar_mem(mip,mem,2); + x=mirvar_mem(mip,mem,3); + y=mirvar_mem(mip,mem,4); + v=mirvar_mem(mip,mem,5); + u1=mirvar_mem(mip,mem,6); + u2=mirvar_mem(mip,mem,7); + s=mirvar_mem(mip,mem,8); + r=mirvar_mem(mip,mem,9); + hash=mirvar_mem(mip,mem,10); + + innum(mip,a2,fp); + innum(mip,a6,fp); + innum(mip,q,fp); + innum(mip,x,fp); + innum(mip,y,fp); + + fscanf(fp,"%d\n",&a); + fscanf(fp,"%d\n",&b); + fscanf(fp,"%d\n",&c); + + fclose(fp); + + ecurve2_init(mip,m,a,b,c,a2,a6,FALSE,MR_PROJECTIVE); /* initialise curve */ + g=epoint_init_mem(mip,mem1,0); + epoint2_set(mip,x,y,0,g); /* initialise point of order q */ + +/* get public key of signer */ + fp=fopen("public.ecs","rt"); + if (fp==NULL) + { + printf("file public.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d",&ep); + innum(mip,x,fp); + fclose(fp); + + public=epoint_init_mem(mip,mem1,1); + epoint2_set(mip,x,x,ep,public); /* decompress */ + +/* get message */ + printf("signed file = "); + gets(ifname); + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".ecs"); + if ((fp=fopen(ifname,"rb"))==NULL) + { /* no message */ + printf("Unable to open file %s\n",ifname); + return 0; + } + hashing(mip,fp,hash); + fclose(fp); + fp=fopen(ofname,"rt"); + if (fp==NULL) + { /* no signature */ + printf("signature file %s does not exist\n",ofname); + return 0; + } + innum(mip,r,fp); + innum(mip,s,fp); + fclose(fp); + if (mr_compare(r,q)>=0 || mr_compare(s,q)>=0) + { + printf("Signature is NOT verified\n"); + return 0; + } + xgcd(mip,s,q,s,s,s); + mad(mip,hash,s,s,q,q,u1); + mad(mip,r,s,s,q,q,u2); + + ecurve2_mult2(mip,u2,public,u1,g,g); + epoint2_get(mip,g,v,v); + divide(mip,v,q,q); + if (mr_compare(v,r)==0) printf("Signature is verified\n"); + else printf("Signature is NOT verified\n"); +/* clear all memory used */ + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(2)); + + return 0; +} + diff --git a/miracl/source/ecsver_s.c b/miracl/source/ecsver_s.c new file mode 100644 index 0000000..77c3068 --- /dev/null +++ b/miracl/source/ecsver_s.c @@ -0,0 +1,168 @@ +/* + * Elliptic Curve Digital Signature Algorithm (ECDSA) + * + * This program verifies the signature given to a in + * .ecs generated by program ecsign + * + * The curve is y^2=x^3+Ax+B mod p + * + * The file common.ecs is presumed to exist, and to contain the domain + * information {p,A,B,q,x,y}, where A and B are curve parameters, (x,y) are + * a point of order q, p is the prime modulus, and q is the order of the + * point (x,y). In fact normally q is the prime number of points counted + * on the curve. + * + * This program is written for static mode. + * For a 160-bit modulus p, MR_STATIC could be defined as 5 in mirdef.h + * for a 32-bit processor, or 10 for a 16-bit processor. + * The system parameters can be found in the file common.ecs + * Assumes MR_GENERIC_MT is defined in mirdef.h + * + */ + +#include +#include "miracl.h" +#include +#include + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +static void hashing(miracl *mip,FILE *fp,big hash) +{ /* compute hash function */ + char h[20]; + sha sh; + int len,ch; + shs_init(&sh); + while ((ch=fgetc(fp))!=EOF) shs_process(&sh,ch); + shs_hash(&sh,h); + len=(MIRACL*MR_STATIC)/8; + if (len>20) len=20; + bytes_to_big(mip,len,h,hash); +} + +int main() +{ + FILE *fp; + int bits,ep; + epoint *g,*public; + char ifname[50],ofname[50]; + big a,b,p,q,x,y,v,u1,u2,r,s,hash; + miracl instance; + miracl *mip=&instance; + char mem[MR_BIG_RESERVE(12)]; /* reserve space on the stack for 12 bigs */ + char mem1[MR_ECP_RESERVE(2)]; /* and two elliptic curve points */ + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(2)); + +/* get public data */ +#ifndef MR_EDWARDS + fp=fopen("common.ecs","rt"); + if (fp==NULL) + { + printf("file common.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&bits); +#else + fp=fopen("edwards.ecs","rt"); + if (fp==NULL) + { + printf("file edwards.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d\n",&bits); +#endif + + mirsys(mip,bits/4,16); /* Use Hex Internally */ + a=mirvar_mem(mip,mem,0); + b=mirvar_mem(mip,mem,1); + p=mirvar_mem(mip,mem,2); + q=mirvar_mem(mip,mem,3); + x=mirvar_mem(mip,mem,4); + y=mirvar_mem(mip,mem,5); + v=mirvar_mem(mip,mem,6); + u1=mirvar_mem(mip,mem,7); + u2=mirvar_mem(mip,mem,8); + s=mirvar_mem(mip,mem,9); + r=mirvar_mem(mip,mem,10); + hash=mirvar_mem(mip,mem,11); + + innum(mip,p,fp); + innum(mip,a,fp); + innum(mip,b,fp); + innum(mip,q,fp); + innum(mip,x,fp); + innum(mip,y,fp); + + fclose(fp); + + ecurve_init(mip,a,b,p,MR_PROJECTIVE); /* initialise curve */ + g=epoint_init_mem(mip,mem1,0); + epoint_set(mip,x,y,0,g); /* initialise point of order q */ + +/* get public key of signer */ + fp=fopen("public.ecs","rt"); + if (fp==NULL) + { + printf("file public.ecs does not exist\n"); + return 0; + } + fscanf(fp,"%d",&ep); + innum(mip,x,fp); + fclose(fp); + + public=epoint_init_mem(mip,mem1,1); + epoint_set(mip,x,x,ep,public); /* decompress */ + +/* get message */ + printf("signed file = "); + gets(ifname); + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".ecs"); + if ((fp=fopen(ifname,"rb"))==NULL) + { /* no message */ + printf("Unable to open file %s\n",ifname); + return 0; + } + hashing(mip,fp,hash); + fclose(fp); + fp=fopen(ofname,"rt"); + if (fp==NULL) + { /* no signature */ + printf("signature file %s does not exist\n",ofname); + return 0; + } + innum(mip,r,fp); + innum(mip,s,fp); + fclose(fp); + if (mr_compare(r,q)>=0 || mr_compare(s,q)>=0) + { + printf("Signature is NOT verified\n"); + return 0; + } + xgcd(mip,s,q,s,s,s); + mad(mip,hash,s,s,q,q,u1); + mad(mip,r,s,s,q,q,u2); + + ecurve_mult2(mip,u2,public,u1,g,g); + epoint_get(mip,g,v,v); + divide(mip,v,q,q); + if (mr_compare(v,r)==0) printf("Signature is verified\n"); + else printf("Signature is NOT verified\n"); + + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(2)); + + return 0; +} + diff --git a/miracl/source/edwards.ecs b/miracl/source/edwards.ecs new file mode 100644 index 0000000..c96b95f --- /dev/null +++ b/miracl/source/edwards.ecs @@ -0,0 +1,7 @@ +160 +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7 +1 +106 +3FFFFFFFFFFFFFFFFFFFBD446095AE59E082FAE7 +91D021E4D37CEC46EF347AEB7F9B67E689D2622B +7721AC74B602AEF61784F09A7A9B65DFAECA3250 diff --git a/miracl/source/enciph.c b/miracl/source/enciph.c new file mode 100644 index 0000000..65a4e7f --- /dev/null +++ b/miracl/source/enciph.c @@ -0,0 +1,118 @@ +/* + * Program to encipher text using Blum-Goldwasser Probabalistic + * Public Key method + * See "Modern Cryptology - a tutorial" by Gilles Brassard. + * Published by Springer-Verlag, 1988 + * + * Define RSA to use cubing instead of squaring. This is no longer + * provably as difficult to break as factoring the modulus, its a bit + * slower, but it is resistant to chosen ciphertext attack. + * + * + * Note: This implementation uses only the Least Significant Byte + * of the big random number x in encipherment/decipherment, as it has + * proven to be completely secure. However it is conjectured that + * that up to half the bytes in x (the lower half) are also secure. + * They could be used to considerably speed up this method. + * + */ + +#include +#include "miracl.h" +#include +#include + +/* +#define RSA +*/ + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +int main() +{ /* encipher using public key */ + big x,ke; + FILE *ifile; + FILE *ofile; + char ifname[13],ofname[13]; + BOOL fli; + int ch; + long seed,ipt; + miracl *mip=mirsys(100,0); + x=mirvar(0); + ke=mirvar(0); + mip->IOBASE=16; + if ((ifile=fopen("public.key","rt"))==NULL) + { + printf("Unable to open file public.key\n"); + return 0; + } + cinnum(ke,ifile); + fclose(ifile); + printf("Enter 9 digit random number seed = "); + scanf("%ld",&seed); + getchar(); + irand(seed); + bigrand(ke,x); + printf("file to be enciphered = "); + gets(ifname); + fli=FALSE; + if (strlen(ifname)>0) fli=TRUE; + if (fli) + { /* set up input file */ + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".blg"); + if ((ifile=fopen(ifname,"rt"))==NULL) + { + printf("Unable to open file %s\n",ifname); + return 0; + } + printf("enciphering message\n"); + } + else + { /* accept input from keyboard */ + ifile=stdin; + do + { + printf("output filename = "); + gets(ofname); + } while (strlen(ofname)==0); + strip(ofname); + strcat(ofname,".blg"); + printf("input message - finish with cntrl z\n"); + } + ofile=fopen(ofname,"wb"); + ipt=0; + forever + { /* encipher character by character */ +#ifdef RSA + power(x,3,ke,x); +#else + mad(x,x,x,ke,ke,x); +#endif + ch=fgetc(ifile); + if (ch==EOF) break; + ch^=x->w[0]; /* XOR with last byte of x */ + fputc(ch,ofile); + ipt++; + } + fclose(ofile); + if (fli) fclose(ifile); + strip(ofname); + strcat(ofname,".key"); + ofile=fopen(ofname,"wt"); + fprintf(ofile,"%ld\n",ipt); + cotnum(x,ofile); + fclose(ofile); + return 0; +} + diff --git a/miracl/source/enciph.cpp b/miracl/source/enciph.cpp new file mode 100644 index 0000000..cfbdfa3 --- /dev/null +++ b/miracl/source/enciph.cpp @@ -0,0 +1,117 @@ +/* + * Program to encipher text using Blum-Goldwasser Probabalistic + * Public Key method + * See "Modern Cryptology - a tutorial" by Gilles Brassard. + * Published by Springer-Verlag, 1988 + * + * Define RSA to use cubing instead of squaring. This is no longer + * provably as difficult to break as factoring the modulus, its a bit + * slower, but it is resistant to chosen ciphertext attack. + * + * Note: This implementation uses only the Least Significant Byte + * of the big random number x in encipherment/decipherment, as it has + * proven to be completely secure. However it is conjectured that + * that up to half the bytes in x (the lower half) are also secure. + * They could be used to considerably speed up this method. + * + * Requires: big.cpp + */ + +#include +#include +#include "big.h" /* include MIRACL system */ +#include + +using namespace std; + +// #define RSA + +Miracl precision=100; + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +int main() +{ /* encipher using public key */ + Big x,ke; + ifstream public_key("public.key"); + ifstream input_file; + ofstream output_file,key_file; + char ifname[13],ofname[13]; + BOOL fli; + char ch; + long seed,ipt; + miracl *mip=&precision; + + mip->IOBASE=16; + public_key >> ke; + cout << "Enter 9 digit random number seed = "; + cin >> seed; + irand(seed); + x=rand(ke); + cout << "file to be enciphered = "; + cin >> ifname; +// cin.sync(); +// cin.getline(ifname,13); + fli=FALSE; + if (strlen(ifname)>0) fli=TRUE; + if (fli) + { /* set up input file */ + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".blg"); + input_file.open(ifname,ios::in); + if (!input_file) + { + cout << "Unable to open file " << ifname << "\n";; + return 0; + } + cout << "enciphering message" << endl; + } + else + { /* accept input from keyboard */ + cout << "output filename = "; + cin >> ofname; + strip(ofname); + strcat(ofname,".blg"); + cout << "input message - finish with cntrl z" << endl; + } + output_file.open(ofname,ios::binary|ios::out); + ipt=0; + forever + { /* encipher character by character */ +#ifdef RSA + x=pow(x,3,ke); +#else + x=(x*x)%ke; +#endif + if (fli) + { + if (input_file.eof()) break; + input_file.get(ch); + } + else + { + if (cin.eof()) break; + cin.get(ch); + } + ch^=x[0]; /* XOR with last byte of x */ + output_file << ch; + ipt++; + } + strip(ofname); + strcat(ofname,".key"); + key_file.open(ofname); + key_file << ipt << "\n"; + key_file << x << endl; + return 0; +} + diff --git a/miracl/source/encode.c b/miracl/source/encode.c new file mode 100644 index 0000000..070348e --- /dev/null +++ b/miracl/source/encode.c @@ -0,0 +1,135 @@ +/* + * Program to encode text using RSA public key. + * + * *** For Demonstration use only ***** + * + */ + +#include +#include "miracl.h" +#include +#include + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +miracl *mip; + +int main() +{ /* encode using public key */ + big e,m,y,ke,mn,mx; + FILE *ifile; + FILE *ofile; + static char line[500]; + static char buff[256]; + char ifname[13],ofname[13]; + BOOL fli,last; + int i,ipt,klen; + mip=mirsys(100,0); + e=mirvar(0); + m=mirvar(0); + y=mirvar(0); + ke=mirvar(0); + mn=mirvar(0); + mx=mirvar(0); + if ((ifile=fopen("public.key","rt"))==NULL) + { + printf("Unable to open file public.key\n"); + return 0; + } + mip->IOBASE=16; + cinnum(ke,ifile); + fclose(ifile); + nroot(ke,3,mn); + multiply(mn,mn,m); + multiply(mn,m,mx); + subtract(mx,m,mx); + klen=0; + copy(mx,m); + while (size(m)>0) + { /* find key length in characters */ + klen++; + subdiv(m,128,m); + } + klen--; + printf("file to be encoded = "); + gets(ifname); + fli=FALSE; + if (strlen(ifname)>0) fli=TRUE; + if (fli) + { /* set up input file */ + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".rsa"); + if ((ifile=fopen(ifname,"rt"))==NULL) + { + printf("Unable to open file %s\n",ifname); + return 0; + } + printf("encoding message\n"); + } + else + { /* accept input from keyboard */ + ifile=stdin; + do + { + printf("output filename = "); + gets(ofname); + } while (strlen(ofname)==0); + strip(ofname); + strcat(ofname,".rsa"); + printf("input message - finish with cntrl z\n"); + } + ofile=fopen(ofname,"wt"); + ipt=0; + last=FALSE; + while (!last) + { /* encode line by line */ + if (fgets(&line[ipt],132,ifile)==NULL) last=TRUE; + if (line[ipt]==EOF) last=TRUE; + ipt=strlen(line); + if (ipt=klen) + { /* chop up into klen-sized chunks and encode */ + for (i=0;iIOBASE=128; + cinstr(m,buff); + power(m,3,ke,e); + mip->IOBASE=16; + cotnum(e,ofile); + } + if (last && ipt>0) + { /* now deal with left overs */ + mip->IOBASE=128; + cinstr(m,line); + if (mr_compare(m,mn)<0) + { /* pad out with random number if necessary */ + bigrand(mn,y); + multiply(mn,mn,e); + subtract(e,y,e); + multiply(mn,e,y); + add(m,y,m); + } + power(m,3,ke,e); + mip->IOBASE=16; + cotnum(e,ofile); + } + } + fclose(ofile); + if (fli) fclose(ifile); + return 0; +} + diff --git a/miracl/source/encode.cpp b/miracl/source/encode.cpp new file mode 100644 index 0000000..17daf5f --- /dev/null +++ b/miracl/source/encode.cpp @@ -0,0 +1,128 @@ +/* + * Program to encode text using RSA public key. + * + * Note that an exponent of 3 must be used with extreme care! + * + * For example:- + * If the same message m is encrypted under 3 or more different public keys + * the message can be recovered without factoring the modulus (using the + * Chinese remainder thereom). + * If the messages m and m+1 are encrypted under the same public key, again + * the message can be recovered without factoring the modulus. Indeed any + * simple relationship between a pair of messages can be exploited in a + * similar way. + * + * Requires: big.cpp + */ + +#include +#include +#include +#include "big.h" /* include MIRACL system */ + +using namespace std; + +Miracl precision=100; + +void strip(char *name) +{ /* strip off filename extension */ + int i; + for (i=0;name[i]!='\0';i++) + { + if (name[i]!='.') continue; + name[i]='\0'; + break; + } +} + +int main() +{ /* encode using public key */ + Big e,m,y,ke,mn,mx; + ifstream public_key("public.key"); + ifstream input_file; + ofstream output_file; + static char line[500]; + static char buff[256]; + static char ifname[13],ofname[13]; + BOOL fli,last; + int i,ipt,klen; + miracl *mip=&precision; + mip->IOBASE=16; + public_key >> ke; + mn=root(ke,3); + mx=mn*mn*mn-mn*mn; + /* find key length in characters */ + klen=bits(mx)/7; + cout << "file to be encoded = " ; + cin.getline(ifname,13); + fli=FALSE; + if (strlen(ifname)>0) fli=TRUE; + if (fli) + { /* set up input file */ + strcpy(ofname,ifname); + strip(ofname); + strcat(ofname,".rsa"); + input_file.open(ifname,ios::in); + if (!input_file) + { + cout << "Unable to open file " << ifname << "\n"; + return 0; + } + cout << "encoding message\n"; + } + else + { /* accept input from keyboard */ + cout << "output filename = "; + cin >> ofname; + strip(ofname); + strcat(ofname,".rsa"); + cout << "input message - finish with cntrl z\n"; + } + output_file.open(ofname); + ipt=0; + last=FALSE; + while (!last) + { /* encode line by line */ + if (fli) + { + input_file.getline(&line[ipt],132); + if (input_file.eof() || input_file.fail()) last=TRUE; + } + else + { + cin.getline(&line[ipt],132); + if (cin.eof() || cin.fail()) last=TRUE; + } + strcat(line,"\n"); + ipt=strlen(line); + if (ipt=klen) + { /* chop up into klen-sized chunks and encode */ + for (i=0;iIOBASE=128; + m=buff; + e=pow(m,3,ke); + mip->IOBASE=16; + output_file << e << endl; + } + if (last && ipt>0) + { /* now deal with left overs */ + mip->IOBASE=128; + m=line; + if (mIOBASE=16; + output_file << e << endl; + } + } + return 0; +} + diff --git a/miracl/source/fact.c b/miracl/source/fact.c new file mode 100644 index 0000000..0c0cd54 --- /dev/null +++ b/miracl/source/fact.c @@ -0,0 +1,31 @@ +/* + * Program to calculate factorials. + */ + +#include +#include "miracl.h" /* include MIRACL system */ + +int main() +{ /* calculate factorial of number */ + big nf; /* declare "big" variable nf */ + int n,m; +#if MIRACL==16 +#ifdef MR_FLASH + mirsys(500,10); /* initialise system to base 10, 500 digits per "big" */ +#else + mirsys(5000,10); /* bigger numbers possible if no flash arithmetic */ +#endif +#else + mirsys(5000,10); /* 5000 digits per "big" */ +#endif + nf=mirvar(1); /* initialise "big" variable nf=1 */ + printf("factorial program\n"); + printf("input number n= \n"); + m=scanf("%d",&n); + getchar(); + while (n>1) premult(nf,n--,nf); /* nf=n!=n*(n-1)*(n-2)*....3*2*1 */ + printf("n!= \n"); + otnum(nf,stdout); /* output result */ + return 0; +} + diff --git a/miracl/source/fact.cpp b/miracl/source/fact.cpp new file mode 100644 index 0000000..15d9cbc --- /dev/null +++ b/miracl/source/fact.cpp @@ -0,0 +1,25 @@ +/* + * Program to calculate factorials. + * + * Requires: big.cpp + */ + +#include +#include "big.h" /* include MIRACL system */ + +using namespace std; + +Miracl precision(5000,10); /* bigs are 5000 decimal digits long */ + +int main() +{ /* calculate factorial of number */ + Big nf=1; /* declare "Big" variable nf */ + int n; + set_io_buffer_size(5000); + cout << "factorial program\ninput number n= \n"; + cin >> n; + while (n>1) nf*=(n--); /* nf=n!=n*(n-1)*(n-2)*....3*2*1 */ + cout << "n!= \n" << nf << "\n"; + return 0; +} + diff --git a/miracl/source/factor.c b/miracl/source/factor.c new file mode 100644 index 0000000..206bd0c --- /dev/null +++ b/miracl/source/factor.c @@ -0,0 +1,1701 @@ +/* + * Program to factor Integers + * + * Current parameters assume a large 32-bit address space is available. + * + * This program is cobbled together from the implementations of various + * factoring algorithms better described in:- + * + * brute.c/cpp - brute force division by small primes + * brent.c/cpp - Pollard Rho method as improved by Brent + * pollard.c/cpp - Pollard (p-1) method + * williams.c/cpp - Williams (p+1) method + * lenstra.c/cpp - Lenstra's Elliptic Curve method + * qsieve.c/cpp - The Multiple polynomial quadratic sieve + * + * Note that the .cpp C++ implementations are easier to follow + * + * NOTE: The quadratic sieve program requires a lot of memory for + * bigger numbers. It may fail if you system cannot provide the memory + * requested. + */ + +#include +#include +#include +#include +#include "miracl.h" + +#define LIMIT 15000 +#define BTRIES 1000 +#define MULT 2310 /* 2*3*5*7*11 */ +#define NEXT 13 /* .. next prime */ +#define mr_min(a,b) ((a) < (b)? (a) : (b)) + +static big *fu; +static BOOL *cp,*plus,*minus; +big n; +FILE *output; +static BOOL suppress=FALSE; +static int PADDING; +static miracl *mip; + +void brute(void) +{ /* find factors by brute force division */ + big x,y; + int m,p; + gprime(LIMIT); + x=mirvar(0); + y=mirvar(0); + m=0; + p=mip->PRIMES[0]; + forever + { /* try division by each prime in turn */ + if (subdiv(n,p,y)==0) + { /* factor found */ + copy(y,n); + if (!suppress) printf("PRIME FACTOR "); + fprintf(output,"%d\n",p); + if (size(n)==1) exit(0); + continue; + } + if (size(y)<=p) + { /* must be prime */ + if (!suppress) printf("PRIME FACTOR "); + cotnum(n,output); + exit(0); + } + p=mip->PRIMES[++m]; + if (p==0) break; + } + if (isprime(n)) + { + if (!suppress) printf("PRIME FACTOR "); + cotnum(n,output); + exit(0); + } + mr_free(x); + mr_free(y); + gprime(0); +} + +void brent(void) +{ /* factoring program using Brents method */ + long k,r,i,m,iter; + big x,y,ys,z,q,c3,t; + x=mirvar(0); + y=mirvar(0); + ys=mirvar(0); + z=mirvar(0); + q=mirvar(0); + c3=mirvar(3); + t=mirvar(0); + m=10; + r=1; + iter=0; + do + { + if (!suppress) printf("iterations=%5ld",iter); + convert(1,q); + do + { + copy(y,x); + for (i=1;i<=r;i++) + mad(y,y,c3,n,n,y); + k=0; + do + { + iter++; + if (iter>BTRIES) + { + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + mr_free(t); + mr_free(x); + mr_free(y); + mr_free(ys); + mr_free(z); + mr_free(q); + mr_free(c3); + return; + } + if (iter%10==0) if (!suppress) + { + printf("\b\b\b\b\b%5ld",iter); + fflush(stdout); + } + copy(y,ys); + for (i=1;i<=mr_min(m,r-k);i++) + { + mad(y,y,c3,n,n,y); + subtract(y,x,z); + mad(z,q,q,n,n,q); + } + egcd(q,n,z); + k+=m; + } while (kPRIMES[i]; + if (prstart) break; + k=pr-start%pr; + for (j=k;j<=MULT/2;j+=pr) + plus[j]=FALSE; + k=start%pr; + for (j=k;j<=MULT/2;j+=pr) + minus[j]=FALSE; + } +} + +void pollard(int lim1,long lim2) +{ /* factoring program using Pollards (p-1) method */ + long i,p,pa,interval; + int phase,m,pos,btch,iv; + big t,b,bw,bvw,bd,bp,q; + t=mirvar(0); + b=mirvar(0); + q=mirvar(0); + bw=mirvar(0); + bvw=mirvar(0); + bd=mirvar(0); + bp=mirvar(0); + gprime(lim1); + for (m=1;m<=MULT/2;m+=2) + if (igcd(MULT,m)==1) + { + fu[m]=mirvar(0); + cp[m]=TRUE; + } + else cp[m]=FALSE; + phase=1; + p=0; + btch=50; + i=0; + convert(3,b); + if (!suppress) printf("phase 1 - trying all primes less than %d\n",lim1); + if (!suppress) printf("prime= %8ld",p); + forever + { + if (phase==1) + { /* looking for all factors of (p-1) < lim1 */ + p=mip->PRIMES[i]; + if (mip->PRIMES[i+1]==0) + { + phase=2; + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("phase 2 - trying last prime less than %ld\n" + ,lim2); + printf("prime= %8ld",p); + } + power(b,8,n,bw); + convert(1,t); + copy(b,bp); + copy(b,fu[1]); + for (m=3;m<=MULT/2;m+=2) + { /* store fu[m] = b^(m*m) */ + mad(t,bw,bw,n,n,t); + mad(bp,t,t,n,n,bp); + if (cp[m]) copy(bp,fu[m]); + } + power(b,MULT,n,t); + power(t,MULT,n,t); + mad(t,t,t,n,n,bd); /* bd=b^(2*MULT*MULT) */ + iv=p/MULT; + if (p%MULT>MULT/2) iv++; + interval=(long)iv*MULT; + p=interval+1; + marks(interval); + power(t,2*iv-1,n,bw); + power(t,iv,n,bvw); + power(bvw,iv,n,bvw); /* bvw = b^(MULT*MULT*iv*iv) */ + subtract(bvw,fu[p%MULT],q); + btch*=100; + i++; + continue; + } + pa=p; + while ((lim1/p) > pa) pa*=p; + power(b,(int)pa,n,b); + decr(b,1,q); + } + else + { /* looking for last PRIME FACTOR of (p-1) < lim2 */ + p+=2; + pos=p%MULT; + if (pos>MULT/2) + { /* increment giant step */ + iv++; + interval=(long)iv*MULT; + p=interval+1; + marks(interval); + pos=1; + mad(bw,bd,bd,n,n,bw); + mad(bvw,bw,bw,n,n,bvw); + } + if (!cp[pos]) continue; + + /* if neither interval+/-pos is prime, don't bother */ + if (!plus[pos] && !minus[pos]) continue; + + subtract(bvw,fu[pos],t); + mad(q,t,t,n,n,q); /* batching gcds */ + } + if (i++%btch==0) + { /* try for a solution */ + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b%8ld",p); + fflush(stdout); + } + egcd(q,n,t); + if (size(t)==1) + { + if (p>lim2) + { + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + break; + } + else continue; + } + if (mr_compare(t,n)==0) + { + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("degenerate case\n"); + } + break; + } + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + if (isprime(t)) printf("PRIME FACTOR "); + else printf("COMPOSITE FACTOR "); + } + else if (!isprime(t)) printf("& "); + cotnum(t,output); + divide(n,t,n); + if (isprime(n)) + { + if (!suppress) printf("PRIME FACTOR "); + cotnum(n,output); + exit(0); + } + break; + } + } + gprime(0); + mr_free(t); + mr_free(b); + mr_free(q); + mr_free(bw); + mr_free(bvw); + mr_free(bd); + mr_free(bp); + for (m=1;m<=MULT/2;m+=2) + if (igcd(MULT,m)==1) mr_free(fu[m]); +} + +void williams(int lim1,long lim2,int ntrys) +{ /* factoring program using Williams (p+1) method */ + int k,phase,m,nt,iv,pos,btch; + long i,p,pa,interval; + big b,q,fp,fvw,fd,fn,t; + b=mirvar(0); + q=mirvar(0); + t=mirvar(0); + fp=mirvar(0); + fvw=mirvar(0); + fd=mirvar(0); + fn=mirvar(0); + gprime(lim1); + + + for (m=1;m<=MULT/2;m+=2) + if (igcd(MULT,m)==1) + { + fu[m]=mirvar(0); + cp[m]=TRUE; + } + else cp[m]=FALSE; + for (nt=0,k=3;k<10;k++) + { /* try more than once for p+1 condition (may be p-1) */ + convert(k,b); /* try b=3,4,5.. */ + convert((k*k-4),t); + if (egcd(t,n,t)!=1) continue; /* check (b*b-4,n)!=0 */ + nt++; + phase=1; + p=0; + btch=50; + i=0; + if (!suppress) printf("phase 1 - trying all primes less than %d\n",lim1); + if (!suppress) printf("prime= %8ld",p); + forever + { /* main loop */ + if (phase==1) + { /* looking for all factors of p+1 < lim1 */ + p=mip->PRIMES[i]; + if (mip->PRIMES[i+1]==0) + { /* now change gear */ + phase=2; + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("phase 2 - trying last prime less than %ld\n" + ,lim2); + printf("prime= %8ld",p); + } + copy(b,fu[1]); + copy(b,fp); + mad(b,b,b,n,n,fd); + decr(fd,2,fd); + negify(b,t); + mad(fd,b,t,n,n,fn); + for (m=5;m<=MULT/2;m+=2) + { /* store fu[m] = Vm(b) */ + negify(fp,t); + mad(fn,fd,t,n,n,t); + copy(fn,fp); + copy(t,fn); + if (!cp[m]) continue; + copy(t,fu[m]); + } + convert(MULT,t); + lucas(b,t,n,fp,fd); + iv=p/MULT; + if (p%MULT>MULT/2) iv++; + interval=(long)iv*MULT; + p=interval+1; + marks(interval); + convert(iv,t); + lucas(fd,t,n,fp,fvw); + negify(fp,fp); + subtract(fvw,fu[p%MULT],q); + btch*=100; + i++; + continue; + } + pa=p; + while ((lim1/p) > pa) pa*=p; + convert((int)pa,t); + lucas(b,t,n,fp,q); + copy(q,b); + decr(q,2,q); + } + else + { /* phase 2 - looking for last large PRIME FACTOR of (p+1) */ + p+=2; + pos=p%MULT; + if (pos>MULT/2) + { /* increment giant step */ + iv++; + interval=(long)iv*MULT; + p=interval+1; + marks(interval); + pos=1; + copy(fvw,t); + mad(fvw,fd,fp,n,n,fvw); + negify(t,fp); + } + if (!cp[pos]) continue; + + /* if neither interval+/-pos is prime, don't bother */ + if (!plus[pos] && !minus[pos]) continue; + + subtract(fvw,fu[pos],t); + mad(q,t,t,n,n,q); /* batching gcds */ + } + if (i++%btch==0) + { /* try for a solution */ + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b%8ld",p); + fflush(stdout); + } + egcd(q,n,t); + if (size(t)==1) + { + if (p>lim2) + { + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + break; + } + else continue; + } + if (mr_compare(t,n)==0) + { + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("degenerate case\n"); + } + break; + } + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + if (isprime(t)) printf("PRIME FACTOR "); + else printf("COMPOSITE FACTOR "); + } + else if (!isprime(t)) printf("& "); + cotnum(t,output); + divide(n,t,n); + if (isprime(n)) + { + if (!suppress) printf("PRIME FACTOR "); + cotnum(n,output); + exit(0); + } + nt=ntrys; + break; + } + } + if (nt>=ntrys) break; + } + gprime(0); + mr_free(b); + mr_free(q); + mr_free(t); + mr_free(fp); + mr_free(fvw); + mr_free(fd); + mr_free(fn); + for (m=1;m<=MULT/2;m+=2) + if (igcd(MULT,m)==1) mr_free(fu[m]); +} + + +static big ak,t,ww,s1,d1,s2,d2; + +void duplication(big sum,big diff,big x,big z) +{ /* double a point on the curve P(x,z)=2.P(x1,z1) */ + nres_modmult(sum,sum,t); + nres_modmult(diff,diff,z); + nres_modmult(t,z,x); /* x = sum^2.diff^2 */ + nres_modsub(t,z,t); /* t = sum^2-diff^2 */ + nres_modmult(ak,t,ww); + nres_modadd(z,ww,z); /* z = ak*t +diff^2 */ + nres_modmult(z,t,z); /* z = z.t */ +} + +void addition(big xd,big zd,big sm1,big df1,big sm2,big df2,big x,big z) +{ /* add two points on the curve P(x,z)=P(x1,z1)+P(x2,z2) * + * given their difference P(xd,zd) */ + nres_modmult(df2,sm1,x); + nres_modmult(df1,sm2,z); + nres_modadd(z,x,t); + nres_modsub(z,x,z); + nres_modmult(t,t,x); + nres_modmult(x,zd,x); /* x = zd.[df1.sm2+sm1.df2]^2 */ + nres_modmult(z,z,z); + nres_modmult(z,xd,z); /* z = xd.[df1.sm2-sm1.df2]^2 */ +} + +void ellipse(big x,big z,int r,big x1,big z1,big x2,big z2) +{ /* calculate point r.P(x,z) on curve */ + int k,rr; + k=1; + rr=r; + copy(x,x1); + copy(z,z1); + nres_modadd(x1,z1,s1); + nres_modsub(x1,z1,d1); + duplication(s1,d1,x2,z2); /* generate 2.P */ + while ((rr/=2)>1) k*=2; + while (k>0) + { /* use binary method */ + nres_modadd(x1,z1,s1); /* form sums and differences */ + nres_modsub(x1,z1,d1); /* x+z and x-z for P1 and P2 */ + nres_modadd(x2,z2,s2); + nres_modsub(x2,z2,d2); + if ((r&k)==0) + { /* double P(x1,z1) mP to 2mP */ + addition(x,z,s1,d1,s2,d2,x2,z2); + duplication(s1,d1,x1,z1); + } + else + { /* double P(x2,z2) (m+1)P to (2m+2)P */ + addition(x,z,s1,d1,s2,d2,x1,z1); + duplication(s2,d2,x2,z2); + } + k/=2; + } +} + +int lenstra(int lim1,long lim2,int nc,int kurve,int ncurves) +{ /* factoring program using Lenstras Elliptic Curve method */ + int phase,m,iv,pos,btch,u,v,ncr; + long i,p,pa,interval; + big q,x,z,a,x1,z1,x2,z2,xt,zt,fvw; + q=mirvar(0); + x=mirvar(0); + z=mirvar(0); + a=mirvar(0); + x1=mirvar(0); + z1=mirvar(0); + x2=mirvar(0); + z2=mirvar(0); + s1=mirvar(0); + d1=mirvar(0); + s2=mirvar(0); + d2=mirvar(0); + ak=mirvar(0); + xt=mirvar(0); + zt=mirvar(0); + fvw=mirvar(0); + t=mirvar(0); + ww=mirvar(0); + gprime(lim1); + + for (m=1;m<=MULT/2;m+=2) + if (igcd(MULT,m)==1) + { + fu[m]=mirvar(0); + cp[m]=TRUE; + } + else cp[m]=FALSE; + + + prepare_monty(n); + /* try a new curve */ + /* generating an elliptic curve */ + ncr=nc; + u=kurve*kurve-5; + v=4*kurve; + + convert(u,x); nres(x,x); + convert(v,z); nres(z,z); + nres_modsub(z,x,a); /* a=v-u */ + + copy(x,t); + nres_modmult(x,x,x); + nres_modmult(x,t,x); /* x=u^3 */ + + copy(z,t); + nres_modmult(z,z,z); + nres_modmult(z,t,z); /* z=v^3 */ + + copy(a,t); + nres_modmult(t,t,t); + nres_modmult(t,a,t); /* t=(v-u)^3 */ + + convert(3*u,a); nres(a,a); + convert(v,ak); nres(ak,ak); + nres_modadd(a,ak,a); + nres_modmult(t,a,t); /* t=(v-u)^3.(3u+v) */ + + convert(u,a); nres(a,a); + copy(a,ak); + nres_modmult(a,a,a); + nres_modmult(a,ak,a); /* a=u^3 */ + convert(v,ak); nres(ak,ak); + nres_modmult(a,ak,a); /* a=u^3.v */ + nres_premult(a,16,a); + nres_moddiv(t,a,ak); /* ak=(v-u)^3.(3u+v)/16u^3v */ + + phase=1; + p=0; + i=0; + btch=50; + if (!suppress) printf("curve %3d phase 1 - trying all primes less than %d\n",nc,lim1); + if (!suppress) printf("prime= %8ld",p); + ncr++; + forever + { /* main loop */ + if (phase==1) + { + p=mip->PRIMES[i]; + if (mip->PRIMES[i+1]==0) + { /* now change gear */ + phase=2; + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf(" phase 2 - trying last prime less than %ld\n", + lim2); + printf("prime= %8ld",p); + } + copy(x,xt); + copy(z,zt); + nres_modadd(x,z,s2); + nres_modsub(x,z,d2); /* P = (s2,d2) */ + duplication(s2,d2,x,z); + nres_modadd(x,z,s1); + nres_modsub(x,z,d1); /* 2.P = (s1,d1) */ + + nres_moddiv(x1,z1,fu[1]); /* fu[1] = x1/z1 */ + + addition(x1,z1,s1,d1,s2,d2,x2,z2); /* 3.P = (x2,z2) */ + for (m=5;m<=MULT/2;m+=2) + { /* calculate m.P = (x,z) and store fu[m] = x/z */ + nres_modadd(x2,z2,s2); + nres_modsub(x2,z2,d2); + addition(x1,z1,s2,d2,s1,d1,x,z); + copy(x2,x1); + copy(z2,z1); + copy(x,x2); + copy(z,z2); + if (!cp[m]) continue; + copy(z2,fu[m]); + nres_moddiv(x2,fu[m],fu[m]); + } + ellipse(xt,zt,MULT,x,z,x2,z2); + nres_modadd(x,z,xt); + nres_modsub(x,z,zt); /* MULT.P = (xt,zt) */ + iv=(int)(p/MULT); + if (p%MULT>MULT/2) iv++; + interval=(long)iv*MULT; + p=interval+1; + marks(interval); + ellipse(x,z,iv,x1,z1,x2,z2); /* (x1,z1) = iv.MULT.P */ + nres_moddiv(x1,z1,fvw); /* fvw = x1/z1 */ + nres_modsub(fvw,fu[p%MULT],q); + btch*=100; + i++; + continue; + } + pa=p; + while ((lim1/p) > pa) pa*=p; + ellipse(x,z,(int)pa,x1,z1,x2,z2); + copy(x1,x); + copy(z1,z); + copy(z,q); + } + else + { /* phase 2 - looking for last large PRIME FACTOR of (p+1+d) */ + p+=2; + pos=(int)(p%MULT); + if (pos>MULT/2) + { /* increment giant step */ + iv++; + interval=(long)iv*MULT; + p=interval+1; + marks(interval); + pos=1; + nres_moddiv(x2,z2,fvw); + nres_modadd(x2,z2,s2); + nres_modsub(x2,z2,d2); + addition(x1,z1,s2,d2,xt,zt,x,z); + copy(x2,x1); + copy(z2,z1); + copy(x,x2); + copy(z,z2); + } + if (!cp[pos]) continue; + + /* if neither interval +/- pos is prime, don't bother */ + if (!plus[pos] && !minus[pos]) continue; + + nres_modsub(fvw,fu[pos],t); + nres_modmult(q,t,q); + } + if (i++%btch==0) + { /* try for a solution */ + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b%8ld",p); + fflush(stdout); + } + egcd(q,n,t); + if (size(t)==1) + { + if (p>lim2) + { + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + fflush(stdout); + } + break; + } + else continue; + } + if (mr_compare(t,n)==0) + { + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + printf("degenerate case\n"); + } + break; + } + + if (!suppress) + { + printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); + if (isprime(t)) printf("PRIME FACTOR "); + else printf("COMPOSITE FACTOR "); + } + else if (!isprime(t)) printf("& "); + cotnum(t,output); + divide(n,t,n); + if (isprime(n)) + { + if (!suppress) printf("PRIME FACTOR "); + cotnum(n,output); + exit(0); + } + ncr=ncurves+1; + break; + } + } + + gprime(0); + mr_free(ww); + mr_free(t); + mr_free(q); + mr_free(x); + mr_free(z); + mr_free(a); + mr_free(x1); + mr_free(z1); + mr_free(x2); + mr_free(z2); + mr_free(s1); + mr_free(d1); + mr_free(s2); + mr_free(d2); + mr_free(ak); + mr_free(xt); + mr_free(zt); + mr_free(fvw); + for (m=1;m<=MULT/2;m+=2) + if (igcd(MULT,m)==1) mr_free(fu[m]); + return ncr; +} + +void do_lenstra(int lim1,long lim2,int ncurves) +{ + int nc=1; + int kurve=5; + + for (nc=1;nc<=ncurves;) + { + kurve++; + nc=lenstra(lim1,lim2,nc,kurve,ncurves); + } +} + +#define SSIZE 100000 /* Maximum sieve size */ + +static big NN,TT,DD,RR,VV,PP,XX,YY,DG,IG,AA,BB; +static big *x,*y,*z,*w; +static unsigned int **EE,**G; +static int *epr,*r1,*r2,*rp,*b,*pr,*e,*hash; +static unsigned char *logp,*sieve; +static int mm,mlf,jj,nbts,nlp,lp,hmod,hmod2; +static BOOL partial; + +int knuth(int mm,int *epr,big N,big D) +{ /* Input number to be factored N and find best multiplier k * + * for use over a factor base epr[] of size mm. Set D=k.N. */ + double dp,fks,top; + BOOL found; + int i,j,bk,nk,kk,r,p; + static int K[]={0,1,2,3,5,6,7,10,11,13,14,15,17,0}; + top=(-10.0e0); + found=FALSE; + nk=0; + bk=0; + epr[0]=1; + epr[1]=2; + do + { /* search for best Knuth-Schroepel multiplier */ + kk=K[++nk]; + if (kk==0) + { /* finished */ + kk=K[bk]; + found=TRUE; + } + premult(N,kk,D); + fks=log(2.0e0)/(2.0e0); + r=remain(D,8); + if (r==1) fks*=(4.0e0); + if (r==5) fks*=(2.0e0); + fks-=log((double)kk)/(2.0e0); + i=0; + j=1; + while (jPRIMES[++i]; + r=remain(D,p); + if (spmd(r,(p-1)/2,p)<=1) + { /* use only if Jacobi symbol = 0 or 1 */ + epr[++j]=p; + dp=(double)p; + if (kk%p==0) fks+=log(dp)/dp; + else fks+=2*log(dp)/(dp-1.0e0); + } + } + if (fks>top) + { /* find biggest fks */ + top=fks; + bk=nk; + } + } while (!found); + return kk; +} + +BOOL factored(long lptr,big T) +{ /* factor quadratic residue */ + BOOL facted; + int i,j,r,st; + partial=FALSE; + facted=FALSE; + for (j=1;j<=mm;j++) + { /* now attempt complete factorisation of T */ + r=(int)(lptr%epr[j]); + if (r<0) r+=epr[j]; + if (r!=r1[j] && r!=r2[j]) continue; + while (subdiv(T,epr[j],XX)==0) + { /* cast out epr[j] */ + e[j]++; + copy(XX,T); + } + st=size(T); + if (st==1) + { + facted=TRUE; + break; + } + if (size(XX)<=epr[j]) + { /* st is prime < epr[mm]^2 */ + if (st>=MR_TOOBIG || (st/epr[mm])>(1+mlf/50)) break; + if (st<=epr[mm]) + for (i=j;i<=mm;i++) + if (st==epr[i]) + { + e[i]++; + facted=TRUE; + break; + } + if (facted) break; + lp=st; /* factored with large prime */ + partial=TRUE; + facted=TRUE; + break; + } + } + return facted; +} + +BOOL gotcha(void) +{ /* use new factorisation */ + int r,j,i,k,n,rb,had,hp; + unsigned int t; + BOOL found; + found=TRUE; + if (partial) + { /* check partial factorisation for usefulness */ + had=lp%hmod; + forever + { /* hash search for matching large prime */ + hp=hash[had]; + if (hp<0) + { /* failed to find match */ + found=FALSE; + break; + } + if (pr[hp]==lp) break; /* hash hit! */ + had=(had+(hmod2-lp%hmod2))%hmod; + } + if (!found && nlp>=mlf) return FALSE; + } + copy(PP,XX); + convert(1,YY); + for (k=1;k<=mm;k++) + { /* build up square part in YY * + * reducing e[k] to 0s and 1s */ + if (e[k]<2) continue; + r=e[k]/2; + e[k]%=2; + expint(epr[k],r,TT); + multiply(TT,YY,YY); + } +/* debug only + cotnum(XX,stdout); + cotnum(YY,stdout); + if (e[0]==1) printf("-1"); + else printf("1"); + for (k=1;k<=mm;k++) + { + if (e[k]==0) continue; + printf(".%d",epr[k]); + } + if (partial) printf(".%d\n",lp); + else printf("\n"); +*/ + if (partial) + { /* factored with large prime */ + if (!found) + { /* store new partial factorization */ + hash[had]=nlp; + pr[nlp]=lp; + copy(XX,z[nlp]); + copy(YY,w[nlp]); + for (n=0,rb=0,j=0;j<=mm;j++) + { + G[nlp][n]|=((e[j]&1)<>rb); + e[j]+=(t&1); + if (e[j]==2) + { + premult(YY,epr[j],YY); + divide(YY,NN,NN); + e[j]=0; + } + if (++rb==nbts) n++,rb=0; + } + premult(YY,lp,YY); + divide(YY,NN,NN); + } + } + else if (!suppress) + { + printf("\b\b\b\b\b\b "); + fflush(stdout); + } + if (found) + { + for (k=mm;k>=0;k--) + { /* use new factorization in search for solution */ + if (e[k]%2==0) continue; + if (b[k]<0) + { /* no solution this time */ + found=FALSE; + break; + } + i=b[k]; + mad(XX,x[i],XX,NN,NN,XX); /* This is very inefficient - */ + mad(YY,y[i],YY,NN,NN,YY); /* There must be a better way! */ + for (n=0,rb=0,j=0;j<=mm;j++) + { /* Gaussian elimination */ + t=(EE[i][n]>>rb); + e[j]+=(t&1); + if (++rb==nbts) n++,rb=0; + } + } + for (j=0;j<=mm;j++) + { /* update YY */ + if (e[j]<2) continue; + convert(epr[j],TT); + power(TT,e[j]/2,NN,TT); + mad(YY,TT,YY,NN,NN,YY); + } + if (!found) + { /* store details in E, x and y for later */ + b[k]=jj; + copy(XX,x[jj]); + copy(YY,y[jj]); + for (n=0,rb=0,j=0;j<=mm;j++) + { + EE[jj][n]|=((e[j]&1)<20) mm=(d*d*d*d)/4096; + +/* only half the primes (on average) wil be used, so generate twice as + many (+ a bit for luck) */ + + dp=(double)2*(double)(mm+100); /* number of primes to generate */ + maxp=(int)(dp*(log(dp*log(dp)))); /* Rossers upper bound */ + gprime(maxp); + + epr=(int *)mr_alloc(mm+1,sizeof(int)); + + k=knuth(mm,epr,NN,DD); + + if (nroot(DD,2,RR)) + { + if (!suppress) + { + printf("%dN is a perfect square!\n",k); + if (isprime(RR)) printf("PRIME FACTOR "); + else printf("COMPOSITE FACTOR "); + } + else if (!isprime(RR)) printf("& "); + cotnum(RR,output); + divide(NN,RR,NN); + if (!suppress) + { + if (isprime(NN)) printf("PRIME FACTOR "); + else printf("COMPOSITE FACTOR "); + } + else if (!isprime(NN)) printf("& "); + cotnum(NN,output); + return (-1); + } + if(!suppress) + { + printf("using multiplier k= %d and %d small primes as factor base\n",k,mm); + } + gprime(0); /* reclaim PRIMES space */ + + mlf=2*mm; + +/* now get space for arrays */ + + r1=(int *)mr_alloc((mm+1),sizeof(int)); + r2=(int *)mr_alloc((mm+1),sizeof(int)); + rp=(int *)mr_alloc((mm+1),sizeof(int)); + b=(int *)mr_alloc((mm+1),sizeof(int)); + e=(int *)mr_alloc((mm+1),sizeof(int)); + + logp=(unsigned char *)mr_alloc(mm+1,1); + + pr=(int *)mr_alloc((mlf+1),sizeof(int)); + hash=(int *)mr_alloc((2*mlf+1),sizeof(int)); + + sieve=(unsigned char *)mr_alloc(SSIZE+1,1); + + x=(big *)mr_alloc(mm+1,sizeof(big *)); + y=(big *)mr_alloc(mm+1,sizeof(big *)); + z=(big *)mr_alloc(mlf+1,sizeof(big *)); + w=(big *)mr_alloc(mlf+1,sizeof(big *)); + + for (i=0;i<=mm;i++) + { + x[i]=mirvar(0); + y[i]=mirvar(0); + } + for (i=0;i<=mlf;i++) + { + z[i]=mirvar(0); + w[i]=mirvar(0); + } + + EE=(unsigned int **)mr_alloc(mm+1,sizeof(int *)); + G=(unsigned int **)mr_alloc(mlf+1,sizeof(int *)); + + pak=1+mm/(MR_IBITS); + for (i=0;i<=mm;i++) + { + b[i]=(-1); + EE[i]=(unsigned int *)mr_alloc(pak,sizeof(int)); + } + + mip->ERCON=TRUE; + for (i=0;i<=mlf;i++) + { + G[i]=(unsigned int *)mr_alloc(pak,sizeof(int)); + if (G[i]==NULL) + { /* Out of space - try a quick fix */ + mlf=mm; + for (j=mm+1;jERCON=FALSE; + mip->ERNUM=0; + return 1; +} + +int qsieve(int d) +{ /* factoring via quadratic sieve */ + unsigned int i,j,a,*SV; + unsigned char logpi; + int k,S,r,s1,s2,s,NS,logm,ptr,threshold,epri; + long M,la,lptr; + + if (initv(d)<0) exit(0); + + hmod=2*mlf+1; /* set up hash table */ + convert(hmod,TT); + while (!isprime(TT)) decr(TT,2,TT); + hmod=size(TT); + hmod2=hmod-2; + for (k=0;k0) logm++; /* logm = log(M) */ + rp[0]=logp[0]=0; + for (k=1;k<=mm;k++) + { /* find root mod each prime, and approx log of each prime */ + r=subdiv(DD,epr[k],TT); + rp[k]=sqrmp(r,epr[k]); + logp[k]=0; + r=epr[k]; + while((r/=2)>0) logp[k]++; + } + r=subdiv(DD,8,TT); /* take special care of 2 */ + if (r==5) logp[1]++; + if (r==1) logp[1]+=2; + + threshold=logm+logb2(RR)-2*logp[mm]; + + jj=0; + nlp=0; + premult(DD,2,DG); + nroot(DG,2,DG); + + lgconv(M,TT); + divide(DG,TT,DG); + nroot(DG,2,DG); + if (subdiv(DG,2,TT)==0) incr(DG,1,DG); + if (subdiv(DG,4,TT)==1) incr(DG,2,DG); + if (!suppress) printf("working... 0"); + forever + { /* try a new polynomial */ + r=mip->NTRY; + mip->NTRY=1; /* speed up search for prime */ + do + { /* looking for suitable prime DG = 3 mod 4 */ + do { + incr(DG,4,DG); + } while(!isprime(DG)); + decr(DG,1,TT); + subdiv(TT,2,TT); + powmod(DD,TT,DG,TT); /* check D is quad residue */ + } while (size(TT)!=1); + mip->NTRY=r; + incr(DG,1,TT); + subdiv(TT,4,TT); + powmod(DD,TT,DG,BB); + negify(DD,TT); + mad(BB,BB,TT,DG,TT,TT); + negify(TT,TT); + premult(BB,2,AA); + xgcd(AA,DG,AA,AA,AA); + mad(AA,TT,TT,DG,DG,AA); + multiply(AA,DG,TT); + add(BB,TT,BB); /* BB^2 = DD mod DG^2 */ + multiply(DG,DG,AA); /* AA = DG*DG */ + xgcd(DG,DD,IG,IG,IG); /* IG = 1/DG mod DD */ + + r1[0]=r2[0]=0; + for (k=1;k<=mm;k++) + { /* find roots of quadratic mod each prime */ + s=subdiv(BB,epr[k],TT); + r=subdiv(AA,epr[k],TT); + r=invers(r,epr[k]); /* r = 1/AA mod p */ + s1=(epr[k]-s+rp[k]); + s2=(epr[k]-s+epr[k]-rp[k]); + r1[k]=smul(s1,r,epr[k]); + r2[k]=smul(s2,r,epr[k]); + } + + for (ptr=(-NS);ptr='0' && s[i]<='9';i++) + ; + if (!i) /* No digits found */ + { + printf ("Error - invalid number\n"); + exit (20); + } + op=s[i]; + s[i]=0; + lgconv(atol(s),n); + s+=i; + *s=op; + } + if (minus) negify(n,n); + do + op=*s++; + while (op==' '); + if (op==0 || op==')' || op==']' || op=='}') + { + eval_power (oldn[2],n,oldop[2]); + eval_product (oldn[1],n,oldop[1]); + eval_sum (oldn[0],n,oldop[0]); + copy(n,t); + mr_free(n); + for (i=0;i<2;i++) mr_free(oldn[i]); + return; + } + else + { + if (op==RAISE) + { + eval_power (oldn[2],n,oldop[2]); + copy(n,oldn[2]); + oldop[2]=RAISE; + } + else + { + if (op==TIMES || op=='/' || op=='%') + { + eval_power (oldn[2],n,oldop[2]); + oldop[2]=0; + eval_product (oldn[1],n,oldop[1]); + copy(n,oldn[1]); + oldop[1]=op; + } + else + { + if (op=='+' || op=='-') + { + eval_power (oldn[2],n,oldop[2]); + oldop[2]=0; + eval_product (oldn[1],n,oldop[1]); + oldop[1]=0; + eval_sum (oldn[0],n,oldop[0]); + copy(n,oldn[0]); + oldop[0]=op; + } + else /* Error - invalid operator */ + { + printf ("Error - invalid operator\n"); + exit (20); + } + } + } + } + goto LOOP; +} + +int main(int argc,char **argv) +{ + FILE *ifile; + int ip,b,d=250; + argv++;argc--; + if (argc<1) + { + printf("Incorrect Usage\n"); + printf("factor \n"); + printf("OR\n"); + printf("factor -f \n"); + printf("e.g. factor 999999999999999999999999999999999999999999999999999997\n"); +#if defined(unix) + printf("or factor -f 10^100-19\n\n"); +#else + printf("or factor -f 10#100-19\n\n"); +#endif + printf("To suppress the commentary, use flag -s\n"); + printf("To input from a file, use flag -i \n"); + printf("To output to a file, use flag -o \n"); + printf("To set max. number size, set -dn, where n is number of decimal digits\n"); + printf("(Default is -d150). Must be first flag and before number.\n"); +#if defined(unix) + printf("e.g. factor -d200 -f 10^200-1 -s -o factors.dat\n\n"); +#else + printf("e.g. factor -d200 -f 10#200-1 -s -o factors.dat\n\n"); +#endif + printf("Freeware from Certivox, Dublin, Ireland\n"); + printf("Full C source code and MIRACL multiprecision library available\n"); + printf("Email to mscott@indigo.ie for details\n"); + return 0; + } + + b=(d*45)/100; +#ifndef MR_NOFULLWIDTH + mip=mirsys(-b,0); +#else + mip=mirsys(-b,MAXBASE); +#endif + + mip->NTRY=100; + n=mirvar(0); + + ip=0; + output=stdout; + + while (ipNTRY=100; + n=mirvar(0); + continue; + + } + if (strcmp(argv[ip],"-f")==0) + { + ip++; + s=argv[ip++]; + t=mirvar(0); + eval(); + copy(t,n); + mr_free(t); + cotnum(n,stdout); + continue; + } + if (strcmp(argv[ip],"-s")==0) + { + ip++; + suppress=TRUE; + continue; + } + if (strcmp(argv[ip],"-i")==0) + { + ip++; + ifile=fopen(argv[ip++],"rt"); + if (ifile==NULL) break; + cinnum(n,ifile); + cotnum(n,stdout); + continue; + } + if (strcmp(argv[ip],"-o")==0) + { + ip++; + output=fopen(argv[ip++],"wt"); + continue; + } + cinstr(n,argv[ip++]); + } + + if (size(n)==0) + { + printf("No number to factor!\n"); + return 0; + } + if (size(n)<0) + { + printf("Positive numbers only!\n"); + return 0; + } + if (isprime(n)) + { + cotnum(n,output); + printf("this number is prime!\n"); + return 0; + } + + if (!suppress) printf("first trying brute force division by small primes\n"); + brute(); + if (!suppress) printf("now trying %d iterations of brent's method\n",BTRIES); + brent(); + fu= (big *)mr_alloc((1+MULT/2),sizeof(big)); + cp=(BOOL *)mr_alloc((1+MULT/2),sizeof(BOOL)); + plus=(BOOL *)mr_alloc((1+MULT/2),sizeof(BOOL)); + minus=(BOOL *)mr_alloc((1+MULT/2),sizeof(BOOL)); + + if (digits()>25) + { + if (!suppress) printf("now trying william's (p+1) method\n"); + williams(10000,1000000L,1); + if (!suppress) printf("now trying pollard's (p-1) method\n"); + pollard(100000,5000000L); + } + if (digits()>35) + { + if (!suppress) printf("now trying lenstra's method using 10 curves\n"); + do_lenstra(20000,2000000L,10); + if (digits()>64) + { + if (!suppress) printf("now trying 80 more curves\n"); + do_lenstra(20000,2000000L,80); + } + if (digits()>72) + { + if (!suppress) printf("trying 300 last curves\n"); + do_lenstra(50000,5000000,300); + } + } + + mr_free(minus); + mr_free(plus); + mr_free(cp); + mr_free(fu); + if (digits()<110) + { + if (!suppress) printf("finally - the multiple polynomial quadratic sieve - with large prime (*)\n"); + qsieve(digits()); + } + if (!suppress) printf("I give up \nCOMPOSITE FACTOR "); + else printf("& "); + cotnum(n,output); + return 0; +} + diff --git a/miracl/source/findbase.cpp b/miracl/source/findbase.cpp new file mode 100644 index 0000000..ac4c363 --- /dev/null +++ b/miracl/source/findbase.cpp @@ -0,0 +1,278 @@ +// +// cl /O2 /GX findbase.cpp gf2m.cpp big.cpp miracl.lib +// +// program to find "best" irreducible polynomial for GF(2^m) +// See http://eprint.iacr.org/2007/192 +// cl /O2 /GX findbase.cpp gf2m.cpp big.cpp miracl.lib +// To generate the code for the reduction in a form for inclusion in +// mrgf2m.c, function reduce2(.) use the irp.cpp utility +// + +#include +#include "gf2m.h" + +using namespace std; + +Miracl precision=100; + +/* Max word size to be supported with irreducible polynomial */ + +#define MAX_WORD_SIZE MIRACL + +/* define bit length of machine word - this can be changed here to 16 or whatever */ + +#define WORDLENGTH MAX_WORD_SIZE + +/* insert costs of each operation in clock cycles */ + +#define XOR 1 + +/* cost of shifts (left and right) per shift size */ + + +/* MSP430 Costs MIRACL = 16 */ + +//int ls[16]={0,1,2,3,4,5,6,5,2,3,4,5,6,5,4,3}; +//int rs[16]={0,2,3,4,5,6,7,5,2,3,4,5,6,5,4,3}; + + +/* Atmeg128 Costs MIRACL = 8 */ + +//int ls[8]={0,1,2,3,2,3,4,3}; +//int rs[8]={0,1,2,3,2,3,4,3}; + + +/* Pentium Costs MIRACL = 32 */ + +//int ls[32]={0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +//int rs[32]={0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; + + +/* x86-64 Costs MIRACL=64 */ + +int ls[64]={0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; +int rs[64]={0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; + + +/* ARM Costs MIRACL = 32 */ + +//int ls[32]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; +//int rs[32]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + + +int priceit(int *s,int *d) +{ /* given the shifts and the cost per shift - put a price on it */ + int i,j,k,price,best; + if (s[0]==0) return 0; + + price=d[s[1]]; + for (i=2;i<=s[0];i++) + { + best=s[i]-s[i-1]; /* a number of one-bit shifts is always an option */ + if (d[s[i]]< best) best=d[s[i]]; + for (j=1;j<=i-1;j++) + { /* see is there a cheaper way */ + k=s[i]-s[j]; + if (d[k]=sharray[sharray[0]]) + { /* shift greatest so far - put it on the end */ + sharray[0]++; + sharray[sharray[0]]=sh; + return; + } +/* insert */ + i=1; + while (sh>sharray[i]) i++; + + for (j=sharray[0];j>=i;j--) + sharray[j+1]=sharray[j]; + + sharray[0]++; + sharray[i]=sh; + return; +} + +int cost(int W,int M,int A,int B,int C,int *shifts) +{ + int i,j,len,rsh[4],lsh[4],ii; + int xors,lshifts[5],rshifts[5]; + + lshifts[0]=rshifts[0]=0; + + rsh[0]=M%W; + lsh[0]=W-rsh[0]; + + rsh[1]=(M-A)%W; + lsh[1]=W-rsh[1]; + + len=2; + if (B) + { + len=4; + rsh[2]=(M-B)%W; + lsh[2]=W-rsh[2]; + rsh[3]=(M-C)%W; + lsh[3]=W-rsh[3]; + } + + xors=0; + for (i=0;iM=m; + get_mip()->AA=a; + get_mip()->BB=b; + get_mip()->CC=c; + + if (b==0) modulus=pow((Big)2,m)+pow((Big)2,a)+1; + else modulus=pow((Big)2,m)+pow((Big)2,a)+pow((Big)2,b)+pow((Big)2,c)+1; + copy(modulus.getbig(),get_mip()->modulus); + copy(modulus.getbig(),getbig(modulo)); + + w4=2; + for (int i=1;i<=m/2;i++) + { + w4*=w4; + w5=w4+2; + if (gcd(w5,modulo)!=1) return FALSE; + } + + return TRUE; +} + +int main(int argc,char **argv) +{ + int i,M,A,B,C,L,xors,shifts,price,bestprice; + long cheapest,wcost; + int CA,CB,CC; + + argc--; argv++; + + if (argc!=1 && argc!=2) + { + cout << "Bad Parameters" << endl; + cout << "findbase " << endl; + cout << "finds irreducible polynomials for field F(2^M)" << endl; + cout << "findbase " << endl; + cout << "finds irreducible polynomials with cost less than or equal to L" << endl; + exit(0); + } + + get_mip()->IOBASE=16; + M=atoi(argv[0]); + if (argc==2) L=atoi(argv[1]); + else L=0; + + cheapest=1000000L; + + cout << "Looking for suitable trinomial basis x^M+x^A+1" << endl; + + for (A=M-MAX_WORD_SIZE;A>=1;A--) + { + if (A%2==0) continue; // odds only + if (irreducible(M,A,0,0)) + { + xors=cost(WORDLENGTH,M,A,0,0,&shifts); + price=xors+shifts; + wcost=1000*price-A; + if (wcost=1;A--) + { + if (A%2==0) continue; // odds only + for (B=A-1;B>=1;B--) + { + if (B%2==0) continue; // odds only + for (C=B-1;C>=1;C--) + { + if (C%2==0) continue; // odds only + if (irreducible(M,A,B,C)) + { + xors=cost(WORDLENGTH,M,A,B,C,&shifts); + price=xors+shifts; + wcost=1000*price-C; + if (wcostfn); +return b;} + +Big Flash::num(void) {Big b; numer(fn,b.fn); return b;} +Big Flash::den(void) {Big b; denom(fn,b.fn); return b;} + +Flash operator-(const Flash& f) {Flash nf; negify(f.fn,nf.fn); return nf;} + +Flash operator+(const Flash& f1, const Flash& f2) +{Flash aff; fadd(f1.fn,f2.fn,aff.fn); return aff;} + +Flash operator-(const Flash& f1, const Flash& f2) +{Flash mff; fsub(f1.fn,f2.fn,mff.fn); return mff;} + +Flash operator*(const Flash& f1, const Flash& f2) +{Flash xff; fmul(f1.fn,f2.fn,xff.fn); return xff;} + +Flash operator/(const Flash& f1, const Flash& f2) +{Flash dff; fdiv(f1.fn,f2.fn,dff.fn); return dff;} +Flash operator%(const Flash& f1, const Flash& f2) +{Flash rff; fmodulo(f1.fn,f2.fn,rff.fn); return rff;} + +Flash pi() {Flash z; fpi(z.fn); return z;} + +Flash inverse(const Flash& f) {Flash z; frecip(f.fn, z.fn); return z;} + +Flash cos(const Flash& f) {Flash z; fcos(f.fn, z.fn); return z;} +Flash sin(const Flash& f) {Flash z; fsin(f.fn, z.fn); return z;} +Flash tan(const Flash& f) {Flash z; ftan(f.fn, z.fn); return z;} + +Flash acos(const Flash& f){Flash z; facos(f.fn, z.fn);return z;} +Flash asin(const Flash& f){Flash z; fasin(f.fn, z.fn);return z;} +Flash atan(const Flash& f){Flash z; fatan(f.fn, z.fn);return z;} + +Flash cosh(const Flash& f){Flash z; fcosh(f.fn, z.fn);return z;} +Flash sinh(const Flash& f){Flash z; fsinh(f.fn, z.fn);return z;} +Flash tanh(const Flash& f){Flash z; ftanh(f.fn, z.fn);return z;} + +Flash acosh(const Flash& f){Flash z; facosh(f.fn, z.fn);return z;} +Flash asinh(const Flash& f){Flash z; fasinh(f.fn, z.fn);return z;} +Flash atanh(const Flash& f){Flash z; fatanh(f.fn, z.fn);return z;} + +Flash log(const Flash& f) {Flash z; flog(f.fn, z.fn); return z;} +Flash exp(const Flash& f) {Flash z; fexp(f.fn, z.fn); return z;} +Flash pow(const Flash& f1,const Flash& f2) +{Flash z;fpowf(f1.fn,f2.fn,z.fn); return z;} + +Flash sqrt(const Flash& f) {Flash z; froot(f.fn, 2, z.fn); return z;} +Flash nroot(const Flash& f,int n) {Flash z; froot(f.fn,n,z.fn); return z;} +Flash fabs(const Flash& f) {Flash z; absol(f.fn,z.fn); return z;} + +#ifndef MR_NO_STANDARD_IO + +istream& operator>>(istream& s, Flash& x) +{ + miracl *mip=get_mip(); + s >> mip->IOBUFF; + if (s.eof() || s.bad()) + { + zero(x.fn); + return s; + } + cinstr(x.fn,mip->IOBUFF); + return s; +} + +ostream& operator<<(ostream& s, const Flash& x) +{ + miracl *mip=get_mip(); + cotstr(x.fn,mip->IOBUFF); + s << mip->IOBUFF; + return s; +} + +#endif + +#endif + diff --git a/miracl/source/floating.cpp b/miracl/source/floating.cpp new file mode 100644 index 0000000..6c97aaf --- /dev/null +++ b/miracl/source/floating.cpp @@ -0,0 +1,677 @@ +/* + * MIRACL C++ Float functions float.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of Class Float functions + */ + +#include +#include "floating.h" + +using namespace std; + +#define TAN 1 +#define SIN 2 +#define COS 3 + +static Float *spi; +static int precision=4; // must be power of 2 +static BOOL pi_cooked=FALSE; + +Float makefloat(int a,int b) +{ + return (Float)a/b; +} + +Float fabs(const Float& f) +{ + Float r=f; + if (r.m<0) r.m.negate(); + return r; +} + +int norm(int type,Float& y) +{ // convert y to 1st quadrant angle, and return sign + int s=PLUS; + Float pi,w,t; + if (y.sign()<0) + { + y.negate(); + if (type!=COS) s=-s; + } + pi=fpi(); + w=pi/2; + if (fcomp(y,w)<=0) return s; + w=2*pi; + if (fcomp(y,w)>0) + { // reduce mod 2.pi + t=y/w; + t=trunc(t); + t*=w; + y-=t; + } + if (fcomp(y,pi)>0) + { + y-=pi; + if (type!=TAN) s=(-s); + } + w=pi/2; + if (fcomp(y,w)>0) + { + y=pi-y; + if (type!=SIN) s=(-s); + } + return s; +} + +Float cos(const Float& f) +{ // see Brent - "The complexity of multiprecision arithmetic" + int i,q,sgn; + Float t,r,y,x=f; + Float one=(Float)1; + Big lambda; + sgn=norm(COS,x); + + if (x.iszero()) return sgn*one; + + q=isqrt(MIRACL*precision,2); + lambda=pow((Big)2,q); + + x/=(Float)lambda; + + r=0; y=one; x*=x; + for (i=2;i<=q+2;i+=2) + { + t=x; t.negate(); t/=(i*(i-1)); y*=t; + // y*=(-x/(i*(i-1))); + if (!r.add(y)) break; + } + + for (i=0;isb) return 1; + if (sab.e) return sa; + if (a.ey) return 1; + if (x0) return PLUS; + if (m<0) return MINUS; + return 0; +} + +Float operator-(const Float& f) +{ + Float r=f; + r.m.negate(); + return r; +} + +Float& Float::operator=(const Float &f) +{ + e=f.e; + m=f.m; + return *this; +} + +Float::Float(double d) +{ + Big t; + double ip,word; + int c,s=PLUS; + if (d<0) {s=MINUS; d=-d;} + + m=0; + e=0; + if (d==0.0) return; + + c=1; + word=pow(2.0,(double)MIRACL); + + while (d>=word) + { + d/=word; c++; + } + while (d<1.0) + { + d*=word; c--; + } + + d=modf(d,&ip); + m=(mr_small)ip; + forever + { + d*=word; + d=modf(d,&ip); + t=(mr_small)ip; + m=shift(m,1)+t; + if (d==0.0 || length(m)>precision) break; + } + e=c; + if (s==MINUS) m.negate(); +} + +Float& Float::operator=(double d) +{ + Float t=d; + *this=t; + return *this; +} + +double todouble(const Float &f) +{ + int i,s; + Big x=f.m; + double word,d=0.0; + mr_small dig; + + if (f.iszero()) return d; + + if (f.m>=0) s=PLUS; + else {s=MINUS; x.negate();} + + word=pow(2.0,(double)MIRACL); + for (i=0;i0) for (i=0;i=b.e) + { + if (e-b.e>precision) return FALSE; + y.shift(b.e-e); + m+=y; + + if (m.iszero()) e=0; + else e+=length(m)-precision; + } + else + { + if (b.e-e>precision) {*this=b; return TRUE;} + m.shift(e-b.e); + m+=y; + + if (m.iszero()) e=0; + else e=b.e+length(m)-precision; + } + + m.shift(precision-length(m)); + + return TRUE; +} + + +Float& Float::operator+=(const Float &b) +{ + add(b); + return *this; +} + +BOOL Float::sub(const Float &b) +{ + + if (b.iszero()) return FALSE; + if (iszero()) {*this=-b; return TRUE;} + + Big y=b.m; + + m.shift(precision-length(m)); // make them precision length + y.shift(precision-length(y)); + + if (e>=b.e) + { + if (e-b.e>precision) return FALSE; + y.shift(b.e-e); + m-=y; + if (m.iszero()) e=0; + else e+=length(m)-precision; + } + else + { + if (b.e-e>precision) {*this=-b; return TRUE;} + m.shift(e-b.e); + m-=y; + if (m.iszero()) e=0; + else e=b.e+length(m)-precision; + } + + m.shift(precision-length(m)); + return TRUE; +} + +Float& Float::operator-=(const Float &b) +{ + sub(b); + return *this; +} + +Float operator+(const Float& a,const Float &b) +{ + Float r=a; + r+=b; + return r; +} + +Float operator-(const Float& a,const Float &b) +{ + Float r=a; + r-=b; + return r; +} + +Float& Float::operator*=(const Float& b) +{ + BOOL extra; + + if (iszero() || b.isone()) return *this; + if (b.iszero() || isone()) {*this=b; return *this;} + + if (&b==this) + { + if (m<0) m.negate(); // result will be positive + m.shift(precision-length(m)); // make them precision length + extra=fmth(precision,m,m,m); + e+=e; + if (extra) e--; + } + else + { + Big y=b.m; + int s=PLUS; + + if (m<0) { s*=MINUS; m.negate(); } + if (y<0) { s*=MINUS; y.negate(); } + + m.shift(precision-length(m)); // make them precision length + y.shift(precision-length(y)); + + extra=fmth(precision,m,y,m); + + if (s<0) m.negate(); + e+=b.e; + if (extra) e--; + } + return *this; +} + +Float operator*(const Float& a,const Float& b) +{ + Float r=a; + r*=b; + return r; +} + +Float operator*(const Float& a,int b) +{ + Float r=a; + r*=b; + return r; +} + +Float operator*(int a,const Float& b) +{ + Float r=b; + r*=a; + return r; +} + +Float& Float::operator*=(int x) +{ + int olm=length(m); + m*=x; + e+=length(m)-olm; + + m.shift(precision-length(m)); + return *this; +} + +Float& Float::operator/=(int x) +{ + int olm; + if (x==1) return *this; + + m.shift(precision-length(m)); + olm=length(m); + m/=x; + e+=length(m)-olm; + + m.shift(precision-length(m)); + return *this; +} + +Float operator/(const Float& f,int x) +{ + Float r=f; + r/=x; + return r; +} + +Float& Float::operator/=(const Float &f) +{ + Float g=reciprocal(f); + *this*=g; + return *this; +} + +Float operator/(const Float& a,const Float &b) +{ + Float r=reciprocal(b); + r*=a; + return r; +} + +void setprecision(int p) {precision=(1< +#include "floating.h" + +using namespace std; + +Miracl precision(18,0); // 18=2^4+2 + +int main() +{ /* Brents example program */ + Float x,y,z; + setprecision(4); // 16=2^4 + cout << fpi() << endl; + x=exp(fpi()*sqrt((Float)163/9)); + cout << x << endl; + cout << pow(x,3) << endl; + return 0; +} + diff --git a/miracl/source/gcc386.mcs b/miracl/source/gcc386.mcs new file mode 100644 index 0000000..fdab7b7 --- /dev/null +++ b/miracl/source/gcc386.mcs @@ -0,0 +1,472 @@ +; MCS file for Gnu GCC 80386-Pentium compiler +; +; *IMPORTANT* +; The optimizer may not like the generated code - if so switch it off +; Or try -fomit-frame-pointer. Or -fno-omit-frame-pointer +; With gcc V4.7 [-O2 -fno-omit-frame-pointer] works OK +; +; Sorry about all the %'s! Each % must be input here as %% +; Triple register is cl|edi|ebp +; MUL_START. Initialise registers. Make ebx and esi point to multipliers a +; and b. edi points at result c. Note edi is shared. +; Initialise Triple register to 0 +; See makemcs.txt for more information about this file +; + +MACRO PMUL_START + ASM ( + "pushl %%%%ebp\n" + "pushl %%%%edi\n" + "pushl %%%%esi\n" + "movl %%0,%%%%ebx\n" + "movl %%1,%%%%esi\n" + "movl %%2,%%%%edi\n" + "xorl %%%%ecx,%%%%ecx\n" + "movl %%3,%%%%ebp\n" +ENDM + +MACRO PMUL + "movl %%%%ebp,%%%%eax\n" + "mull 4*%d(%%%%ebx)\n" + "addl %%%%ecx,%%%%eax\n" + "adcl $0,%%%%edx\n" + "movl %%%%edx,%%%%ecx\n" + "movl $0,4*%d(%%%%esi)\n" + "movl %%%%eax,4*%d(%%%%edi)\n" +ENDM + +MACRO PMUL_END + "movl %%%%ebp,%%%%eax\n" + "mull %%%%ecx\n" + "movl %%%%eax,(%%%%esi)\n" + "movl %%%%edx,4(%%%%esi)\n" + "popl %%%%esi\n" + "popl %%%%edi\n" + "popl %%%%ebp\n" + : + :"m"(a),"m"(b),"m"(c),"m"(sn) + :"eax","edi","esi","ebx","ecx","edx","memory" + ); + +ENDM + +MACRO MUL_START + ASM ( + "pushl %%%%ebp\n" + "pushl %%%%edi\n" + "pushl %%%%esi\n" + "movl %%0,%%%%ebx\n" + "movl %%1,%%%%esi\n" + "movl %%2,%%%%edi\n" + "pushl %%%%edi\n" + "xorl %%%%ecx,%%%%ecx\n" + "xorl %%%%edi,%%%%edi\n" + "xorl %%%%ebp,%%%%ebp\n" +ENDM +; +; STEP macro. Calculates a double-register partial product +; and adds it to the triple register total +; Parameters 1 & 2: Indices i and j for partial product multipliers a[i] +; and b[j] +MACRO STEP + "movl 4*%d(%%%%ebx),%%%%eax\n" + "mull 4*%d(%%%%esi)\n" + "addl %%%%eax,%%%%ebp\n" + "adcl %%%%edx,%%%%edi\n" + "adc %%%%ch,%%%%cl\n" +ENDM +; +; LAST +; +MACRO LAST + "movl 4*%d(%%%%ebx),%%%%eax\n" + "mull 4*%d(%%%%esi)\n" + "addl %%%%eax,%%%%ebp\n" +ENDM +; +; MFIN macro. Finish column calculation. Store Sum for this column +; and get Carry for next +; Parameter 1: Index k for Column Sum c[k] +MACRO MFIN + "movl %%%%edi,%%%%edx\n" + "popl %%%%edi\n" + "movl %%%%ebp,4*%d(%%%%edi)\n" + "pushl %%%%edi\n" + "movl %%%%edx,%%%%ebp\n" + "movl %%%%ecx,%%%%edi\n" + "xor %%%%cl,%%%%cl\n" +ENDM +; +; MUL_END +; Parameter 1: Index for final carry c[.] +MACRO MUL_END + "popl %%%%edi\n" + "movl %%%%ebp,4*%d(%%%%edi)\n" + "popl %%%%esi\n" + "popl %%%%edi\n" + "popl %%%%ebp\n" + : + :"m"(a),"m"(b),"m"(c) + :"eax","edi","esi","ebx","ecx","edx","memory" + ); +ENDM +; +; SQR_START +; +MACRO SQR_START + ASM ( + "pushl %%%%ebp\n" + "pushl %%%%edi\n" + "pushl %%%%esi\n" + "movl %%0,%%%%ebx\n" + "movl %%1,%%%%esi\n" + "xorl %%%%ecx,%%%%ecx\n" + "xorl %%%%edi,%%%%edi\n" + "xorl %%%%ebp,%%%%ebp\n" +ENDM +; +; DSTEP macro. Calculates a double-register partial product +; and add it twice to a triple register total +; Parameters 1 & 2 : Indices of partial product multipliers +MACRO DSTEP + "movl 4*%d(%%%%ebx),%%%%eax\n" + "mull 4*%d(%%%%ebx)\n" + "addl %%%%eax,%%%%ebp\n" + "adcl %%%%edx,%%%%edi\n" + "adc %%%%ch,%%%%cl\n" + "addl %%%%eax,%%%%ebp\n" + "adcl %%%%edx,%%%%edi\n" + "adc %%%%ch,%%%%cl\n" +ENDM +; +; SELF macro. Calculate the double-register square and +; add it to a triple register total +; Parameter 1 : Index of diagonal element +MACRO SELF + "movl 4*%d(%%%%ebx),%%%%eax\n" + "mull %%%%eax\n" + "addl %%%%eax,%%%%ebp\n" + "adcl %%%%edx,%%%%edi\n" + "adc %%%%ch,%%%%cl\n" +ENDM +; +; SFIN macro. Finish column calculation for squaring. Store Sum +; and get Carry for next column. +; Parameter 1: Index of Column Sum +MACRO SFIN + "movl %%%%ebp,4*%d(%%%%esi)\n" + "movl %%%%edi,%%%%ebp\n" + "movl %%%%ecx,%%%%edi\n" + "xor %%%%cl,%%%%cl\n" +ENDM +; +; SQR_END +; Parameter 1: Index for final carry +MACRO SQR_END + "movl %%%%ebp,4*%d(%%%%esi)\n" + "popl %%%%esi\n" + "popl %%%%edi\n" + "popl %%%%ebp\n" + : + :"m"(a),"m"(c) + :"eax","edi","esi","ebx","ecx","edx","memory" + ); +ENDM +; +; REDC_START +; +MACRO REDC_START + ASM ( + "pushl %%%%ebp\n" + "pushl %%%%edi\n" + "pushl %%%%esi\n" + "movl %%0,%%%%ebx\n" + "movl %%1,%%%%esi\n" + "movl %%2,%%%%edx\n" + "pushl %%%%edx\n" + "xorl %%%%edi,%%%%edi\n" + "xorl %%%%ecx,%%%%ecx\n" + "movl (%%%%ebx),%%%%ebp\n" +ENDM +; +; RFINU macro +; +MACRO RFINU + "movl %%%%ebp,%%%%eax\n" + "popl %%%%edx\n" + "pushl %%%%edx\n" + "mull %%%%edx\n" + "movl %%%%eax,4*%d(%%%%ebx)\n" + "mull (%%%%esi)\n" + "addl %%%%eax,%%%%ebp\n" + "adcl %%%%edx,%%%%edi\n" + "adc %%%%ch,%%%%cl\n" + "movl %%%%edi,%%%%ebp\n" + "movl %%%%ecx,%%%%edi\n" + "xorl %%%%ecx,%%%%ecx\n" + "addl 4*(%d+1)(%%%%ebx),%%%%ebp\n" + "adcl %%%%ecx,%%%%edi\n" +ENDM +; +; RFIND macro +; +MACRO RFIND + "movl %%%%ebp,4*%d(%%%%ebx)\n" + "movl %%%%edi,%%%%ebp\n" + "movl %%%%ecx,%%%%edi\n" + "xorl %%%%ecx,%%%%ecx\n" + "addl 4*(%d+1)(%%%%ebx),%%%%ebp\n" + "adcl %%%%ecx,%%%%edi\n" +ENDM +; +; REDC_END +; +MACRO REDC_END + "movl %%%%ebp,4*%d(%%%%ebx)\n" + "movl %%%%edi,4*(%d+1)(%%%%ebx)\n" + "popl %%%%edx\n" + "popl %%%%esi\n" + "popl %%%%edi\n" + "popl %%%%ebp\n" + : + :"m"(a),"m"(b),"m"(ndash) + :"eax","edi","esi","ebx","ecx","edx","memory" + ); +ENDM +; +; ADD_START macro - initialise for add. Do first one +; +MACRO ADD_START + ASM ( + "pushl %%%%esi\n" + "pushl %%%%edi\n" + "movl %%0,%%%%esi\n" + "movl %%1,%%%%ebx\n" + "movl %%3,%%%%edi\n" + "movl (%%%%esi),%%%%eax\n" + "addl (%%%%ebx),%%%%eax\n" + "movl %%%%eax,(%%%%edi)\n" +ENDM +; +; ADD macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO ADD + "movl 4*%d(%%%%esi),%%%%eax\n" + "adcl 4*%d(%%%%ebx),%%%%eax\n" + "movl %%%%eax,4*%d(%%%%edi)\n" +ENDM +; +; ADD_END macro. Catch Carry +; +MACRO ADD_END + "movl $0,%%%%eax\n" + "adcl %%%%eax,%%%%eax\n" + "movl %%%%eax,%%2\n" + "popl %%%%edi\n" + "popl %%%%esi\n" + : + :"m"(a),"m"(b),"m"(carry),"m"(c) + :"eax","edi","esi","ebx","memory" + ); +ENDM +; +; INC_START macro +; +MACRO INC_START + ASM ( + "pushl %%%%edi\n" + "movl %%0,%%%%edi\n" + "movl %%1,%%%%ebx\n" + "movl (%%%%ebx),%%%%eax\n" + "addl %%%%eax,(%%%%edi)\n" +ENDM +; +; INC macro. Increment number in memory. Don't forget carry +; +MACRO INC + "movl 4*%d(%%%%ebx),%%%%eax\n" + "adcl %%%%eax,4*%d(%%%%edi)\n" +ENDM +; +; INC_END macro. Catch Carry +; +MACRO INC_END + "movl $0,%%%%eax\n" + "adcl %%%%eax,%%%%eax\n" + "movl %%%%eax,%%2\n" + "popl %%%%edi\n" + : + :"m"(a),"m"(b),"m"(carry) + :"eax","edi","ebx","memory" + ); +ENDM +; +; SUB_START macro. Do first one. +; +MACRO SUB_START + ASM ( + "pushl %%%%esi\n" + "pushl %%%%edi\n" + "movl %%0,%%%%esi\n" + "movl %%1,%%%%ebx\n" + "movl %%3,%%%%edi\n" + "movl (%%%%esi),%%%%eax\n" + "subl (%%%%ebx),%%%%eax\n" + "movl %%%%eax,(%%%%edi)\n" +ENDM +; +; SUB macro. Subtract two numbers in memory and store result in memory. +; +MACRO SUB + "movl 4*%d(%%%%esi),%%%%eax\n" + "sbbl 4*%d(%%%%ebx),%%%%eax\n" + "movl %%%%eax,4*%d(%%%%edi)\n" +ENDM +; +; SUB_END macro. Catch Carry +; +MACRO SUB_END + "movl $0,%%%%eax\n" + "adcl %%%%eax,%%%%eax\n" + "movl %%%%eax,%%2\n" + "popl %%%%edi\n" + "popl %%%%esi\n" + : + :"m"(a),"m"(b),"m"(carry),"m"(c) + :"eax","edi","esi","ebx","memory" + ); +ENDM +; +; DEC_START macro. Do first one. +; +MACRO DEC_START + ASM ( + "pushl %%%%edi\n" + "movl %%0,%%%%edi\n" + "movl %%1,%%%%ebx\n" + "movl (%%%%ebx),%%%%eax\n" + "subl %%%%eax,(%%%%edi)\n" +ENDM +; +; DEC macro. Decrement from number in memory. Don't forget borrow. +; +MACRO DEC + "movl 4*%d(%%%%ebx),%%%%eax\n" + "sbbl %%%%eax,4*%d(%%%%edi)\n" +ENDM +; +; DEC_END macro +; +MACRO DEC_END + "movl $0,%%%%eax\n" + "adcl %%%%eax,%%%%eax\n" + "movl %%%%eax,%%2\n" + "popl %%%%edi\n" + : + :"m"(a),"m"(b),"m"(carry) + :"eax","edi","ebx","memory" + ); +ENDM +; +; KADD_START macro +; +MACRO KADD_START + ASM ( + "pushl %%%%esi\n" + "pushl %%%%edi\n" + "movl %%0,%%%%esi\n" + "movl %%1,%%%%ebx\n" + "movl %%3,%%%%edi\n" + "movl %%4,%%%%ecx\n" + "xorl %%%%eax,%%%%eax\n" + "k%d:\n" +ENDM +; +; KASL macro +; +MACRO KASL + "decl %%%%ecx\n" + "je k%d\n" + "leal 4*%d(%%%%esi),%%%%esi\n" + "leal 4*%d(%%%%ebx),%%%%ebx\n" + "leal 4*%d(%%%%edi),%%%%edi\n" + "jmp k%d\n" + "k%d:\n" +ENDM +; +; KADD_END macro +; +MACRO KADD_END + "movl $0,%%%%eax\n" + "adcl %%%%eax,%%%%eax\n" + "movl %%%%eax,%%2\n" + "popl %%%%edi\n" + "popl %%%%esi\n" + : + :"m"(a),"m"(b),"m"(carry),"m"(c),"m"(n) + :"eax","edi","esi","ebx","ecx","memory" + ); +ENDM +; +; KINC_START macro. Zero carry flag. +; +MACRO KINC_START + ASM ( + "pushl %%%%edi\n" + "movl %%0,%%%%edi\n" + "movl %%1,%%%%ebx\n" + "movl %%3,%%%%ecx\n" + "xorl %%%%eax,%%%%eax\n" + "k%d:\n" +ENDM +; +; KIDL macro +; +MACRO KIDL + "decl %%%%ecx\n" + "je k%d\n" + "leal 4*%d(%%%%ebx),%%%%ebx\n" + "leal 4*%d(%%%%edi),%%%%edi\n" + "jmp k%d\n" + "k%d:\n" +ENDM +; +; KINC_END macro +; +MACRO KINC_END + "movl $0,%%%%eax\n" + "adcl %%%%eax,%%%%eax\n" + "movl %%%%eax,%%2\n" + "popl %%%%edi\n" + : + :"m"(a),"m"(b),"m"(carry),"m"(n) + :"eax","edi","ebx","ecx","memory" + ); +ENDM +; +; KDEC_START macro +; +MACRO KDEC_START + ASM ( + "pushl %%%%edi\n" + "movl %%0,%%%%edi\n" + "movl %%1,%%%%ebx\n" + "movl %%3,%%%%ecx\n" + "xorl %%%%eax,%%%%eax\n" + "k%d:\n" +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + "movl $0,%%%%eax\n" + "adcl %%%%eax,%%%%eax\n" + "movl %%%%eax,%%2\n" + "popl %%%%edi\n" + : + :"m"(a),"m"(b),"m"(carry),"m"(n) + :"eax","edi","ebx","ecx","memory" + ); +ENDM + diff --git a/miracl/source/gccarm.mcs b/miracl/source/gccarm.mcs new file mode 100644 index 0000000..c6821f0 --- /dev/null +++ b/miracl/source/gccarm.mcs @@ -0,0 +1,602 @@ +; +; ARM Macros file for GCC compiler +; +; Triple register is R4|R3|R2 +; MUL_START. Initialise registers. Make R5 and R6 point to multipliers a +; and b. R7 points at result c. +; Initialise Triple register to 0 +; See makemcs.txt for more information about this file +; +; File fixed for new GCC versions +; Hybrid method implemented - note the need to push r11 and r12 in H2_MUL_START +; +; +MACRO PMUL_START + ASM ( + "MOV r5,%%0\n" + "MOV r6,%%1\n" + "MOV r7,%%2\n" + "MOV r4,%%3\n" + "MOV r3,#0\n" + "MOV r2,#0\n" +ENDM + +MACRO PMUL + "LDR r0,[r5,#(4*%d)]\n" + "UMULL r8,r9,r0,r4\n" + "ADDS r8,r8,r3\n" + "ADC r3,r9,r2\n" + "STR r2,[r6,#(4*%d)]\n" + "STR r8,[r7,#(4*%d)]\n" +ENDM + +MACRO PMUL_END + "UMULL r8,r9,r3,r4\n" + "STR r8,[r6]\n" + "STR r9,[r6,#4]\n" + : + :"r"(a),"r"(b),"r"(c),"r"(sn) + :"r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","memory" + ); +ENDM +; +; H2_MUL_START macro +; for hybrid method - process elements 2x2 +; +MACRO H2_MUL_START + ASM ( + "LDR r5,%%0\n" + "LDR r6,%%1\n" + "LDR r7,%%2\n" + "PUSH {r11,r12}\n" + "MOV r4,#0\n" + "MOV r3,#0\n" + "MOV r2,#0\n" + "MOV r10,#0\n" + "MOV r11,#0\n" +ENDM + +MACRO H2_STEP + "LDR r8,[r5,#(4*%d)]\n" + "LDR r9,[r5,#(4*%d+4)]\n" + "LDR r12,[r6,#(4*%d)]\n" + "UMULL r0,r1,r8,r12\n" + "ADDS r2,r2,r0\n" + "ADCS r3,r3,r1\n" + "ADC r11,r11,#0\n" + "UMULL r0,r1,r9,r12\n" + "ADDS r3,r3,r0\n" + "ADCS r4,r4,r1\n" + "ADDCS r11,r11,#0x100\n" + "LDR r12,[r6,#(4*%d+4)]\n" + "UMULL r0,r1,r8,r12\n" + "ADDS r3,r3,r0\n" + "ADCS r4,r4,r1\n" + "ADDCS r11,r11,#0x100\n" + "UMULL r0,r1,r9,r12\n" + "ADDS r4,r4,r0\n" + "ADCS r10,r10,r1\n" + "ADDCS r11,r11,#0x10000\n" +ENDM + +MACRO H2_LAST + "LDR r8,[r5,#(4*%d)]\n" + "LDR r9,[r5,#(4*%d+4)]\n" + "LDR r12,[r6,#(4*%d)]\n" + "UMULL r0,r1,r8,r12\n" + "ADDS r2,r2,r0\n" + "ADCS r3,r3,r1\n" + "UMULL r0,r1,r9,r12\n" + "ADD r3,r3,r0\n" + "LDR r12,[r6,#(4*%d+4)]\n" + "UMULL r0,r1,r8,r12\n" + "ADD r3,r3,r0\n" +ENDM + +MACRO H2_MFIN + "STR r2,[r7,#(4*%d)]\n" + "STR r3,[r7,#(4*%d)]\n" + "AND r0,r11,#0xFF\n" + "ADDS r2,r4,r0\n" + "AND r0,r11,#0xFF00\n" + "ADCS r3,r10,r0,LSR#8\n" + "ADDCS r11,r11,#0x10000\n" + "MOV r4,r11,LSR#16\n" + "MOV r10,#0\n" + "MOV r11,#0\n" +ENDM + +MACRO H2_MUL_END + "STR r2,[r7,#(4*%d)]\n" + "STR r3,[r7,#(4*%d)]\n" + "POP {r11,r12}\n" + : + :"m"(a),"m"(b),"m"(c) + :"r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12","memory" + ); +ENDM + +MACRO MUL_START + ASM ( + "MOV r5,%%0\n" + "MOV r6,%%1\n" + "MOV r7,%%2\n" + "MOV r4,#0\n" + "MOV r3,#0\n" + "MOV r2,#0\n" +ENDM +; +; STEP macro. Calculates a double-register partial product +; and adds it to the triple register total +; Parameters 1 & 2: Indices i and j for partial product multipliers a[i] +; and b[j] + +MACRO STEP + "LDR r0,[r5,#(4*%d)]\n" + "LDR r1,[r6,#(4*%d)]\n" + "UMULL r8,r9,r0,r1\n" + "ADDS r2,r2,r8\n" + "ADCS r3,r3,r9\n" + "ADC r4,r4,#0\n" +ENDM + +; +; MFIN macro. Finish column calculation. Store Sum for this column +; and get Carry for next +; Parameter 1: Index k for Column Sum c[k] + +MACRO MFIN + "STR r2,[r7,#(4*%d)]\n" + "MOV r2,r3\n" + "MOV r3,r4\n" + "MOV r4,#0\n" +ENDM +; +; LAST +; +MACRO LAST + "LDR r0,[r5,#(4*%d)]\n" + "LDR r1,[r6,#(4*%d)]\n" + "MLA r2,r0,r1,r2\n" +ENDM +; +; MUL_END +; Parameter 1: Index for final carry c[.] +MACRO MUL_END + "STR r2,[r7,#(4*%d)]\n" + : + :"r"(a),"r"(b),"r"(c) + :"r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","memory" + ); +ENDM + +MACRO H2_SQR_START + ASM ( + "LDR r5,%%0\n" + "LDR r7,%%1\n" + "PUSH {r11,r12}\n" + "MOV r4,#0\n" + "MOV r3,#0\n" + "MOV r2,#0\n" + "MOV r10,#0\n" + "MOV r11,#0\n" +ENDM + +MACRO H2_DSTEP + "LDR r8,[r5,#(4*%d)]\n" + "LDR r9,[r5,#(4*%d+4)]\n" + "LDR r12,[r5,#(4*%d)]\n" + "UMULL r0,r1,r8,r12\n" + "ADDS r2,r2,r0\n" + "ADCS r3,r3,r1\n" + "ADC r11,r11,#0\n" + "ADDS r2,r2,r0\n" + "ADCS r3,r3,r1\n" + "ADC r11,r11,#0\n" + "UMULL r0,r1,r9,r12\n" + "ADDS r3,r3,r0\n" + "ADCS r4,r4,r1\n" + "ADDCS r11,r11,#0x100\n" + "ADDS r3,r3,r0\n" + "ADCS r4,r4,r1\n" + "ADDCS r11,r11,#0x100\n" + "LDR r12,[r5,#(4*%d+4)]\n" + "UMULL r0,r1,r8,r12\n" + "ADDS r3,r3,r0\n" + "ADCS r4,r4,r1\n" + "ADDCS r11,r11,#0x100\n" + "ADDS r3,r3,r0\n" + "ADCS r4,r4,r1\n" + "ADDCS r11,r11,#0x100\n" + "UMULL r0,r1,r9,r12\n" + "ADDS r4,r4,r0\n" + "ADCS r10,r10,r1\n" + "ADDCS r11,r11,#0x10000\n" + "ADDS r4,r4,r0\n" + "ADCS r10,r10,r1\n" + "ADDCS r11,r11,#0x10000\n" +ENDM + +MACRO H2_SELF + "LDR r8,[r5,#(4*%d)]\n" + "LDR r9,[r5,#(4*%d+4)]\n" + "UMULL r0,r1,r8,r8\n" + "ADDS r2,r2,r0\n" + "ADCS r3,r3,r1\n" + "ADC r11,r11,#0\n" + "UMULL r0,r1,r8,r9\n" + "ADDS r3,r3,r0\n" + "ADCS r4,r4,r1\n" + "ADDCS r11,r11,#0x100\n" + "ADDS r3,r3,r0\n" + "ADCS r4,r4,r1\n" + "ADDCS r11,r11,#0x100\n" + "UMULL r0,r1,r9,r9\n" + "ADDS r4,r4,r0\n" + "ADCS r10,r10,r1\n" + "ADDCS r11,r11,#0x10000\n" +ENDM + +MACRO H2_SFIN + "STR r2,[r7,#(4*%d)]\n" + "STR r3,[r7,#(4*%d)]\n" + "AND r0,r11,#0xFF\n" + "ADDS r2,r4,r0\n" + "AND r0,r11,#0xFF00\n" + "ADCS r3,r10,r0,LSR#8\n" + "ADDCS r11,r11,#0x10000\n" + "MOV r4,r11,LSR#16\n" + "MOV r10,#0\n" + "MOV r11,#0\n" +ENDM + +MACRO H2_SQR_END + "STR r2,[r7,#(4*%d)]\n" + "STR r3,[r7,#(4*%d)]\n" + "POP {r11,r12}\n" + : + :"m"(a),"m"(c) + :"r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","r10","r11","r12","memory" + ); +ENDM + +; +; SQR_START +; +MACRO SQR_START + ASM ( + "MOV r5,%%0\n" + "MOV r7,%%1\n" + "MOV r4,#0\n" + "MOV r3,#0\n" + "MOV r2,#0\n" +ENDM +; +; DSTEP macro. Calculates a double-register partial product +; and add it twice to a triple register total +; Parameters 1 & 2 : Indices of partial product multipliers +MACRO DSTEP + "LDR r0,[r5,#(4*%d)]\n" + "LDR r1,[r5,#(4*%d)]\n" + "UMULL r8,r9,r0,r1\n" + "ADDS r2,r2,r8\n" + "ADCS r3,r3,r9\n" + "ADC r4,r4,#0\n" + "ADDS r2,r2,r8\n" + "ADCS r3,r3,r9\n" + "ADC r4,r4,#0\n" +ENDM +; +; SELF macro. Calculate the double-register square and +; add it to a triple register total +; Parameter 1 : Index of diagonal element +MACRO SELF + "LDR r0,[r5,#(4*%d)]\n" + "UMULL r8,r9,r0,r0\n" + "ADDS r2,r2,r8\n" + "ADCS r3,r3,r9\n" + "ADC r4,r4,#0\n" +ENDM +; +; SFIN macro. Finish column calculation for squaring. Store Sum +; and get Carry for next column. +; Parameter 1: Index of Column Sum +MACRO SFIN + "STR r2,[r7,#(4*%d)]\n" + "MOV r2,r3\n" + "MOV r3,r4\n" + "MOV r4,#0\n" +ENDM +; +; SQR_END +; Parameter 1: Index for final carry +MACRO SQR_END + "STR r2,[r7,#(4*%d)]\n" + : + :"r"(a),"r"(c) + :"r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","memory" + ); +ENDM +; +; REDC_START macro +; +MACRO REDC_START + ASM ( + "MOV r5,%%0\n" + "MOV r6,%%1\n" + "MOV r7,%%2\n" + "MOV r4,#0\n" + "MOV r3,#0\n" + "LDR r2,[r5]\n" +ENDM +; +; RFINU macro +; +MACRO RFINU + "MUL r1,r7,r2\n" + "STR r1,[r5,#(4*%d)]\n" + "LDR r0,[r6]\n" + "UMULL r8,r9,r0,r1\n" + "ADDS r0,r2,r8\n" + "ADCS r2,r3,r9\n" + "ADC r3,r4,#0\n" + "LDR r0,[r5,#(4*(%d+1))]\n" + "ADDS r2,r2,r0\n" + "ADC r3,r3,#0\n" + "MOV r4,#0\n" +ENDM +; +; RFIND macro +; +MACRO RFIND + "STR r2,[r5,#(4*%d)]\n" + "LDR r0,[r5,#(4*(%d+1))]\n" + "ADDS r2,r3,r0\n" + "ADC r3,r4,#0\n" + "MOV r4,#0\n" +ENDM +; +; REDC_END +; +MACRO REDC_END + "STR r2,[r5,#(4*%d)]\n" + "STR r3,[r5,#(4*(%d+1))]\n" + : + :"r"(a),"r"(b),"r"(ndash) + :"r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","memory" + ); +ENDM +; +; ADD_START macro - initialise for add/subtract, do first one +; +MACRO ADD_START + ASM ( + "MOV r6,%%1\n" + "MOV r7,%%2\n" + "MOV r8,%%3\n" + "LDR r0,[r6]\n" + "LDR r1,[r7]\n" + "ADDS r0,r0,r1\n" + "STR r0,[r8]\n" +ENDM +; +; ADD macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO ADD + "LDR r0,[r6,#(4*%d)]\n" + "LDR r1,[r7,#(4*%d)]\n" + "ADCS r0,r0,r1\n" + "STR r0,[r8,#(4*%d)]\n" +ENDM +; +; ADD_END macro. Catch carry +; +MACRO ADD_END + "MOV r0,#0\n" + "MOVCS r0,#1\n" + "MOV %%0,r0\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(c) + :"r0","r1","r6","r7","r8","memory" + ); +ENDM +; +; INC_START macro. Do first one +; +MACRO INC_START + ASM ( + "MOV r6,%%1\n" + "MOV r7,%%2\n" + "LDR r0,[r6]\n" + "LDR r1,[r7]\n" + "ADDS r0,r0,r1\n" + "STR r0,[r6]\n" +ENDM +; +; INC macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO INC + "LDR r0,[r6,#(4*%d)]\n" + "LDR r1,[r7,#(4*%d)]\n" + "ADCS r0,r0,r1\n" + "STR r0,[r6,#(4*%d)]\n" +ENDM +; +; INC_END macro. Catch carry +; +MACRO INC_END + "MOV r0,#0\n" + "MOVCS r0,#1\n" + "MOV %%0,r0\n" + :"=r"(carry) + :"r"(a),"r"(b) + :"r0","r1","r6","r7","memory" + ); +ENDM +; +; SUB_START macro +; +MACRO SUB_START + ASM ( + "MOV r6,%%1\n" + "MOV r7,%%2\n" + "MOV r8,%%3\n" + "LDR r0,[r6]\n" + "LDR r1,[r7]\n" + "SUBS r0,r0,r1\n" + "STR r0,[r8]\n" +ENDM +; +; SUB macro. Subtract two numbers in memory and store result in memory. +; +MACRO SUB + "LDR r0,[r6,#(4*%d)]\n" + "LDR r1,[r7,#(4*%d)]\n" + "SBCS r0,r0,r1\n" + "STR r0,[r8,#(4*%d)]\n" +ENDM +; +; SUB_END macro. Catch carry +; +MACRO SUB_END + "MOV r0,#0\n" + "MOVCC r0,#1\n" + "MOV %%0,r0\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(c) + :"r0","r1","r6","r7","r8","memory" + ); +ENDM +; +; DEC_START macro +; +MACRO DEC_START + ASM ( + "MOV r6,%%1\n" + "MOV r7,%%2\n" + "LDR r0,[r6]\n" + "LDR r1,[r7]\n" + "SUBS r0,r0,r1\n" + "STR r0,[r6]\n" +ENDM +; +; DEC macro. Subtract two numbers in memory and store result in memory. +; +MACRO DEC + "LDR r0,[r6,#(4*%d)]\n" + "LDR r1,[r7,#(4*%d)]\n" + "SBCS r0,r0,r1\n" + "STR r0,[r6,#(4*%d)]\n" +ENDM +; +; DEC_END macro. Catch carry +; +MACRO DEC_END + "MOV r0,#0\n" + "MOVCC r0,#1\n" + "MOV %%0,r0\n" + :"=r"(carry) + :"r"(a),"r"(b) + :"r0","r1","r6","r7","memory" + ); +ENDM +; +; KADD_START macro. Zero Carry flag +; +MACRO KADD_START + ASM ( + "LDR r6,%%1\n" + "LDR r7,%%2\n" + "LDR r8,%%3\n" + "LDR r9,%%4\n" + "MOV r0,#0\n" + "ADDS r0,r0,r0\n" + "k%d:\n" +ENDM +; +; KASL macro. Important that carry flag is undisturbed! +; +MACRO KASL + "SUB r9,r9,#1\n" + "TEQ r9,#0\n" + "BEQ k%d\n" + "ADD r6,r6,#(4*%d)\n" + "ADD r7,r7,#(4*%d)\n" + "ADD r8,r8,#(4*%d)\n" + "B k%d\n" + "k%d:\n" +ENDM +; +; KADD_END macro +; +MACRO KADD_END + "MOV r0,#0\n" + "MOVCS r0,#1\n" + "MOV %%0,r0\n" + :"=r"(carry) + :"m"(a),"m"(b),"m"(c),"m"(n) + :"r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","memory" + ); +ENDM +; +; KINC_START macro. Set carry to Zero +; +MACRO KINC_START + ASM ( + "LDR r6,%%1\n" + "LDR r7,%%2\n" + "LDR r9,%%3\n" + "MOV r0,#0\n" + "ADDS r0,r0,r0\n" + "k%d:\n" +ENDM +; +; KIDL macro. Important that carry flag is undisturbed! +; +MACRO KIDL + "SUB r9,r9,#1\n" + "TEQ r9,#0\n" + "BEQ k%d\n" + "ADD r6,r6,#(4*%d)\n" + "ADD r7,r7,#(4*%d)\n" + "B k%d\n" + "k%d:\n" +ENDM +; +; KINC_END macro +; +MACRO KINC_END + "MOV r0,#0\n" + "MOVCS r0,#1\n" + "MOV %%0,r0\n" + :"=r"(carry) + :"m"(a),"m"(b),"m"(n) + :"r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","memory" + ); +ENDM +; +; KDEC_START macro. Set carry +; +MACRO KDEC_START + ASM ( + "LDR r6,%%1\n" + "LDR r7,%%2\n" + "LDR r9,%%3\n" + "SUBS r0,r0,r0\n" + "k%d:\n" +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + "MOV r0,#0\n" + "MOVCC r0,#1\n" + "MOV %%0,r0\n" + :"=r"(carry) + :"m"(a),"m"(b),"m"(n) + :"r0","r1","r2","r3","r4","r5","r6","r7","r8","r9","memory" + ); +ENDM + diff --git a/miracl/source/gcclmul.mcs b/miracl/source/gcclmul.mcs new file mode 100644 index 0000000..3ade31d --- /dev/null +++ b/miracl/source/gcclmul.mcs @@ -0,0 +1,29 @@ +; MCS file for Gnu GCC AMD64 compiler +; +; Sorry about all the %'s! Each % must be input here as %% +; +; "Triple register" is %xmm2 +; +MACRO MULB_START + ASM ( + "movq %%0,%%%%rbx\n" + "movq %%1,%%%%rsi\n" + "movq %%2,%%%%rdi\n" + "pxor %%%%xmm2,%%%%xmm2\n" +ENDM +MACRO STEPB + "movq 8*%d(%%%%rbx),%%%%xmm0\n" + "movq 8*%d(%%%%rsi),%%%%xmm1\n" + "pclmulqdq $0,%%%%xmm0,%%%%xmm1\n" + "pxor %%%%xmm1,%%%%xmm2\n" +ENDM +MACRO MBFIN + "movq %%%%xmm2,8*%d(%%%%rdi)\n" + "psrldq $8,%%%%xmm2\n" +ENDM +MACRO MULB_END + : + :"m"(a),"m"(b),"m"(c) + :"rdi","rsi","rbx","xmm0","xmm1","xmm2","memory" + ); +ENDM diff --git a/miracl/source/gccmsp430.mcs b/miracl/source/gccmsp430.mcs new file mode 100644 index 0000000..2926eea --- /dev/null +++ b/miracl/source/gccmsp430.mcs @@ -0,0 +1,407 @@ +; Comba/KCM Macros for TI msp430 +; +; Triple register is r11|r10|r9 +; +; See makemcs.txt for more information about this file +; +; Contributed by Piotr Szczechowiak +; (uses hardware multiplier) +; +MACRO MUL_START + asm( + "mov %%[a],r13\n\t" + "mov %%[b],r14\n\t" + "mov %%[c],r15\n\t" + "clr r9\n\t" + "clr r10\n\t" + "clr r11\n\t" + "clr r12\n\t" + "push r2\n\t" + "dint\n\t" + "nop\n\t" +ENDM +; +; STEP macros +; +MACRO STEP + "mov 2*%d(r13),&__MPY\n\t" + "mov 2*%d(r14),&__OP2\n\t" + "add &__RESLO,r9\n\t" + "addc &__RESHI,r10\n\t" + "addc r12,r11\n\t" +ENDM +; +; MFIN macro +; +MACRO MFIN + "mov r9,2*%d(r15)\n\t" + "mov r10,r9\n\t" + "mov r11,r10\n\t" + "clr r11\n\t" +ENDM +; +; LAST +; +MACRO LAST + "mov 2*%d(r13),&__MPY\n\t" + "mov 2*%d(r14),&__OP2\n\t" + "add &__RESLO,r9\n\t" +ENDM +; +; MULE +; +MACRO MUL_END + "mov r9,2*%d(r15)\n\t" + "pop r2\n\t" + "eint\n\t" + : + : [a] "m" (a), [b] "m" (b), [c] "m" (c) + :"r9","r10","r11","r12","r13","r14","r15" + ); +ENDM +; +; SQR_START +; +MACRO SQR_START + asm( + "mov %%[a],r14\n\t" + "mov %%[c],r15\n\t" + "clr r10\n\t" + "clr r11\n\t" + "clr r12\n\t" + "clr r13\n\t" + "push r2\n\t" + "dint\n\t" + "nop\n\t" +ENDM +; +; DSTEP +; +MACRO DSTEP + "mov 2*%d(r14),&__MPY\n\t" + "mov 2*%d(r14),&__OP2\n\t" + "add &__RESLO,r10\n\t" + "addc &__RESHI,r11\n\t" + "addc r13,r12\n\t" + "add &__RESLO,r10\n\t" + "addc &__RESHI,r11\n\t" + "addc r13,r12\n\t" +ENDM +; +; SELF +; +MACRO SELF + "mov 2*%d(r14),&__MPY\n\t" + "mov 2*%d(r14),&__OP2\n\t" + "add &__RESLO,r10\n\t" + "addc &__RESHI,r11\n\t" + "addc r13,r12\n\t" +ENDM +; +; SFIN +; +MACRO SFIN + "mov r10,2*%d(r15)\n\t" + "mov r11,r10\n\t" + "mov r12,r11\n\t" + "clr r12\n\t" +ENDM +; +; SQR_END +; +MACRO SQR_END + "mov r10,2*%d(r15)\n\t" + "pop r2\n\t" + "eint\n\t" + : + : [a] "m" (a), [c] "m" (c) + :"r10","r11","r12","r13","r14","r15" + ); +ENDM +; +; REDC_START +; +MACRO REDC_START + asm( + "mov %%[a],r13\n\t" + "mov %%[b],r14\n\t" + "mov %%[ndash],r15\n\t" + "clr r9\n\t" + "clr r10\n\t" + "clr r11\n\t" + "clr r12\n\t" + "mov @r13,r9\n\t" + "push r2\n\t" + "dint\n\t" + "nop\n\t" +ENDM +; +; RFINU macro +; +MACRO RFINU + "mov r9,&__MPY\n\t" + "mov @r15,&__OP2\n\t" + "add &__RESLO,2*%d(r13)\n\t" + "mov @r14,&__MPY\n\t" + "mov &__RESLO,&__OP2\n\t" + "add &__RESLO,r9\n\t" + "addc &__RESHI,r10\n\t" + "addc r12,r11\n\t" + "mov r10,r9\n\t" + "mov r11,r10\n\t" + "clr r11\n\t" + "add 2*%d+1(r13),r9\n\t" + "addc r12,r10\n\t" + "clr r11\n\t" +ENDM +; +; RFIND macro +; +MACRO RFIND + "mov r9,2*%d(r13)\n\t" + "mov r10,r9\n\t" + "mov r11,r10\n\t" + "clr r11\n\t" + "add 2*%d+1(r13),r9\n\t" + "addc r12,r10\n\t" + "clr r11\n\t" +ENDM +; +; REDC_END macro +; +MACRO REDC_END + "mov r9,2*%d(r15)\n\t" + "mov r10,2*%d+1(r15)\n\t" + "pop r2\n\t" + "eint\n\t" + : + : [a] "m" (a), [b] "m" (b), [ndash] "m" (ndash) + :"r9","r10","r11","r12","r13","r14","r15" + ); +ENDM +; +; ADD_START macro +; +MACRO ADD_START + asm( + "mov %%[a],r11\n\t" + "mov %%[b],r12\n\t" + "mov @r11+,r13\n\t" + "mov @r12+,r14\n\t" + "add r14,r13\n\t" + "mov %%[c],r15\n\t" + "mov r13,2*0(r15)\n\t" +ENDM +; +; ADD macro - c[.]=a[.]+b[.] +; +MACRO ADD + "mov @r11+,r13\n\t" + "mov @r12+,r14\n\t" + "addc r14,r13\n\t" + "mov r13,2*%d(r15)\n\t" +ENDM +; +; ADD_END macro. +; +MACRO ADD_END + "clr r14\n\t" + "adc r14\n\t" + "mov r14,%%[carry]\n\t" + : [carry] "=m" (carry) + : [a] "m" (a), [b] "m" (b), [c] "m" (c), "[carry]" (carry) + :"r11","r12","r13","r14","r15" + ); +ENDM +; +; INC_START macro. Do first one. +; +MACRO INC_START + asm( + "mov %%[a],r12\n\t" + "mov %%[b],r13\n\t" + "mov 2*0(r12),r14\n\t" + "mov @r13+,r15\n\t" + "add r15,r14\n\t" + "mov r14,2*0(r12)\n\t" +ENDM +; +; INC macro a[.]+=b[.] +; +MACRO INC + "mov 2*%d(r12),r14\n\t" + "mov @r13+,r15\n\t" + "addc r15,r14\n\t" + "mov r14,2*%d(r12)\n\t" +ENDM +MACRO INC_END + "clr r15\n\t" + "adc r15\n\t" + "mov r15,%%[carry]\n\t" + : [carry] "=m" (carry) + : [a] "m" (a), [b] "m" (b), "[carry]" (carry) + :"r12","r13","r14","r15" + ); +ENDM +MACRO SUB_START + asm( + "mov %%[a],r11\n\t" + "mov %%[b],r12\n\t" + "mov @r11+,r13\n\t" + "mov @r12+,r14\n\t" + "sub r14,r13\n\t" + "mov %%[c],r15\n\t" + "mov r13,2*0(r15)\n\t" +ENDM +; +; SUB macro - c[.]=a[.]-b[.] +; +MACRO SUB + "mov @r11+,r13\n\t" + "mov @r12+,r14\n\t" + "subc r14,r13\n\t" + "mov r13,2*%d(r15)\n\t" +ENDM +MACRO SUB_END + "clr r14\n\t" + "adc r14\n\t" + "xor.b #1,r14\n\t" + "mov r14,%%[carry]\n\t" + : [carry] "=m" (carry) + : [a] "m" (a), [b] "m" (b), [c] "m" (c), "[carry]" (carry) + :"r11","r12","r13","r14","r15" + ); +ENDM +; +; DEC_START macro +; +MACRO DEC_START + asm( + "mov %%[a],r12\n\t" + "mov %%[b],r13\n\t" + "mov 2*0(r12),r14\n\t" + "mov @r13+,r15\n\t" + "sub r15,r14\n\t" + "mov r14,2*0(r12)\n\t" +ENDM +; +; DEC macro a[.]-=b[.] +; +MACRO DEC + "mov 2*%d(r12),r14\n\t" + "mov @r13+,r15\n\t" + "subc r15,r14\n\t" + "mov r14,2*%d(r12)\n\t" +ENDM +; +; DEC_END macro +; +MACRO DEC_END + "clr r15\n\t" + "adc r15\n\t" + "xor.b #1,r15\n\t" + "mov r15,%%[carry]\n\t" + : [carry] "=m" (carry) + : [a] "m" (a), [b] "m" (b), "[carry]" (carry) + :"r12","r13","r14","r15" + ); +ENDM +; +; KADD_START macro. Zero Carry +; +MACRO KADD_START + asm( + "mov %%[a],r12\n\t" + "mov %%[b],r13\n\t" + "mov %%[c],r14\n\t" + "mov %%[n],r15\n\t" + "clrc\n\t" + "k%d:\n" +ENDM +; +; KASL macro +; +MACRO KASL + "dec r15\n\t" + "jz k%d\n\t" + "clr r11\n\t" + "adc r11\n\t" + "add #2*%d,r12\n\t" + "add #2*%d,r13\n\t" + "add #2*%d,r14\n\t" + "rrc r11\n\t" + "jmp k%d\n\t" + "k%d:\n\t" +ENDM +; +; KADD_END macro +; +MACRO KADD_END + "clr r11\n\t" + "adc r11\n\t" + "mov r11,%%[carry]\n\t" + : [carry] "=m" (carry) + : [a] "m" (a), [b] "m" (b), [c] "m" (c) , [n] "m" (n), "[carry]" (carry) + :"r11","r12","r13","r14","r15" + ); +ENDM +; +; KINC_START macro +; +MACRO KINC_START + asm( + "mov %%[a],r12\n\t" + "mov %%[b],r13\n\t" + "mov %%[n],r15\n\t" + "clrc\n\t" + "k%d:\n" +ENDM +; +; KIDL macro +; +MACRO KIDL + "dec r15\n\t" + "jz k%d\n\t" + "clr r14\n\t" + "adc r14\n\t" + "add #2*%d,r12\n\t" + "add #2*%d,r13\n\t" + "rrc r14\n\t" + "jmp k%d\n\t" + "k%d:\n\t" +ENDM +; +; KINC_END macro +; +MACRO KINC_END + "clr r14\n\t" + "adc r14\n\t" + "mov r14,%%[carry]\n\t" + : [carry] "=m" (carry) + : [a] "m" (a), [b] "m" (b), [n] "m" (n), "[carry]" (carry) + :"r12","r13","r14","r15" + ); +ENDM +; +; KDEC_START macro. Zero carry +; +MACRO KDEC_START + asm( + "mov %%[a],r12\n\t" + "mov %%[b],r13\n\t" + "mov %%[n],r15\n\t" + "clrc\n\t" + "k%d:\n" +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + "clr r14\n\t" + "adc r14\n\t" + "mov r14,%%[carry]\n\t" + : [carry] "=m" (carry) + : [a] "m" (a), [b] "m" (b), [n] "m" (n), "[carry]" (carry) + :"r12","r13","r14","r15" + ); +ENDM diff --git a/miracl/source/gccppc.mcs b/miracl/source/gccppc.mcs new file mode 100644 index 0000000..7031f11 --- /dev/null +++ b/miracl/source/gccppc.mcs @@ -0,0 +1,436 @@ +; +; powerPC Macros file for GCC compiler +; +; Triple register is R20|R19|R18 +; MUL_START. Initialise registers. Make R21 and R22 point to multipliers a +; and b. R23 points at result c. +; Initialise Triple register to 0 +; See makemcs.txt for more information about this file +; + +MACRO PMUL_START + ASM ( + "mr %%%%r21,%%0\n" + "mr %%%%r22,%%1\n" + "mr %%%%r23,%%2\n" + "mr %%%%r18,%%3\n" + "xor %%%%r19,%%%%r19,%%%%r19\n" + "xor %%%%r20,%%%%r20,%%%%r20\n" +ENDM + +MACRO PMUL + "ld %%%%r16,8*%d(%%%%r21)\n" + "mulld %%%%r24,%%%%r16,%%%%r18\n" + "mulhdu %%%%r25,%%%%r16,%%%%r18\n" + "addc %%%%r24,%%%%r19,%%%%r24\n" + "addze %%%%r19,%%%%r25\n" + "std %%%%r20,8*%d(%%%%r22)\n" + "std %%%%r24,8*%d(%%%%r23)\n" +ENDM + +MACRO PMUL_END + "mulld %%%%r24,%%%%r18,%%%%r19\n" + "mulhdu %%%%r25,%%%%r18,%%%%r19\n" + "std %%%%r24,0(%%%%r22)\n" + "std %%%%r25,8(%%%%r22)\n" + : + :"r"(a),"r"(b),"r"(c),"r"(sn) + :"r18","r19","r20","r21","r22","r23","r24","r25","memory" + ); +ENDM + +MACRO MUL_START + ASM ( + "mr %%%%r21,%%0\n" + "mr %%%%r22,%%1\n" + "mr %%%%r23,%%2\n" + "xor %%%%r18,%%%%r18,%%%%r18\n" + "xor %%%%r19,%%%%r19,%%%%r19\n" + "xor %%%%r20,%%%%r20,%%%%r20\n" +ENDM +; +; STEP macro. Calculates a double-register partial product +; and adds it to the triple register total +; Parameters 1 & 2: Indices i and j for partial product multipliers a[i] +; and b[j] +MACRO STEP + "ld %%%%r16,8*%d(%%%%r21)\n" + "ld %%%%r17,8*%d(%%%%r22)\n" + "mulld %%%%r24,%%%%r16,%%%%r17\n" + "mulhdu %%%%r25,%%%%r16,%%%%r17\n" + "addc %%%%r18,%%%%r18,%%%%r24\n" + "adde %%%%r19,%%%%r19,%%%%r25\n" + "addze %%%%r20,%%%%r20\n" +ENDM + +; +; MFIN macro. Finish column calculation. Store Sum for this column +; and get Carry for next +; Parameter 1: Index k for Column Sum c[k] +MACRO MFIN + "std %%%%r18,8*%d(%%%%r23)\n" + "mr %%%%r18,%%%%r19\n" + "mr %%%%r19,%%%%r20\n" + "xor %%%%r20,%%%%r20,%%%%r20\n" +ENDM +; +; LAST +; +MACRO LAST + "ld %%%%r16,8*%d(%%%%r21)\n" + "ld %%%%r17,8*%d(%%%%r22)\n" + "mulld %%%%r24,%%%%r16,%%%%r17\n" + "add %%%%r18,%%%%r24,%%%%r18\n" +ENDM +; +; MUL_END +; Parameter 1: Index for final carry c[.] +MACRO MUL_END + "std %%%%r18,8*%d(%%%%r23)\n" + : + :"r"(a),"r"(b),"r"(c) + :"r16","r17","r18","r19","r20","r21","r22","r23","r24","r25","memory" + ); +ENDM +; +; SQR_START +; +MACRO SQR_START + ASM ( + "mr %%%%r21,%%0\n" + "mr %%%%r23,%%1\n" + "xor %%%%r18,%%%%r18,%%%%r18\n" + "xor %%%%r19,%%%%r19,%%%%r19\n" + "xor %%%%r20,%%%%r20,%%%%r20\n" +ENDM +; +; DSTEP macro. Calculates a double-register partial product +; and add it twice to a triple register total +; Parameters 1 & 2 : Indices of partial product multipliers +MACRO DSTEP + "ld %%%%r16,8*%d(%%%%r21)\n" + "ld %%%%r17,8*%d(%%%%r21)\n" + "mulld %%%%r24,%%%%r16,%%%%r17\n" + "mulhdu %%%%r25,%%%%r16,%%%%r17\n" + "addc %%%%r18,%%%%r18,%%%%r24\n" + "adde %%%%r19,%%%%r19,%%%%r25\n" + "addze %%%%r20,%%%%r20\n" + "addc %%%%r18,%%%%r18,%%%%r24\n" + "adde %%%%r19,%%%%r19,%%%%r25\n" + "addze %%%%r20,%%%%r20\n" +ENDM +; +; SELF macro. Calculate the double-register square and +; add it to a triple register total +; Parameter 1 : Index of diagonal element +MACRO SELF + "ld %%%%r16,8*%d(%%%%r21)\n" + "mulld %%%%r24,%%%%r16,%%%%r16\n" + "mulhdu %%%%r25,%%%%r16,%%%%r16\n" + "addc %%%%r18,%%%%r18,%%%%r24\n" + "adde %%%%r19,%%%%r19,%%%%r25\n" + "addze %%%%r20,%%%%r20\n" +ENDM +; +; SFIN macro. Finish column calculation for squaring. Store Sum +; and get Carry for next column. +; Parameter 1: Index of Column Sum +MACRO SFIN + "std %%%%r18,8*%d(%%%%r23)\n" + "mr %%%%r18,%%%%r19\n" + "mr %%%%r19,%%%%r20\n" + "xor %%%%r20,%%%%r20,%%%%r20\n" +ENDM +; +; SQR_END +; Parameter 1: Index for final carry +MACRO SQR_END + "std %%%%r18,8*%d(%%%%r23)\n" + : + :"r"(a),"r"(c) + :"r16","r17","r18","r19","r20","r21","r22","r23","r24","r25","memory" + ); +ENDM +; +; REDC_START macro +; +MACRO REDC_START + ASM ( + "mr %%%%r21,%%0\n" + "mr %%%%r22,%%1\n" + "mr %%%%r23,%%2\n" + "xor %%%%r20,%%%%r20,%%%%r20\n" + "xor %%%%r19,%%%%r19,%%%%r19\n" + "ld %%%%r18,0(%%%%r21)\n" +ENDM +; +; RFINU macro +; +MACRO RFINU + "mulld %%%%r17,%%%%r23,%%%%r18\n" + "std %%%%r17,8*%d(%%%%r21)\n" + "ld %%%%r16,0(%%%%r22)\n" + "mulld %%%%r24,%%%%r16,%%%%r17\n" + "mulhdu %%%%r25,%%%%r16,%%%%r17\n" + "addc %%%%r16,%%%%r18,%%%%r24\n" + "adde %%%%r18,%%%%r19,%%%%r25\n" + "addze %%%%r19,%%%%r20\n" + "ld %%%%r16,8*(%d+1)(%%%%r21)\n" + "addc %%%%r18,%%%%r18,%%%%r16\n" + "addze %%%%r19,%%%%r19\n" + "xor %%%%r20,%%%%r20,%%%%r20\n" +ENDM +; +; RFIND macro +; +MACRO RFIND + "std %%%%r18,8*%d(%%%%r21)\n" + "ld %%%%r16,8*(%d+1)(%%%%r21)\n" + "addc %%%%r18,%%%%r19,%%%%r16\n" + "addze %%%%r19,%%%%r20\n" + "xor %%%%r20,%%%%r20,%%%%r20\n" +ENDM +; +; REDC_END +; +MACRO REDC_END + "std %%%%r18,8*%d(%%%%r21)\n" + "std %%%%r19,8*(%d+1)(%%%%r21)\n" + : + :"r"(a),"r"(b),"r"(ndash) + :"r16","r17","r18","r19","r20","r21","r22","r23","r24","r25","memory" + ); +ENDM +; +; ADD_START macro - initialise for add/subtract, do first one +; +MACRO ADD_START + ASM ( + "mr %%%%r22,%%1\n" + "mr %%%%r23,%%2\n" + "mr %%%%r24,%%3\n" + "ld %%%%r16,0(%%%%r22)\n" + "ld %%%%r17,0(%%%%r23)\n" + "addc %%%%r16,%%%%r16,%%%%r17\n" + "std %%%%r16,0(%%%%r24)\n" +ENDM +; +; ADD macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO ADD + "ld %%%%r16,8*%d(%%%%r22)\n" + "ld %%%%r17,8*%d(%%%%r23)\n" + "adde %%%%r16,%%%%r16,%%%%r17\n" + "std %%%%r16,8*%d(%%%%r24)\n" +ENDM +; +; ADD_END macro. Catch carry +; +MACRO ADD_END + "xor %%%%r16,%%%%r16,%%%%r16\n" + "addze %%%%r16,%%%%r16\n" + "mr %%0,%%%%r16\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(c) + :"r16","r17","r22","r23","r24","memory" + ); +ENDM +; +; INC_START macro. Do first one +; +MACRO INC_START + ASM ( + "mr %%%%r22,%%1\n" + "mr %%%%r23,%%2\n" + "ld %%%%r16,0(%%%%r22)\n" + "ld %%%%r17,0(%%%%r23)\n" + "addc %%%%r16,%%%%r16,%%%%r17\n" + "std %%%%r16,0(%%%%r22)\n" +ENDM +; +; INC macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO INC + "ld %%%%r16,8*%d(%%%%r22)\n" + "ld %%%%r17,8*%d(%%%%r23)\n" + "adde %%%%r16,%%%%r16,%%%%r17\n" + "std %%%%r16,8*%d(%%%%r22)\n" +ENDM +; +; INC_END macro. Catch carry +; +MACRO INC_END + "xor %%%%r16,%%%%r16,%%%%r16\n" + "addze %%%%r16,%%%%r16\n" + "mr %%0,%%%%r16\n" + :"=r"(carry) + :"r"(a),"r"(b) + :"r16","r17","r22","r23","memory" + ); +ENDM +; +; SUB_START macro +; +MACRO SUB_START + ASM ( + "mr %%%%r22,%%1\n" + "mr %%%%r23,%%2\n" + "mr %%%%r24,%%3\n" + "ld %%%%r16,0(%%%%r22)\n" + "ld %%%%r17,0(%%%%r23)\n" + "subfc %%%%r16,%%%%r17,%%%%r16\n" + "std %%%%r16,0(%%%%r24)\n" +ENDM +; +; SUB macro. Subtract two numbers in memory and store result in memory. +; +MACRO SUB + "ld %%%%r16,8*%d(%%%%r22)\n" + "ld %%%%r17,8*%d(%%%%r23)\n" + "subfe %%%%r16,%%%%r17,%%%%r16\n" + "std %%%%r16,8*%d(%%%%r24)\n" +ENDM +; +; SUB_END macro. Catch carry +; +MACRO SUB_END + "xor %%%%r16,%%%%r16,%%%%r16\n" + "addze %%%%r16,%%%%r16\n" + "subfic %%%%r17,%%%%r16,1\n" + "mr %%0,%%%%r17\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(c) + :"r16","r17","r22","r23","r24","memory" + ); +ENDM +; +; DEC_START macro +; +MACRO DEC_START + ASM ( + "mr %%%%r22,%%1\n" + "mr %%%%r23,%%2\n" + "ld %%%%r16,0(%%%%r22)\n" + "ld %%%%r17,0(%%%%r23)\n" + "subfc %%%%r16,%%%%r17,%%%%r16\n" + "std %%%%r16,0(%%%%r22)\n" +ENDM +; +; DEC macro. Subtract two numbers in memory and store result in memory. +; +MACRO DEC + "ld %%%%r16,8*%d(%%%%r22)\n" + "ld %%%%r17,8*%d(%%%%r23)\n" + "subfe %%%%r16,%%%%r17,%%%%r16\n" + "std %%%%r16,8*%d(%%%%r22)\n" +ENDM +; +; DEC_END macro. Catch carry +; +MACRO DEC_END + "xor %%%%r16,%%%%r16,%%%%r16\n" + "addze %%%%r16,%%%%r16\n" + "subfic %%%%r17,%%%%r16,1\n" + "mr %%0,%%%%r17\n" + :"=r"(carry) + :"r"(a),"r"(b) + :"r16","r17","r22","r23","memory" + ); +ENDM +; +; KADD_START macro. Zero Carry flag +; +MACRO KADD_START + ASM ( + "mr %%%%r22,%%1\n" + "mr %%%%r23,%%2\n" + "mr %%%%r24,%%3\n" + "mtctr %%4\n" + "xor %%%%r16,%%%%r16,%%%%r16\n" + "addc %%%%r16,%%%%r16,%%%%r16\n" + "k%d:\n" +ENDM +; +; KASL macro. Important that carry flag is undisturbed! +; +MACRO KASL + "bdz k%d\n" + "addi %%%%r22,%%%%r22,8*%d\n" + "addi %%%%r23,%%%%r23,8*%d\n" + "addi %%%%r24,%%%%r24,8*%d\n" + "b k%d\n" + "k%d:\n" +ENDM +; +; KADD_END macro +; +MACRO KADD_END + "xor %%%%r16,%%%%r16,%%%%r16\n" + "addze %%%%r16,%%%%r16\n" + "mr %%0,%%%%r16\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(c),"r"(n) + :"r16","r17","r18","r19","r20","r21","r22","r23","r24","r25","memory" + ); +ENDM +; +; KINC_START macro. Set carry to Zero +; +MACRO KINC_START + ASM ( + "mr %%%%r22,%%1\n" + "mr %%%%r23,%%2\n" + "mtctr %%3\n" + "xor %%%%r16,%%%%r16,%%%%r16\n" + "addc %%%%r16,%%%%r16,%%%%r16\n" + "k%d:\n" +ENDM +; +; KIDL macro. Important that carry flag is undisturbed! +; +MACRO KIDL + "bdz k%d\n" + "addi %%%%r22,%%%%r22,8*%d\n" + "addi %%%%r23,%%%%r23,8*%d\n" + "b k%d\n" + "k%d: \n" +ENDM +; +; KINC_END macro +; +MACRO KINC_END + "xor %%%%r16,%%%%r16,%%%%r16\n" + "addze %%%%r16,%%%%r16\n" + "mr %%0,%%%%r16\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(n) + :"r16","r17","r18","r19","r20","r21","r22","r23","r24","r25","memory" + ); +ENDM +; +; KDEC_START macro. Set carry +; +MACRO KDEC_START + ASM ( + "mr %%%%r22,%%1\n" + "mr %%%%r23,%%2\n" + "mtctr %%3\n" + "subfc %%%%r16,%%%%r16,%%%%r16\n" + "k%d:\n" +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + "xor %%%%r16,%%%%r16,%%%%r16\n" + "addze %%%%r16,%%%%r16\n" + "subfic %%%%r17,%%%%r16,1\n" + "mr %%0,%%%%r17\n" + :"=r"(carry) + :"r"(a),"r"(b),"r"(n) + :"r16","r17","r18","r19","r20","r21","r22","r23","r24","r25","memory" + ); +ENDM + diff --git a/miracl/source/gccsse2.mcs b/miracl/source/gccsse2.mcs new file mode 100644 index 0000000..6fce165 --- /dev/null +++ b/miracl/source/gccsse2.mcs @@ -0,0 +1,490 @@ +; MCS file for Gnu GCC 3.3+ 80386-Pentium compiler +; +; Sorry about all the %'s! Each % must be input here as %% +; Triple register is xmm0 +; MUL_START. Initialise registers. Make ebx and esi point to multipliers a +; and b. edi points at result c. +; Initialise Triple register to 0 +; See makemcs.txt for more information about this file +; + +MACRO PMUL_START + ASM ( + "pushl %%%%ebp\n" + "pushl %%%%edi\n" + "pushl %%%%esi\n" + "movl %%0,%%%%ebx\n" + "movl %%1,%%%%esi\n" + "movl %%2,%%%%edi\n" + "xorl %%%%ecx,%%%%ecx\n" + "movl %%3,%%%%ebp\n" +ENDM + +MACRO PMUL + "movl %%%%ebp,%%%%eax\n" + "mull 4*%d(%%%%ebx)\n" + "addl %%%%ecx,%%%%eax\n" + "adcl $0,%%%%edx\n" + "movl %%%%edx,%%%%ecx\n" + "movl $0,4*%d(%%%%esi)\n" + "movl %%%%eax,4*%d(%%%%edi)\n" +ENDM + +MACRO PMUL_END + "movl %%%%ebp,%%%%eax\n" + "mull %%%%ecx\n" + "movl %%%%eax,(%%%%esi)\n" + "movl %%%%edx,4(%%%%esi)\n" + "popl %%%%esi\n" + "popl %%%%edi\n" + "popl %%%%ebp\n" + : + :"m"(a),"m"(b),"m"(c),"m"(sn) + :"eax","edi","esi","ebx","ecx","edx","ebp","memory" + ); + +ENDM + +MACRO MUL_START + ASM ( + "pushl %%%%edi\n" + "pushl %%%%esi\n" + "movl %%0,%%%%ebx\n" + "movl %%1,%%%%esi\n" + "movl %%2,%%%%edi\n" + "pxor %%%%xmm0,%%%%xmm0\n" +ENDM +; +; STEP macro. Calculates a double-register partial product +; and adds it to the triple register total +; Parameters 1 & 2: Indices i and j for partial product multipliers a[i] +; and b[j] +MACRO STEP + "movd 4*%d(%%%%ebx),%%%%xmm1\n" + "movd 4*%d(%%%%esi),%%%%xmm2\n" + "pmuludq %%%%xmm2,%%%%xmm1\n" + "pshufd $0xd8,%%%%xmm1,%%%%xmm1\n" + "paddq %%%%xmm1,%%%%xmm0\n" +ENDM +MACRO STEP1M + "movd 4*%d(%%%%ebx),%%%%xmm1\n" + "movd 4*%d(%%%%esi),%%%%xmm2\n" + "pmuludq %%%%xmm2,%%%%xmm1\n" +ENDM +MACRO STEP1A + "pshufd $0xd8,%%%%xmm1,%%%%xmm1\n" + "paddq %%%%xmm1,%%%%xmm0\n" +ENDM +MACRO STEP2M + "movd 4*%d(%%%%ebx),%%%%xmm3\n" + "movd 4*%d(%%%%esi),%%%%xmm4\n" + "pmuludq %%%%xmm4,%%%%xmm3\n" +ENDM +MACRO STEP2A + "pshufd $0xd8,%%%%xmm3,%%%%xmm3\n" + "paddq %%%%xmm3,%%%%xmm0\n" +ENDM +; +; LAST +; +MACRO LAST + "movd 4*%d(%%%%ebx),%%%%xmm1\n" + "movd 4*%d(%%%%esi),%%%%xmm2\n" + "pmuludq %%%%xmm2,%%%%xmm1\n" + "paddq %%%%xmm1,%%%%xmm0\n" +ENDM +; +; MFIN macro. Finish column calculation. Store Sum for this column +; and get Carry for next +; Parameter 1: Index k for Column Sum c[k] +MACRO MFIN + "movd %%%%xmm0,4*%d(%%%%edi)\n" + "movq %%%%xmm0,%%%%xmm7\n" + "psrlq $32,%%%%xmm7\n" + "psrldq $8,%%%%xmm0\n" + "paddq %%%%xmm7,%%%%xmm0\n" +ENDM +; +; MUL_END +; Parameter 1: Index for final carry c[.] +MACRO MUL_END + "movd %%%%xmm0,4*%d(%%%%edi)\n" + "popl %%%%esi\n" + "popl %%%%edi\n" + : + :"m"(a),"m"(b),"m"(c) + :"edi","esi","ebx","xmm0","xmm1","xmm2","xmm3","xmm4","xmm7","memory" + ); +ENDM +; +; SQR_START +; +MACRO SQR_START + ASM ( + "pushl %%%%edi\n" + "pushl %%%%esi\n" + "movl %%0,%%%%ebx\n" + "movl %%1,%%%%esi\n" + "pxor %%%%xmm0,%%%%xmm0\n" +ENDM +; +; DSTEP macro. Calculates a double-register partial product +; and add it twice to a triple register total +; Parameters 1 & 2 : Indices of partial product multipliers +MACRO DSTEP + "movd 4*%d(%%%%ebx),%%%%xmm1\n" + "movd 4*%d(%%%%ebx),%%%%xmm2\n" + "pmuludq %%%%xmm2,%%%%xmm1\n" + "pshufd $0xd8,%%%%xmm1,%%%%xmm1\n" + "paddq %%%%xmm1,%%%%xmm0\n" + "paddq %%%%xmm1,%%%%xmm0\n" +ENDM +MACRO DSTEP1M + "movd 4*%d(%%%%ebx),%%%%xmm1\n" + "movd 4*%d(%%%%ebx),%%%%xmm2\n" + "pmuludq %%%%xmm2,%%%%xmm1\n" +ENDM +MACRO DSTEP1A + "pshufd $0xd8,%%%%xmm1,%%%%xmm1\n" + "paddq %%%%xmm1,%%%%xmm0\n" + "paddq %%%%xmm1,%%%%xmm0\n" +ENDM +MACRO DSTEP2M + "movd 4*%d(%%%%ebx),%%%%xmm3\n" + "movd 4*%d(%%%%ebx),%%%%xmm4\n" + "pmuludq %%%%xmm4,%%%%xmm3\n" +ENDM +MACRO DSTEP2A + "pshufd $0xd8,%%%%xmm3,%%%%xmm3\n" + "paddq %%%%xmm3,%%%%xmm0\n" + "paddq %%%%xmm3,%%%%xmm0\n" +ENDM +; +; SELF macro. Calculate the double-register square and +; add it to a triple register total +; Parameter 1 : Index of diagonal element +MACRO SELF + "movd 4*%d(%%%%ebx),%%%%xmm1\n" + "pmuludq %%%%xmm1,%%%%xmm1\n" + "pshufd $0xd8,%%%%xmm1,%%%%xmm1\n" + "paddq %%%%xmm1,%%%%xmm0\n" +ENDM +; +; SFIN macro. Finish column calculation for squaring. Store Sum +; and get Carry for next column. +; Parameter 1: Index of Column Sum +MACRO SFIN + "movd %%%%xmm0,4*%d(%%%%esi)\n" + "movq %%%%xmm0,%%%%xmm7\n" + "psrlq $32,%%%%xmm7\n" + "psrldq $8,%%%%xmm0\n" + "paddq %%%%xmm7,%%%%xmm0\n" +ENDM +; +; SQR_END +; Parameter 1: Index for final carry +MACRO SQR_END + "movd %%%%xmm0,4*%d(%%%%esi)\n" + "popl %%%%esi\n" + "popl %%%%edi\n" + : + :"m"(a),"m"(c) + :"edi","esi","ebx","xmm0","xmm1","xmm2","xmm3","xmm4","xmm7","memory" + ); +ENDM +; +; REDC_START +; +MACRO REDC_START + ASM ( + "pushl %%%%edi\n" + "pushl %%%%esi\n" + "movl %%0,%%%%ebx\n" + "movl %%1,%%%%esi\n" + "movd %%2,%%%%xmm6\n" + "movd (%%%%ebx),%%%%xmm0\n" +ENDM +; +; RFINU macro +; +MACRO RFINU + "movq %%%%xmm0,%%%%xmm7\n" + "pmuludq %%%%xmm6,%%%%xmm7\n" + "movd %%%%xmm7,4*%d(%%%%ebx)\n" + "movd (%%%%esi),%%%%xmm1\n" + "pmuludq %%%%xmm7,%%%%xmm1\n" + "pshufd $0xd8,%%%%xmm1,%%%%xmm1\n" + "paddq %%%%xmm1,%%%%xmm0\n" + "movq %%%%xmm0,%%%%xmm7\n" + "psrlq $32,%%%%xmm7\n" + "psrldq $8,%%%%xmm0\n" + "paddq %%%%xmm7,%%%%xmm0\n" + "movd 4*(%d+1)(%%%%ebx),%%%%xmm1\n" + "paddq %%%%xmm1,%%%%xmm0\n" +ENDM +; +; RFIND macro +; +MACRO RFIND + "movd %%%%xmm0,4*%d(%%%%ebx)\n" + "movq %%%%xmm0,%%%%xmm7\n" + "psrlq $32,%%%%xmm7\n" + "psrldq $8,%%%%xmm0\n" + "paddq %%%%xmm7,%%%%xmm0\n" + "movd 4*(%d+1)(%%%%ebx),%%%%xmm1\n" + "paddq %%%%xmm1,%%%%xmm0\n" +ENDM +; +; REDC_END +; +MACRO REDC_END + "movd %%%%xmm0,4*%d(%%%%ebx)\n" + "movq %%%%xmm0,%%%%xmm7\n" + "psrlq $32,%%%%xmm7\n" + "psrldq $8,%%%%xmm0\n" + "paddq %%%%xmm7,%%%%xmm0\n" + "movd %%%%xmm0,4*(%d+1)(%%%%ebx)\n" + "popl %%%%esi\n" + "popl %%%%edi\n" + : + :"m"(a),"m"(b),"m"(ndash) + :"edi","esi","ebx","xmm0","xmm1","xmm2","xmm3","xmm4","xmm7","memory" + ); +ENDM +; +; ADD_START macro - initialise for add. Do first one +; +MACRO ADD_START + ASM ( + "pushl %%%%esi\n" + "pushl %%%%edi\n" + "movl %%0,%%%%esi\n" + "movl %%1,%%%%ebx\n" + "movl %%3,%%%%edi\n" + "movl (%%%%esi),%%%%eax\n" + "addl (%%%%ebx),%%%%eax\n" + "movl %%%%eax,(%%%%edi)\n" +ENDM +; +; ADD macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO ADD + "movl 4*%d(%%%%esi),%%%%eax\n" + "adcl 4*%d(%%%%ebx),%%%%eax\n" + "movl %%%%eax,4*%d(%%%%edi)\n" +ENDM +; +; ADD_END macro. Catch Carry +; +MACRO ADD_END + "movl $0,%%%%eax\n" + "adcl %%%%eax,%%%%eax\n" + "movl %%%%eax,%%2\n" + "popl %%%%edi\n" + "popl %%%%esi\n" + : + :"m"(a),"m"(b),"m"(carry),"m"(c) + :"eax","edi","esi","ebx","memory" + ); +ENDM +; +; INC_START macro +; +MACRO INC_START + ASM ( + "pushl %%%%edi\n" + "movl %%0,%%%%edi\n" + "movl %%1,%%%%ebx\n" + "movl (%%%%ebx),%%%%eax\n" + "addl %%%%eax,(%%%%edi)\n" +ENDM +; +; INC macro. Increment number in memory. Don't forget carry +; +MACRO INC + "movl 4*%d(%%%%ebx),%%%%eax\n" + "adcl %%%%eax,4*%d(%%%%edi)\n" +ENDM +; +; INC_END macro. Catch Carry +; +MACRO INC_END + "movl $0,%%%%eax\n" + "adcl %%%%eax,%%%%eax\n" + "movl %%%%eax,%%2\n" + "popl %%%%edi\n" + : + :"m"(a),"m"(b),"m"(carry) + :"eax","edi","ebx","memory" + ); +ENDM +; +; SUB_START macro. Do first one. +; +MACRO SUB_START + ASM ( + "pushl %%%%esi\n" + "pushl %%%%edi\n" + "movl %%0,%%%%esi\n" + "movl %%1,%%%%ebx\n" + "movl %%3,%%%%edi\n" + "movl (%%%%esi),%%%%eax\n" + "subl (%%%%ebx),%%%%eax\n" + "movl %%%%eax,(%%%%edi)\n" +ENDM +; +; SUB macro. Subtract two numbers in memory and store result in memory. +; +MACRO SUB + "movl 4*%d(%%%%esi),%%%%eax\n" + "sbbl 4*%d(%%%%ebx),%%%%eax\n" + "movl %%%%eax,4*%d(%%%%edi)\n" +ENDM +; +; SUB_END macro. Catch Carry +; +MACRO SUB_END + "movl $0,%%%%eax\n" + "adcl %%%%eax,%%%%eax\n" + "movl %%%%eax,%%2\n" + "popl %%%%edi\n" + "popl %%%%esi\n" + : + :"m"(a),"m"(b),"m"(carry),"m"(c) + :"eax","edi","esi","ebx","memory" + ); +ENDM +; +; DEC_START macro. Do first one. +; +MACRO DEC_START + ASM ( + "pushl %%%%edi\n" + "movl %%0,%%%%edi\n" + "movl %%1,%%%%ebx\n" + "movl (%%%%ebx),%%%%eax\n" + "subl %%%%eax,(%%%%edi)\n" +ENDM +; +; DEC macro. Decrement from number in memory. Don't forget borrow. +; +MACRO DEC + "movl 4*%d(%%%%ebx),%%%%eax\n" + "sbbl %%%%eax,4*%d(%%%%edi)\n" +ENDM +; +; DEC_END macro +; +MACRO DEC_END + "movl $0,%%%%eax\n" + "adcl %%%%eax,%%%%eax\n" + "movl %%%%eax,%%2\n" + "popl %%%%edi\n" + : + :"m"(a),"m"(b),"m"(carry) + :"eax","edi","ebx","memory" + ); +ENDM +; +; KADD_START macro +; +MACRO KADD_START + ASM ( + "pushl %%%%esi\n" + "pushl %%%%edi\n" + "movl %%0,%%%%esi\n" + "movl %%1,%%%%ebx\n" + "movl %%3,%%%%edi\n" + "movl %%4,%%%%ecx\n" + "xorl %%%%eax,%%%%eax\n" + "k%d:\n" +ENDM +; +; KASL macro +; +MACRO KASL + "decl %%%%ecx\n" + "je k%d\n" + "leal 4*%d(%%%%esi),%%%%esi\n" + "leal 4*%d(%%%%ebx),%%%%ebx\n" + "leal 4*%d(%%%%edi),%%%%edi\n" + "jmp k%d\n" + "k%d:\n" +ENDM +; +; KADD_END macro +; +MACRO KADD_END + "movl $0,%%%%eax\n" + "adcl %%%%eax,%%%%eax\n" + "movl %%%%eax,%%2\n" + "popl %%%%edi\n" + "popl %%%%esi\n" + : + :"m"(a),"m"(b),"m"(carry),"m"(c),"m"(n) + :"eax","edi","esi","ebx","ecx","memory" + ); +ENDM +; +; KINC_START macro. Zero carry flag. +; +MACRO KINC_START + ASM ( + "pushl %%%%edi\n" + "movl %%0,%%%%edi\n" + "movl %%1,%%%%ebx\n" + "movl %%3,%%%%ecx\n" + "xorl %%%%eax,%%%%eax\n" + "k%d:\n" +ENDM +; +; KIDL macro +; +MACRO KIDL + "decl %%%%ecx\n" + "je k%d\n" + "leal 4*%d(%%%%ebx),%%%%ebx\n" + "leal 4*%d(%%%%edi),%%%%edi\n" + "jmp k%d\n" + "k%d:\n" +ENDM +; +; KINC_END macro +; +MACRO KINC_END + "movl $0,%%%%eax\n" + "adcl %%%%eax,%%%%eax\n" + "movl %%%%eax,%%2\n" + "popl %%%%edi\n" + : + :"m"(a),"m"(b),"m"(carry),"m"(n) + :"eax","edi","ebx","ecx","memory" + ); +ENDM +; +; KDEC_START macro +; +MACRO KDEC_START + ASM ( + "pushl %%%%edi\n" + "movl %%0,%%%%edi\n" + "movl %%1,%%%%ebx\n" + "movl %%3,%%%%ecx\n" + "xorl %%%%eax,%%%%eax\n" + "k%d:\n" +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + "movl $0,%%%%eax\n" + "adcl %%%%eax,%%%%eax\n" + "movl %%%%eax,%%2\n" + "popl %%%%edi\n" + : + :"m"(a),"m"(b),"m"(carry),"m"(n) + :"eax","edi","ebx","ecx","memory" + ); +ENDM + diff --git a/miracl/source/genkey.c b/miracl/source/genkey.c new file mode 100644 index 0000000..4715c7d --- /dev/null +++ b/miracl/source/genkey.c @@ -0,0 +1,105 @@ +/* + * Program to generate RSA keys suitable for use with an encryption + * exponent of 3, and which are also 'Blum Integers'. + * + * Note that an exponent of 3 must be used with extreme care! + * + * For example:- + * If the same message m is encrypted under 3 or more different public keys + * the message can be recovered without factoring the modulus (using the + * Chinese remainder thereom). + * If the messages m and m+1 are encrypted under the same public key, again + * the message can be recovered without factoring the modulus. Indeed any + * simple relationship between a pair of messages can be exploited in a + * similar way. + * + */ + +#include +#include "miracl.h" +#define NP 2 /* use two primes - could be more */ +#define PRIME_BITS 512 /* >=256 bits */ + +static miracl *mip; + +static big pd,pl,ph; + +long randise(void) +{ /* get a random number */ + long seed; + printf("Enter 9 digit random number seed = "); + scanf("%ld",&seed); + getchar(); + return seed; +} + +void strongp(big p,int n,long seed1,long seed2) +{ /* generate strong prime number =11 mod 12 suitable for RSA encryption */ + int r,r1,r2; + irand(seed1); + bigbits(2*n/3,pd); + nxprime(pd,pd); + expb2(n-1,ph); + divide(ph,pd,ph); + expb2(n-2,pl); + divide(pl,pd,pl); + subtract(ph,pl,ph); + irand(seed2); + bigrand(ph,ph); + add(ph,pl,ph); + r1=subdiv(pd,12,pl); + r2=subdiv(ph,12,pl); + r=0; + while ((r1*(r2+r))%12!=5) r++; + incr(ph,r,ph); + do + { /* find p=2*r*pd+1 = 11 mod 12 */ + multiply(ph,pd,p); + premult(p,2,p); + incr(p,1,p); + incr(ph,12,ph); + } while (!isprime(p)); +} + +int main() +{ /* calculate public and private keys * + * for rsa encryption */ + int i; + long seed[2*NP]; + big p[NP],ke; + FILE *outfile; + mip=mirsys(100,0); + gprime(15000); /* speeds up large prime generation */ + for (i=0;iIOBASE=16; + outfile=fopen("public.key","wt"); + cotnum(ke,outfile); + fclose(outfile); + outfile=fopen("private.key","wt"); + for (i=0;i +#include +#include +#include "big.h" /* include MIRACL system */ +#define NP 2 /* two primes only - could be more */ + +using namespace std; + +// if MR_STATIC is defined, it should be 100 + +Miracl precision=100; + +static Big pd,pl,ph; + +long randise() +{ /* get a random number */ + long seed; + cout << "Enter 9 digit random number seed = "; + cin >> seed; + return seed; +} + +Big strongp(int n,long seed1,long seed2) +{ /* generate strong prime number =11 mod 12 suitable for RSA encryption */ + Big p; + int r,r1,r2; + irand(seed1); + pd=rand(2*n/3,2); + pd=nextprime(pd); + ph=pow((Big)2,n-1)/pd; + pl=pow((Big)2,n-2)/pd; + ph-=pl; + irand(seed2); + ph=rand(ph); + ph+=pl; + r1=pd%12; + r2=ph%12; + r=0; + while ((r1*(r2+r))%12!=5) r++; + ph+=r; + do + { /* find p=2*r*pd+1 = 11 mod 12 */ + p=2*ph*pd+1; + ph+=12; + } while (!prime(p)); + return p; +} + +int main() +{ /* calculate public and private keys * + * for rsa encryption */ + int k,i; + long seed[2*NP]; + Big p[NP],ke; + ofstream public_key("public.key"); + ofstream private_key("private.key"); + miracl *mip=&precision; + + gprime(15000); /* speeds up large prime generation */ + do + { + cout << "size of each prime in bits= "; + cin >> k; + } while (k<128); + for (i=0;i<2*NP;i++) + seed[i]=randise(); + cout << "generating keys - please wait\n"; + ke=1; + for (i=0;iIOBASE=16; + public_key << ke << endl; + for (i=0;i +#include "miracl.h" +#define NPRIMES 6 /* =9 for > 256 bit primes */ +#define PROOT 2 + +int main() +{ /* program to find a trap-door prime */ + BOOL found; + int i,spins; + long seed; + big pp[NPRIMES],q,p,t; + FILE *fp; + mirsys(50,0); + for (i=0;i +#include +#include +#include "big.h" /* include MIRACL system */ +#define NPRIMES 5 /* =9 for > 256 bit primes */ +#define PROOT 2 + +using namespace std; + +Miracl precision=100; + +int main() +{ /* program to find a trap-door prime */ + BOOL found; + int i,spins; + long seed; + Big pp[NPRIMES],q,p,t; + ofstream prime_data("prime.dat"); + cout << "Enter 9 digit seed= "; + cin >> seed; + irand(seed); + cout << "Enter 4 digit seed= "; + cin >> spins; + for (i=0;i. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL C++ functions gf2m.cpp + * + * AUTHOR : M. Scott + * + * PURPOSE : Implementation of class GF2m + * + * NOTE: : Must be used in conjunction with big.h and big.cpp + * + */ + +#include "gf2m.h" + + +GF2m square(const GF2m& b) {GF2m r=b; modsquare2(r.fn,r.fn); return r;} + +GF2m inverse(const GF2m& b) {GF2m r=b; inverse2(r.fn,r.fn); return r;} + +BOOL GF2m::iszero() const +{ if (size(fn)==0) return TRUE; else return FALSE; } + +BOOL GF2m::isone() const +{ if (size(fn)==1) return TRUE; else return FALSE; } + +BOOL modulo(int m,int a,int b,int c,BOOL check) {return prepare_basis(m,a,b,c,check);} + +GF2m& GF2m::operator/=(const GF2m& b) +{ GF2m z=b; inverse2(z.fn,z.fn); modmult2(fn,z.fn,fn); return *this;} +#ifndef MR_NO_RAND +GF2m random2(void) +{GF2m z; rand2(z.fn); return z;} +#endif +GF2m operator+(const GF2m& b1,const GF2m& b2) +{GF2m abb=b1; abb+=b2; return abb;} + +GF2m operator+(const GF2m& b1,int b2) +{GF2m abb=b1; abb+=b2; return abb;} + +GF2m operator*(const GF2m& b1,const GF2m& b2) +{ + GF2m abb=b1; + if (&b1==&b2) + abb*=abb; + else + abb*=b2; + return abb; +} + +GF2m operator/(const GF2m& b1,const GF2m& b2) +{GF2m abb; inverse2(b2.fn,abb.fn); modmult2(b1.fn,abb.fn,abb.fn); return abb;} + +#ifndef MR_STATIC +GF2m pow(const GF2m& b,int m) +{GF2m z; power2(b.fn,m,z.fn); return z;} +#endif + +GF2m sqrt(const GF2m& b) +{GF2m z; sqroot2(b.fn,z.fn); return z;} + +GF2m halftrace(const GF2m& b) +{GF2m z; halftrace2(b.fn,z.fn); return z;} + +GF2m quad(const GF2m& b) +{GF2m z; if (!quad2(b.fn,z.fn)) zero(z.fn); return z;} + +GF2m gcd(const GF2m& b1,const GF2m& b2) +{GF2m g; gcd2(b1.fn,b2.fn,g.fn); return g;} + +void kar2x2(const GF2m *x,const GF2m *y,GF2m *z) +{ + z[0]=x[0]*y[0]; + z[2]=x[1]*y[1]; + z[1]=(x[0]+x[1])*(y[0]+y[1]); +} + +void kar3x3(const GF2m *x,const GF2m *y,GF2m *z) +{ + z[0]=x[0]*y[0]; + z[2]=x[1]*y[1]; + z[4]=x[2]*y[2]; + z[1]= (x[0]+x[1])*(y[0]+y[1])+z[2]+z[0]; + z[3]= (x[1]+x[2])*(y[1]+y[2])+z[2]+z[4]; + z[2]+=(x[0]+x[2])*(y[0]+y[2])+z[0]+z[4]; +} diff --git a/miracl/source/hail.c b/miracl/source/hail.c new file mode 100644 index 0000000..58082fe --- /dev/null +++ b/miracl/source/hail.c @@ -0,0 +1,41 @@ +/* + * Program to investigate hailstone numbers. + * Gruenberger F. 'Computer Recreations' Scientific American. April 1984. + * + */ + +#include +#include "miracl.h" + +int main () +{ /* hailstone numbers */ + + int iter,r; + big x,y,mx; + mirsys(400,10); + x=mirvar(0); + y=mirvar(0); + mx=mirvar(0); + iter=0; + printf("number = \n"); + innum(x,stdin); + do + { /* main loop */ + if (mr_compare(x,mx)>0) copy(x,mx); + r=subdiv(x,2,y); + if (r!=0) + { /* what goes up ... */ + premult(x,3,x); + incr(x,1,x); + } + /* ... must come down */ + else copy(y,x); + otnum(x,stdout); + iter++; + } while (size(x)!=1); + printf("path length = %d \n",iter); + printf("maximum = \n"); + otnum(mx,stdout); + return 0; +} + diff --git a/miracl/source/hail.cpp b/miracl/source/hail.cpp new file mode 100644 index 0000000..c3d21df --- /dev/null +++ b/miracl/source/hail.cpp @@ -0,0 +1,35 @@ +/* + * Program to investigate hailstone numbers. + * Gruenberger F. 'Computer Recreations' Scientific American. April 1984. + * + * Requires: big.cpp + */ + +#include +#include "big.h" + +using namespace std; + +Miracl precision(400,10); + +int main() +{ /* hailstone numbers */ + Big r,x,mx=0; + int iter; + iter=0; + cout << "number = \n"; + cin >> x; + do + { + if (x>mx) mx=x; + r=x%2; + if (r!=0) x=3*x+1; + else x/=2; + cout << x << endl; + iter++; + } while (x!=1); + cout << "path length = " << iter << "\n"; + cout << "maximum = " << mx << "\n"; + return 0; +} + diff --git a/miracl/source/hilbert.c b/miracl/source/hilbert.c new file mode 100644 index 0000000..e8a9ca2 --- /dev/null +++ b/miracl/source/hilbert.c @@ -0,0 +1,111 @@ +/* + * Solve set of linear equations involving + * a Hilbert matrix + * i.e. solves Hx=b, where b is the vector [1,1,1....1] + * + */ + +#include +#include "miracl.h" + +static flash AA[50][50]; +static flash bb[50]; + +BOOL gauss(flash A[][50],flash b[],int n) +{ /* solve Ax=b using Gaussian elimination * + * solution x returned in b */ + int i,j,k,m; + BOOL ok; + flash w,s; + w=mirvar(0); + s=mirvar(0); + ok=TRUE; + for (i=0;i0) m=j; + } + if (m!=i) for (k=i;k<=n;k++) + { + copy(A[i][k],w); + copy(A[m][k],A[i][k]); + copy(w,A[m][k]); + } + if (size(A[i][i])==0) + { + ok=FALSE; + break; + } + for (j=i+1;j=i;k--) + { + fmul(s,A[i][k],w); + fsub(A[j][k],w,A[j][k]); + } + } + } + if (ok) for (j=n-1;j>=0;j--) + { /* Backward substitution */ + zero(s); + for (k=j+1;k49); + for (i=0;i +#include "flash.h" + +using namespace std; + +Miracl precision=20; + +static Flash A[20][20]; +static Flash b[20]; + +BOOL gauss(Flash A[][20],Flash b[],int n) +{ /* solve Ax=b using Gaussian elimination * + * solution returned in b */ + int i,ii,j,jj,k,m; + int row[20]; + BOOL ok; + Flash s; + ok=TRUE; + for (i=0;is) + { + m=j; + s=fabs(A[jj][i]); + } + } + + if (s==0) + { // no non-zero pivot found + ok=FALSE; + break; + } + + k=row[i]; row[i]=row[m]; row[m]=k; // swap row indices + + ii=row[i]; + for (j=i+1;j=i;k--) A[jj][k]-=s*A[ii][k]; + } + } + if (ok) for (j=n-1;j>=0;j--) + { /* Backward substitution */ + s=0; + for (k=j+1;kRPOINT=OFF; /* use fractions for output */ + do + { + cout << "Order of Hilbert matrix H= "; + cin >> n; + } while (n<2 || n>19); + for (i=0;iEXACT) cout << "Result is exact!\n"; + } + else cout << "H is singular!\n"; + + return 0; +} + diff --git a/miracl/source/identity.c b/miracl/source/identity.c new file mode 100644 index 0000000..52e0876 --- /dev/null +++ b/miracl/source/identity.c @@ -0,0 +1,218 @@ +/* + * Program to find discrete logarithms of user identities + * using Pollard's rho method. + * + * Suitable trap-door primes are generated by "genprime" program + * + * See "Non-Interactive Public-Key Cryptography" + * by U. Maurer & Y. Yacobi. Proc Eurocrypt '91 + * + */ + +#include +#include +#include +#include "miracl.h" +#define NPRIMES 15 +#define PROOT 2 + +static big p,p1,order,lim1,lim2; +static big pp[NPRIMES],rem[NPRIMES]; +static BOOL flag=FALSE; +static int np; + +void iterate(big x,big q,big r,big a,big b) +{ /* apply Pollards random mapping */ + if (mr_compare(x,lim1)<0) + { + mad(x,q,q,p,p,x); + incr(a,1,a); + if (mr_compare(a,order)==0) zero(a); + return; + + } + if (mr_compare(x,lim2)<0) + { + mad(x,x,x,p,p,x); + premult(a,2,a); + if (mr_compare(a,order)>=0) subtract(a,order,a); + premult(b,2,b); + if (mr_compare(b,order)>=0) subtract(b,order,b); + return; + } + mad(x,r,r,p,p,x); + incr(b,1,b); + if (mr_compare(b,order)==0) zero(b); +} + +long rho(big q,big r,big m,big n) +{ /* find q^m = r^n */ + long iter,rr,i; + + char stack_mem[mr_big_reserve(6,50)]; + big ax,bx,ay,by,x,y; + + memset(stack_mem,0,mr_big_reserve(6,50)); + + ax=mirvar_mem(stack_mem,0); + bx=mirvar_mem(stack_mem,1); + ay=mirvar_mem(stack_mem,2); + by=mirvar_mem(stack_mem,3); + x=mirvar_mem(stack_mem,4); + y=mirvar_mem(stack_mem,5); + + convert(1,y); + zero(ay); zero(by); + + iter=0L; + rr=1L; + do + { /* Brent's Cycle finder */ + copy(y,x); + copy(ay,ax); + copy(by,bx); + rr*=2; + for (i=1L;i<=rr;i++) + { + iter++; + iterate(y,q,r,ay,by); + if (mr_compare(x,y)==0) break; + } + } while (mr_compare(x,y)!=0); + subtract(ax,ay,m); + if (size(m)<0) add(m,order,m); + subtract(by,bx,n); + if (size(n)<0) add(n,order,n); + return iter; +} + +void getprime(char *fname) +{ /* get prime details from file */ + FILE *fp; + int i; + fp=fopen(fname,"rt"); + if (fp==NULL) + { + printf("file %s not found\n",fname); + exit(0); + } + fscanf(fp,"%d\n",&np); + for (i=0;iIOBUFF); + printf("Check Identity= %s\n",mip->IOBUFF); + return 0; +} + diff --git a/miracl/source/imratio.c b/miracl/source/imratio.c new file mode 100644 index 0000000..77dac62 --- /dev/null +++ b/miracl/source/imratio.c @@ -0,0 +1,154 @@ +/* + * program to calculate modquare/modmult, inverse/modmult, + * jacobi/modmult and modadd/modmult ratios + */ + +#include +#include "miracl.h" +#include + +#define MIN_TIME 15.0 + +int sizes[]={160,256,512,640}; +int num_sizes=4; + +int main() +{ + time_t seed; + int i,j,k,bits; + long iterations; + big x,nx,y,ny,n,w; + clock_t start; + double square_time,mult_time,xgcd_time,jac_time,add_time; + +#ifndef MR_NOFULLWIDTH + mirsys(80,0); +#else + mirsys(80,MAXBASE); +#endif + x=mirvar(0); + nx=mirvar(0); + y=mirvar(0); + ny=mirvar(0); + n=mirvar(0); + w=mirvar(0); + + printf("MIRACL - %d bit version\n",MIRACL); +#ifdef MR_LITTLE_ENDIAN + printf("Little Endian processor\n"); +#endif +#ifdef MR_BIG_ENDIAN + printf("Big Endian processor\n"); +#endif +#ifdef MR_NOASM + printf("C-Only Version of MIRACL\n"); +#else + printf("Using some assembly language\n"); +#endif +#ifdef MR_STRIPPED_DOWN + printf("Stripped down version of MIRACL - no error messages\n"); +#endif +#ifdef MR_KCM + k=MR_KCM*MIRACL; + printf("Using KCM method \n"); + printf("Optimized for %d, %d, %d, %d...etc. bit moduli\n",k,k*2,k*4,k*8); +#endif +#ifdef MR_COMBA + k=MR_COMBA*MIRACL; + printf("Using COMBA method \n"); + printf("Optimized for %d bit moduli\n",k); +#endif +#ifdef MR_PENTIUM + printf("Floating-point co-processor arithmetic used for Pentium\n"); +#endif +#ifndef MR_KCM +#ifndef MR_COMBA +#ifndef MR_PENTIUM + printf("No special optimizations\n"); +#endif +#endif +#endif + +#ifdef MR_NOFULLWIDTH + printf("No Fullwidth base possible\n"); +#endif + + printf("NOTE: times are elapsed real-times - so make sure nothing else is running!\n\n"); + + time(&seed); + irand((unsigned long)seed); + printf("Calculating Modsquare/Modmult, Inverse/Modmult, Jacobi/Modmult Modadd/Modmult ratios\n"); + printf("Please Wait......\n"); + for (j=0;j +#include "miracl.h" +#include + +#define MIN_TIME 10.0 + +int m[]={103,163,233,283,313,379,571}; +int a[]={9, 99,159,249,121,317,507}; +int b[]={0, 97, 0,219, 0,315,475}; +int c[]={0, 3, 0, 27, 0,283,417}; + +int main() +{ + time_t seed; + int i,j,k,bits; + long iterations; + big x,y,w; + clock_t start; + double square_time,sqrt_time,mult_time,inverse_time; + +#ifndef MR_NOFULLWIDTH + mirsys(80,0); +#else + mirsys(80,MAXBASE); +#endif + x=mirvar(0); + y=mirvar(0); + w=mirvar(0); + + printf("MIRACL - %d bit version\n",MIRACL); +#ifdef MR_LITTLE_ENDIAN + printf("Little Endian processor\n"); +#endif +#ifdef MR_BIG_ENDIAN + printf("Big Endian processor\n"); +#endif + + printf("C-Only Version of MIRACL\n"); + +#ifdef MR_STRIPPED_DOWN + printf("Stripped down version of MIRACL - no error messages\n"); +#endif + + printf("NOTE: times are elapsed real-times - so make sure nothing else is running!\n\n"); + + time(&seed); + irand((unsigned long)seed); + printf("Calculating Square/Multiply (S/M), Square Root/Multiply (R/M) and Inverse/Multiply (I/M) ratios\n"); + printf("Please Wait......\n"); + + for (j=0;j<7;j++) + { + bits=m[j]; + if (!prepare_basis(m[j],a[j],b[j],c[j],TRUE)) + { + printf("Problem\n"); + return 0; + } + rand2(x); + rand2(y); + + iterations=0; + start=clock(); + do { + for (i=0;i<1000;i++) modmult2(x,y,w); + iterations++; + mult_time=(clock()-start)/(double)CLOCKS_PER_SEC; + } while (mult_time +#include +#include "miracl.h" + +#define NPRIMES 10 +#define PROOT 2 + +static big p,p1,order,lim1,lim2; +static BOOL flag=FALSE; + +void iterate(big x,big q,big r,big a,big b) +{ /* apply Pollards random mapping */ + if (mr_compare(x,lim1)<0) + { + mad(x,q,q,p,p,x); + incr(a,1,a); + if (mr_compare(a,order)==0) zero(a); + return; + } + if (mr_compare(x,lim2)<0) + { + mad(x,x,x,p,p,x); + premult(a,2,a); + if (mr_compare(a,order)>=0) subtract(a,order,a); + premult(b,2,b); + if (mr_compare(b,order)>=0) subtract(b,order,b); + return; + } + mad(x,r,r,p,p,x); + incr(b,1,b); + if (mr_compare(b,order)==0) zero(b); +} + +long rho(big q,big r,big m,big n) +{ /* find q^m = r^n */ + long iter,rr,i; + big ax,bx,ay,by,x,y; + ax=mirvar(0); + bx=mirvar(0); + ay=mirvar(0); + by=mirvar(0); + x=mirvar(1); + y=mirvar(1); + iter=0L; + rr=1L; + do + { /* Brent's Cycle finder */ + copy(y,x); + copy(ay,ax); + copy(by,bx); + rr*=2; + for (i=1;i<=rr;i++) + { + iter++; + iterate(y,q,r,ay,by); + if (mr_compare(x,y)==0) break; + } + } while (mr_compare(x,y)!=0); + + subtract(ax,ay,m); + if (size(m)<0) add(m,order,m); + subtract(by,bx,n); + if (size(n)<0) add(n,order,n); + mirkill(y); + mirkill(x); + mirkill(by); + mirkill(ay); + mirkill(bx); + mirkill(ax); + return iter; +} + +int main() +{ + int i,id,np; + long iter; + big pp[NPRIMES],rem[NPRIMES]; + big m,n,Q,R,q,w,x; + FILE *fp; + big_chinese bc; + miracl *mip=mirsys(50,0); + for (i=0;iIOBUFF); + printf("*%s",mip->IOBUFF); + } + printf("\n\nEnter y= "); + cinnum(q,stdin); + crt_init(&bc,np,pp); + for (i=0;i +#include +#include "big.h" /* include MIRACL system */ +#include "crt.h" /* chinese remainder thereom */ +#define NPRIMES 10 +#define PROOT 2 + +using namespace std; + +Miracl precision=100; + +static Big p,p1,order,lim1,lim2; +static BOOL flag=FALSE; + +void iterate(Big &x,Big &q,Big &r,Big &a,Big &b) +{ /* apply Pollards random mapping */ + if (x=order) a-=order; + b*=2; + if (b>=order) b-=order; + return; + } + x=(x*r)%p; + b+=1; + if (b==order) b=0; +} + +long rho(Big &q,Big &r,Big &m,Big &n) +{ /* find q^m = r^n */ + long iter,rr,i; + Big ax,bx,ay,by,x,y; + x=1; + y=1; + iter=0L; + rr=1L; + do + { /* Brent's Cycle finder */ + x=y; + ax=ay; + bx=by; + rr*=2; + for (i=1;i<=rr;i++) + { + iter++; + iterate(y,q,r,ay,by); + if (x==y) break; + } + } while (x!=y); + m=ax-ay; + if (m<0) m+=order; + n=by-bx; + if (n<0) n+=order; + return iter; +} + +int main() +{ + int i,np; + long iter; + Big pp[NPRIMES],rem[NPRIMES]; + Big m,n,Q,R,q,w,x; + ifstream prime_data("prime.dat"); + p1=1; + prime_data >> np; + for (i=0;i> pp[i]; + for (i=0;i " << endl; + cout << "OR" << endl; + cout << "irp " << endl; + cout << "The code that is generated can be copied into the" << endl; + cout << "function reduce2 in the module mrgf2m.c" << endl; + return 0; + } + + A=B=C=0; + W=atoi(argv[0]); + M=atoi(argv[1]); + A=atoi(argv[2]); + if (W<0 || W%8!=0 || A<1 || M-A < W) exit(0); + + if (argc==5) + { + B=atoi(argv[3]); + C=atoi(argv[4]); + if (B<1 || C<1 || B>A || C>B) exit(0); + } + + k1=1+M/W; + + rs1=M%W; + ls1=W-rs1; + + k2=1+(M-A)/W; + + rs2=(M-A)%W; + ls2=W-rs2; + + if (B) + { + k3=1+(M-B)/W; + rs3=(M-B)%W; + ls3=W-rs3; + + k4=1+(M-C)/W; + rs4=(M-C)%W; + ls4=W-rs4; + } + + for (i=0;i<64;i++) ind[i]=0; + + if (rs1==0) + { + shift[k1-1][ind[k1-1]]=0; + ind[k1-1]++; + } + else + { + shift[k1-1][ind[k1-1]]=rs1; + ind[k1-1]++; + shift[k1][ind[k1]]=-ls1; + ind[k1]++; + } + + if (rs2==0) + { + shift[k2-1][ind[k2-1]]=0; + ind[k2-1]++; + } + else + { + shift[k2-1][ind[k2-1]]=rs2; + ind[k2-1]++; + shift[k2][ind[k2]]=-ls2; + ind[k2]++; + } + + if (B) + { + if (rs3==0) + { + shift[k3-1][ind[k3-1]]=0; + ind[k3-1]++; + } + else + { + shift[k3-1][ind[k3-1]]=rs3; + ind[k3-1]++; + shift[k3][ind[k3]]=-ls3; + ind[k3]++; + } + if (rs4==0) + { + shift[k4-1][ind[k4-1]]=0; + ind[k4-1]++; + } + else + { + shift[k4-1][ind[k4-1]]=rs4; + ind[k4-1]++; + shift[k4][ind[k4]]=-ls4; + ind[k4]++; + } + } + + if (B) printf(" if (M==%d && A==%d && B==%d && C==%d)\n",M,A,B,C); + else printf(" if (M==%d && A==%d)\n",M,A); + + printf(" {\n for (i=xl-1;i>=%d;i--)\n {\n",k1); + printf(" w=gx[i]; gx[i]=0;\n"); + + nxor=0; nsh=0; + for (i=0;i<64;i++) + { + if (ind[i]==0) continue; + nxor++; + printf(" gx[i-%d]^=",i); + xxor=0; + for (j=0;j0) {printf("(w>>%d)",shift[i][j]); xxor++; nsh++; } + if (shift[i][j]<0) {printf("(w<<%d)",-shift[i][j]); xxor++; nsh++;} + } + + nxor+=(xxor-1); + printf(";\n"); + } + printf(" } /* XORs= %d shifts= %d */\n",nxor,nsh); + printf(" top=gx[%d]>>%d; ",k1-1,rs1); + printf("gx[0]^=top; "); + printf("top<<=%d;\n",rs1); + + for (i=0;i<64;i++) ind[i]=0; + + if (rs2==0) + { + shift[k1-k2][ind[k1-k2]]=0; + ind[k1-k2]++; + } + else + { + shift[k1-k2][ind[k1-k2]]=rs2; + ind[k1-k2]++; + if (k1>k2) + { + shift[k1-k2-1][ind[k1-k2-1]]=-ls2; + ind[k1-k2-1]++; + } + } + + if (B) + { + if (rs3==0) + { + shift[k1-k3][ind[k1-k3]]=0; + ind[k1-k3]++; + } + else + { + shift[k1-k3][ind[k1-k3]]=rs3; + ind[k1-k3]++; + if (k1>k3) + { + shift[k1-k3-1][ind[k1-k3-1]]=-ls3; + ind[k1-k3-1]++; + } + } + if (rs4==0) + { + shift[k1-k4][ind[k1-k4]]=0; + ind[k1-k4]++; + } + else + { + shift[k1-k4][ind[k1-k4]]=rs4; + ind[k1-k4]++; + if (k1>k4) + { + shift[k1-k4-1][ind[k1-k4-1]]=-ls4; + ind[k1-k4-1]++; + } + } + } + + for (i=0;i<64;i++) + { + if (ind[i]==0) continue; + printf(" gx[%d]^=",i); + xxor=0; + for (j=0;j0) {printf("(top>>%d)",shift[i][j]); xxor++;} + if (shift[i][j]<0) {printf("(top<<%d)",-shift[i][j]); xxor++;} + } + printf(";\n"); + } + + printf(" gx[%d]^=top;\n",k1-1); + printf(" x->len=%d;\n",k1); + printf(" if (gx[%d]==0) mr_lzero(x);\n",k1-1); + printf(" return;\n }\n"); + return 0; +} diff --git a/miracl/source/itanium.mcs b/miracl/source/itanium.mcs new file mode 100644 index 0000000..19f9e96 --- /dev/null +++ b/miracl/source/itanium.mcs @@ -0,0 +1,390 @@ +; Comba/KCM Macros for 64-bit Itanium +; +; Scheduled Version +; +; Note that: +; mr_small is a 64-bit unsigned long +; +; Triple register is extra|sumh1|sumlo +; +; See makemcs.txt for more information about this file +; + +MACRO PMUL_START + carry=0; +ENDM + +MACRO PMUL + ma=a[%d]; + u=_m64_xmalu(ma,sn,carry); + carry=_m64_xmahu(ma,sn,carry); + b[%d]=0; + c[%d]=u; +ENDM + +MACRO PMUL_END + b[0]=_m64_xmalu(carry,sn,0); + b[1]=_m64_xmahu(carry,sn,0); +ENDM + + +MACRO MUL_START + extra=sumhi=sumlo=0; +ENDM +; +; STEP macros +; +MACRO STEP + ma=a[%d]; mb=b[%d]; + hi1=_m64_xmahu(ma,mb,sumlo); + lo1=_m64_xmalu(ma,mb,sumlo); + sumhi+=hi1; + extra+=(sumhima) carry=0; + else if (uma) carry=0; + else if (ua[0]); + c[0]=u; +ENDM +; +; SUB macro - c[.]=a[.]-b[.] +; +MACRO SUB + ma=a[%d]; + u=ma-b[%d]-carry; + if (uma) carry=1; + c[%d]=u; +ENDM +MACRO SUB_END +ENDM +; +; DEC_START macro +; +MACRO DEC_START + u=a[0]-b[0]; + carry=(u>a[0]); + a[0]=u; +ENDM +; +; DEC macro a[.]-=b[.] +; +MACRO DEC + ma=a[%d]; + u=ma-b[%d]-carry; + if (uma) carry=1; + a[%d]=u; +ENDM +; +; DEC_END macro +; +MACRO DEC_END +ENDM +; +; KADD_START macro. Zero Carry +; +MACRO KADD_START + carry=0; + k%d: +ENDM +; +; KASL macro +; +MACRO KASL + n--; + if (n==0) goto k%d; + a+=%d; + b+=%d; + c+=%d; + goto k%d; + k%d: +ENDM +; +; KADD_END macro +; +MACRO KADD_END +ENDM +; +; KINC_START macro +; +MACRO KINC_START + carry=0; + k%d: +ENDM +; +; KIDL macro +; +MACRO KIDL + n--; + if (n==0) goto k%d; + a+=%d; + b+=%d; + goto k%d; + k%d: +ENDM +; +; KINC_END macro +; +MACRO KINC_END +ENDM +; +; KDEC_START macro. Zero carry +; +MACRO KDEC_START + carry=0; + k%d: +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END +ENDM + diff --git a/miracl/source/kangaroo.c b/miracl/source/kangaroo.c new file mode 100644 index 0000000..a131cce --- /dev/null +++ b/miracl/source/kangaroo.c @@ -0,0 +1,90 @@ +/* + * Test program to find discrete logarithms using Pollard's lambda method + * for catching kangaroos. This algorithm appears to be the best + * available for breaking the Diffie-Hellman key exchange algorithm and + * its variants + * + * See "Monte Carlo Methods for Index Computation" + * by J.M. Pollard in Math. Comp. Vol. 32 1978 pp 918-924 + */ + +#include +#include +#include "miracl.h" + +#define LIMIT 100000000L +#define LEAPS 10000 /* = square root of LIMIT */ +#define ALPHA 16 /* primitive root */ + +static char *modulus= +"295NZNjq8kIndq5Df0NDrA3qk4wxKpbXX4G5bC11A2lRKxcbnap2XDgE4X286glvmxDN66uSaeTjRMrelTY5WfLn"; + +int main() +{ /* Pollard's lambda algorithm for finding discrete logs * + * which are known to be less than a certain limit LIMIT */ + big x,n,t,trap,table[32]; + int i,j,m; + long dm,dn,s,distance[32]; + miracl *mip=mirsys(50,0); + x=mirvar(0); + n=mirvar(0); + t=mirvar(0); + trap=mirvar(0); + for (s=1L,m=1;;m++) + { /* find table size */ + distance[m-1]=s; + s*=2; + if ((2*s/m)>(LEAPS/4)) break; + } + mip->IOBASE=60; /* get large modulus */ + cinstr(n,modulus); + mip->IOBASE=10; + printf("solve discrete logarithm problem - using Pollard's kangaroos\n"); + printf("finds x in y=%d^x mod n, given y, for fixed n and small x\n",ALPHA); + printf("known to be less than %ld\n",LIMIT); + printf("n= "); + cotnum(n,stdout); + for (i=0;i +#include "big.h" /* include MIRACL system */ + +using namespace std; + +Miracl precision=50; + +#define LIMIT 100000000L +#define LEAPS 10000 /* = square root of LIMIT */ +#define ALPHA 16 /* primitive root */ + +static char *Modulus=(char *) +"295NZNjq8kIndq5Df0NDrA3qk4wxKpbXX4G5bC11A2lRKxcbnap2XDgE4X286glvmxDN66uSaeTjRMrelTY5WfLn"; + +int main() +{ /* Pollard's lambda algorithm for finding discrete logs * + * which are known to be less than a certain limit LIMIT */ + Big x,n,trap,table[32]; + int i,j,m; + long dm,dn,s,distance[32]; + miracl *mip=&precision; + for (s=1L,m=1;;m++) + { /* find table size */ + distance[m-1]=s; + s*=2; + if ((2*s/m)>(LEAPS/4)) break; + } + mip->IOBASE=60; /* get large Modulus */ + n=Modulus; + mip->IOBASE=10; + cout << "solve discrete logarithm problem - using Pollard's kangaroos\n"; + cout << "finds x in y=" << ALPHA << "^x mod n, given y, for fixed n and small x\n"; + cout << "known to be less than " << LIMIT << "\n"; + cout << "n= " << n << endl; + for (i=0;i +#include +#include "miracl.h" + +#define LIMIT1 10000 /* must be int, and > MULT/2 */ +#define LIMIT2 1000000L /* may be long */ +#define MULT 2310 /* must be int, product of small primes 2.3... */ +#define NEXT 13 /* next small prime */ +#define NCURVES 200 /* no. of curves to try */ + +miracl *mip; +static big ak,t,w,s1,d1,s2,d2; +static BOOL plus[1+MULT/2],minus[1+MULT/2]; + +void marks(long start) +{ /* mark non-primes in this interval. Note * + * that those < NEXT are dealt with already */ + int i,pr,j,k; + for (j=1;j<=MULT/2;j+=2) plus[j]=minus[j]=TRUE; + for (i=0;;i++) + { /* mark in both directions */ + pr=mip->PRIMES[i]; + if (prstart) break; + k=pr-start%pr; + for (j=k;j<=MULT/2;j+=pr) + plus[j]=FALSE; + k=start%pr; + for (j=k;j<=MULT/2;j+=pr) + minus[j]=FALSE; + } +} + +void duplication(big sum,big diff,big x,big z) +{ /* double a point on the curve P(x,z)=2.P(x1,z1) */ + nres_modmult(sum,sum,t); + nres_modmult(diff,diff,z); + nres_modmult(t,z,x); /* x = sum^2.diff^2 */ + nres_modsub(t,z,t); /* t = sum^2-diff^2 */ + nres_modmult(ak,t,w); + nres_modadd(z,w,z); /* z = ak*t +diff^2 */ + nres_modmult(z,t,z); /* z = z.t */ +} + +void addition(big xd,big zd,big sm1,big df1,big sm2,big df2,big x,big z) +{ /* add two points on the curve P(x,z)=P(x1,z1)+P(x2,z2) * + * given their difference P(xd,zd) */ + nres_modmult(df2,sm1,x); + nres_modmult(df1,sm2,z); + nres_modadd(z,x,t); + nres_modsub(z,x,z); + nres_modmult(t,t,x); + nres_modmult(x,zd,x); /* x = zd.[df1.sm2+sm1.df2]^2 */ + nres_modmult(z,z,z); + nres_modmult(z,xd,z); /* z = xd.[df1.sm2-sm1.df2]^2 */ +} + +void ellipse(big x,big z,int r,big x1,big z1,big x2,big z2) +{ /* calculate point r.P(x,z) on curve */ + int k,rr; + k=1; + rr=r; + copy(x,x1); + copy(z,z1); + nres_modadd(x1,z1,s1); + nres_modsub(x1,z1,d1); + duplication(s1,d1,x2,z2); /* generate 2.P */ + while ((rr/=2)>1) k*=2; + while (k>0) + { /* use binary method */ + nres_modadd(x1,z1,s1); /* form sums and differences */ + nres_modsub(x1,z1,d1); /* x+z and x-z for P1 and P2 */ + nres_modadd(x2,z2,s2); + nres_modsub(x2,z2,d2); + if ((r&k)==0) + { /* double P(x1,z1) mP to 2mP */ + addition(x,z,s1,d1,s2,d2,x2,z2); + duplication(s1,d1,x1,z1); + } + else + { /* double P(x2,z2) (m+1)P to (2m+2)P */ + addition(x,z,s1,d1,s2,d2,x1,z1); + duplication(s2,d2,x2,z2); + } + k/=2; + } +} + +int main() +{ /* factoring program using Lenstras Elliptic Curve method */ + int phase,m,k,nc,iv,pos,btch,u,v; + long i,p,pa,interval; + big q,x,z,a,x1,z1,x2,z2,xt,zt,n,fvw; + static big fu[1+MULT/2]; + static BOOL cp[1+MULT/2]; + mip=mirsys(30,0); + q=mirvar(0); + x=mirvar(0); + z=mirvar(0); + a=mirvar(0); + x1=mirvar(0); + z1=mirvar(0); + x2=mirvar(0); + z2=mirvar(0); + n=mirvar(0); + t=mirvar(0); + s1=mirvar(0); + d1=mirvar(0); + s2=mirvar(0); + d2=mirvar(0); + ak=mirvar(0); + xt=mirvar(0); + zt=mirvar(0); + fvw=mirvar(0); + w=mirvar(0); + gprime(LIMIT1); + for (m=1;m<=MULT/2;m+=2) + if (igcd(MULT,m)==1) + { + fu[m]=mirvar(0); + cp[m]=TRUE; + } + else cp[m]=FALSE; + printf("input number to be factored\n"); + cinnum(n,stdin); + + if (isprime(n)) + { + printf("this number is prime!\n"); + return 0; + } + prepare_monty(n); + + for (nc=1,k=6;k<100;k++) + { /* try a new curve */ + /* generating an elliptic curve */ + u=k*k-5; + v=4*k; + convert(u,x); nres(x,x); + convert(v,z); nres(z,z); + nres_modsub(z,x,a); /* a=v-u */ + + copy(x,t); + nres_modmult(x,x,x); + nres_modmult(x,t,x); /* x=u^3 */ + + copy(z,t); + nres_modmult(z,z,z); + nres_modmult(z,t,z); /* z=v^3 */ + + copy(a,t); + nres_modmult(t,t,t); + nres_modmult(t,a,t); /* t=(v-u)^3 */ + + convert(3*u,a); nres(a,a); + convert(v,ak); nres(ak,ak); + nres_modadd(a,ak,a); + nres_modmult(t,a,t); /* t=(v-u)^3.(3u+v) */ + + convert(u,a); nres(a,a); + copy(a,ak); + nres_modmult(a,a,a); + nres_modmult(a,ak,a); /* a=u^3 */ + convert(v,ak); nres(ak,ak); + nres_modmult(a,ak,a); /* a=u^3.v */ + nres_premult(a,16,a); + nres_moddiv(t,a,ak); /* ak=(v-u)^3.(3u+v)/16u^3v */ + + nc++; + + phase=1; + p=0; + i=0; + btch=50; + printf("phase 1 - trying all primes less than %d\n",LIMIT1); + printf("prime= %8ld",p); + forever + { /* main loop */ + if (phase==1) + { + p=mip->PRIMES[i]; + if (mip->PRIMES[i+1]==0) + { /* now change gear */ + phase=2; + printf("\nphase 2 - trying last prime less than %ld\n", + LIMIT2); + printf("prime= %8ld",p); + copy(x,xt); + copy(z,zt); + nres_modadd(x,z,s2); + nres_modsub(x,z,d2); /* P = (s2,d2) */ + duplication(s2,d2,x,z); + nres_modadd(x,z,s1); + nres_modsub(x,z,d1); /* 2.P = (s1,d1) */ + + nres_moddiv(x1,z1,fu[1]); /* fu[1] = x1/z1 */ + + addition(x1,z1,s1,d1,s2,d2,x2,z2); /* 3.P = (x2,z2) */ + for (m=5;m<=MULT/2;m+=2) + { /* calculate m.P = (x,z) and store fu[m] = x/z */ + nres_modadd(x2,z2,s2); + nres_modsub(x2,z2,d2); + addition(x1,z1,s2,d2,s1,d1,x,z); + copy(x2,x1); + copy(z2,z1); + copy(x,x2); + copy(z,z2); + if (!cp[m]) continue; + copy(z2,fu[m]); + nres_moddiv(x2,fu[m],fu[m]); + } + ellipse(xt,zt,MULT,x,z,x2,z2); + nres_modadd(x,z,xt); + nres_modsub(x,z,zt); /* MULT.P = (xt,zt) */ + iv=(int)(p/MULT); + if (p%MULT>MULT/2) iv++; + interval=(long)iv*MULT; + p=interval+1; + ellipse(x,z,iv,x1,z1,x2,z2); /* (x1,z1) = iv.MULT.P */ + nres_moddiv(x1,z1,fvw); /* fvw = x1/z1 */ + nres_modsub(fvw,fu[p%MULT],q); + marks(interval); + btch*=100; + i++; + continue; + } + pa=p; + while ((LIMIT1/p) > pa) pa*=p; + ellipse(x,z,(int)pa,x1,z1,x2,z2); + copy(x1,x); + copy(z1,z); + copy(z,q); + } + else + { /* phase 2 - looking for last large prime factor of (p+1+d) */ + p+=2; + pos=(int)(p%MULT); + if (pos>MULT/2) + { /* increment giant step */ + iv++; + interval=(long)iv*MULT; + p=interval+1; + marks(interval); + pos=1; + nres_moddiv(x2,z2,fvw); + nres_modadd(x2,z2,s2); + nres_modsub(x2,z2,d2); + addition(x1,z1,s2,d2,xt,zt,x,z); + copy(x2,x1); + copy(z2,z1); + copy(x,x2); + copy(z,z2); + } + if (!cp[pos]) continue; + + /* if neither interval +/- pos is prime, don't bother */ + if (!plus[pos] && !minus[pos]) continue; + nres_modsub(fvw,fu[pos],t); + nres_modmult(q,t,q); + } + if (i++%btch==0) + { /* try for a solution */ + printf("\b\b\b\b\b\b\b\b%8ld",p); + fflush(stdout); + egcd(q,n,t); + if (size(t)==1) + { + if (p>LIMIT2) break; + else continue; + } + if (mr_compare(t,n)==0) + { + printf("\ndegenerate case"); + break; + } + printf("\nfactors are\n"); + if (isprime(t)) printf("prime factor "); + else printf("composite factor "); + cotnum(t,stdout); + divide(n,t,n); + if (isprime(n)) printf("prime factor "); + else printf("composite factor "); + cotnum(n,stdout); + return 0; + } + } + if (nc>NCURVES) break; + printf("\ntrying a different curve %d\n",nc); + } + printf("\nfailed to factor\n"); + return 0; +} + diff --git a/miracl/source/lenstra.cpp b/miracl/source/lenstra.cpp new file mode 100644 index 0000000..1c5e981 --- /dev/null +++ b/miracl/source/lenstra.cpp @@ -0,0 +1,248 @@ +/* + * Program to factor big numbers using Lenstras elliptic curve method. + * Works when for some prime divisor p of n, p+1+d has only + * small factors, where d depends on the particular curve used. + * See "Speeding the Pollard and Elliptic Curve Methods" + * by Peter Montgomery, Math. Comp. Vol. 48 Jan. 1987 pp243-264 + * + * Requires: big.cpp zzn.cpp + * + */ + +#include +#include +#include "zzn.h" + +using namespace std; + +#define LIMIT1 10000 /* must be int, and > MULT/2 */ +#define LIMIT2 1000000L /* may be long */ +#define MULT 2310 /* must be int, product of small primes 2.3... */ +#define NEXT 13 /* next small prime */ +#define NCURVES 20 /* number of curves to try */ + +Miracl precision=50; /* number of ints per ZZn */ + +miracl *mip; +static long p; +static int iv; +static ZZn ak,q,x,z,x1,z1,x2,z2,xt,zt,fvw,fu[1+MULT/2]; +static BOOL cp[1+MULT/2],Plus[1+MULT/2],Minus[1+MULT/2]; + +void marks(long start) +{ /* mark non-primes in this interval. Note * + * that those < NEXT are dealt with already */ + int i,pr,j,k; + for (j=1;j<=MULT/2;j+=2) Plus[j]=Minus[j]=TRUE; + for (i=0;;i++) + { /* mark in both directions */ + pr=mip->PRIMES[i]; + if (prstart) break; + k=pr-start%pr; + for (j=k;j<=MULT/2;j+=pr) + Plus[j]=FALSE; + k=start%pr; + for (j=k;j<=MULT/2;j+=pr) + Minus[j]=FALSE; + } +} + +void duplication(ZZn sum,ZZn diff,ZZn& x,ZZn& z) +{ /* double a point on the curve P(x,z)=2.P(x1,z1) */ + ZZn t; + t=sum*sum; + z=diff*diff; + x=z*t; /* x = sum^2.diff^2 */ + t-=z; /* t = sum^2-diff^2 */ + z+=ak*t; /* z = ak*t +diff^2 */ + z*=t; +} + +void addition(ZZn xd,ZZn zd,ZZn sm1,ZZn df1,ZZn sm2,ZZn df2,ZZn& x,ZZn& z) +{ /* add two points on the curve P(x,z)=P(x1,z1)+P(x2,z2) * + * given their difference P(xd,zd) */ + ZZn t; + x=df2*sm1; + z=df1*sm2; + t=z+x; + z-=x; + x=t*t; + x*=zd; /* x = zd.[df1.sm2+sm1.df2]^2 */ + z*=z; + z*=xd; /* z = xd.[df1.sm2-sm1.df2]^2 */ + +} + +void ellipse(ZZn x,ZZn z,int r,ZZn& x1,ZZn& z1,ZZn& x2,ZZn& z2) +{ /* calculate point r.P(x,z) on curve */ + int k,rr; + k=1; + rr=r; + x1=x; + z1=z; + duplication(x1+z1,x1-z1,x2,z2); /* generate 2.P */ + while ((rr/=2)>1) k*=2; + while (k>0) + { /* use binary method */ + if ((r&k)==0) + { /* double P(x1,z1) mP to 2mP */ + addition(x,z,x1+z1,x1-z1,x2+z2,x2-z2,x2,z2); + duplication(x1+z1,x1-z1,x1,z1); + } + else + { /* double P(x2,z2) (m+1)P to (2m+2)P */ + addition(x,z,x1+z1,x1-z1,x2+z2,x2-z2,x1,z1); + duplication(x2+z2,x2-z2,x2,z2); + } + k/=2; + } +} + +void next_phase() +{ /* now change gear */ + ZZn s1,d1,s2,d2; + long interval; + xt=x; + zt=z; + s2=x+z; + d2=x-z; /* P = (s2,d2) */ + duplication(s2,d2,x,z); + s1=x+z; + d1=x-z; /* 2.P = (s1,d1) */ + fu[1]=x1/z1; + addition(x1,z1,s1,d1,s2,d2,x2,z2); /* 3.P = (x2,z2) */ + for (int m=5;m<=MULT/2;m+=2) + { /* calculate m.P = (x,z) and store fu[m] = x/z */ + addition(x1,z1,x2+z2,x2-z2,s1,d1,x,z); + x1=x2; + z1=z2; + x2=x; + z2=z; + if (!cp[m]) continue; + fu[m]=x2/z2; + } + ellipse(xt,zt,MULT,x,z,x2,z2); + xt=x+z; + zt=x-z; /* MULT.P = (xt,zt) */ + iv=p/MULT; + if (p%MULT>MULT/2) iv++; + interval=(long)iv*MULT; + p=interval+1; + ellipse(x,z,iv,x1,z1,x2,z2); /* (x1,z1) = iv.MULT.P */ + fvw=x1/z1; + marks(interval); + q=fvw-fu[p%MULT]; +} + +int giant_step() +{ /* increment giant step */ + long interval; + iv++; + interval=(long)iv*MULT; + p=interval+1; + marks(interval); + fvw=x2/z2; + addition(x1,z1,x2+z2,x2-z2,xt,zt,x,z); + x1=x2; + z1=z2; + x2=x; + z2=z; + return 1; +} + +int main() +{ /* factoring program using Lenstras Elliptic Curve method */ + int phase,m,k,nc,pos,btch; + long i,pa; + Big n,t; + ZZn tt,u,v; + mip=&precision; + gprime(LIMIT1); + for (m=1;m<=MULT/2;m+=2) + if (igcd(MULT,m)==1) cp[m]=TRUE; + else cp[m]=FALSE; + cout << "input number to be factored\n"; + cin >> n; + if (prime(n)) + { + cout << "this number is prime!\n"; + return 0; + } + modulo(n); /* do all arithmetic mod n */ + for (nc=1,k=6;k<100;k++) + { /* try a new curve */ + u=k*k-5; + v=4*k; + x=u*u*u; + z=v*v*v; + + ak=((v-u)*(v-u)*(v-u)*(3*u+v))/(16*u*u*u*v); + + phase=1; + p=0; + i=0; + btch=50; + cout << "phase 1 - trying all primes less than " << LIMIT1; + cout << "\nprime= " << setw(8) << p; + forever + { /* main loop */ + if (phase==1) + { + p=mip->PRIMES[i]; + if (mip->PRIMES[i+1]==0) + { /* now change gear */ + phase=2; + cout << "\nphase 2 - trying last prime less than "; + cout << LIMIT2 << "\nprime= " << setw(8) << p; + next_phase(); + btch*=100; + i++; + continue; + } + pa=p; + while ((LIMIT1/p) > pa) pa*=p; + ellipse(x,z,(int)pa,x1,z1,x2,z2); + x=x1; + q=z=z1; + } + else + { /* looking for last large prime factor of (p+1+d) */ + p+=2; + pos=p%MULT; + if (pos>MULT/2) pos=giant_step(); + if (!cp[pos]) continue; + /* if neither interval +/- pos is prime, don't bother */ + if (!Plus[pos] && !Minus[pos]) continue; + q*=(fvw-fu[pos]); /* batch gcds */ + } + if (i++%btch==0) + { /* try for a solution */ + cout << "\b\b\b\b\b\b\b\b" << setw(8) << p << flush; + t=gcd(q,n); + if (t==1) + { + if (p>LIMIT2) break; + else continue; + } + if (t==n) + { + cout << "\ndegenerate case"; + break; + } + if (prime(t)) cout << "\nprime factor " << t; + else cout << "\ncomposite factor " << t; + n/=t; + if (prime(n)) cout << "\nprime factor " << n; + else cout << "\ncomposite factor " << n; + cout << endl; + return 0; + } + } + if (nc>NCURVES) break; + cout << "\ntrying a different curve " << nc << "\n"; + } + cout << "\nfailed to factor\n"; + return 0; +} + diff --git a/miracl/source/limlee.c b/miracl/source/limlee.c new file mode 100644 index 0000000..2a8ae40 --- /dev/null +++ b/miracl/source/limlee.c @@ -0,0 +1,194 @@ +/* + * Lim-Lee prime generation + * + * See "A Key recovery Attack on Discrete Log-based Schemes using a Prime + * Order Subgroup", Lim & Lee, Crypto '97 + * + * For certain Discrete Log based protocols these primes are preferable + * to those generated for example by the utilty dssetup.c + * This program can be used in place of dssetup.c + * + * When run the program generates a prime p PBITS in length, where + * p-1=2*pa*pb*pc....*q, where q is a prime QBITS in length, and pa,pb,pc + * etc are all primes > QBITS in length. Also generated is g, a generator + * of the prime-order sub-group, of order q. + * + * Finally p, q and g are output to the file common.dss + * + * It may be quicker, and is quite valid, to make OBITS > QBITS. + * This allows the pool size to be decreased. + * + */ + +#include +#include "miracl.h" + +#define PBITS 1024 +#define QBITS 160 +#define OBITS 160 /* minimum size of primes pa,pb,pc etc >=QBITS */ +#define POOL_SIZE 20 /* greater than PBITS/OBITS, < number of bits in long */ + +static int num1bits(long x) +{ /* returns number of '1' bits in x */ + int n=0; + while (x!=0L) + { + if (x&1L) n++; + x>>=1; + } + return n; +} + +static long increment(long permutation) +{ /* move onto next permutation with same number of '1' bits */ + int n=num1bits(permutation); + do + { + permutation++; + } while (num1bits(permutation)!=n); + return permutation; +} + +int main() +{ + FILE *fp; + big q,p,p1,h,t,g,low,high; + big pool[POOL_SIZE]; + BOOL fail; + int i,j,p1bits,np; + long seed,m,permutation; + miracl *mip=mirsys(100,0); + q=mirvar(0); + p=mirvar(0); + h=mirvar(0); + t=mirvar(0); + g=mirvar(0); + p1=mirvar(0); + low=mirvar(0); + high=mirvar(0); + gprime(10000); + +/* randomise */ + printf("Enter 9 digit random number seed = "); + scanf("%ld",&seed); + getchar(); + irand(seed); + + p1bits=PBITS-QBITS-1; + +/* find number of primes pa, pb, pc etc., that will be needed */ + + np=1; + while (p1bits/np >= OBITS) np++; + np--; + +/* find the high/low limits for these primes, so that + the generated prime p will be exactly PBITS in length */ + + expb2(p1bits-1,t); + nroot(t,np,low); /* np-th integer root */ + incr(low,1,low); + + premult(t,2,t); + decr(t,1,t); + nroot(t,np,high); + + subtract(high,low,t); /* raise low limit up to half-way... */ + subdiv(t,2,t); + subtract(high,t,low); + +/* generate q */ + forever + { /* make sure leading two bits of q 11... */ + expb2(QBITS,q); + bigbits(QBITS-2,t); + subtract(q,t,q); + nxprime(q,q); + if (logb2(q)>QBITS) continue; + break; + } + printf("q= (%d bits)\n",logb2(q)); + cotnum(q,stdout); + +/* generate prime pool from which permutations of np + primes will be picked until a Lim-Lee prime is found */ + + for (i=0;i0) continue; + copy(p1,pool[i]); + break; + } + } + +/* The '1' bits in the permutation indicate which primes are + picked from the pool. If np=5, start at 11111, then 101111 etc */ + + permutation=1L; + for (i=0;i=POOL_SIZE) + { /* ran out of primes... */ + fail=TRUE; + break; + } + if (m&permutation) + { + multiply(p1,pool[i],p1); + j++; + } + } + if (fail) break; + printf("."); + premult(q,2,p); + multiply(p,p1,p); + incr(p,1,p); + permutation=increment(permutation); + if (logb2(p)!=PBITS) continue; + if (isprime(p)) break; + } + + if (fail) + { + printf("\nFailed - very unlikely! - try increasing POOL_SIZE\n"); + return 0; + } + + printf("\np= (%d bits)\n",logb2(p)); + cotnum(p,stdout); + +/* finally find g */ + do { + decr(p,1,t); + bigrand(t,h); + divide(t,q,t); + powmod(h,t,p,g); + } while(size(g)==1); + + printf("g= (%d bits)\n",logb2(g)); + cotnum(g,stdout); + + fp=fopen("common.dss","wt"); + fprintf(fp,"%d\n",PBITS); + mip->IOBASE=16; + cotnum(p,fp); + cotnum(q,fp); + cotnum(g,fp); + fclose(fp); + return 0; +} + diff --git a/miracl/source/limlee.cpp b/miracl/source/limlee.cpp new file mode 100644 index 0000000..d9d7016 --- /dev/null +++ b/miracl/source/limlee.cpp @@ -0,0 +1,181 @@ +/* + * Lim-Lee prime generation + * + * See "A Key recovery Attack on Discrete Log-based Schemes using a Prime + * Order Subgroup", Lim & Lee, Crypto '97 + * + * For certain Discrete Log based protocols these primes are preferable + * to those generated for example by the utilty dssetup.c + * This program can be used in place of dssetup.cpp + * + * When run the program generates a prime p PBITS in length, where + * p-1=2*pa*pb*pc....*q, where q is a prime QBITS in length, and pa,pb,pc + * etc are all primes > QBITS in length. Also generated is g, a generator + * of the prime-order sub-group, of order q. + * + * Finally p, q and g are output to the file common.dss + * + * It may be quicker, and is quite valid, to make OBITS > QBITS. + * This allows the pool size to be decreased. + * + * Requires: big.cpp + * + */ + +#include +#include +#include +#include "big.h" + +using namespace std; + +#define PBITS 1024 +#define QBITS 160 +#define OBITS 160 /* Size of pa, pb, pc etc., >=QBITS */ +#define POOL_SIZE 20 /* greater than PBITS/OBITS */ + +Miracl precision=100; + +static int num1bits(long x) +{ /* returns number of '1' bits in x */ + int n=0; + while (x!=0) + { + if (x&1L) n++; + x>>=1; + } + return n; +} + +static long increment(long permutation) +{ /* move onto next permutation with same number of '1' bits */ + int n=num1bits(permutation); + do + { + permutation++; + } while (num1bits(permutation)!=n); + return permutation; +} + +int main() +{ + ofstream common("common.dss"); + Big q,p,p1,x,h,t,g,low,high; + Big pool[POOL_SIZE]; + BOOL fail; + int i,j,p1bits,np; + long seed,m,permutation; + miracl *mip=&precision; + +/* randomise */ + cout << "Enter 9 digit random number seed = "; + cin >> seed; + irand(seed); + + p1bits=PBITS-QBITS-1; + +/* find number of primes pa, pb, pc etc., that will be needed */ + + np=1; + while (p1bits/np >= OBITS) np++; + np--; + +/* find the high/low limits for these primes, so that + the generated prime p will be exactly PBITS in length */ + + t=pow((Big)2,p1bits-1); + low=root(t,np)+1; /* np-th integer root */ + + t=2*t-1; + high=root(t,np); + + low=high-(high-low)/2; /* raise low limit to half-way... */ + +/* generate q */ + forever + { /* make sure leading two bits of q 11... */ + q=pow((Big)2,QBITS)-rand(QBITS-2,2); + while (!prime(q)) q+=1; + if (bits(q)>QBITS) continue; + break; + } + cout << "q= (" << bits(q) << " bits)" << endl; + cout << q << endl; + +/* generate prime pool from which permutations of np + primes will be picked until a Lim-Lee prime is found */ + + for (i=0;ihigh) continue; + pool[i]=p1; + break; + } + } + +/* The '1' bits in the permutation indicate which primes are + picked from the pool. If np=5, start at 11111, then 101111 etc */ + + permutation=1L; + for (i=0;i=POOL_SIZE) + { /* ran out of primes... */ + fail=TRUE; + break; + } + if (m&permutation) + { + p1*=pool[i]; + j++; + } + } + if (fail) break; + cout << "." << flush; + p=2*q*p1+1; + permutation=increment(permutation); + if (bits(p)!=PBITS) continue; + if (prime(p)) break; + } + + if (fail) + { + printf("\nFailed - very unlikely! - try increasing POOL_SIZE\n"); + return 0; + } + + cout << "\np= (" << bits(p) << " bits)\n"; + cout << p << endl; + +/* finally find g */ + + do { + h=rand(p-1); + g=pow(h,(p-1)/q,p); + } while (g==1); + + cout << "g= (" << bits(g) << " bits)\n"; + cout << g << endl; + + common << PBITS << endl; + mip->IOBASE=16; + common << p << endl; + common << q << endl; + common << g << endl; + + return 0; +} + diff --git a/miracl/source/mersenne.c b/miracl/source/mersenne.c new file mode 100644 index 0000000..2d419d7 --- /dev/null +++ b/miracl/source/mersenne.c @@ -0,0 +1,75 @@ +/* + * Program to calculate mersenne primes + * using Lucas-Lehmer test - Knuth p.391 + * + * Try this only in a 32-bit (or better!) environment + * + */ + +#include +#include "miracl.h" +#define LIMIT 100000 + +int main() +{ /* calculate mersenne primes */ + BOOL compo; + big L,m,T; + int i,k,q,p,r; + miracl *mip=mirsys(5000,0); + L=mirvar(0); + m=mirvar(0); + T=mirvar(0); + gprime(LIMIT); + for (k=1;;k++) + { /* test only prime exponents */ + q=mip->PRIMES[k]; + if (q==0) break; + expb2(q,m); + decr(m,1,m); /* m=2^q-1 */ + +/* try to find a factor. Should perhaps keep trying over a bigger range... */ + + compo=FALSE; + for(i=2;i<16*q;i+=2) + { /* prime factors (if they exist) are always * + * of the form i*q+1, and 1 or 7 mod 8 */ + p=i*q+1; + if ((p-1)%q!=0) break; /* check for overflow */ + if (p%8!=1 && p%8!=7) continue; + if (spmd(3,p-1,p)!=1) continue; /* check for prime p */ + + r=subdiv(m,p,T); + if (r==0) + { + if (size(T)!=1) compo=TRUE; + break; + } + } + if (compo) + { + printf("2^%d-1 is NOT prime ; factor = %7d\n",q,p); + continue; + } + + convert(4,L); + for(i=1;i<=q-2;i++) + { /* Lucas-Lehmer test */ + fft_mult(L,L,L); + decr(L,2,L); + + sftbit(L,-q,T); + add(L,T,L); + sftbit(T,q,T); + subtract(L,T,L); + if (mr_compare(L,m)>=0) subtract(L,m,L); + } + if (size(L)==0) + { /* mersenne prime found! */ + printf("2^%d-1 is prime = \n",q); + cotnum(m,stdout); + } + else printf("2^%d-1 is NOT prime\n",q); + } + return 0; +} + diff --git a/miracl/source/mersenne.cpp b/miracl/source/mersenne.cpp new file mode 100644 index 0000000..005de83 --- /dev/null +++ b/miracl/source/mersenne.cpp @@ -0,0 +1,73 @@ +/* + * Program to calculate mersenne primes + * using Lucas-Lehmer test - Knuth p.391 + * + * Try this only in a 32-bit (or better) environment + * + * Requires: big.cpp + * + */ + +#include +#include "big.h" + +using namespace std; + +#define LIMIT 100000 + +Miracl precision=1000; + +int main() +{ /* calculate mersenne primes */ + BOOL compo; + Big L,m,T; + int i,k,q,r,p; + miracl *mip=&precision; + gprime(LIMIT); + for (k=1;;k++) + { /* test only prime exponents */ + q=mip->PRIMES[k]; + if (q==0) break; + m=pow((Big)2,q)-1; + +/* try to find a factor. Should perhaps keep trying over a bigger range... */ + + compo=FALSE; + for (i=2;i<16*q;i+=2) + { /* prime factors (if they exist) are always * + * of the form i*q+1, and 1 or 7 mod 8 */ + p=i*q+1; + if ((p-1)%q!=0) break; /* check for overflow */ + if (p%8!=1 && p%8!=7) continue; + if (spmd(3,p-1,p)!=1) continue; + r=m%p; + if (r==0) + { + if (m!=p) compo=TRUE; + break; + } + } + if (compo) + { + cout << "2^" << q << "-1 is NOT prime ; factor = " << p << endl; + continue; + } + + L=4; + for(i=1;i<=q-2;i++) + { /* Lucas-Lehmer test */ + L=L*L-2; + T=(L>>q); /* find remainder mod m */ + L=L-(T<=m) L-=m; + } + if (L==0) + { /* mersenne prime found! */ + cout << "2^" << q << "-1 is prime" << endl; + cout << m << endl; + } + else cout << "2^" << q << "-1 is NOT prime" << endl; + } + return 0; +} + diff --git a/miracl/source/mips.mcs b/miracl/source/mips.mcs new file mode 100644 index 0000000..4ee709a --- /dev/null +++ b/miracl/source/mips.mcs @@ -0,0 +1,473 @@ +; +; Mips Macros file for GCC compiler +; +; Triple register is $10|HI|LO +; MUL_START. Initialise registers. Make $5 and $6 point to multipliers a +; and b. $7 points at result c. +; Initialise Triple register to 0 +; See makemcs.txt for more information about this file +; +; + +MACRO PMUL_START + ASM ( + "ADDU $5,$0,%%0\n" + "ADDU $6,$0,%%1\n" + "ADDU $7,$0,%%2\n" + "ADDU $4,$0,%%3\n" + "MTLO $0\n" + "MTHI $0\n" +ENDM + +MACRO PMUL + "LW $3,4*%d($5)\n" + "MADDU $3,$4\n" + "SW $0,4*%d($6)\n" + "MFLO $3\n" + "SW $3,4*%d($7)\n" + "MFHI $1\n" + "MTLO $1\n" + "MTHI $0\n" +ENDM + +MACRO PMUL_END + "MFLO $3\n" + "MULTU $3,$4\n" + "MFLO $3\n" + "SW $3,0($6)\n" + "MFHI $3\n" + "SW $3,4($6)\n" + : + :"r"(a),"r"(b),"r"(c),"r"(sn) + :"$1","$3","$4","$5","$6","$7","$8","$9","$10","memory" + ); +ENDM + + +MACRO MUL_START + ASM ( + "ADDU $5,$0,%%0\n" + "ADDU $6,$0,%%1\n" + "ADDU $7,$0,%%2\n" + "MTLO $0\n" + "MTHI $0\n" + "ADDU $10,$0,$0\n" +ENDM +; +; STEP macro. Calculates a double-register partial product +; and adds it to the triple register total +; Parameters 1 & 2: Indices i and j for partial product multipliers a[i] +; and b[j] + +MACRO STEP + "LW $2,4*%d($5)\n" + "LW $3,4*%d($6)\n" + "MFHI $9\n" + "MADDU $2,$3\n" + "MFHI $8\n" + "SLTU $1,$8,$9\n" + "ADDU $10,$1,$10\n" +ENDM + +; +; MFIN macro. Finish column calculation. Store Sum for this column +; and get Carry for next +; Parameter 1: Index k for Column Sum c[k] +MACRO MFIN + "MFLO $2\n" + "MFHI $1\n" + "MTLO $1\n" + "MTHI $10\n" + "ADDU $10,$0,$0\n" + "SW $2,4*%d($7)\n" +ENDM +; +; LAST +; +MACRO LAST + "LW $2,4*%d($5)\n" + "LW $3,4*%d($6)\n" + "MADDU $2,$3\n" +ENDM +; +; MUL_END +; Parameter 1: Index for final carry c[.] +MACRO MUL_END + "MFLO $2\n" + "SW $2,4*%d($7)\n" + : + :"r"(a),"r"(b),"r"(c) + :"$1","$2","$3","$4","$5","$6","$7","$8","$9","$10","memory" + ); +ENDM + +; +; SQR_START +; +MACRO SQR_START + ASM ( + "ADDU $5,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "MTLO $0\n" + "MTHI $0\n" + "ADDU $10,$0,$0\n" +ENDM +; +; DSTEP macro. Calculates a double-register partial product +; and add it twice to a triple register total +; Parameters 1 & 2 : Indices of partial product multipliers +MACRO DSTEP + "LW $2,4*%d($5)\n" + "LW $3,4*%d($5)\n" + "MFHI $9\n" + "MADDU $2,$3\n" + "MFHI $8\n" + "SLTU $1,$8,$9\n" + "ADDU $10,$1,$10\n" + "MFHI $9\n" + "MADDU $2,$3\n" + "MFHI $8\n" + "SLTU $1,$8,$9\n" + "ADDU $10,$1,$10\n" +ENDM + +; +; SELF macro. Calculate the double-register square and +; add it to a triple register total +; Parameter 1 : Index of diagonal element +MACRO SELF + "LW $2,4*%d($5)\n" + "MFHI $9\n" + "MADDU $2,$2\n" + "MFHI $8\n" + "SLTU $1,$8,$9\n" + "ADDU $10,$1,$10\n" +ENDM +; +; SFIN macro. Finish column calculation for squaring. Store Sum +; and get Carry for next column. +; Parameter 1: Index of Column Sum +MACRO SFIN + "MFLO $2\n" + "MFHI $1\n" + "MTLO $1\n" + "MTHI $10\n" + "ADDU $10,$0,$0\n" + "SW $2,4*%d($7)\n" +ENDM +; +; SQR_END +; Parameter 1: Index for final carry +MACRO SQR_END + "MFLO $2\n" + "SW $2,4*%d($7)\n" + : + :"r"(a),"r"(c) + :"$1","$2","$3","$4","$5","$6","$7","$8","$9","$10","memory" + ); +ENDM +; +; REDC_START macro +; +MACRO REDC_START + ASM ( + "ADDU $5,$0,%%0\n" + "ADDU $6,$0,%%1\n" + "ADDU $7,$0,%%2\n" + "MTHI $0\n" + "ADDU $10,$0,$0\n" + "LW $1,($5)\n" + "MTLO $1\n" +ENDM +; +; RFINU macro - this is terrible! Note that mul instruction is signed, and therefore no good here. +; The HI|LO register must be saved, as it will be overwritten by MULTU +; +MACRO RFINU + "MFHI $8\n" /* extract HI|LO */ + "MFLO $4\n" + "MULTU $4,$7\n" /* sp=LO*ndash */ + "MFLO $3\n" /* $3 = LO */ + "LW $2,($6)\n" /* get b[0] */ + "SW $3,4*%d($5)\n" /* store in a[.] */ + "MTHI $8\n" /* restore HI|LO */ + "MTLO $4\n" + "MFHI $9\n" + "MADDU $2,$3\n" + "MFHI $8\n" + "SLTU $1,$8,$9\n" + "ADDU $10,$1,$10\n" /* += sp*b[0] */ + "MFHI $1\n" /* shift out LO */ + "MTLO $1\n" + "MTHI $10\n" + "ADDU $10,$0,$0\n" + "LW $3,4*(%d+1)($5)\n" + "ADDIU $2,$0,1\n" + "MADDU $3,$2\n" +ENDM +; +; RFIND macro +; +MACRO RFIND + "MFLO $3\n" + "MFHI $1\n" + "MTLO $1\n" + "MTHI $10\n" + "ADDU $10,$0,$0\n" + "SW $3,4*%d($5)\n" + "LW $3,4*(%d+1)($5)\n" + "ADDIU $2,$0,1\n" + "MADDU $2,$3\n" +ENDM +; +; REDC_END +; +MACRO REDC_END + "MFLO $3\n" + "MFHI $2\n" + "SW $3,4*%d($5)\n" + "SW $2,4*(%d+1)($5)\n" + : + :"r"(a),"r"(b),"r"(ndash) + :"$1","$2","$3","$4","$5","$6","$7","$8","$9","$10","memory" + ); +ENDM +; +; ADD_START macro - initialise for add/subtract, do first one +; $4 holds the carry bit +; +MACRO ADD_START + ASM ( + "ADDU $6,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "ADDU $8,$0,%%3\n" + "LW $2,($6)\n" + "LW $3,($7)\n" + "ADDU $5,$3,$2\n" + "SW $5,($8)\n" + "SLTU $4,$5,$3\n" +ENDM +; +; ADD macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO ADD + "LW $3,4*%d($6)\n" + "LW $2,4*%d($7)\n" + "ADDU $5,$3,$2\n" + "SLTU $9,$5,$3\n" + "ADDU $2,$5,$4\n" + "SLTU $4,$2,$5\n" + "OR $4,$9,$4\n" + "SW $2,4*%d($8)\n" +ENDM +; +; ADD_END macro. Catch carry +; +MACRO ADD_END + "ADDU %%2,$0,$4\n" + : + :"r"(a),"r"(b),"r"(carry),"r"(c) + :"$2","$3","$4","$5","$6","$7","$8","9","memory" + ); +ENDM +; +; INC_START macro. Do first one +; +MACRO INC_START + ASM ( + "ADDU $6,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "LW $3,($6)\n" + "LW $2,($7)\n" + "ADDU $5,$2,$3\n" + "SW $5,($6)\n" + "SLTU $4,$5,$3\n" +ENDM +; +; INC macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO INC + "LW $3,4*%d($6)\n" + "LW $2,4*%d($7)\n" + "ADDU $5,$3,$2\n" + "SLTU $8,$5,$3\n" + "ADDU $2,$5,$4\n" + "SLTU $4,$2,$5\n" + "OR $4,$8,$4\n" + "SW $2,4*%d($6)\n" +ENDM +; +; INC_END macro. Catch carry +; +MACRO INC_END + "ADDU %%2,$0,$4\n" + : + :"r"(a),"r"(b),"r"(carry) + :"$2","$3","$4","$5","$6","$7","$8","memory" + ); +ENDM +; +; SUB_START macro +; +MACRO SUB_START + ASM ( + "ADDU $6,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "ADDU $8,$0,%%3\n" + "LW $3,($6)\n" + "LW $2,($7)\n" + "SUBU $5,$3,$2\n" + "SW $5,($8)\n" + "SLTU $4,$3,$5\n" +ENDM +; +; SUB macro. Subtract two numbers in memory and store result in memory. +; +MACRO SUB + "LW $3,4*%d($6)\n" + "LW $2,4*%d($7)\n" + "SUBU $5,$3,$2\n" + "SLTU $9,$3,$5\n" + "SUBU $2,$5,$4\n" + "SLTU $4,$5,$2\n" + "OR $4,$9,$4\n" + "SW $2,4*%d($8)\n" +ENDM +; +; SUB_END macro. Catch carry +; +MACRO SUB_END + "ADDU %%2,$0,$4\n" + : + :"r"(a),"r"(b),"r"(carry),"r"(c) + :"$2","$3","$4","$5","$6","$7","$8","9","memory" + ); +ENDM +; +; DEC_START macro +; +MACRO DEC_START + ASM ( + "ADDU $6,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "LW $3,($6)\n" + "LW $2,($7)\n" + "SUBU $5,$3,$2\n" + "SW $5,($6)\n" + "SLTU $4,$3,$5\n" +ENDM +; +; DEC macro. Subtract two numbers in memory and store result in memory. +; +MACRO DEC + "LW $3,4*%d($6)\n" + "LW $2,4*%d($7)\n" + "SUBU $5,$3,$2\n" + "SLTU $8,$3,$5\n" + "SUBU $2,$5,$4\n" + "SLTU $4,$5,$2\n" + "OR $4,$8,$4\n" + "SW $2,4*%d($6)\n" +ENDM +; +; DEC_END macro. Catch carry +; +MACRO DEC_END + "ADDU %%2,$0,$4\n" + : + :"r"(a),"r"(b),"r"(carry) + :"$2","$3","$4","$5","$6","$7","8","memory" + ); +ENDM +; +; KADD_START macro. Zero Carry flag +; +MACRO KADD_START + ASM ( + "ADDU $6,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "ADDU $8,$0,%%3\n" + "ADDU $9,$0,%%4\n" + "ADDU $4,$0,$0\n" + "k%d:\n" +ENDM +; +; KASL macro. Important that carry flag is undisturbed! +; +MACRO KASL + "SUBIU $9,$9,1\n" + "BLEZ $9,k%d\n" + "NOP\n" + "ADDIU $6,$6,4*%d\n" + "ADDIU $7,$7,4*%d\n" + "J k%d\n" + "ADDIU $8,$8,4*%d\n" + "k%d\n" +ENDM +; +; KADD_END macro +; +MACRO KADD_END + "ADDU %%2,$0,$4\n" + : + :"r"(a),"r"(b),"r"(carry),"r"(c),"r"(n) + :"$2","$3","$4","$5","$6","$7","$8","$9","memory" + ); +ENDM +; +; KINC_START macro. Set carry to Zero +; +MACRO KINC_START + __asm { + "ADDU $6,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "ADDU $9,$0,%%4\n" + "ADDU $4,$0,$0\n" + "k%d:\n" +ENDM +; +; KIDL macro. Important that carry flag is undisturbed! +; +MACRO KIDL + "SUBIU $9,$9,1\n" + "BLEZ $9,k%d\n" + "NOP\n" + "ADDIU $6,$6,4*%d\n" + "J k%d\n" + "ADDIU $7,$7,4*%d\n" + "k%d\n" +ENDM +; +; KINC_END macro +; +MACRO KINC_END + "ADDU %%2,$0,$4\n" + : + :"r"(a),"r"(b),"r"(carry),"r"(n) + :"$2","$3","$4","$5","$6","$7","$8","$9","memory" + ); +ENDM +; +; KDEC_START macro. Set carry +; +MACRO KDEC_START + ASM ( + "ADDU $6,$0,%%0\n" + "ADDU $7,$0,%%1\n" + "ADDU $9,$0,%%4\n" + "ADDU $4,$0,$0\n" + "k%d:\n" +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + "ADDU %%2,$0,$4\n" + : + :"r"(a),"r"(b),"r"(carry),"r"(n) + :"$2","$3","$4","$5","$6","$7","$8","$9","memory" + ); +ENDM + diff --git a/miracl/source/mr87f.c b/miracl/source/mr87f.c new file mode 100644 index 0000000..7c3878e --- /dev/null +++ b/miracl/source/mr87f.c @@ -0,0 +1,388 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * Many processors support a floating-point coprocessor, which may + * implement a faster multiplication instruction than the corresponding + * integer instruction. This is the case for the 80486/Pentium processor + * which has a built-in co-processor. This can be exploited to give even + * faster performance. + * + * As before the fixed modulus size to be used is pre-defined as + * MR_PENTIUM in mirdef.h + * + * Note that since the partial products are accumulated in a 64-bit register + * this implies that a full-width number base (2^32) cannot be used. + * The maximum number base that can be used is 2^x where x is + * calculated such that 2^(64-2*x) > 2*MR_PENTIUM. This means that + * x will usually be 28 or 29 + * + * To use this code:- + * + * (1) Define MR_PENTIUM in mirdef.h to the fixed size of the modulus + * + * (2) Use as a number base the value of x calculated as shown above + * For example, for 512 bit exponentiation, #define MR_PENTIUM 18 + * in mirdef.h and call mirsys(50,536870912L) in your main program. + * (Observe that 536870912 = 2^29, and that 18*29 = 522, big enough + * for 512 bit calculations). + * + * (3) Use Montgomery representation when implementing your crypto-system + * i.e. use monty_powmod(). This will automatically call the + * routines in this module. + * + * Note that this module generates a *lot* of code e.g. > 49kbytes for + * MR_PENTIUM = 36. Compile using -B switch - you will need + * the TASM macro-assembler. If out-of-memory, try using the TASMX /ml + * version of the assembler. + * + * Note that it is *VITAL* that double arrays be aligned on 8-byte + * boundaries for maximum speed on a Pentium. + * + * Many thanks are due to Paul Rubin, who suggested to me that this approach + * might be faster than the all-integer method described elsewhere. + * + * The FP stack is primed in prepare_monty() :- + * magic - (2^63+2^62)*base. By adding and then subtracting this number we + * get the top half of the sum. + * 1/base - Inverse of the number base + * ndash - Montgomery's constant + */ + +#include "miracl.h" + +#ifdef MR_PENTIUM + +#if INLINE_ASM == 1 +#define N 8 +#define POINTER QWORD PTR +#define PBX bx +#define PSI si +#define PDI di +#define PCX cx +#endif + +#if INLINE_ASM == 2 +#define N 8 +#define POINTER QWORD PTR +#define PBX bx +#define PSI si +#define PDI di +#define PCX cx +#endif + +#if INLINE_ASM == 3 +#define N 8 +#define POINTER QWORD PTR +#define PBX ebx +#define PSI esi +#define PDI edi +#define PCX ecx +#endif + +#ifdef INLINE_ASM +#ifndef MR_LMM + /* not implemented for large memory model 16 bit */ + +void fastmodmult(_MIPD_ big x,big y,big z) +{ + int ij; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + big w0=mr_mip->w0; + big modulus=mr_mip->modulus; + mr_small *wg,*mg,*xg,*yg; + wg=w0->w; + mg=modulus->w; + xg=x->w; + yg=y->w; + + for (ij=2*MR_PENTIUM;ij<(int)(w0->len&MR_OBITS);ij++) w0->w[ij]=0.0; + w0->len=2*MR_PENTIUM; + + ASM + { + FSTEP MACRO i,j +/* some fancy Pentium scheduling going on here ... */ + fld POINTER [PBX+N*i] + fmul POINTER [PSI+N*j] + fxch st(2) + fadd + ENDM + + FRSTEP MACRO i,j + fld POINTER [PDI+N*i] + fmul POINTER [PSI+N*j] + fxch st(2) + fadd + ENDM + + FDSTEP MACRO i,j + fld POINTER [PBX+N*i] + fmul POINTER [PBX+N*j] + fxch st(2) + fadd + ENDM + + SELF MACRO k + fld POINTER [PBX+N*k] + fmul st,st(0) + fadd + ENDM + + RFINU MACRO k + fld st(0) + + fadd st,st(2) + fsub st,st(2) + + fsubr st,st(1) + fmul st,st(4) + fld st(0) + + fadd st,st(3) + fsub st,st(3) + + fsub + fst POINTER [PDI+N*k] + fmul POINTER [PSI] + fadd + fmul st,st(2) + ENDM + + RFIND MACRO k + fld st(0) + + fadd st,st(2) + fsub st,st(2) + + fsub st(1),st + fmul st,st(3) + fxch st(1) + fstp POINTER [PDI+N*k] + + ENDM + + DIAG MACRO ns,ne + CNT1=ns + CNT2=ne + fld POINTER [PBX+N*CNT1] + fmul POINTER [PSI+N*CNT2] + CNT1=CNT1+1 + CNT2=CNT2-1 + WHILE CNT1 LE ne + FSTEP CNT1,CNT2 + CNT1=CNT1+1 + CNT2=CNT2-1 + ENDM + fadd + ENDM + + SDIAG MACRO ns,ne + CNT1=ns + CNT2=ne + IF CNT1 LT CNT2 + fstp st(5) /* store carry */ + fldz + fld POINTER [PBX+N*CNT1] + fmul POINTER [PBX+N*CNT2] + CNT1=CNT1+1 + CNT2=CNT2-1 + WHILE CNT1 LT CNT2 + FDSTEP CNT1,CNT2 + CNT1=CNT1+1 + CNT2=CNT2-1 + ENDM + fadd + fld st(0) /* now double it ... */ + fadd + fadd st,st(5) /* add in carry */ + ENDIF + ENDM + + RDIAGU MACRO ns,ne + CNT1=ns + CNT2=ne + IF CNT1 LT ne + fld POINTER [PDI+N*CNT1] + fmul POINTER [PSI+N*CNT2] + CNT1=CNT1+1 + CNT2=CNT2-1 + WHILE CNT1 LT ne + FRSTEP CNT1,CNT2 + CNT1=CNT1+1 + CNT2=CNT2-1 + ENDM + fadd + ENDIF + ENDM + + RDIAGD MACRO ns,ne + CNT1=ns + CNT2=ne + fld POINTER [PDI+N*CNT1] + fmul POINTER [PSI+N*CNT2] + CNT1=CNT1+1 + CNT2=CNT2-1 + WHILE CNT1 LE ne + FRSTEP CNT1,CNT2 + CNT1=CNT1+1 + CNT2=CNT2-1 + ENDM + fadd + ENDM + + MODMULT MACRO + CNT=0 + WHILE CNT LT MR_PENTIUM + DIAG 0,CNT + xchg PSI,PCX + RDIAGU 0,CNT + RFINU CNT + xchg PSI,PCX + CNT=CNT+1 + ENDM + SCNT=0 + WHILE SCNT LT (MR_PENTIUM-1) + SCNT=SCNT+1 + DIAG SCNT,(MR_PENTIUM-1) + xchg PSI,PCX + RDIAGD SCNT,(MR_PENTIUM-1) + RFIND CNT + xchg PSI,PCX + CNT=CNT+1 + ENDM + RFIND CNT + CNT=CNT+1 + fstp POINTER [PDI+N*CNT] + ENDM + + MODSQUARE MACRO + CNT=0 + WHILE CNT LT MR_PENTIUM + SDIAG 0,CNT + IF (CNT MOD 2) EQ 0 + SELF (CNT/2) + ENDIF + RDIAGU 0,CNT + RFINU CNT + CNT=CNT+1 + ENDM + SCNT=0 + WHILE SCNT LT (MR_PENTIUM-1) + SCNT=SCNT+1 + SDIAG SCNT,(MR_PENTIUM-1) + IF (CNT MOD 2) EQ 0 + SELF (CNT/2) + ENDIF + RDIAGD SCNT,(MR_PENTIUM-1) + RFIND CNT + CNT=CNT+1 + ENDM + RFIND CNT + CNT=CNT+1 + fstp POINTER [PDI+N*CNT] + ENDM + } + ASM + { + push PDI + push PSI + + mov PBX,xg + mov PSI,yg + mov PCX,mg + mov PDI,wg + + + fldz + + MODMULT + + pop PSI + pop PDI + } + + for (ij=MR_PENTIUM;ij<(int)(z->len&MR_OBITS);ij++) z->w[ij]=0.0; + z->len=MR_PENTIUM; + for (ij=0;ijw[ij]=w0->w[ij+MR_PENTIUM]; + if (z->w[MR_PENTIUM-1]==0.0) mr_lzero(z); +} + +void fastmodsquare(_MIPD_ x,z) +big x,z; +{ + int ij; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + big w0=mr_mip->w0; + big modulus=mr_mip->modulus; + mr_small *wg,*mg,*xg; + wg=w0->w; + mg=modulus->w; + xg=x->w; + + for (ij=2*MR_PENTIUM;ij<(int)(w0->len&MR_OBITS);ij++) w0->w[ij]=0.0; + w0->len=2*MR_PENTIUM; + + ASM + { + push PDI + push PSI + + mov PBX,xg + mov PSI,mg + mov PDI,wg + + fldz + + MODSQUARE + + pop PSI + pop PDI + } + for (ij=MR_PENTIUM;ij<(int)(z->len&MR_OBITS);ij++) z->w[ij]=0.0; + z->len=MR_PENTIUM; + + for (ij=0;ijw[ij]=w0->w[ij+MR_PENTIUM]; + if (z->w[MR_PENTIUM-1]==0.0) mr_lzero(z); + +} + +#endif +#endif +#endif + diff --git a/miracl/source/mr87v.c b/miracl/source/mr87v.c new file mode 100644 index 0000000..c2b10d8 --- /dev/null +++ b/miracl/source/mr87v.c @@ -0,0 +1,591 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * Many processors support a floating-point coprocessor, which may + * implement a faster multiplication instruction than the corresponding + * integer instruction. This is the case for the Pentium processor + * which has a built-in co-processor. This can be exploited to give even + * faster performance. + * + * Note that since the partial products are accumulated in a 64-bit register + * this implies that a full-width number base (2^32) cannot be used. + * The maximum number base that can be used is 2^x where x is + * calculated such that 2^(64-2*x) > 2*WORDS_IN_MODULUS. This means that + * x will usually be 28 or 29 + * + * To use this code:- + * + * (1) Implemented and tested only for the Pentium processor and + * using the Borland C compiler (BCC and BCC32) + * + * (2) Define MR_PENTIUM in mirdef.h. Determine the maximum modulus to be + * used, and from that determine the value of WORDS_IN_MODULUS. + * + * (3) Use as a number base the value of x calculated as shown above. + * For example, for 512 bit exponentiation, WORDS_IN_MODULUS will be 18 + * so call mirsys(50,536870912L) in your main program. + * (Observe that 536870912 = 2^29, and that 18*29 = 522, big enough + * for 512 bit calculations). + * + * (4) Use Montgomery representation when implementing your crypto-system + * e.g. use monty_powmod(). This will automatically call the + * routines in this module. + * + * Note that it is *VITAL* that double arrays be aligned on 8-byte + * boundaries for the Pentium. The Borland C compiler does *not* do this + * automatically!!!! + * + * Many thanks are due to Paul Rubin, who suggested to me that this approach + * might be faster than the all-integer methods described elsewhere. + * + * Further speed increases can be acheived by loop-unrolling. Completely + * unrolled code (a la Comba) has been experimented with, and gives a + * 25% speed-up in some cases. Note that the basic code for a single partial + * product takes only 3 cycles. + * + * fld ... ;1 cycle + * fmul ... ;1 cycle + * fxch st(2) ;0 cycle + * fadd ;1 cycle + * + * Compare this with the integer "mul" instruction which takes 10 cycles + * on a Pentium + * + * Interestingly the fmul is faster than the fimul. So paradoxically it is + * quicker to manipulate 64-bit doubles than it is to manipulate 32-bit + * integers. Clearly the Pentium FP processor has been optimised for real + * arithmetic. However this requires us to convert all bigs from integer + * arrays to double arrays (see mrmonty.c) which is very wasteful of space + * and rather awkward. + * + * + * The FP stack is primed in prepare_monty() :- + * magic - (2^63+2^62)*base. By adding and then subtracting this number we + * get the top half of the sum. + * 1/base - Inverse of the number base + * ndash - Montgomery's constant + * + */ + +#include "miracl.h" + +#ifdef MR_PENTIUM +#define N 8 +#define POINTER QWORD PTR + +#if INLINE_ASM == 1 +#define PAX ax +#define PBP bp +#define PBX bx +#define PSI si +#define PDI di +#define PCX cx +#define PDX dx +#endif + +#if INLINE_ASM == 2 +#define PAX ax +#define PBP bp +#define PBX bx +#define PSI si +#define PDI di +#define PCX cx +#define PDX dx +#endif + +#if INLINE_ASM == 3 +#define PAX eax +#define PBP ebp +#define PBX ebx +#define PSI esi +#define PDI edi +#define PCX ecx +#define PDX edx +#endif + +#ifdef INLINE_ASM +#ifndef MR_LMM + /* not implemented for large memory model 16 bit */ + +void fastmodmult(_MIPD_ big x,big y,big z) +{ + int ij,rn,nrn; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + big modulus=mr_mip->modulus; + big w0=mr_mip->w0; + mr_small *wg,*mg,*xg,*yg; + wg=w0->w; + mg=modulus->w; + xg=x->w; + yg=y->w; + rn=(int)modulus->len; + for (ij=2*rn;ij<(int)(w0->len&MR_OBITS);ij++) w0->w[ij]=0.0; + w0->len=2*rn; + nrn=N*rn; + + ASM push PBP + ASM push PDI + ASM push PSI + + ASM mov PBX,xg + ASM mov PSI,yg + ASM mov PDX,mg + ASM mov PDI,wg + ASM mov PAX,nrn + + ASM mov PBP,N + + ASM fldz + + ASM xor PCX,PCX + m1: + ASM push PCX + ASM add PSI,PCX + ASM fld POINTER [PBX] + ASM fmul POINTER [PSI] + ASM add PBX,PBP + ASM sub PSI,PBP + ASM test PCX,PCX + ASM jz m3 + m2: + ASM fld POINTER [PBX] + ASM fmul POINTER [PSI] + ASM fxch st(2) + ASM add PBX,PBP + ASM sub PSI,PBP + ASM fadd + ASM sub PCX,PBP + ASM jnz m2 + m3: + ASM sub PBX,PBP + ASM add PSI,PBP + ASM fadd + ASM pop PCX + ASM sub PBX,PCX /* restore PBX */ + + ASM xchg PSI,PDX /* PSI -> modulus */ + ASM push PCX + ASM test PCX,PCX + ASM jz m6 + ASM add PSI,PCX + ASM fld POINTER [PDI] + ASM fmul POINTER [PSI] + ASM add PDI,PBP + ASM sub PSI,PBP + ASM sub PCX,PBP + ASM jz m5 + m4: /* this is typical of the critical inner loop */ + ASM fld POINTER [PDI] /* 1 cycle */ + ASM fmul POINTER [PSI] /* 1 cycle */ + ASM fxch st(2) /* 0 cycle */ + ASM add PDI,PBP /* 1 cycle */ + ASM sub PSI,PBP /* 0 cycle */ + ASM fadd /* 1 cycle */ + ASM sub PCX,PBP /* 1 cycle */ + ASM jnz m4 /* 0 cycle */ + /* total = 5 cycles */ + m5: + ASM fadd + m6: + + ASM fld st(0) + ASM fadd st,st(2) + ASM fsub st,st(2) + ASM fsubr st,st(1) + ASM fmul st,st(4) + ASM fld st(0) + ASM fadd st,st(3) + ASM fsub st,st(3) + ASM fsub + ASM fst POINTER [PDI] + ASM fmul POINTER [PSI] + ASM fadd + ASM fmul st,st(2) + + ASM xchg PSI,PDX + ASM pop PCX + ASM sub PDI,PCX /* restore PDI */ + + + ASM add PCX,PBP /* increment PCX */ + ASM cmp PCX,PAX + ASM jl m1 + + ASM sub PCX,PBP /* PCX=12 */ + ASM add PSI,PCX + ASM add PBX,PCX /* PBX -> x[4] */ + ASM add PDX,PCX + ASM add PDI,PCX + ASM sub PCX,PBP /* going back down again PCX=8 */ + m7: + ASM push PCX + ASM sub PBX,PCX + ASM fld POINTER [PBX] + ASM fmul POINTER [PSI] + ASM add PBX,PBP + ASM sub PSI,PBP + ASM test PCX,PCX + ASM jz m9 + m8: + ASM fld POINTER [PBX] + ASM fmul POINTER [PSI] + ASM fxch st(2) + ASM add PBX,PBP + ASM sub PSI,PBP + ASM fadd + ASM sub PCX,PBP + ASM jnz m8 + m9: + ASM sub PBX,PBP + ASM add PSI,PBP + ASM fadd + ASM pop PCX + ASM add PSI,PCX /* restore PSI */ + + ASM sub PDI,PCX + ASM xchg PSI,PDX /* PSI -> modulus */ + ASM push PCX + ASM fld POINTER [PDI] + ASM fmul POINTER [PSI] + ASM add PDI,PBP + ASM sub PSI,PBP + ASM test PCX,PCX + ASM jz m11 + m10: + ASM fld POINTER [PDI] + ASM fmul POINTER [PSI] + ASM fxch st(2) + ASM add PDI,PBP + ASM sub PSI,PBP + ASM fadd + ASM sub PCX,PBP + ASM jnz m10 + m11: + ASM sub PDI,PBP + ASM add PSI,PBP + ASM fadd + ASM pop PCX + ASM add PSI,PCX /* restore PSI */ + ASM xchg PSI,PDX + + ASM push PDI + ASM add PDI,PAX + ASM sub PDI,PCX + ASM sub PDI,PBP + + + ASM fld st(0) + ASM fadd st,st(2) + ASM fsub st,st(2) + ASM fst st(5) + ASM fmul st,st(3) + ASM fxch st(5) + ASM fsub + ASM fstp POINTER [PDI] + ASM fld st(3) + + ASM pop PDI + + ASM sub PCX,PBP + ASM jge m7 + + ASM add PDI,PAX + + ASM fld st(0) + ASM fadd st,st(2) + ASM fsub st,st(2) + ASM fst st(5) + ASM fmul st,st(3) + ASM fxch st(5) + ASM fsub + ASM fstp POINTER [PDI] + ASM fld st(3) + + ASM add PDI,PBP + ASM fstp POINTER [PDI] + + ASM pop PSI + ASM pop PDI + ASM pop PBP + + for (ij=rn;ij<(int)(z->len&MR_OBITS);ij++) z->w[ij]=0.0; + z->len=rn; + for (ij=0;ijw[ij]=w0->w[ij+rn]; + if (z->w[rn-1]==0.0) mr_lzero(z); + +} + +void fastmodsquare(_MIPD_ big x,big z) +{ + int ij,rn,nrn; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + big modulus=mr_mip->modulus; + big w0=mr_mip->w0; + mr_small *wg,*mg,*xg; + wg=w0->w; + mg=modulus->w; + xg=x->w; + + rn=(int)modulus->len; + for (ij=2*rn;ij<(int)(w0->len&MR_OBITS);ij++) w0->w[ij]=0.0; + w0->len=2*rn; + nrn=N*rn; + + + ASM push PBP + ASM push PDI + ASM push PSI + + ASM mov PBX,xg + ASM mov PSI,xg + ASM mov PDX,mg + ASM mov PDI,wg + ASM mov PAX,nrn + + ASM mov PBP,N + + ASM fldz + + ASM xor PCX,PCX + s1: + ASM push PBX + ASM push PSI + ASM test PCX,PCX + ASM jz s4 + ASM add PSI,PCX + ASM fstp st(5) + ASM fldz + ASM fld POINTER [PBX] + ASM fmul POINTER [PSI] + ASM sub PSI,PBP + ASM add PBX,PBP + ASM cmp PSI,PBX + ASM jle s3 + s2: + ASM fld POINTER [PBX] + ASM fmul POINTER [PSI] + ASM fxch st(2) + ASM sub PSI,PBP + ASM add PBX,PBP + ASM fadd + ASM cmp PSI,PBX + ASM jg s2 + s3: + ASM fadd + ASM fld st(0) + ASM fadd + ASM fadd st,st(5) + s4: + ASM cmp PSI,PBX + ASM jne s5 + ASM fld POINTER [PBX] + ASM fmul st,st(0) + ASM fadd + s5: + ASM pop PSI + ASM pop PBX /* restore pointers */ + + ASM xchg PSI,PDX /* PSI -> modulus */ + ASM push PCX + ASM test PCX,PCX + ASM jz s8 + ASM add PSI,PCX + ASM fld POINTER [PDI] + ASM fmul POINTER [PSI] + ASM add PDI,PBP + ASM sub PSI,PBP + ASM sub PCX,PBP + ASM jz s7 + s6: + ASM fld POINTER [PDI] + ASM fmul POINTER [PSI] + ASM fxch st(2) + ASM add PDI,PBP + ASM sub PSI,PBP + ASM fadd + ASM sub PCX,PBP + ASM jnz s6 + s7: + ASM fadd + s8: + + ASM fld st(0) + ASM fadd st,st(2) + ASM fsub st,st(2) + ASM fsubr st,st(1) + ASM fmul st,st(4) + ASM fld st(0) + ASM fadd st,st(3) + ASM fsub st,st(3) + ASM fsub + ASM fst POINTER [PDI] + ASM fmul POINTER [PSI] + ASM fadd + ASM fmul st,st(2) + + ASM xchg PSI,PDX + ASM pop PCX + ASM sub PDI,PCX /* restore PDI */ + + ASM add PCX,PBP /* increment PCX */ + ASM cmp PCX,PAX + ASM jl s1 + + ASM sub PCX,PBP /* PCX=12 */ + ASM add PSI,PCX + ASM add PBX,PCX /* PBX -> x[4] */ + ASM add PDX,PCX + ASM add PDI,PCX + ASM sub PCX,PBP /* going back down again PCX=8 */ + s9: + ASM push PBX + ASM push PSI + ASM test PCX,PCX + ASM jz s13 + s10: + ASM sub PBX,PCX + ASM fstp st(5) + ASM fldz + ASM fld POINTER [PBX] + ASM fmul POINTER [PSI] + ASM sub PSI,PBP + ASM add PBX,PBP + ASM cmp PSI,PBX + ASM jle s12 + s11: + ASM fld POINTER [PBX] + ASM fmul POINTER [PSI] + ASM fxch st(2) + ASM sub PSI,PBP + ASM add PBX,PBP + ASM fadd + ASM cmp PSI,PBX + ASM jg s11 + s12: + ASM fadd + ASM fld st(0) + ASM fadd + ASM fadd st,st(5) + s13: + ASM cmp PSI,PBX + ASM jne s14 + ASM fld POINTER [PBX] + ASM fmul st,st(0) + ASM fadd + s14: + ASM pop PSI + ASM pop PBX + + ASM sub PDI,PCX + ASM xchg PSI,PDX /* PSI -> modulus */ + ASM push PCX + ASM fld POINTER [PDI] + ASM fmul POINTER [PSI] + ASM add PDI,PBP + ASM sub PSI,PBP + ASM test PCX,PCX + ASM jz s16 + s15: + ASM fld POINTER [PDI] + ASM fmul POINTER [PSI] + ASM fxch st(2) + ASM add PDI,PBP + ASM sub PSI,PBP + ASM fadd + ASM sub PCX,PBP + ASM jnz s15 + s16: + ASM sub PDI,PBP + ASM add PSI,PBP + ASM fadd + ASM pop PCX + ASM add PSI,PCX /* restore PSI */ + ASM xchg PSI,PDX + + ASM push PDI + ASM add PDI,PAX + ASM sub PDI,PCX + ASM sub PDI,PBP + + ASM fld st(0) + ASM fadd st,st(2) + ASM fsub st,st(2) + ASM fst st(5) + ASM fmul st,st(3) + ASM fxch st(5) + ASM fsub + ASM fstp POINTER [PDI] + ASM fld st(3) + + ASM pop PDI + + ASM sub PCX,PBP + ASM jge s9 + + ASM add PDI,PAX + + ASM fld st(0) + ASM fadd st,st(2) + ASM fsub st,st(2) + ASM fst st(5) + ASM fmul st,st(3) + ASM fxch st(5) + ASM fsub + ASM fstp POINTER [PDI] + ASM fld st(3) + + ASM add PDI,PBP + ASM fstp POINTER [PDI] + + ASM pop PSI + ASM pop PDI + ASM pop PBP + + + for (ij=rn;ij<(int)(z->len&MR_OBITS);ij++) z->w[ij]=0.0; + z->len=rn; + for (ij=0;ijw[ij]=w0->w[ij+rn]; + if (z->w[rn-1]==0.0) mr_lzero(z); +} + +#endif +#endif +#endif + + diff --git a/miracl/source/mraes.c b/miracl/source/mraes.c new file mode 100644 index 0000000..71b7373 --- /dev/null +++ b/miracl/source/mraes.c @@ -0,0 +1,1045 @@ + + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * Implementation of the NIST Advanced Ecryption Standard + * + * Could/Should be speeded up by assembly patches in time critical loops in + * aes_ecb_encrypt() and aes_ecb_decrypt() + * + * Note that the AES winner has not yet been determined! Nonetheless + * we are jumping the gun a little and implementing one of the favourites + * RIJNDAEL, partly because it is entirely patent-free. + * + * We were right! Rijndael is the AES from October 2nd 2000 + */ + +#include +#include "miracl.h" + +/* Define this if INTEL AES-NI intrinsics are supported - for example with GCC compiler - use flag -maes */ +/* #define AES_NI_SUPPORT */ + +#ifdef AES_NI_SUPPORT +#include +#endif + +#define MR_WORD mr_unsign32 + +/* this is fixed */ +#define NB 4 + +/* rotates x one bit to the left */ + +#define ROTL(x) (((x)>>7)|((x)<<1)) + +/* Rotates 32-bit word left by 1, 2 or 3 byte */ + +#define ROTL8(x) (((x)<<8)|((x)>>24)) +#define ROTL16(x) (((x)<<16)|((x)>>16)) +#define ROTL24(x) (((x)<<24)|((x)>>8)) + +static const MR_BYTE InCo[4]={0xB,0xD,0x9,0xE}; /* Inverse Coefficients */ + +static const MR_BYTE ptab[]= +{1,3,5,15,17,51,85,255,26,46,114,150,161,248,19,53, +95,225,56,72,216,115,149,164,247,2,6,10,30,34,102,170, +229,52,92,228,55,89,235,38,106,190,217,112,144,171,230,49, +83,245,4,12,20,60,68,204,79,209,104,184,211,110,178,205, +76,212,103,169,224,59,77,215,98,166,241,8,24,40,120,136, +131,158,185,208,107,189,220,127,129,152,179,206,73,219,118,154, +181,196,87,249,16,48,80,240,11,29,39,105,187,214,97,163, +254,25,43,125,135,146,173,236,47,113,147,174,233,32,96,160, +251,22,58,78,210,109,183,194,93,231,50,86,250,21,63,65, +195,94,226,61,71,201,64,192,91,237,44,116,156,191,218,117, +159,186,213,100,172,239,42,126,130,157,188,223,122,142,137,128, +155,182,193,88,232,35,101,175,234,37,111,177,200,67,197,84, +252,31,33,99,165,244,7,9,27,45,119,153,176,203,70,202, +69,207,74,222,121,139,134,145,168,227,62,66,198,81,243,14, +18,54,90,238,41,123,141,140,143,138,133,148,167,242,13,23, +57,75,221,124,132,151,162,253,28,36,108,180,199,82,246,1}; + +static const MR_BYTE ltab[]= +{0,255,25,1,50,2,26,198,75,199,27,104,51,238,223,3, +100,4,224,14,52,141,129,239,76,113,8,200,248,105,28,193, +125,194,29,181,249,185,39,106,77,228,166,114,154,201,9,120, +101,47,138,5,33,15,225,36,18,240,130,69,53,147,218,142, +150,143,219,189,54,208,206,148,19,92,210,241,64,70,131,56, +102,221,253,48,191,6,139,98,179,37,226,152,34,136,145,16, +126,110,72,195,163,182,30,66,58,107,40,84,250,133,61,186, +43,121,10,21,155,159,94,202,78,212,172,229,243,115,167,87, +175,88,168,80,244,234,214,116,79,174,233,213,231,230,173,232, +44,215,117,122,235,22,11,245,89,203,95,176,156,169,81,160, +127,12,246,111,23,196,73,236,216,67,31,45,164,118,123,183, +204,187,62,90,251,96,177,134,59,82,161,108,170,85,41,157, +151,178,135,144,97,190,220,252,188,149,207,205,55,63,91,209, +83,57,132,60,65,162,109,71,20,42,158,93,86,242,211,171, +68,17,146,217,35,32,46,137,180,124,184,38,119,153,227,165, +103,74,237,222,197,49,254,24,13,99,140,128,192,247,112,7}; + +static const MR_BYTE fbsub[]= +{99,124,119,123,242,107,111,197,48,1,103,43,254,215,171,118, +202,130,201,125,250,89,71,240,173,212,162,175,156,164,114,192, +183,253,147,38,54,63,247,204,52,165,229,241,113,216,49,21, +4,199,35,195,24,150,5,154,7,18,128,226,235,39,178,117, +9,131,44,26,27,110,90,160,82,59,214,179,41,227,47,132, +83,209,0,237,32,252,177,91,106,203,190,57,74,76,88,207, +208,239,170,251,67,77,51,133,69,249,2,127,80,60,159,168, +81,163,64,143,146,157,56,245,188,182,218,33,16,255,243,210, +205,12,19,236,95,151,68,23,196,167,126,61,100,93,25,115, +96,129,79,220,34,42,144,136,70,238,184,20,222,94,11,219, +224,50,58,10,73,6,36,92,194,211,172,98,145,149,228,121, +231,200,55,109,141,213,78,169,108,86,244,234,101,122,174,8, +186,120,37,46,28,166,180,198,232,221,116,31,75,189,139,138, +112,62,181,102,72,3,246,14,97,53,87,185,134,193,29,158, +225,248,152,17,105,217,142,148,155,30,135,233,206,85,40,223, +140,161,137,13,191,230,66,104,65,153,45,15,176,84,187,22}; + +static const MR_BYTE rbsub[]= +{82,9,106,213,48,54,165,56,191,64,163,158,129,243,215,251, +124,227,57,130,155,47,255,135,52,142,67,68,196,222,233,203, +84,123,148,50,166,194,35,61,238,76,149,11,66,250,195,78, +8,46,161,102,40,217,36,178,118,91,162,73,109,139,209,37, +114,248,246,100,134,104,152,22,212,164,92,204,93,101,182,146, +108,112,72,80,253,237,185,218,94,21,70,87,167,141,157,132, +144,216,171,0,140,188,211,10,247,228,88,5,184,179,69,6, +208,44,30,143,202,63,15,2,193,175,189,3,1,19,138,107, +58,145,17,65,79,103,220,234,151,242,207,206,240,180,230,115, +150,172,116,34,231,173,53,133,226,249,55,232,28,117,223,110, +71,241,26,113,29,41,197,137,111,183,98,14,170,24,190,27, +252,86,62,75,198,210,121,32,154,219,192,254,120,205,90,244, +31,221,168,51,136,7,199,49,177,18,16,89,39,128,236,95, +96,81,127,169,25,181,74,13,45,229,122,159,147,201,156,239, +160,224,59,77,174,42,245,176,200,235,187,60,131,83,153,97, +23,43,4,126,186,119,214,38,225,105,20,99,85,33,12,125}; + +static const MR_WORD rco[]= +{1,2,4,8,16,32,64,128,27,54,108,216,171,77,154,47}; + +static const MR_WORD ftable[]= +{0xa56363c6,0x847c7cf8,0x997777ee,0x8d7b7bf6,0xdf2f2ff,0xbd6b6bd6, +0xb16f6fde,0x54c5c591,0x50303060,0x3010102,0xa96767ce,0x7d2b2b56, +0x19fefee7,0x62d7d7b5,0xe6abab4d,0x9a7676ec,0x45caca8f,0x9d82821f, +0x40c9c989,0x877d7dfa,0x15fafaef,0xeb5959b2,0xc947478e,0xbf0f0fb, +0xecadad41,0x67d4d4b3,0xfda2a25f,0xeaafaf45,0xbf9c9c23,0xf7a4a453, +0x967272e4,0x5bc0c09b,0xc2b7b775,0x1cfdfde1,0xae93933d,0x6a26264c, +0x5a36366c,0x413f3f7e,0x2f7f7f5,0x4fcccc83,0x5c343468,0xf4a5a551, +0x34e5e5d1,0x8f1f1f9,0x937171e2,0x73d8d8ab,0x53313162,0x3f15152a, +0xc040408,0x52c7c795,0x65232346,0x5ec3c39d,0x28181830,0xa1969637, +0xf05050a,0xb59a9a2f,0x907070e,0x36121224,0x9b80801b,0x3de2e2df, +0x26ebebcd,0x6927274e,0xcdb2b27f,0x9f7575ea,0x1b090912,0x9e83831d, +0x742c2c58,0x2e1a1a34,0x2d1b1b36,0xb26e6edc,0xee5a5ab4,0xfba0a05b, +0xf65252a4,0x4d3b3b76,0x61d6d6b7,0xceb3b37d,0x7b292952,0x3ee3e3dd, +0x712f2f5e,0x97848413,0xf55353a6,0x68d1d1b9,0x0,0x2cededc1, +0x60202040,0x1ffcfce3,0xc8b1b179,0xed5b5bb6,0xbe6a6ad4,0x46cbcb8d, +0xd9bebe67,0x4b393972,0xde4a4a94,0xd44c4c98,0xe85858b0,0x4acfcf85, +0x6bd0d0bb,0x2aefefc5,0xe5aaaa4f,0x16fbfbed,0xc5434386,0xd74d4d9a, +0x55333366,0x94858511,0xcf45458a,0x10f9f9e9,0x6020204,0x817f7ffe, +0xf05050a0,0x443c3c78,0xba9f9f25,0xe3a8a84b,0xf35151a2,0xfea3a35d, +0xc0404080,0x8a8f8f05,0xad92923f,0xbc9d9d21,0x48383870,0x4f5f5f1, +0xdfbcbc63,0xc1b6b677,0x75dadaaf,0x63212142,0x30101020,0x1affffe5, +0xef3f3fd,0x6dd2d2bf,0x4ccdcd81,0x140c0c18,0x35131326,0x2fececc3, +0xe15f5fbe,0xa2979735,0xcc444488,0x3917172e,0x57c4c493,0xf2a7a755, +0x827e7efc,0x473d3d7a,0xac6464c8,0xe75d5dba,0x2b191932,0x957373e6, +0xa06060c0,0x98818119,0xd14f4f9e,0x7fdcdca3,0x66222244,0x7e2a2a54, +0xab90903b,0x8388880b,0xca46468c,0x29eeeec7,0xd3b8b86b,0x3c141428, +0x79dedea7,0xe25e5ebc,0x1d0b0b16,0x76dbdbad,0x3be0e0db,0x56323264, +0x4e3a3a74,0x1e0a0a14,0xdb494992,0xa06060c,0x6c242448,0xe45c5cb8, +0x5dc2c29f,0x6ed3d3bd,0xefacac43,0xa66262c4,0xa8919139,0xa4959531, +0x37e4e4d3,0x8b7979f2,0x32e7e7d5,0x43c8c88b,0x5937376e,0xb76d6dda, +0x8c8d8d01,0x64d5d5b1,0xd24e4e9c,0xe0a9a949,0xb46c6cd8,0xfa5656ac, +0x7f4f4f3,0x25eaeacf,0xaf6565ca,0x8e7a7af4,0xe9aeae47,0x18080810, +0xd5baba6f,0x887878f0,0x6f25254a,0x722e2e5c,0x241c1c38,0xf1a6a657, +0xc7b4b473,0x51c6c697,0x23e8e8cb,0x7cdddda1,0x9c7474e8,0x211f1f3e, +0xdd4b4b96,0xdcbdbd61,0x868b8b0d,0x858a8a0f,0x907070e0,0x423e3e7c, +0xc4b5b571,0xaa6666cc,0xd8484890,0x5030306,0x1f6f6f7,0x120e0e1c, +0xa36161c2,0x5f35356a,0xf95757ae,0xd0b9b969,0x91868617,0x58c1c199, +0x271d1d3a,0xb99e9e27,0x38e1e1d9,0x13f8f8eb,0xb398982b,0x33111122, +0xbb6969d2,0x70d9d9a9,0x898e8e07,0xa7949433,0xb69b9b2d,0x221e1e3c, +0x92878715,0x20e9e9c9,0x49cece87,0xff5555aa,0x78282850,0x7adfdfa5, +0x8f8c8c03,0xf8a1a159,0x80898909,0x170d0d1a,0xdabfbf65,0x31e6e6d7, +0xc6424284,0xb86868d0,0xc3414182,0xb0999929,0x772d2d5a,0x110f0f1e, +0xcbb0b07b,0xfc5454a8,0xd6bbbb6d,0x3a16162c}; + +static const MR_WORD rtable[]= +{0x50a7f451,0x5365417e,0xc3a4171a,0x965e273a,0xcb6bab3b,0xf1459d1f, +0xab58faac,0x9303e34b,0x55fa3020,0xf66d76ad,0x9176cc88,0x254c02f5, +0xfcd7e54f,0xd7cb2ac5,0x80443526,0x8fa362b5,0x495ab1de,0x671bba25, +0x980eea45,0xe1c0fe5d,0x2752fc3,0x12f04c81,0xa397468d,0xc6f9d36b, +0xe75f8f03,0x959c9215,0xeb7a6dbf,0xda595295,0x2d83bed4,0xd3217458, +0x2969e049,0x44c8c98e,0x6a89c275,0x78798ef4,0x6b3e5899,0xdd71b927, +0xb64fe1be,0x17ad88f0,0x66ac20c9,0xb43ace7d,0x184adf63,0x82311ae5, +0x60335197,0x457f5362,0xe07764b1,0x84ae6bbb,0x1ca081fe,0x942b08f9, +0x58684870,0x19fd458f,0x876cde94,0xb7f87b52,0x23d373ab,0xe2024b72, +0x578f1fe3,0x2aab5566,0x728ebb2,0x3c2b52f,0x9a7bc586,0xa50837d3, +0xf2872830,0xb2a5bf23,0xba6a0302,0x5c8216ed,0x2b1ccf8a,0x92b479a7, +0xf0f207f3,0xa1e2694e,0xcdf4da65,0xd5be0506,0x1f6234d1,0x8afea6c4, +0x9d532e34,0xa055f3a2,0x32e18a05,0x75ebf6a4,0x39ec830b,0xaaef6040, +0x69f715e,0x51106ebd,0xf98a213e,0x3d06dd96,0xae053edd,0x46bde64d, +0xb58d5491,0x55dc471,0x6fd40604,0xff155060,0x24fb9819,0x97e9bdd6, +0xcc434089,0x779ed967,0xbd42e8b0,0x888b8907,0x385b19e7,0xdbeec879, +0x470a7ca1,0xe90f427c,0xc91e84f8,0x0,0x83868009,0x48ed2b32, +0xac70111e,0x4e725a6c,0xfbff0efd,0x5638850f,0x1ed5ae3d,0x27392d36, +0x64d90f0a,0x21a65c68,0xd1545b9b,0x3a2e3624,0xb1670a0c,0xfe75793, +0xd296eeb4,0x9e919b1b,0x4fc5c080,0xa220dc61,0x694b775a,0x161a121c, +0xaba93e2,0xe52aa0c0,0x43e0223c,0x1d171b12,0xb0d090e,0xadc78bf2, +0xb9a8b62d,0xc8a91e14,0x8519f157,0x4c0775af,0xbbdd99ee,0xfd607fa3, +0x9f2601f7,0xbcf5725c,0xc53b6644,0x347efb5b,0x7629438b,0xdcc623cb, +0x68fcedb6,0x63f1e4b8,0xcadc31d7,0x10856342,0x40229713,0x2011c684, +0x7d244a85,0xf83dbbd2,0x1132f9ae,0x6da129c7,0x4b2f9e1d,0xf330b2dc, +0xec52860d,0xd0e3c177,0x6c16b32b,0x99b970a9,0xfa489411,0x2264e947, +0xc48cfca8,0x1a3ff0a0,0xd82c7d56,0xef903322,0xc74e4987,0xc1d138d9, +0xfea2ca8c,0x360bd498,0xcf81f5a6,0x28de7aa5,0x268eb7da,0xa4bfad3f, +0xe49d3a2c,0xd927850,0x9bcc5f6a,0x62467e54,0xc2138df6,0xe8b8d890, +0x5ef7392e,0xf5afc382,0xbe805d9f,0x7c93d069,0xa92dd56f,0xb31225cf, +0x3b99acc8,0xa77d1810,0x6e639ce8,0x7bbb3bdb,0x97826cd,0xf418596e, +0x1b79aec,0xa89a4f83,0x656e95e6,0x7ee6ffaa,0x8cfbc21,0xe6e815ef, +0xd99be7ba,0xce366f4a,0xd4099fea,0xd67cb029,0xafb2a431,0x31233f2a, +0x3094a5c6,0xc066a235,0x37bc4e74,0xa6ca82fc,0xb0d090e0,0x15d8a733, +0x4a9804f1,0xf7daec41,0xe50cd7f,0x2ff69117,0x8dd64d76,0x4db0ef43, +0x544daacc,0xdf0496e4,0xe3b5d19e,0x1b886a4c,0xb81f2cc1,0x7f516546, +0x4ea5e9d,0x5d358c01,0x737487fa,0x2e410bfb,0x5a1d67b3,0x52d2db92, +0x335610e9,0x1347d66d,0x8c61d79a,0x7a0ca137,0x8e14f859,0x893c13eb, +0xee27a9ce,0x35c961b7,0xede51ce1,0x3cb1477a,0x59dfd29c,0x3f73f255, +0x79ce1418,0xbf37c773,0xeacdf753,0x5baafd5f,0x146f3ddf,0x86db4478, +0x81f3afca,0x3ec468b9,0x2c342438,0x5f40a3c2,0x72c31d16,0xc25e2bc, +0x8b493c28,0x41950dff,0x7101a839,0xdeb30c08,0x9ce4b4d8,0x90c15664, +0x6184cb7b,0x70b632d5,0x745c6c48,0x4257b8d0}; + +#ifndef MR_SMALL_AES + +static const MR_WORD ftable1[]= +{0x6363c6a5,0x7c7cf884,0x7777ee99,0x7b7bf68d,0xf2f2ff0d,0x6b6bd6bd, +0x6f6fdeb1,0xc5c59154,0x30306050,0x1010203,0x6767cea9,0x2b2b567d, +0xfefee719,0xd7d7b562,0xabab4de6,0x7676ec9a,0xcaca8f45,0x82821f9d, +0xc9c98940,0x7d7dfa87,0xfafaef15,0x5959b2eb,0x47478ec9,0xf0f0fb0b, +0xadad41ec,0xd4d4b367,0xa2a25ffd,0xafaf45ea,0x9c9c23bf,0xa4a453f7, +0x7272e496,0xc0c09b5b,0xb7b775c2,0xfdfde11c,0x93933dae,0x26264c6a, +0x36366c5a,0x3f3f7e41,0xf7f7f502,0xcccc834f,0x3434685c,0xa5a551f4, +0xe5e5d134,0xf1f1f908,0x7171e293,0xd8d8ab73,0x31316253,0x15152a3f, +0x404080c,0xc7c79552,0x23234665,0xc3c39d5e,0x18183028,0x969637a1, +0x5050a0f,0x9a9a2fb5,0x7070e09,0x12122436,0x80801b9b,0xe2e2df3d, +0xebebcd26,0x27274e69,0xb2b27fcd,0x7575ea9f,0x909121b,0x83831d9e, +0x2c2c5874,0x1a1a342e,0x1b1b362d,0x6e6edcb2,0x5a5ab4ee,0xa0a05bfb, +0x5252a4f6,0x3b3b764d,0xd6d6b761,0xb3b37dce,0x2929527b,0xe3e3dd3e, +0x2f2f5e71,0x84841397,0x5353a6f5,0xd1d1b968,0x0,0xededc12c, +0x20204060,0xfcfce31f,0xb1b179c8,0x5b5bb6ed,0x6a6ad4be,0xcbcb8d46, +0xbebe67d9,0x3939724b,0x4a4a94de,0x4c4c98d4,0x5858b0e8,0xcfcf854a, +0xd0d0bb6b,0xefefc52a,0xaaaa4fe5,0xfbfbed16,0x434386c5,0x4d4d9ad7, +0x33336655,0x85851194,0x45458acf,0xf9f9e910,0x2020406,0x7f7ffe81, +0x5050a0f0,0x3c3c7844,0x9f9f25ba,0xa8a84be3,0x5151a2f3,0xa3a35dfe, +0x404080c0,0x8f8f058a,0x92923fad,0x9d9d21bc,0x38387048,0xf5f5f104, +0xbcbc63df,0xb6b677c1,0xdadaaf75,0x21214263,0x10102030,0xffffe51a, +0xf3f3fd0e,0xd2d2bf6d,0xcdcd814c,0xc0c1814,0x13132635,0xececc32f, +0x5f5fbee1,0x979735a2,0x444488cc,0x17172e39,0xc4c49357,0xa7a755f2, +0x7e7efc82,0x3d3d7a47,0x6464c8ac,0x5d5dbae7,0x1919322b,0x7373e695, +0x6060c0a0,0x81811998,0x4f4f9ed1,0xdcdca37f,0x22224466,0x2a2a547e, +0x90903bab,0x88880b83,0x46468cca,0xeeeec729,0xb8b86bd3,0x1414283c, +0xdedea779,0x5e5ebce2,0xb0b161d,0xdbdbad76,0xe0e0db3b,0x32326456, +0x3a3a744e,0xa0a141e,0x494992db,0x6060c0a,0x2424486c,0x5c5cb8e4, +0xc2c29f5d,0xd3d3bd6e,0xacac43ef,0x6262c4a6,0x919139a8,0x959531a4, +0xe4e4d337,0x7979f28b,0xe7e7d532,0xc8c88b43,0x37376e59,0x6d6ddab7, +0x8d8d018c,0xd5d5b164,0x4e4e9cd2,0xa9a949e0,0x6c6cd8b4,0x5656acfa, +0xf4f4f307,0xeaeacf25,0x6565caaf,0x7a7af48e,0xaeae47e9,0x8081018, +0xbaba6fd5,0x7878f088,0x25254a6f,0x2e2e5c72,0x1c1c3824,0xa6a657f1, +0xb4b473c7,0xc6c69751,0xe8e8cb23,0xdddda17c,0x7474e89c,0x1f1f3e21, +0x4b4b96dd,0xbdbd61dc,0x8b8b0d86,0x8a8a0f85,0x7070e090,0x3e3e7c42, +0xb5b571c4,0x6666ccaa,0x484890d8,0x3030605,0xf6f6f701,0xe0e1c12, +0x6161c2a3,0x35356a5f,0x5757aef9,0xb9b969d0,0x86861791,0xc1c19958, +0x1d1d3a27,0x9e9e27b9,0xe1e1d938,0xf8f8eb13,0x98982bb3,0x11112233, +0x6969d2bb,0xd9d9a970,0x8e8e0789,0x949433a7,0x9b9b2db6,0x1e1e3c22, +0x87871592,0xe9e9c920,0xcece8749,0x5555aaff,0x28285078,0xdfdfa57a, +0x8c8c038f,0xa1a159f8,0x89890980,0xd0d1a17,0xbfbf65da,0xe6e6d731, +0x424284c6,0x6868d0b8,0x414182c3,0x999929b0,0x2d2d5a77,0xf0f1e11, +0xb0b07bcb,0x5454a8fc,0xbbbb6dd6,0x16162c3a}; + +static const MR_WORD rtable1[]= +{0xa7f45150,0x65417e53,0xa4171ac3,0x5e273a96,0x6bab3bcb,0x459d1ff1, +0x58faacab,0x3e34b93,0xfa302055,0x6d76adf6,0x76cc8891,0x4c02f525, +0xd7e54ffc,0xcb2ac5d7,0x44352680,0xa362b58f,0x5ab1de49,0x1bba2567, +0xeea4598,0xc0fe5de1,0x752fc302,0xf04c8112,0x97468da3,0xf9d36bc6, +0x5f8f03e7,0x9c921595,0x7a6dbfeb,0x595295da,0x83bed42d,0x217458d3, +0x69e04929,0xc8c98e44,0x89c2756a,0x798ef478,0x3e58996b,0x71b927dd, +0x4fe1beb6,0xad88f017,0xac20c966,0x3ace7db4,0x4adf6318,0x311ae582, +0x33519760,0x7f536245,0x7764b1e0,0xae6bbb84,0xa081fe1c,0x2b08f994, +0x68487058,0xfd458f19,0x6cde9487,0xf87b52b7,0xd373ab23,0x24b72e2, +0x8f1fe357,0xab55662a,0x28ebb207,0xc2b52f03,0x7bc5869a,0x837d3a5, +0x872830f2,0xa5bf23b2,0x6a0302ba,0x8216ed5c,0x1ccf8a2b,0xb479a792, +0xf207f3f0,0xe2694ea1,0xf4da65cd,0xbe0506d5,0x6234d11f,0xfea6c48a, +0x532e349d,0x55f3a2a0,0xe18a0532,0xebf6a475,0xec830b39,0xef6040aa, +0x9f715e06,0x106ebd51,0x8a213ef9,0x6dd963d,0x53eddae,0xbde64d46, +0x8d5491b5,0x5dc47105,0xd406046f,0x155060ff,0xfb981924,0xe9bdd697, +0x434089cc,0x9ed96777,0x42e8b0bd,0x8b890788,0x5b19e738,0xeec879db, +0xa7ca147,0xf427ce9,0x1e84f8c9,0x0,0x86800983,0xed2b3248, +0x70111eac,0x725a6c4e,0xff0efdfb,0x38850f56,0xd5ae3d1e,0x392d3627, +0xd90f0a64,0xa65c6821,0x545b9bd1,0x2e36243a,0x670a0cb1,0xe757930f, +0x96eeb4d2,0x919b1b9e,0xc5c0804f,0x20dc61a2,0x4b775a69,0x1a121c16, +0xba93e20a,0x2aa0c0e5,0xe0223c43,0x171b121d,0xd090e0b,0xc78bf2ad, +0xa8b62db9,0xa91e14c8,0x19f15785,0x775af4c,0xdd99eebb,0x607fa3fd, +0x2601f79f,0xf5725cbc,0x3b6644c5,0x7efb5b34,0x29438b76,0xc623cbdc, +0xfcedb668,0xf1e4b863,0xdc31d7ca,0x85634210,0x22971340,0x11c68420, +0x244a857d,0x3dbbd2f8,0x32f9ae11,0xa129c76d,0x2f9e1d4b,0x30b2dcf3, +0x52860dec,0xe3c177d0,0x16b32b6c,0xb970a999,0x489411fa,0x64e94722, +0x8cfca8c4,0x3ff0a01a,0x2c7d56d8,0x903322ef,0x4e4987c7,0xd138d9c1, +0xa2ca8cfe,0xbd49836,0x81f5a6cf,0xde7aa528,0x8eb7da26,0xbfad3fa4, +0x9d3a2ce4,0x9278500d,0xcc5f6a9b,0x467e5462,0x138df6c2,0xb8d890e8, +0xf7392e5e,0xafc382f5,0x805d9fbe,0x93d0697c,0x2dd56fa9,0x1225cfb3, +0x99acc83b,0x7d1810a7,0x639ce86e,0xbb3bdb7b,0x7826cd09,0x18596ef4, +0xb79aec01,0x9a4f83a8,0x6e95e665,0xe6ffaa7e,0xcfbc2108,0xe815efe6, +0x9be7bad9,0x366f4ace,0x99fead4,0x7cb029d6,0xb2a431af,0x233f2a31, +0x94a5c630,0x66a235c0,0xbc4e7437,0xca82fca6,0xd090e0b0,0xd8a73315, +0x9804f14a,0xdaec41f7,0x50cd7f0e,0xf691172f,0xd64d768d,0xb0ef434d, +0x4daacc54,0x496e4df,0xb5d19ee3,0x886a4c1b,0x1f2cc1b8,0x5165467f, +0xea5e9d04,0x358c015d,0x7487fa73,0x410bfb2e,0x1d67b35a,0xd2db9252, +0x5610e933,0x47d66d13,0x61d79a8c,0xca1377a,0x14f8598e,0x3c13eb89, +0x27a9ceee,0xc961b735,0xe51ce1ed,0xb1477a3c,0xdfd29c59,0x73f2553f, +0xce141879,0x37c773bf,0xcdf753ea,0xaafd5f5b,0x6f3ddf14,0xdb447886, +0xf3afca81,0xc468b93e,0x3424382c,0x40a3c25f,0xc31d1672,0x25e2bc0c, +0x493c288b,0x950dff41,0x1a83971,0xb30c08de,0xe4b4d89c,0xc1566490, +0x84cb7b61,0xb632d570,0x5c6c4874,0x57b8d042}; + +static const MR_WORD ftable2[]= +{0x63c6a563,0x7cf8847c,0x77ee9977,0x7bf68d7b,0xf2ff0df2,0x6bd6bd6b, +0x6fdeb16f,0xc59154c5,0x30605030,0x1020301,0x67cea967,0x2b567d2b, +0xfee719fe,0xd7b562d7,0xab4de6ab,0x76ec9a76,0xca8f45ca,0x821f9d82, +0xc98940c9,0x7dfa877d,0xfaef15fa,0x59b2eb59,0x478ec947,0xf0fb0bf0, +0xad41ecad,0xd4b367d4,0xa25ffda2,0xaf45eaaf,0x9c23bf9c,0xa453f7a4, +0x72e49672,0xc09b5bc0,0xb775c2b7,0xfde11cfd,0x933dae93,0x264c6a26, +0x366c5a36,0x3f7e413f,0xf7f502f7,0xcc834fcc,0x34685c34,0xa551f4a5, +0xe5d134e5,0xf1f908f1,0x71e29371,0xd8ab73d8,0x31625331,0x152a3f15, +0x4080c04,0xc79552c7,0x23466523,0xc39d5ec3,0x18302818,0x9637a196, +0x50a0f05,0x9a2fb59a,0x70e0907,0x12243612,0x801b9b80,0xe2df3de2, +0xebcd26eb,0x274e6927,0xb27fcdb2,0x75ea9f75,0x9121b09,0x831d9e83, +0x2c58742c,0x1a342e1a,0x1b362d1b,0x6edcb26e,0x5ab4ee5a,0xa05bfba0, +0x52a4f652,0x3b764d3b,0xd6b761d6,0xb37dceb3,0x29527b29,0xe3dd3ee3, +0x2f5e712f,0x84139784,0x53a6f553,0xd1b968d1,0x0,0xedc12ced, +0x20406020,0xfce31ffc,0xb179c8b1,0x5bb6ed5b,0x6ad4be6a,0xcb8d46cb, +0xbe67d9be,0x39724b39,0x4a94de4a,0x4c98d44c,0x58b0e858,0xcf854acf, +0xd0bb6bd0,0xefc52aef,0xaa4fe5aa,0xfbed16fb,0x4386c543,0x4d9ad74d, +0x33665533,0x85119485,0x458acf45,0xf9e910f9,0x2040602,0x7ffe817f, +0x50a0f050,0x3c78443c,0x9f25ba9f,0xa84be3a8,0x51a2f351,0xa35dfea3, +0x4080c040,0x8f058a8f,0x923fad92,0x9d21bc9d,0x38704838,0xf5f104f5, +0xbc63dfbc,0xb677c1b6,0xdaaf75da,0x21426321,0x10203010,0xffe51aff, +0xf3fd0ef3,0xd2bf6dd2,0xcd814ccd,0xc18140c,0x13263513,0xecc32fec, +0x5fbee15f,0x9735a297,0x4488cc44,0x172e3917,0xc49357c4,0xa755f2a7, +0x7efc827e,0x3d7a473d,0x64c8ac64,0x5dbae75d,0x19322b19,0x73e69573, +0x60c0a060,0x81199881,0x4f9ed14f,0xdca37fdc,0x22446622,0x2a547e2a, +0x903bab90,0x880b8388,0x468cca46,0xeec729ee,0xb86bd3b8,0x14283c14, +0xdea779de,0x5ebce25e,0xb161d0b,0xdbad76db,0xe0db3be0,0x32645632, +0x3a744e3a,0xa141e0a,0x4992db49,0x60c0a06,0x24486c24,0x5cb8e45c, +0xc29f5dc2,0xd3bd6ed3,0xac43efac,0x62c4a662,0x9139a891,0x9531a495, +0xe4d337e4,0x79f28b79,0xe7d532e7,0xc88b43c8,0x376e5937,0x6ddab76d, +0x8d018c8d,0xd5b164d5,0x4e9cd24e,0xa949e0a9,0x6cd8b46c,0x56acfa56, +0xf4f307f4,0xeacf25ea,0x65caaf65,0x7af48e7a,0xae47e9ae,0x8101808, +0xba6fd5ba,0x78f08878,0x254a6f25,0x2e5c722e,0x1c38241c,0xa657f1a6, +0xb473c7b4,0xc69751c6,0xe8cb23e8,0xdda17cdd,0x74e89c74,0x1f3e211f, +0x4b96dd4b,0xbd61dcbd,0x8b0d868b,0x8a0f858a,0x70e09070,0x3e7c423e, +0xb571c4b5,0x66ccaa66,0x4890d848,0x3060503,0xf6f701f6,0xe1c120e, +0x61c2a361,0x356a5f35,0x57aef957,0xb969d0b9,0x86179186,0xc19958c1, +0x1d3a271d,0x9e27b99e,0xe1d938e1,0xf8eb13f8,0x982bb398,0x11223311, +0x69d2bb69,0xd9a970d9,0x8e07898e,0x9433a794,0x9b2db69b,0x1e3c221e, +0x87159287,0xe9c920e9,0xce8749ce,0x55aaff55,0x28507828,0xdfa57adf, +0x8c038f8c,0xa159f8a1,0x89098089,0xd1a170d,0xbf65dabf,0xe6d731e6, +0x4284c642,0x68d0b868,0x4182c341,0x9929b099,0x2d5a772d,0xf1e110f, +0xb07bcbb0,0x54a8fc54,0xbb6dd6bb,0x162c3a16}; + +static const MR_WORD rtable2[]= +{0xf45150a7,0x417e5365,0x171ac3a4,0x273a965e,0xab3bcb6b,0x9d1ff145, +0xfaacab58,0xe34b9303,0x302055fa,0x76adf66d,0xcc889176,0x2f5254c, +0xe54ffcd7,0x2ac5d7cb,0x35268044,0x62b58fa3,0xb1de495a,0xba25671b, +0xea45980e,0xfe5de1c0,0x2fc30275,0x4c8112f0,0x468da397,0xd36bc6f9, +0x8f03e75f,0x9215959c,0x6dbfeb7a,0x5295da59,0xbed42d83,0x7458d321, +0xe0492969,0xc98e44c8,0xc2756a89,0x8ef47879,0x58996b3e,0xb927dd71, +0xe1beb64f,0x88f017ad,0x20c966ac,0xce7db43a,0xdf63184a,0x1ae58231, +0x51976033,0x5362457f,0x64b1e077,0x6bbb84ae,0x81fe1ca0,0x8f9942b, +0x48705868,0x458f19fd,0xde94876c,0x7b52b7f8,0x73ab23d3,0x4b72e202, +0x1fe3578f,0x55662aab,0xebb20728,0xb52f03c2,0xc5869a7b,0x37d3a508, +0x2830f287,0xbf23b2a5,0x302ba6a,0x16ed5c82,0xcf8a2b1c,0x79a792b4, +0x7f3f0f2,0x694ea1e2,0xda65cdf4,0x506d5be,0x34d11f62,0xa6c48afe, +0x2e349d53,0xf3a2a055,0x8a0532e1,0xf6a475eb,0x830b39ec,0x6040aaef, +0x715e069f,0x6ebd5110,0x213ef98a,0xdd963d06,0x3eddae05,0xe64d46bd, +0x5491b58d,0xc471055d,0x6046fd4,0x5060ff15,0x981924fb,0xbdd697e9, +0x4089cc43,0xd967779e,0xe8b0bd42,0x8907888b,0x19e7385b,0xc879dbee, +0x7ca1470a,0x427ce90f,0x84f8c91e,0x0,0x80098386,0x2b3248ed, +0x111eac70,0x5a6c4e72,0xefdfbff,0x850f5638,0xae3d1ed5,0x2d362739, +0xf0a64d9,0x5c6821a6,0x5b9bd154,0x36243a2e,0xa0cb167,0x57930fe7, +0xeeb4d296,0x9b1b9e91,0xc0804fc5,0xdc61a220,0x775a694b,0x121c161a, +0x93e20aba,0xa0c0e52a,0x223c43e0,0x1b121d17,0x90e0b0d,0x8bf2adc7, +0xb62db9a8,0x1e14c8a9,0xf1578519,0x75af4c07,0x99eebbdd,0x7fa3fd60, +0x1f79f26,0x725cbcf5,0x6644c53b,0xfb5b347e,0x438b7629,0x23cbdcc6, +0xedb668fc,0xe4b863f1,0x31d7cadc,0x63421085,0x97134022,0xc6842011, +0x4a857d24,0xbbd2f83d,0xf9ae1132,0x29c76da1,0x9e1d4b2f,0xb2dcf330, +0x860dec52,0xc177d0e3,0xb32b6c16,0x70a999b9,0x9411fa48,0xe9472264, +0xfca8c48c,0xf0a01a3f,0x7d56d82c,0x3322ef90,0x4987c74e,0x38d9c1d1, +0xca8cfea2,0xd498360b,0xf5a6cf81,0x7aa528de,0xb7da268e,0xad3fa4bf, +0x3a2ce49d,0x78500d92,0x5f6a9bcc,0x7e546246,0x8df6c213,0xd890e8b8, +0x392e5ef7,0xc382f5af,0x5d9fbe80,0xd0697c93,0xd56fa92d,0x25cfb312, +0xacc83b99,0x1810a77d,0x9ce86e63,0x3bdb7bbb,0x26cd0978,0x596ef418, +0x9aec01b7,0x4f83a89a,0x95e6656e,0xffaa7ee6,0xbc2108cf,0x15efe6e8, +0xe7bad99b,0x6f4ace36,0x9fead409,0xb029d67c,0xa431afb2,0x3f2a3123, +0xa5c63094,0xa235c066,0x4e7437bc,0x82fca6ca,0x90e0b0d0,0xa73315d8, +0x4f14a98,0xec41f7da,0xcd7f0e50,0x91172ff6,0x4d768dd6,0xef434db0, +0xaacc544d,0x96e4df04,0xd19ee3b5,0x6a4c1b88,0x2cc1b81f,0x65467f51, +0x5e9d04ea,0x8c015d35,0x87fa7374,0xbfb2e41,0x67b35a1d,0xdb9252d2, +0x10e93356,0xd66d1347,0xd79a8c61,0xa1377a0c,0xf8598e14,0x13eb893c, +0xa9ceee27,0x61b735c9,0x1ce1ede5,0x477a3cb1,0xd29c59df,0xf2553f73, +0x141879ce,0xc773bf37,0xf753eacd,0xfd5f5baa,0x3ddf146f,0x447886db, +0xafca81f3,0x68b93ec4,0x24382c34,0xa3c25f40,0x1d1672c3,0xe2bc0c25, +0x3c288b49,0xdff4195,0xa8397101,0xc08deb3,0xb4d89ce4,0x566490c1, +0xcb7b6184,0x32d570b6,0x6c48745c,0xb8d04257}; + +static const MR_WORD ftable3[]= +{0xc6a56363,0xf8847c7c,0xee997777,0xf68d7b7b,0xff0df2f2,0xd6bd6b6b, +0xdeb16f6f,0x9154c5c5,0x60503030,0x2030101,0xcea96767,0x567d2b2b, +0xe719fefe,0xb562d7d7,0x4de6abab,0xec9a7676,0x8f45caca,0x1f9d8282, +0x8940c9c9,0xfa877d7d,0xef15fafa,0xb2eb5959,0x8ec94747,0xfb0bf0f0, +0x41ecadad,0xb367d4d4,0x5ffda2a2,0x45eaafaf,0x23bf9c9c,0x53f7a4a4, +0xe4967272,0x9b5bc0c0,0x75c2b7b7,0xe11cfdfd,0x3dae9393,0x4c6a2626, +0x6c5a3636,0x7e413f3f,0xf502f7f7,0x834fcccc,0x685c3434,0x51f4a5a5, +0xd134e5e5,0xf908f1f1,0xe2937171,0xab73d8d8,0x62533131,0x2a3f1515, +0x80c0404,0x9552c7c7,0x46652323,0x9d5ec3c3,0x30281818,0x37a19696, +0xa0f0505,0x2fb59a9a,0xe090707,0x24361212,0x1b9b8080,0xdf3de2e2, +0xcd26ebeb,0x4e692727,0x7fcdb2b2,0xea9f7575,0x121b0909,0x1d9e8383, +0x58742c2c,0x342e1a1a,0x362d1b1b,0xdcb26e6e,0xb4ee5a5a,0x5bfba0a0, +0xa4f65252,0x764d3b3b,0xb761d6d6,0x7dceb3b3,0x527b2929,0xdd3ee3e3, +0x5e712f2f,0x13978484,0xa6f55353,0xb968d1d1,0x0,0xc12ceded, +0x40602020,0xe31ffcfc,0x79c8b1b1,0xb6ed5b5b,0xd4be6a6a,0x8d46cbcb, +0x67d9bebe,0x724b3939,0x94de4a4a,0x98d44c4c,0xb0e85858,0x854acfcf, +0xbb6bd0d0,0xc52aefef,0x4fe5aaaa,0xed16fbfb,0x86c54343,0x9ad74d4d, +0x66553333,0x11948585,0x8acf4545,0xe910f9f9,0x4060202,0xfe817f7f, +0xa0f05050,0x78443c3c,0x25ba9f9f,0x4be3a8a8,0xa2f35151,0x5dfea3a3, +0x80c04040,0x58a8f8f,0x3fad9292,0x21bc9d9d,0x70483838,0xf104f5f5, +0x63dfbcbc,0x77c1b6b6,0xaf75dada,0x42632121,0x20301010,0xe51affff, +0xfd0ef3f3,0xbf6dd2d2,0x814ccdcd,0x18140c0c,0x26351313,0xc32fecec, +0xbee15f5f,0x35a29797,0x88cc4444,0x2e391717,0x9357c4c4,0x55f2a7a7, +0xfc827e7e,0x7a473d3d,0xc8ac6464,0xbae75d5d,0x322b1919,0xe6957373, +0xc0a06060,0x19988181,0x9ed14f4f,0xa37fdcdc,0x44662222,0x547e2a2a, +0x3bab9090,0xb838888,0x8cca4646,0xc729eeee,0x6bd3b8b8,0x283c1414, +0xa779dede,0xbce25e5e,0x161d0b0b,0xad76dbdb,0xdb3be0e0,0x64563232, +0x744e3a3a,0x141e0a0a,0x92db4949,0xc0a0606,0x486c2424,0xb8e45c5c, +0x9f5dc2c2,0xbd6ed3d3,0x43efacac,0xc4a66262,0x39a89191,0x31a49595, +0xd337e4e4,0xf28b7979,0xd532e7e7,0x8b43c8c8,0x6e593737,0xdab76d6d, +0x18c8d8d,0xb164d5d5,0x9cd24e4e,0x49e0a9a9,0xd8b46c6c,0xacfa5656, +0xf307f4f4,0xcf25eaea,0xcaaf6565,0xf48e7a7a,0x47e9aeae,0x10180808, +0x6fd5baba,0xf0887878,0x4a6f2525,0x5c722e2e,0x38241c1c,0x57f1a6a6, +0x73c7b4b4,0x9751c6c6,0xcb23e8e8,0xa17cdddd,0xe89c7474,0x3e211f1f, +0x96dd4b4b,0x61dcbdbd,0xd868b8b,0xf858a8a,0xe0907070,0x7c423e3e, +0x71c4b5b5,0xccaa6666,0x90d84848,0x6050303,0xf701f6f6,0x1c120e0e, +0xc2a36161,0x6a5f3535,0xaef95757,0x69d0b9b9,0x17918686,0x9958c1c1, +0x3a271d1d,0x27b99e9e,0xd938e1e1,0xeb13f8f8,0x2bb39898,0x22331111, +0xd2bb6969,0xa970d9d9,0x7898e8e,0x33a79494,0x2db69b9b,0x3c221e1e, +0x15928787,0xc920e9e9,0x8749cece,0xaaff5555,0x50782828,0xa57adfdf, +0x38f8c8c,0x59f8a1a1,0x9808989,0x1a170d0d,0x65dabfbf,0xd731e6e6, +0x84c64242,0xd0b86868,0x82c34141,0x29b09999,0x5a772d2d,0x1e110f0f, +0x7bcbb0b0,0xa8fc5454,0x6dd6bbbb,0x2c3a1616}; + +static const MR_WORD rtable3[]= +{0x5150a7f4,0x7e536541,0x1ac3a417,0x3a965e27,0x3bcb6bab,0x1ff1459d, +0xacab58fa,0x4b9303e3,0x2055fa30,0xadf66d76,0x889176cc,0xf5254c02, +0x4ffcd7e5,0xc5d7cb2a,0x26804435,0xb58fa362,0xde495ab1,0x25671bba, +0x45980eea,0x5de1c0fe,0xc302752f,0x8112f04c,0x8da39746,0x6bc6f9d3, +0x3e75f8f,0x15959c92,0xbfeb7a6d,0x95da5952,0xd42d83be,0x58d32174, +0x492969e0,0x8e44c8c9,0x756a89c2,0xf478798e,0x996b3e58,0x27dd71b9, +0xbeb64fe1,0xf017ad88,0xc966ac20,0x7db43ace,0x63184adf,0xe582311a, +0x97603351,0x62457f53,0xb1e07764,0xbb84ae6b,0xfe1ca081,0xf9942b08, +0x70586848,0x8f19fd45,0x94876cde,0x52b7f87b,0xab23d373,0x72e2024b, +0xe3578f1f,0x662aab55,0xb20728eb,0x2f03c2b5,0x869a7bc5,0xd3a50837, +0x30f28728,0x23b2a5bf,0x2ba6a03,0xed5c8216,0x8a2b1ccf,0xa792b479, +0xf3f0f207,0x4ea1e269,0x65cdf4da,0x6d5be05,0xd11f6234,0xc48afea6, +0x349d532e,0xa2a055f3,0x532e18a,0xa475ebf6,0xb39ec83,0x40aaef60, +0x5e069f71,0xbd51106e,0x3ef98a21,0x963d06dd,0xddae053e,0x4d46bde6, +0x91b58d54,0x71055dc4,0x46fd406,0x60ff1550,0x1924fb98,0xd697e9bd, +0x89cc4340,0x67779ed9,0xb0bd42e8,0x7888b89,0xe7385b19,0x79dbeec8, +0xa1470a7c,0x7ce90f42,0xf8c91e84,0x0,0x9838680,0x3248ed2b, +0x1eac7011,0x6c4e725a,0xfdfbff0e,0xf563885,0x3d1ed5ae,0x3627392d, +0xa64d90f,0x6821a65c,0x9bd1545b,0x243a2e36,0xcb1670a,0x930fe757, +0xb4d296ee,0x1b9e919b,0x804fc5c0,0x61a220dc,0x5a694b77,0x1c161a12, +0xe20aba93,0xc0e52aa0,0x3c43e022,0x121d171b,0xe0b0d09,0xf2adc78b, +0x2db9a8b6,0x14c8a91e,0x578519f1,0xaf4c0775,0xeebbdd99,0xa3fd607f, +0xf79f2601,0x5cbcf572,0x44c53b66,0x5b347efb,0x8b762943,0xcbdcc623, +0xb668fced,0xb863f1e4,0xd7cadc31,0x42108563,0x13402297,0x842011c6, +0x857d244a,0xd2f83dbb,0xae1132f9,0xc76da129,0x1d4b2f9e,0xdcf330b2, +0xdec5286,0x77d0e3c1,0x2b6c16b3,0xa999b970,0x11fa4894,0x472264e9, +0xa8c48cfc,0xa01a3ff0,0x56d82c7d,0x22ef9033,0x87c74e49,0xd9c1d138, +0x8cfea2ca,0x98360bd4,0xa6cf81f5,0xa528de7a,0xda268eb7,0x3fa4bfad, +0x2ce49d3a,0x500d9278,0x6a9bcc5f,0x5462467e,0xf6c2138d,0x90e8b8d8, +0x2e5ef739,0x82f5afc3,0x9fbe805d,0x697c93d0,0x6fa92dd5,0xcfb31225, +0xc83b99ac,0x10a77d18,0xe86e639c,0xdb7bbb3b,0xcd097826,0x6ef41859, +0xec01b79a,0x83a89a4f,0xe6656e95,0xaa7ee6ff,0x2108cfbc,0xefe6e815, +0xbad99be7,0x4ace366f,0xead4099f,0x29d67cb0,0x31afb2a4,0x2a31233f, +0xc63094a5,0x35c066a2,0x7437bc4e,0xfca6ca82,0xe0b0d090,0x3315d8a7, +0xf14a9804,0x41f7daec,0x7f0e50cd,0x172ff691,0x768dd64d,0x434db0ef, +0xcc544daa,0xe4df0496,0x9ee3b5d1,0x4c1b886a,0xc1b81f2c,0x467f5165, +0x9d04ea5e,0x15d358c,0xfa737487,0xfb2e410b,0xb35a1d67,0x9252d2db, +0xe9335610,0x6d1347d6,0x9a8c61d7,0x377a0ca1,0x598e14f8,0xeb893c13, +0xceee27a9,0xb735c961,0xe1ede51c,0x7a3cb147,0x9c59dfd2,0x553f73f2, +0x1879ce14,0x73bf37c7,0x53eacdf7,0x5f5baafd,0xdf146f3d,0x7886db44, +0xca81f3af,0xb93ec468,0x382c3424,0xc25f40a3,0x1672c31d,0xbc0c25e2, +0x288b493c,0xff41950d,0x397101a8,0x8deb30c,0xd89ce4b4,0x6490c156, +0x7b6184cb,0xd570b632,0x48745c6c,0xd04257b8}; + +#endif + +static MR_WORD pack(const MR_BYTE *b) +{ /* pack bytes into a 32-bit Word */ + return ((MR_WORD)b[3]<<24)|((MR_WORD)b[2]<<16)|((MR_WORD)b[1]<<8)|(MR_WORD)b[0]; +} + +static void unpack(MR_WORD a,MR_BYTE *b) +{ /* unpack bytes from a word */ + b[0]=MR_TOBYTE(a); + b[1]=MR_TOBYTE(a>>8); + b[2]=MR_TOBYTE(a>>16); + b[3]=MR_TOBYTE(a>>24); +} + +/* + +static MR_BYTE xtime(MR_BYTE a) +{ + MR_BYTE b; + if (a&0x80) b=0x1B; + else b=0; + a<<=1; + a^=b; + return a; +} + +*/ + +static MR_BYTE bmul(MR_BYTE x,MR_BYTE y) +{ /* x.y= AntiLog(Log(x) + Log(y)) */ + if (x && y) return ptab[(ltab[x]+ltab[y])%255]; + else return 0; +} + +static MR_WORD SubByte(MR_WORD a) +{ + MR_BYTE b[4]; + unpack(a,b); + b[0]=fbsub[b[0]]; + b[1]=fbsub[b[1]]; + b[2]=fbsub[b[2]]; + b[3]=fbsub[b[3]]; + return pack(b); +} + +static MR_BYTE product(MR_WORD x,MR_WORD y) +{ /* dot product of two 4-byte arrays */ + MR_BYTE xb[4],yb[4]; + unpack(x,xb); + unpack(y,yb); + return bmul(xb[0],yb[0])^bmul(xb[1],yb[1])^bmul(xb[2],yb[2])^bmul(xb[3],yb[3]); +} + +static MR_WORD InvMixCol(MR_WORD x) +{ /* matrix Multiplication */ + MR_WORD y,m; + MR_BYTE b[4]; + + m=pack(InCo); + b[3]=product(m,x); + m=ROTL24(m); + b[2]=product(m,x); + m=ROTL24(m); + b[1]=product(m,x); + m=ROTL24(m); + b[0]=product(m,x); + y=pack(b); + return y; +} + +void aes_reset(aes *a,int mode,char *iv) +{ /* reset mode, or reset iv */ + int i; + a->mode=mode; + for (i=0;i<4*NB;i++) + a->f[i]=0; + if (mode!=MR_ECB && iv!=NULL) + { + for (i=0;i<4*NB;i++) + a->f[i]=iv[i]; + } +} + +void aes_getreg(aes *a,char *ir) +{ + int i; + for (i=0;i<4*NB;i++) ir[i]=a->f[i]; +} + +BOOL aes_init(aes* a,int mode,int nk,char *key,char *iv) +{ /* Key=nk bytes */ + /* currently NB.nk = 16, 24 or 32 */ + /* Key Scheduler. Create expanded encryption key */ + int i,j,k,N,nr; + MR_WORD CipherKey[8]; + + nk/=4; + + if (nk!=4 && nk!=6 && nk!=8) return FALSE; + + /* nr is number of rounds */ + nr=6+nk; + + a->Nk=nk; a->Nr=nr; + + aes_reset(a,mode,iv); + + N=NB*(nr+1); + + for (i=j=0;ifkey[i]=CipherKey[i]; + for (j=nk,k=0;jfkey[j]=a->fkey[j-nk]^SubByte(ROTL24(a->fkey[j-1]))^rco[k]; + if (nk<=6) + { + for (i=1;ifkey[i+j]=a->fkey[i+j-nk]^a->fkey[i+j-1]; + } + else + { + for (i=1;i<4 && (i+j)fkey[i+j]=a->fkey[i+j-nk]^a->fkey[i+j-1]; + if ((j+4)fkey[j+4]=a->fkey[j+4-nk]^SubByte(a->fkey[j+3]); + for (i=5;ifkey[i+j]=a->fkey[i+j-nk]^a->fkey[i+j-1]; + } + } + + /* now for the expanded decrypt key in reverse order */ + + for (j=0;jrkey[j+N-NB]=a->fkey[j]; + for (i=NB;irkey[k+j]=InvMixCol(a->fkey[i+j]); + } + for (j=N-NB;jrkey[j-N+NB]=a->fkey[j]; + + return TRUE; +} + +void aes_ecb_encrypt(aes *a,MR_BYTE *buff) +{ + int i,j,k; + MR_WORD p[4],q[4],*x,*y,*t; + +#ifdef AES_NI_SUPPORT + __m128i ky,m = _mm_loadu_si128((__m128i *) buff); + ky = _mm_loadu_si128((__m128i *) &a->fkey[0]); + m = _mm_xor_si128 (m, ky); + k=NB; + for (i=1;iNr;i++) + { + ky=_mm_loadu_si128((__m128i *) &a->fkey[k]); + m =_mm_aesenc_si128(m, ky); + k+=4; + } + ky=_mm_loadu_si128((__m128i *) &a->fkey[k]); + m=_mm_aesenclast_si128(m, ky); + + _mm_storeu_si128((__m128i *)buff, m); +#else + + for (i=j=0;ifkey[i]; + } + + k=NB; + x=p; y=q; + +/* State alternates between x and y */ + for (i=1;iNr;i++) + { /* Nr is number of rounds. May be odd. */ +#ifndef MR_SMALL_AES + y[0]=a->fkey[k]^ftable[MR_TOBYTE(x[0])]^ + ftable1[MR_TOBYTE(x[1]>>8)]^ + ftable2[MR_TOBYTE(x[2]>>16)]^ + ftable3[x[3]>>24]; + y[1]=a->fkey[k+1]^ftable[MR_TOBYTE(x[1])]^ + ftable1[MR_TOBYTE(x[2]>>8)]^ + ftable2[MR_TOBYTE(x[3]>>16)]^ + ftable3[x[0]>>24]; + y[2]=a->fkey[k+2]^ftable[MR_TOBYTE(x[2])]^ + ftable1[MR_TOBYTE(x[3]>>8)]^ + ftable2[MR_TOBYTE(x[0]>>16)]^ + ftable3[x[1]>>24]; + y[3]=a->fkey[k+3]^ftable[MR_TOBYTE(x[3])]^ + ftable1[MR_TOBYTE(x[0]>>8)]^ + ftable2[MR_TOBYTE(x[1]>>16)]^ + ftable3[x[2]>>24]; +#else + y[0]=a->fkey[k]^ftable[MR_TOBYTE(x[0])]^ + ROTL8(ftable[MR_TOBYTE(x[1]>>8)])^ + ROTL16(ftable[MR_TOBYTE(x[2]>>16)])^ + ROTL24(ftable[x[3]>>24]); + y[1]=a->fkey[k+1]^ftable[MR_TOBYTE(x[1])]^ + ROTL8(ftable[MR_TOBYTE(x[2]>>8)])^ + ROTL16(ftable[MR_TOBYTE(x[3]>>16)])^ + ROTL24(ftable[x[0]>>24]); + y[2]=a->fkey[k+2]^ftable[MR_TOBYTE(x[2])]^ + ROTL8(ftable[MR_TOBYTE(x[3]>>8)])^ + ROTL16(ftable[MR_TOBYTE(x[0]>>16)])^ + ROTL24(ftable[x[1]>>24]); + y[3]=a->fkey[k+3]^ftable[MR_TOBYTE(x[3])]^ + ROTL8(ftable[MR_TOBYTE(x[0]>>8)])^ + ROTL16(ftable[MR_TOBYTE(x[1]>>16)])^ + ROTL24(ftable[x[2]>>24]); +#endif + k+=4; + t=x; x=y; y=t; /* swap pointers */ + } + +/* Last Round */ + + y[0]=a->fkey[k]^(MR_WORD)fbsub[MR_TOBYTE(x[0])]^ + ROTL8((MR_WORD)fbsub[MR_TOBYTE(x[1]>>8)])^ + ROTL16((MR_WORD)fbsub[MR_TOBYTE(x[2]>>16)])^ + ROTL24((MR_WORD)fbsub[x[3]>>24]); + y[1]=a->fkey[k+1]^(MR_WORD)fbsub[MR_TOBYTE(x[1])]^ + ROTL8((MR_WORD)fbsub[MR_TOBYTE(x[2]>>8)])^ + ROTL16((MR_WORD)fbsub[MR_TOBYTE(x[3]>>16)])^ + ROTL24((MR_WORD)fbsub[x[0]>>24]); + y[2]=a->fkey[k+2]^(MR_WORD)fbsub[MR_TOBYTE(x[2])]^ + ROTL8((MR_WORD)fbsub[MR_TOBYTE(x[3]>>8)])^ + ROTL16((MR_WORD)fbsub[MR_TOBYTE(x[0]>>16)])^ + ROTL24((MR_WORD)fbsub[x[1]>>24]); + y[3]=a->fkey[k+3]^(MR_WORD)fbsub[MR_TOBYTE(x[3])]^ + ROTL8((MR_WORD)fbsub[MR_TOBYTE(x[0]>>8)])^ + ROTL16((MR_WORD)fbsub[MR_TOBYTE(x[1]>>16)])^ + ROTL24((MR_WORD)fbsub[x[2]>>24]); + + for (i=j=0;irkey[0]); + m = _mm_xor_si128 (m, ky); + k=NB; + for (i=1;iNr;i++) + { + ky=_mm_loadu_si128((__m128i *) &a->rkey[k]); + m =_mm_aesdec_si128 (m, ky); + k+=4; + } + ky=_mm_loadu_si128((__m128i *) &a->rkey[k]); + m=_mm_aesdeclast_si128(m, ky); + + _mm_storeu_si128((__m128i *)buff, m); +#else + + for (i=j=0;irkey[i]; + } + + k=NB; + x=p; y=q; + +/* State alternates between x and y */ + for (i=1;iNr;i++) + { /* Nr is number of rounds. May be odd. */ +#ifndef MR_SMALL_AES + y[0]=a->rkey[k]^rtable[MR_TOBYTE(x[0])]^ + rtable1[MR_TOBYTE(x[3]>>8)]^ + rtable2[MR_TOBYTE(x[2]>>16)]^ + rtable3[x[1]>>24]; + y[1]=a->rkey[k+1]^rtable[MR_TOBYTE(x[1])]^ + rtable1[MR_TOBYTE(x[0]>>8)]^ + rtable2[MR_TOBYTE(x[3]>>16)]^ + rtable3[x[2]>>24]; + y[2]=a->rkey[k+2]^rtable[MR_TOBYTE(x[2])]^ + rtable1[MR_TOBYTE(x[1]>>8)]^ + rtable2[MR_TOBYTE(x[0]>>16)]^ + rtable3[x[3]>>24]; + y[3]=a->rkey[k+3]^rtable[MR_TOBYTE(x[3])]^ + rtable1[MR_TOBYTE(x[2]>>8)]^ + rtable2[MR_TOBYTE(x[1]>>16)]^ + rtable3[x[0]>>24]; +#else + y[0]=a->rkey[k]^rtable[MR_TOBYTE(x[0])]^ + ROTL8(rtable[MR_TOBYTE(x[3]>>8)])^ + ROTL16(rtable[MR_TOBYTE(x[2]>>16)])^ + ROTL24(rtable[x[1]>>24]); + y[1]=a->rkey[k+1]^rtable[MR_TOBYTE(x[1])]^ + ROTL8(rtable[MR_TOBYTE(x[0]>>8)])^ + ROTL16(rtable[MR_TOBYTE(x[3]>>16)])^ + ROTL24(rtable[x[2]>>24]); + y[2]=a->rkey[k+2]^rtable[MR_TOBYTE(x[2])]^ + ROTL8(rtable[MR_TOBYTE(x[1]>>8)])^ + ROTL16(rtable[MR_TOBYTE(x[0]>>16)])^ + ROTL24(rtable[x[3]>>24]); + y[3]=a->rkey[k+3]^rtable[MR_TOBYTE(x[3])]^ + ROTL8(rtable[MR_TOBYTE(x[2]>>8)])^ + ROTL16(rtable[MR_TOBYTE(x[1]>>16)])^ + ROTL24(rtable[x[0]>>24]); +#endif + k+=4; + t=x; x=y; y=t; /* swap pointers */ + } + +/* Last Round */ + y[0]=a->rkey[k]^(MR_WORD)rbsub[MR_TOBYTE(x[0])]^ + ROTL8((MR_WORD)rbsub[MR_TOBYTE(x[3]>>8)])^ + ROTL16((MR_WORD)rbsub[MR_TOBYTE(x[2]>>16)])^ + ROTL24((MR_WORD)rbsub[x[1]>>24]); + y[1]=a->rkey[k+1]^(MR_WORD)rbsub[MR_TOBYTE(x[1])]^ + ROTL8((MR_WORD)rbsub[MR_TOBYTE(x[0]>>8)])^ + ROTL16((MR_WORD)rbsub[MR_TOBYTE(x[3]>>16)])^ + ROTL24((MR_WORD)rbsub[x[2]>>24]); + y[2]=a->rkey[k+2]^(MR_WORD)rbsub[MR_TOBYTE(x[2])]^ + ROTL8((MR_WORD)rbsub[MR_TOBYTE(x[1]>>8)])^ + ROTL16((MR_WORD)rbsub[MR_TOBYTE(x[0]>>16)])^ + ROTL24((MR_WORD)rbsub[x[3]>>24]); + y[3]=a->rkey[k+3]^(MR_WORD)rbsub[MR_TOBYTE(x[3])]^ + ROTL8((MR_WORD)rbsub[MR_TOBYTE(x[2]>>8)])^ + ROTL16((MR_WORD)rbsub[MR_TOBYTE(x[1]>>16)])^ + ROTL24((MR_WORD)rbsub[x[0]>>24]); + + for (i=j=0;imode) + { + case MR_ECB: + aes_ecb_encrypt(a,(MR_BYTE *)buff); + return 0; + case MR_CBC: + for (j=0;j<4*NB;j++) buff[j]^=a->f[j]; + aes_ecb_encrypt(a,(MR_BYTE *)buff); + for (j=0;j<4*NB;j++) a->f[j]=buff[j]; + return 0; + + case MR_CFB1: + case MR_CFB2: + case MR_CFB4: + bytes=a->mode-MR_CFB1+1; + for (j=0;jf[j]; + for (j=0;j<4*NB;j++) st[j]=a->f[j]; + for (j=bytes;j<4*NB;j++) a->f[j-bytes]=a->f[j]; + aes_ecb_encrypt(a,(MR_BYTE *)st); + for (j=0;jf[16-bytes+j]=buff[j]; + } + return fell_off; + + case MR_OFB1: + case MR_OFB2: + case MR_OFB4: + case MR_OFB8: + case MR_OFB16: + + bytes=a->mode-MR_OFB1+1; + aes_ecb_encrypt(a,(MR_BYTE *)(a->f)); + for (j=0;jf[j]; + return 0; + + case MR_PCFB1: /* error propagating CFB */ + case MR_PCFB2: + case MR_PCFB4: + bytes=a->mode-MR_PCFB1+1; + for (j=0;jf[j]; + for (j=0;j<4*NB;j++) st[j]=a->f[j]; + for (j=bytes;j<4*NB;j++) a->f[j-bytes]=a->f[j]; + aes_ecb_encrypt(a,(MR_BYTE *)st); + for (j=0;jf[16-bytes+j]=buff[j]^st[16-bytes+j]; + } + return fell_off; + + default: + return 0; + } +} + +mr_unsign32 aes_decrypt(aes *a,char *buff) +{ + int j,bytes; + char st[16]; + mr_unsign32 fell_off; + + /* Supported modes of operation */ + fell_off=0; + switch (a->mode) + { + case MR_ECB: + aes_ecb_decrypt(a,(MR_BYTE *)buff); + return 0; + case MR_CBC: + for (j=0;j<4*NB;j++) + { + st[j]=a->f[j]; + a->f[j]=buff[j]; + } + aes_ecb_decrypt(a,(MR_BYTE *)buff); + for (j=0;j<4*NB;j++) + { + buff[j]^=st[j]; + st[j]=0; + } + return 0; + case MR_CFB1: + case MR_CFB2: + case MR_CFB4: + bytes=a->mode-MR_CFB1+1; + for (j=0;jf[j]; + for (j=0;j<4*NB;j++) st[j]=a->f[j]; + for (j=bytes;j<4*NB;j++) a->f[j-bytes]=a->f[j]; + aes_ecb_encrypt(a,(MR_BYTE *)st); + for (j=0;jf[16-bytes+j]=buff[j]; + buff[j]^=st[j]; + } + return fell_off; + case MR_OFB1: + case MR_OFB2: + case MR_OFB4: + case MR_OFB8: + case MR_OFB16: + bytes=a->mode-MR_OFB1+1; + aes_ecb_encrypt(a,(MR_BYTE *)(a->f)); + for (j=0;jf[j]; + return 0; + + case MR_PCFB1: /* error propagating CFB */ + case MR_PCFB2: + case MR_PCFB4: + + bytes=a->mode-MR_PCFB1+1; + for (j=0;jf[j]; + for (j=0;j<4*NB;j++) st[j]=a->f[j]; + for (j=bytes;j<4*NB;j++) a->f[j-bytes]=a->f[j]; + aes_ecb_encrypt(a,(MR_BYTE *)st); + for (j=0;jf[16-bytes+j]=buff[j]^st[16-bytes+j]; + buff[j]^=st[j]; + } + return fell_off; + default: + return 0; + } +} + +void aes_end(aes *a) +{ /* clean up */ + int i; + for (i=0;iNr+1);i++) + a->fkey[i]=a->rkey[i]=0; + for (i=0;i<4*NB;i++) + a->f[i]=0; +} + +/* +int main() +{ + int i,j,nk; + aes a; + MR_BYTE y,x,m; + char key[32]; + char block[16]; + char iv[16]; + for (i=0;i<32;i++) key[i]=0; + key[0]=1; + for (i=0;i<16;i++) iv[i]=i; + for (i=0;i<16;i++) block[i]=i; + + for (nk=16;nk<=32;nk+=8) + { + printf("\nKey Size= %d bits\n",nk*8); + if (!aes_init(&a,MR_CBC,nk,key,iv)) + { + printf("Failed to Initialize\n"); + return 0; + } + + printf("Plain= "); + for (i=0;i<4*NB;i++) printf("%02x",block[i]); + printf("\n"); + aes_encrypt(&a,block); + printf("Encrypt= "); + for (i=0;i<4*NB;i++) printf("%02x",(unsigned char)block[i]); + printf("\n"); + aes_reset(&a,MR_CBC,iv); + aes_decrypt(&a,block); + printf("Decrypt= "); + for (i=0;i<4*NB;i++) printf("%02x",block[i]); + printf("\n"); + + aes_end(&a); + } + return 0; +} +*/ + + diff --git a/miracl/source/mralloc.c b/miracl/source/mralloc.c new file mode 100644 index 0000000..e2d0309 --- /dev/null +++ b/miracl/source/mralloc.c @@ -0,0 +1,85 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL memory allocation routines + * mralloc.c + * + * MIRACL C Memory allocation/deallocation + * Can be replaced with special user-defined routines + * Default is to standard system routines + * + * NOTE: uses calloc() which initialises memory to Zero, so make sure + * any substituted routine does the same! + */ + +#include "miracl.h" +#include + +#ifndef MR_STATIC + +miracl *mr_first_alloc() +{ + return (miracl *)calloc(1,sizeof(miracl)); +} + +void *mr_alloc(_MIPD_ int num,int size) +{ + char *p; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip==NULL) + { + p=(char *)calloc(num,size); + return (void *)p; + } + + if (mr_mip->ERNUM) return NULL; + + p=(char *)calloc(num,size); + if (p==NULL) mr_berror(_MIPP_ MR_ERR_OUT_OF_MEMORY); + return (void *)p; + +} + +void mr_free(void *addr) +{ + if (addr==NULL) return; + free(addr); + return; +} + +#endif diff --git a/miracl/source/mrarth0.c b/miracl/source/mrarth0.c new file mode 100644 index 0000000..41d9633 --- /dev/null +++ b/miracl/source/mrarth0.c @@ -0,0 +1,320 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL arithmetic routines 0 - Add and subtract routines + * mrarth0.c + * + */ +#include "miracl.h" + +void mr_padd(_MIPD_ big x,big y,big z) +{ /* add two big numbers, z=x+y where * + * x and y are positive */ + int i,lx,ly,lz,la; + mr_small carry,psum; + mr_small *gx,*gy,*gz; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + lx = (int)x->len; + ly = (int)y->len; + + if (ly>lx) + { + lz=ly; + la=lx; + if (x!=z) copy(y,z); + else la=ly; + } + else + { + lz=lx; + la=ly; + if (y!=z) copy(x,z); + else la=lx; + } + carry=0; + z->len=lz; + gx=x->w; gy=y->w; gz=z->w; + if (lznib || !mr_mip->check) z->len++; +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif + for (i=0;igx[i]) carry=0; + else if (psum0;i++ ) + { /* add by columns to the length of larger number (if there is a carry) */ + psum=gx[i]+gy[i]+carry; + if (psum>gx[i]) carry=0; + else if (psumcheck && i>=mr_mip->nib) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + return; + } + gz[i]=carry; + } +#ifndef MR_SIMPLE_BASE + } + else + { + for (i=0;i=mr_mip->base) + { /* set carry */ + carry=1; + psum-=mr_mip->base; + } + gz[i]=psum; + } + for (;i0;i++) + { + psum=gx[i]+gy[i]+carry; + carry=0; + if (psum>=mr_mip->base) + { /* set carry */ + carry=1; + psum-=mr_mip->base; + } + gz[i]=psum; + } + if (carry) + { /* carry left over - possible overflow */ + if (mr_mip->check && i>=mr_mip->nib) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + return; + } + gz[i]=carry; + } + } +#endif + if (gz[z->len-1]==0) z->len--; + +} + +void mr_psub(_MIPD_ big x,big y,big z) +{ /* subtract two big numbers z=x-y * + * where x and y are positive and x>y */ + int i,lx,ly; + mr_small borrow,pdiff; + mr_small *gx,*gy,*gz; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + lx = (int)x->len; + ly = (int)y->len; + if (ly>lx) + { + mr_berror(_MIPP_ MR_ERR_NEG_RESULT); + return; + } + if (y!=z) copy(x,z); + else ly=lx; + z->len=lx; + gx=x->w; gy=y->w; gz=z->w; + borrow=0; +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif + for (i=0;i0;i++) + { /* subtract by columns */ + if (i>lx) + { + mr_berror(_MIPP_ MR_ERR_NEG_RESULT); + return; + } + pdiff=gx[i]-gy[i]-borrow; + if (pdiffgx[i]) borrow=1; + gz[i]=pdiff; + } +#ifndef MR_SIMPLE_BASE + } + else for (i=0;i0;i++) + { /* subtract by columns */ + if (i>lx) + { + mr_berror(_MIPP_ MR_ERR_NEG_RESULT); + return; + } + pdiff=gy[i]+borrow; + borrow=0; + if (gx[i]>=pdiff) pdiff=gx[i]-pdiff; + else + { /* set borrow */ + pdiff=mr_mip->base+gx[i]-pdiff; + borrow=1; + } + gz[i]=pdiff; + } +#endif + mr_lzero(z); +} + +static void mr_select(_MIPD_ big x,int d,big y,big z) +{ /* perform required add or subtract operation */ + int sx,sy,sz,jf,xgty; +#ifdef MR_FLASH + if (mr_notint(x) || mr_notint(y)) + { + mr_berror(_MIPP_ MR_ERR_INT_OP); + return; + } +#endif + sx=exsign(x); + sy=exsign(y); + sz=0; + x->len&=MR_OBITS; /* force operands to be positive */ + y->len&=MR_OBITS; + xgty=mr_compare(x,y); + jf=(1+sx)+(1+d*sy)/2; + switch (jf) + { /* branch according to signs of operands */ + case 0: + if (xgty>=0) + mr_padd(_MIPP_ x,y,z); + else + mr_padd(_MIPP_ y,x,z); + sz=MINUS; + break; + case 1: + if (xgty<=0) + { + mr_psub(_MIPP_ y,x,z); + sz=PLUS; + } + else + { + mr_psub(_MIPP_ x,y,z); + sz=MINUS; + } + break; + case 2: + if (xgty>=0) + { + mr_psub(_MIPP_ x,y,z); + sz=PLUS; + } + else + { + mr_psub(_MIPP_ y,x,z); + sz=MINUS; + } + break; + case 3: + if (xgty>=0) + mr_padd(_MIPP_ x,y,z); + else + mr_padd(_MIPP_ y,x,z); + sz=PLUS; + break; + } + if (sz<0) z->len^=MR_MSBIT; /* set sign of result */ + if (x!=z && sx<0) x->len^=MR_MSBIT; /* restore signs to operands */ + if (y!=z && y!=x && sy<0) y->len^=MR_MSBIT; +} + +void add(_MIPD_ big x,big y,big z) +{ /* add two signed big numbers together z=x+y */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(27) + + mr_select(_MIPP_ x,PLUS,y,z); + + MR_OUT +} + +void subtract(_MIPD_ big x,big y,big z) +{ /* subtract two big signed numbers z=x-y */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(28) + + mr_select(_MIPP_ x,MINUS,y,z); + + MR_OUT +} + +void incr(_MIPD_ big x,int n,big z) +{ /* add int to big number: z=x+n */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(7) + + convert(_MIPP_ n,mr_mip->w0); + mr_select(_MIPP_ x,PLUS,mr_mip->w0,z); + + MR_OUT +} + +void decr(_MIPD_ big x,int n,big z) +{ /* subtract int from big number: z=x-n */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(8) + + convert(_MIPP_ n,mr_mip->w0); + mr_select(_MIPP_ x,MINUS,mr_mip->w0,z); + + MR_OUT +} + diff --git a/miracl/source/mrarth1.c b/miracl/source/mrarth1.c new file mode 100644 index 0000000..e1e5381 --- /dev/null +++ b/miracl/source/mrarth1.c @@ -0,0 +1,1068 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ + +/* + * + * MIRACL arithmetic routines 1 - multiplying and dividing BIG NUMBERS by + * integer numbers. + * mrarth1.c + * + */ + +#include "miracl.h" + +#ifdef MR_FP +#include +#endif + +#ifdef MR_WIN64 +#include +#endif + +#ifdef MR_FP_ROUNDING +#ifdef __GNUC__ +#include +#endif + +/* Invert n and set FP rounding. + * Set to round up + * Calculate 1/n + * set to round down (towards zero) + * If rounding cannot be controlled, this function returns 0.0 */ + +mr_large mr_invert(mr_small n) +{ + mr_large inn; + int up= 0x1BFF; + +#ifdef _MSC_VER + #ifdef MR_NOASM +#define NO_EXTENDED + #endif +#endif + +#ifdef NO_EXTENDED + int down=0x1EFF; +#else + int down=0x1FFF; +#endif + +#ifdef __TURBOC__ + asm + { + fldcw WORD PTR up + fld1 + fld QWORD PTR n; + fdiv + fstp TBYTE PTR inn; + fldcw WORD PTR down; + } + return inn; +#endif +#ifdef _MSC_VER + _asm + { + fldcw WORD PTR up + fld1 + fld QWORD PTR n; + fdiv + fstp QWORD PTR inn; + fldcw WORD PTR down; + } + return inn; +#endif +#ifdef __GNUC__ +#ifdef i386 + __asm__ __volatile__ ( + "fldcw %2\n" + "fld1\n" + "fldl %1\n" + "fdivrp\n" + "fstpt %0\n" + "fldcw %3\n" + : "=m"(inn) + : "m"(n),"m"(up),"m"(down) + : "memory" + ); + return inn; +#else + fpsetround(FP_RP); + inn=(mr_large)1.0/n; + fpsetround(FP_RZ); + return inn; +#endif +#endif + return 0.0L; +} + +#endif + +void mr_pmul(_MIPD_ big x,mr_small sn,big z) +{ + int m,xl; + mr_lentype sx; + mr_small carry,*xg,*zg; + +#ifdef MR_ITANIUM + mr_small tm; +#endif +#ifdef MR_WIN64 + mr_small tm; +#endif +#ifdef MR_NOASM + union doubleword dble; + mr_large dbled; + mr_large ldres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (x!=z) + { + zero(z); + if (sn==0) return; + } + else if (sn==0) + { + zero(z); + return; + } + m=0; + carry=0; + sx=x->len&MR_MSBIT; + xl=(int)(x->len&MR_OBITS); + +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH + xg=x->w; zg=z->w; +/* inline 8086 assembly - substitutes for loop below */ +#ifdef INLINE_ASM +#if INLINE_ASM == 1 + ASM cld + ASM mov cx,xl + ASM or cx,cx + ASM je out1 +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les di,DWORD PTR zg + ASM lds si,DWORD PTR xg +#else + ASM mov ax,ds + ASM mov es,ax + ASM mov di,zg + ASM mov si,xg +#endif + ASM mov bx,sn + ASM push bp + ASM xor bp,bp + tcl1: + ASM lodsw + ASM mul bx + ASM add ax,bp + ASM adc dx,0 + ASM stosw + ASM mov bp,dx + ASM loop tcl1 + + ASM mov ax,bp + ASM pop bp +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif + ASM mov carry,ax + out1: +#endif +#if INLINE_ASM == 2 + ASM cld + ASM mov cx,xl + ASM or cx,cx + ASM je out1 +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les di,DWORD PTR zg + ASM lds si,DWORD PTR xg +#else + ASM mov ax,ds + ASM mov es,ax + ASM mov di,zg + ASM mov si,xg +#endif + ASM mov ebx,sn + ASM push ebp + ASM xor ebp,ebp + tcl1: + ASM lodsd + ASM mul ebx + ASM add eax,ebp + ASM adc edx,0 + ASM stosd + ASM mov ebp,edx + ASM loop tcl1 + + ASM mov eax,ebp + ASM pop ebp +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif + ASM mov carry,eax + out1: +#endif +#if INLINE_ASM == 3 + ASM mov ecx,xl + ASM or ecx,ecx + ASM je out1 + ASM mov ebx,sn + ASM mov edi,zg + ASM mov esi,xg + ASM push ebp + ASM xor ebp,ebp + tcl1: + ASM mov eax,[esi] + ASM add esi,4 + ASM mul ebx + ASM add eax,ebp + ASM adc edx,0 + ASM mov [edi],eax + ASM add edi,4 + ASM mov ebp,edx + ASM dec ecx + ASM jnz tcl1 + + ASM mov eax,ebp + ASM pop ebp + ASM mov carry,eax + out1: +#endif +#if INLINE_ASM == 4 + + ASM ( + "movl %4,%%ecx\n" + "orl %%ecx,%%ecx\n" + "je 1f\n" + "movl %3,%%ebx\n" + "movl %1,%%edi\n" + "movl %2,%%esi\n" + "pushl %%ebp\n" + "xorl %%ebp,%%ebp\n" + "0:\n" + "movl (%%esi),%%eax\n" + "addl $4,%%esi\n" + "mull %%ebx\n" + "addl %%ebp,%%eax\n" + "adcl $0,%%edx\n" + "movl %%eax,(%%edi)\n" + "addl $4,%%edi\n" + "movl %%edx,%%ebp\n" + "decl %%ecx\n" + "jnz 0b\n" + + "movl %%ebp,%%eax\n" + "popl %%ebp\n" + "movl %%eax,%0\n" + "1:" + :"=m"(carry) + :"m"(zg),"m"(xg),"m"(sn),"m"(xl) + :"eax","edi","esi","ebx","ecx","edx","memory" + ); + +#endif +#endif +#ifndef INLINE_ASM + for (m=0;mw[m]*sn+carry; + carry=dble.h[MR_TOP]; + z->w[m]=dble.h[MR_BOT]; + } +#else + carry=muldvd(x->w[m],sn,carry,&z->w[m]); +#endif +#endif + if (carry>0) + { + m=xl; + if (m>=mr_mip->nib && mr_mip->check) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + return; + } + z->w[m]=carry; + z->len=m+1; + } + else z->len=xl; +#endif +#ifndef MR_SIMPLE_BASE + } + else while (m0) + { /* multiply each digit of x by n */ + + if (m>mr_mip->nib && mr_mip->check) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + return; + } +#ifdef MR_NOASM + dbled=(mr_large)x->w[m]*sn+carry; + #ifdef MR_FP_ROUNDING + carry=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); + #else + #ifndef MR_FP + if (mr_mip->base==mr_mip->base2) + carry=(mr_small)(dbled>>mr_mip->lg2b); + else + #endif + carry=(mr_small)MR_LROUND(dbled/mr_mip->base); + #endif + z->w[m]=(mr_small)(dbled-(mr_large)carry*mr_mip->base); +#else + #ifdef MR_FP_ROUNDING + carry=imuldiv(x->w[m],sn,carry,mr_mip->base,mr_mip->inverse_base,&z->w[m]); + #else + carry=muldiv(x->w[m],sn,carry,mr_mip->base,&z->w[m]); + #endif +#endif + + m++; + z->len=m; + } +#endif + if (z->len!=0) z->len|=sx; +} + +void premult(_MIPD_ big x,int n,big z) +{ /* premultiply a big number by an int z=x.n */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(9) + + +#ifdef MR_FLASH + if (mr_notint(x)) + { + mr_berror(_MIPP_ MR_ERR_INT_OP); + MR_OUT + return; + } +#endif + if (n==0) /* test for some special cases */ + { + zero(z); + MR_OUT + return; + } + if (n==1) + { + copy(x,z); + MR_OUT + return; + } + if (n<0) + { + n=(-n); + mr_pmul(_MIPP_ x,(mr_small)n,z); + if (z->len!=0) z->len^=MR_MSBIT; + } + else mr_pmul(_MIPP_ x,(mr_small)n,z); + MR_OUT +} + +#ifdef MR_FP_ROUNDING +mr_small mr_sdiv(_MIPD_ big x,mr_small sn,mr_large isn,big z) +#else +mr_small mr_sdiv(_MIPD_ big x,mr_small sn,big z) +#endif +{ + int i,xl; + mr_small sr,*xg,*zg; +#ifdef MR_NOASM + union doubleword dble; + mr_large dbled; + mr_large ldres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + sr=0; + xl=(int)(x->len&MR_OBITS); + if (x!=z) zero(z); +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH + xg=x->w; zg=z->w; +/* inline - substitutes for loop below */ +#ifdef INLINE_ASM +#if INLINE_ASM == 1 + ASM std + ASM mov cx,xl + ASM or cx,cx + ASM je out2 + ASM mov bx,cx + ASM shl bx,1 + ASM sub bx,2 +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les di,DWORD PTR zg + ASM lds si,DWORD PTR xg +#else + ASM mov ax,ds + ASM mov es,ax + ASM mov di,zg + ASM mov si,xg +#endif + ASM add si,bx + ASM add di,bx + ASM mov bx,sn + ASM push bp + ASM xor bp,bp + tcl2: + ASM mov dx,bp + ASM lodsw + ASM div bx + ASM mov bp,dx + ASM stosw + ASM loop tcl2 + + ASM mov ax,bp + ASM pop bp +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif + ASM mov sr,ax + out2: + ASM cld +#endif +#if INLINE_ASM == 2 + ASM std + ASM mov cx,xl + ASM or cx,cx + ASM je out2 + ASM mov bx,cx + ASM shl bx,2 + ASM sub bx,4 +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les di,DWORD PTR zg + ASM lds si,DWORD PTR xg +#else + ASM mov ax,ds + ASM mov es,ax + ASM mov di, zg + ASM mov si, xg +#endif + ASM add si,bx + ASM add di,bx + ASM mov ebx,sn + ASM push ebp + ASM xor ebp,ebp + tcl2: + ASM mov edx,ebp + ASM lodsd + ASM div ebx + ASM mov ebp,edx + ASM stosd + ASM loop tcl2 + + ASM mov eax,ebp + ASM pop ebp +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif + ASM mov sr,eax + out2: + ASM cld +#endif +#if INLINE_ASM == 3 + ASM mov ecx,xl + ASM or ecx,ecx + ASM je out2 + ASM mov ebx,ecx + ASM shl ebx,2 + ASM mov esi, xg + ASM add esi,ebx + ASM mov edi, zg + ASM add edi,ebx + ASM mov ebx,sn + ASM push ebp + ASM xor ebp,ebp + tcl2: + ASM sub esi,4 + ASM mov edx,ebp + ASM mov eax,[esi] + ASM div ebx + ASM sub edi,4 + ASM mov ebp,edx + ASM mov [edi],eax + ASM dec ecx + ASM jnz tcl2 + + ASM mov eax,ebp + ASM pop ebp + ASM mov sr,eax + out2: + ASM nop +#endif +#if INLINE_ASM == 4 + + ASM ( + "movl %4,%%ecx\n" + "orl %%ecx,%%ecx\n" + "je 3f\n" + "movl %%ecx,%%ebx\n" + "shll $2,%%ebx\n" + "movl %2,%%esi\n" + "addl %%ebx,%%esi\n" + "movl %1,%%edi\n" + "addl %%ebx,%%edi\n" + "movl %3,%%ebx\n" + "pushl %%ebp\n" + "xorl %%ebp,%%ebp\n" + "2:\n" + "subl $4,%%esi\n" + "movl %%ebp,%%edx\n" + "movl (%%esi),%%eax\n" + "divl %%ebx\n" + "subl $4,%%edi\n" + "movl %%edx,%%ebp\n" + "movl %%eax,(%%edi)\n" + "decl %%ecx\n" + "jnz 2b\n" + + "movl %%ebp,%%eax\n" + "popl %%ebp\n" + "movl %%eax,%0\n" + "3:" + "nop" + :"=m"(sr) + :"m"(zg),"m"(xg),"m"(sn),"m"(xl) + :"eax","edi","esi","ebx","ecx","edx","memory" + ); +#endif +#endif +#ifndef INLINE_ASM + for (i=xl-1;i>=0;i--) + { +#ifdef MR_NOASM + dble.h[MR_BOT]=x->w[i]; + dble.h[MR_TOP]=sr; + z->w[i]=(mr_small)(dble.d/sn); + sr=(mr_small)(dble.d-(mr_large)z->w[i]*sn); +#else + z->w[i]=muldvm(sr,x->w[i],sn,&sr); +#endif + } +#endif +#endif +#ifndef MR_SIMPLE_BASE + } + else for (i=xl-1;i>=0;i--) + { /* divide each digit of x by n */ +#ifdef MR_NOASM + dbled=(mr_large)sr*mr_mip->base+x->w[i]; +#ifdef MR_FP_ROUNDING + z->w[i]=(mr_small)MR_LROUND(dbled*isn); +#else + z->w[i]=(mr_small)MR_LROUND(dbled/sn); +#endif + sr=(mr_small)(dbled-(mr_large)z->w[i]*sn); +#else +#ifdef MR_FP_ROUNDING + z->w[i]=imuldiv(sr,mr_mip->base,x->w[i],sn,isn,&sr); +#else + z->w[i]=muldiv(sr,mr_mip->base,x->w[i],sn,&sr); +#endif +#endif + } +#endif + z->len=x->len; + mr_lzero(z); + return sr; +} + +int subdiv(_MIPD_ big x,int n,big z) +{ /* subdivide a big number by an int z=x/n * + * returns int remainder */ + mr_lentype sx; +#ifdef MR_FP_ROUNDING + mr_large in; +#endif + int r,i,msb; + mr_small lsb; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(10) +#ifdef MR_FLASH + if (mr_notint(x)) mr_berror(_MIPP_ MR_ERR_INT_OP); +#endif + if (n==0) mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); + if (mr_mip->ERNUM) + { + MR_OUT + return 0; + } + + if (x->len==0) + { + zero(z); + MR_OUT + return 0; + } + if (n==1) /* special case */ + { + copy(x,z); + MR_OUT + return 0; + } + sx=(x->len&MR_MSBIT); + if (n==2 && mr_mip->base==0) + { /* fast division by 2 using shifting */ +#ifndef MR_NOFULLWIDTH + +/* I don't want this code upsetting the compiler ... */ +/* mr_mip->base==0 can't happen with MR_NOFULLWIDTH */ + + copy(x,z); + msb=(int)(z->len&MR_OBITS)-1; + r=(int)z->w[0]&1; + for (i=0;;i++) + { + z->w[i]>>=1; + if (i==msb) + { + if (z->w[i]==0) mr_lzero(z); + break; + } + lsb=z->w[i+1]&1; + z->w[i]|=(lsb<<(MIRACL-1)); + } + + MR_OUT + if (sx==0) return r; + else return (-r); +#endif + } + +#ifdef MR_FP_ROUNDING + in=mr_invert(n); +#endif + if (n<0) + { + n=(-n); +#ifdef MR_FP_ROUNDING + r=(int)mr_sdiv(_MIPP_ x,(mr_small)n,in,z); +#else + r=(int)mr_sdiv(_MIPP_ x,(mr_small)n,z); +#endif + if (z->len!=0) z->len^=MR_MSBIT; + } +#ifdef MR_FP_ROUNDING + else r=(int)mr_sdiv(_MIPP_ x,(mr_small)n,in,z); +#else + else r=(int)mr_sdiv(_MIPP_ x,(mr_small)n,z); +#endif + MR_OUT + if (sx==0) return r; + else return (-r); +} + +int remain(_MIPD_ big x,int n) +{ /* return integer remainder when x divided by n */ + int r; + mr_lentype sx; +#ifdef MR_FP + mr_small dres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(88); + + sx=(x->len&MR_MSBIT); + + if (n==2 && MR_REMAIN(mr_mip->base,2)==0) + { /* fast odd/even check if base is even */ + MR_OUT + if ((int)MR_REMAIN(x->w[0],2)==0) return 0; + else + { + if (sx==0) return 1; + else return (-1); + } + } + if (n==8 && MR_REMAIN(mr_mip->base,8)==0) + { /* fast check */ + MR_OUT + r=(int)MR_REMAIN(x->w[0],8); + if (sx!=0) r=-r; + return r; + } + + copy(x,mr_mip->w0); + r=subdiv(_MIPP_ mr_mip->w0,n,mr_mip->w0); + MR_OUT + return r; +} + +BOOL subdivisible(_MIPD_ big x,int n) +{ + if (remain(_MIPP_ x,n)==0) return TRUE; + else return FALSE; +} + +int hamming(_MIPD_ big x) +{ + int h; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + MR_IN(148); + h=0; + copy(x,mr_mip->w1); + absol(mr_mip->w1,mr_mip->w1); + while (size(mr_mip->w1)!=0) + h+=subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1); + + MR_OUT + return h; +} + +void bytes_to_big(_MIPD_ int len,const char *ptr,big x) +{ /* convert len bytes into a big * + * The first byte is the Most significant */ + int i,j,m,n,r; + unsigned int dig; + unsigned char ch; + mr_small wrd; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(140); + + zero(x); + + if (len<=0) + { + MR_OUT + return; + } +/* remove leading zeros.. */ + + while (*ptr==0) + { + ptr++; len--; + if (len==0) + { + MR_OUT + return; + } + } + +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { /* pack bytes directly into big */ +#endif +#ifndef MR_NOFULLWIDTH + m=MIRACL/8; + n=len/m; + + r=len%m; + wrd=(mr_small)0; + if (r!=0) + { + n++; + for (j=0;jlen=n; + if (n>mr_mip->nib && mr_mip->check) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + MR_OUT + return; + } + if (r!=0) + { + n--; + x->w[n]=wrd; + } + + for (i=n-1;i>=0;i--) + { + for (j=0;jw[i]=wrd; + } + mr_lzero(x); /* needed */ +#endif +#ifndef MR_SIMPLE_BASE + } + else + { + for (i=0;iERNUM) break; +#if MIRACL==8 + mr_shift(_MIPP_ x,1,x); +#else + premult(_MIPP_ x,256,x); +#endif + ch=MR_TOBYTE(ptr[i]); + dig=ch; + incr(_MIPP_ x,(int)dig,x); + } + } +#endif + MR_OUT +} + +int big_to_bytes(_MIPD_ int max,big x,char *ptr,BOOL justify) +{ /* convert positive big into octet string */ + int i,j,r,m,n,len,start; + unsigned int dig; + unsigned char ch; + mr_small wrd; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM || max<0) return 0; + + if (max==0 && justify) return 0; + if (size(x)==0) + { + if (justify) + { + for (i=0;ibase==0) + { +#endif +#ifndef MR_NOFULLWIDTH + m=MIRACL/8; + n=(int)(x->len&MR_OBITS); + n--; + len=n*m; + wrd=x->w[n]; /* most significant */ + r=0; + while (wrd!=(mr_small)0) { r++; wrd>>=8; len++;} + r%=m; + + if (max>0 && len>max) + { + mr_berror(_MIPP_ MR_ERR_TOO_BIG); + MR_OUT + return 0; + } + + if (justify) + { + start=max-len; + for (i=0;iw[n--]; + for (i=r-1;i>=0;i--) + { + ptr[start+i]=(char)(wrd&0xFF); + wrd>>=8; + } + } + + for (i=r;iw[n--]; + for (j=m-1;j>=0;j--) + { + ptr[start+i+j]=(char)(wrd&0xFF); + wrd>>=8; + } + } +#endif +#ifndef MR_SIMPLE_BASE + } + else + { + copy(x,mr_mip->w1); + for (len=0;;len++) + { + if (mr_mip->ERNUM) break; + + if (size(mr_mip->w1)==0) + { + if (justify) + { + if (len==max) break; + } + else break; + } + + if (max>0 && len>=max) + { + mr_berror(_MIPP_ MR_ERR_TOO_BIG); + MR_OUT + return 0; + } +#if MIRACL==8 + ch=mr_mip->w1->w[0]; + mr_shift(_MIPP_ mr_mip->w1,-1,mr_mip->w1); +#else + dig=(unsigned int)subdiv(_MIPP_ mr_mip->w1,256,mr_mip->w1); + ch=MR_TOBYTE(dig); +#endif + for (i=len;i>0;i--) ptr[i]=ptr[i-1]; + ptr[0]=MR_TOBYTE(ch); + } + } +#endif + MR_OUT + if (justify) return max; + else return len; +} + +#ifndef MR_NO_ECC_MULTIADD + +/* Solinas's Joint Sparse Form */ + +void mr_jsf(_MIPD_ big k0,big k1,big u0p,big u0m,big u1p,big u1m) +{ + int j,u0,u1,d0,d1,l0,l1; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(191) + + d0=d1=0; + + convert(_MIPP_ 1,mr_mip->w1); + copy(k0,mr_mip->w2); + copy(k1,mr_mip->w3); + zero(u0p); zero(u0m); zero(u1p); zero(u1m); + + j=0; + while (!mr_mip->ERNUM) + { + if (size(mr_mip->w2)==0 && d0==0 && size(mr_mip->w3)==0 && d1==0) break; + l0=remain(_MIPP_ mr_mip->w2,8); + l0=(l0+d0)&0x7; + l1=remain(_MIPP_ mr_mip->w3,8); + l1=(l1+d1)&0x7; + + if (l0%2==0) u0=0; + else + { + u0=2-(l0%4); + if ((l0==3 || l0==5) && l1%4==2) u0=-u0; + } + if (l1%2==0) u1=0; + else + { + u1=2-(l1%4); + if ((l1==3 || l1==5) && l0%4==2) u1=-u1; + } +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + if (u0>0) mr_addbit(_MIPP_ u0p,j); + if (u0<0) mr_addbit(_MIPP_ u0m,j); + if (u1>0) mr_addbit(_MIPP_ u1p,j); + if (u1<0) mr_addbit(_MIPP_ u1m,j); + +#ifndef MR_ALWAYS_BINARY + } + else + { + if (u0>0) add(_MIPP_ u0p,mr_mip->w1,u0p); + if (u0<0) add(_MIPP_ u0m,mr_mip->w1,u0m); + if (u1>0) add(_MIPP_ u1p,mr_mip->w1,u1p); + if (u1<0) add(_MIPP_ u1m,mr_mip->w1,u1m); + } +#endif + + if (d0+d0==1+u0) d0=1-d0; + if (d1+d1==1+u1) d1=1-d1; + + subdiv(_MIPP_ mr_mip->w2,2,mr_mip->w2); + subdiv(_MIPP_ mr_mip->w3,2,mr_mip->w3); + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) +#endif + j++; +#ifndef MR_ALWAYS_BINARY + else + premult(_MIPP_ mr_mip->w1,2,mr_mip->w1); +#endif + } + MR_OUT + return; +} + +#endif diff --git a/miracl/source/mrarth2.c b/miracl/source/mrarth2.c new file mode 100644 index 0000000..e61c292 --- /dev/null +++ b/miracl/source/mrarth2.c @@ -0,0 +1,1584 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL arithmetic routines 2 - multiplying and dividing BIG NUMBERS. + * mrarth2.c + * + */ + +#include "miracl.h" + +#ifdef MR_FP +#include +#endif + +#ifdef MR_WIN64 +#include +#endif + + +/* If a number has more than this number of digits, then squaring is faster */ + +#define SQR_FASTER_THRESHOLD 5 + +mr_small normalise(_MIPD_ big x,big y) +{ /* normalise divisor */ + mr_small norm,r; +#ifdef MR_FP + mr_small dres; +#endif + int len; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + MR_IN(4) + + if (x!=y) copy(x,y); + len=(int)(y->len&MR_OBITS); +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH + if ((r=y->w[len-1]+1)==0) norm=1; +#ifdef MR_NOASM + else norm=(mr_small)(((mr_large)1 << MIRACL)/r); +#else + else norm=muldvm((mr_small)1,(mr_small)0,r,&r); +#endif + if (norm!=1) mr_pmul(_MIPP_ y,norm,y); +#endif +#ifndef MR_SIMPLE_BASE + } + else + { + norm=MR_DIV(mr_mip->base,(mr_small)(y->w[len-1]+1)); + if (norm!=1) mr_pmul(_MIPP_ y,norm,y); + } +#endif + MR_OUT + return norm; +} + +void multiply(_MIPD_ big x,big y,big z) +{ /* multiply two big numbers: z=x.y */ + int i,xl,yl,j,ti; + mr_small carry,*xg,*yg,*w0g; + +#ifdef MR_ITANIUM + mr_small tm; +#endif +#ifdef MR_WIN64 + mr_small tm,tr; +#endif + mr_lentype sz; + big w0; +#ifdef MR_NOASM + union doubleword dble; + mr_large dbled; + mr_large ldres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + if (y->len==0 || x->len==0) + { + zero(z); + return; + } + if (x!=mr_mip->w5 && y!=mr_mip->w5 && z==mr_mip->w5) w0=mr_mip->w5; + else w0=mr_mip->w0; /* local pointer */ + + MR_IN(5) + +#ifdef MR_FLASH + if (mr_notint(x) || mr_notint(y)) + { + mr_berror(_MIPP_ MR_ERR_INT_OP); + MR_OUT + return; + } +#endif + sz=((x->len&MR_MSBIT)^(y->len&MR_MSBIT)); + xl=(int)(x->len&MR_OBITS); + yl=(int)(y->len&MR_OBITS); + zero(w0); + if (mr_mip->check && xl+yl>mr_mip->nib) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + MR_OUT + return; + } +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH + xg=x->w; yg=y->w; w0g=w0->w; + if (x==y && xl>SQR_FASTER_THRESHOLD) + /* extra hassle make it not */ + /* worth it for small numbers */ + { /* fast squaring */ + for (i=0;iw[i]*x->w[j]+carry+w0->w[i+j]; + w0->w[i+j]=dble.h[MR_BOT]; + carry=dble.h[MR_TOP]; +#else + muldvd2(x->w[i],x->w[j],&carry,&w0->w[i+j]); +#endif + } + w0->w[xl+i]=carry; +#endif + } +#ifdef INLINE_ASM +#if INLINE_ASM == 1 + ASM mov cx,xl + ASM shl cx,1 +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les bx,DWORD PTR w0g +#else + ASM mov bx,w0g +#endif + tcl5: +#ifdef MR_LMM + ASM rcl WORD PTR es:[bx],1 +#else + ASM rcl WORD PTR [bx],1 +#endif + ASM inc bx + ASM inc bx + ASM loop tcl5 + + ASM cld + ASM mov cx,xl +#ifdef MR_LMM + ASM les di,DWORD PTR w0g + ASM lds si,DWORD PTR xg +#else + ASM mov di,w0g + ASM mov si,xg +#endif + + ASM xor bx,bx + tcl7: + ASM lodsw + ASM mul ax + ASM add ax,bx + ASM adc dx,0 +#ifdef MR_LMM + ASM add es:[di],ax +#else + ASM add [di],ax +#endif + ASM adc dx,0 + ASM xor bx,bx + ASM inc di + ASM inc di +#ifdef MR_LMM + ASM add es:[di],dx +#else + ASM add [di],dx +#endif + ASM adc bx,0 + ASM inc di + ASM inc di + ASM loop tcl7 +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif +#endif +#if INLINE_ASM == 2 + ASM mov cx,xl + ASM shl cx,1 +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les bx,DWORD PTR w0g +#else + ASM mov bx,w0g +#endif + tcl5: +#ifdef MR_LMM + ASM rcl DWORD PTR es:[bx],1 +#else + ASM rcl DWORD PTR [bx],1 +#endif + ASM inc bx + ASM inc bx + ASM inc bx + ASM inc bx + ASM loop tcl5 + + ASM cld + ASM mov cx,xl +#ifdef MR_LMM + ASM les di,DWORD PTR w0g + ASM lds si,DWORD PTR xg +#else + ASM mov di,w0g + ASM mov si,xg +#endif + ASM xor ebx,ebx + tcl7: + ASM lodsd + ASM mul eax + ASM add eax,ebx + ASM adc edx,0 +#ifdef MR_LMM + ASM add es:[di],eax +#else + ASM add [di],eax +#endif + ASM adc edx,0 + ASM xor ebx,ebx + ASM add di,4 +#ifdef MR_LMM + ASM add es:[di],edx +#else + ASM add [di],edx +#endif + ASM adc ebx,0 + ASM add di,4 + ASM loop tcl7 +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif +#endif +#if INLINE_ASM == 3 + ASM mov ecx,xl + ASM shl ecx,1 + ASM mov edi,w0g + tcl5: + ASM rcl DWORD PTR [edi],1 + ASM inc edi + ASM inc edi + ASM inc edi + ASM inc edi + ASM loop tcl5 + + ASM mov ecx,xl + ASM mov esi,xg + ASM mov edi,w0g + ASM xor ebx,ebx + tcl7: + ASM mov eax,[esi] + ASM add esi,4 + ASM mul eax + ASM add eax,ebx + ASM adc edx,0 + ASM add [edi],eax + ASM adc edx,0 + ASM xor ebx,ebx + ASM add edi,4 + ASM add [edi],edx + ASM adc ebx,0 + ASM add edi,4 + ASM dec ecx + ASM jnz tcl7 +#endif +#if INLINE_ASM == 4 + ASM ( + "movl %0,%%ecx\n" + "shll $1,%%ecx\n" + "movl %1,%%edi\n" + "tcl5:\n" + "rcll $1,(%%edi)\n" + "incl %%edi\n" + "incl %%edi\n" + "incl %%edi\n" + "incl %%edi\n" + "loop tcl5\n" + + "movl %0,%%ecx\n" + "movl %2,%%esi\n" + "movl %1,%%edi\n" + "xorl %%ebx,%%ebx\n" + "tcl7:\n" + "movl (%%esi),%%eax\n" + "addl $4,%%esi\n" + "mull %%eax\n" + "addl %%ebx,%%eax\n" + "adcl $0,%%edx\n" + "addl %%eax,(%%edi)\n" + "adcl $0,%%edx\n" + "xorl %%ebx,%%ebx\n" + "addl $4,%%edi\n" + "addl %%edx,(%%edi)\n" + "adcl $0,%%ebx\n" + "addl $4,%%edi\n" + "decl %%ecx\n" + "jnz tcl7\n" + : + :"m"(xl),"m"(w0g),"m"(xg) + :"eax","edi","esi","ebx","ecx","edx","memory" + ); +#endif +#endif +#ifndef INLINE_ASM + w0->len=xl+xl-1; + mr_padd(_MIPP_ w0,w0,w0); /* double it */ + carry=0; + for (i=0;iw[i]*x->w[i]+carry+w0->w[ti]; + w0->w[ti]=dble.h[MR_BOT]; + carry=dble.h[MR_TOP]; +#else + muldvd2(x->w[i],x->w[i],&carry,&w0->w[ti]); +#endif + w0->w[ti+1]+=carry; + if (w0->w[ti+1]w[i]*y->w[j]+carry+w0->w[i+j]; + w0->w[i+j]=dble.h[MR_BOT]; + carry=dble.h[MR_TOP]; +#else + muldvd2(x->w[i],y->w[j],&carry,&w0->w[i+j]); +#endif + } + w0->w[yl+i]=carry; +#endif + } +#endif +#ifndef MR_SIMPLE_BASE + } + else + { + if (x==y && xl>SQR_FASTER_THRESHOLD) + { /* squaring can be done nearly twice as fast */ + for (i=0;iw[i]*x->w[j]+w0->w[i+j]+carry; + #ifdef MR_FP_ROUNDING + carry=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); + #else + #ifndef MR_FP + if (mr_mip->base==mr_mip->base2) + carry=(mr_small)(dbled>>mr_mip->lg2b); + else + #endif + carry=(mr_small)MR_LROUND(dbled/mr_mip->base); + #endif + w0->w[i+j]=(mr_small)(dbled-(mr_large)carry*mr_mip->base); +#else + + #ifdef MR_FP_ROUNDING + carry=imuldiv(x->w[i],x->w[j],w0->w[i+j]+carry,mr_mip->base,mr_mip->inverse_base,&w0->w[i+j]); + #else + carry=muldiv(x->w[i],x->w[j],w0->w[i+j]+carry,mr_mip->base,&w0->w[i+j]); + #endif +#endif + } + w0->w[xl+i]=carry; + } + w0->len=xl+xl-1; + mr_padd(_MIPP_ w0,w0,w0); /* double it */ + carry=0; + for (i=0;iw[i]*x->w[i]+w0->w[ti]+carry; +#ifdef MR_FP_ROUNDING + carry=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); +#else +#ifndef MR_FP + if (mr_mip->base==mr_mip->base2) + carry=(mr_small)(dbled>>mr_mip->lg2b); + else +#endif + carry=(mr_small)MR_LROUND(dbled/mr_mip->base); +#endif + w0->w[ti]=(mr_small)(dbled-(mr_large)carry*mr_mip->base); +#else + +#ifdef MR_FP_ROUNDING + carry=imuldiv(x->w[i],x->w[i],w0->w[ti]+carry,mr_mip->base,mr_mip->inverse_base,&w0->w[ti]); +#else + carry=muldiv(x->w[i],x->w[i],w0->w[ti]+carry,mr_mip->base,&w0->w[ti]); +#endif + +#endif + w0->w[ti+1]+=carry; + carry=0; + if (w0->w[ti+1]>=mr_mip->base) + { + carry=1; + w0->w[ti+1]-=mr_mip->base; + } + } + } + else for (i=0;iw[i]*y->w[j]+w0->w[i+j]+carry; + +#ifdef MR_FP_ROUNDING + carry=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); +#else +#ifndef MR_FP + if (mr_mip->base==mr_mip->base2) + carry=(mr_small)(dbled>>mr_mip->lg2b); + else +#endif + carry=(mr_small)MR_LROUND(dbled/mr_mip->base); +#endif + w0->w[i+j]=(mr_small)(dbled-(mr_large)carry*mr_mip->base); +#else + +#ifdef MR_FP_ROUNDING + carry=imuldiv(x->w[i],y->w[j],w0->w[i+j]+carry,mr_mip->base,mr_mip->inverse_base,&w0->w[i+j]); +#else + carry=muldiv(x->w[i],y->w[j],w0->w[i+j]+carry,mr_mip->base,&w0->w[i+j]); +#endif + +#endif + } + w0->w[yl+i]=carry; + } + } +#endif + w0->len=(sz|(xl+yl)); /* set length and sign of result */ + + mr_lzero(w0); + copy(w0,z); + MR_OUT +} + +void divide(_MIPD_ big x,big y,big z) +{ /* divide two big numbers z=x/y : x=x mod y * + * returns quotient only if divide(x,y,x) * + * returns remainder only if divide(x,y,y) */ + mr_small carry,attemp,ldy,sdy,ra,r,d,tst,psum; +#ifdef MR_FP + mr_small dres; +#endif + mr_lentype sx,sy,sz; + mr_small borrow,dig,*w0g,*yg; + int i,k,m,x0,y0,w00; + big w0; + +#ifdef MR_ITANIUM + mr_small tm; +#endif +#ifdef MR_WIN64 + mr_small tm; +#endif +#ifdef MR_NOASM + union doubleword dble; + mr_large dbled; + mr_large ldres; +#endif + BOOL check; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + w0=mr_mip->w0; + + MR_IN(6) + + if (x==y) mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); +#ifdef MR_FLASH + if (mr_notint(x) || mr_notint(y)) mr_berror(_MIPP_ MR_ERR_INT_OP); +#endif + if (y->len==0) mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); + if (mr_mip->ERNUM) + { + MR_OUT + return; + } + sx=(x->len&MR_MSBIT); /* extract signs ... */ + sy=(y->len&MR_MSBIT); + sz=(sx^sy); + x->len&=MR_OBITS; /* ... and force operands to positive */ + y->len&=MR_OBITS; + x0=(int)x->len; + y0=(int)y->len; + copy(x,w0); + w00=(int)w0->len; + if (mr_mip->check && (w00-y0+1>mr_mip->nib)) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + MR_OUT + return; + } + d=0; + if (x0==y0) + { + if (x0==1) /* special case - x and y are both mr_smalls */ + { + d=MR_DIV(w0->w[0],y->w[0]); + w0->w[0]=MR_REMAIN(w0->w[0],y->w[0]); + mr_lzero(w0); + } + else if (MR_DIV(w0->w[x0-1],4)w[x0-1]) + while (mr_compare(w0,y)>=0) + { /* mr_small quotient - so do up to four subtracts instead */ + mr_psub(_MIPP_ w0,y,w0); + d++; + } + } + if (mr_compare(w0,y)<0) + { /* x less than y - so x becomes remainder */ + if (x!=z) /* testing parameters */ + { + copy(w0,x); + if (x->len!=0) x->len|=sx; + } + if (y!=z) + { + zero(z); + z->w[0]=d; + if (d>0) z->len=(sz|1); + } + y->len|=sy; + MR_OUT + return; + } + + if (y0==1) + { /* y is int - so use subdiv instead */ +#ifdef MR_FP_ROUNDING + r=mr_sdiv(_MIPP_ w0,y->w[0],mr_invert(y->w[0]),w0); +#else + r=mr_sdiv(_MIPP_ w0,y->w[0],w0); +#endif + if (y!=z) + { + copy(w0,z); + z->len|=sz; + } + if (x!=z) + { + zero(x); + x->w[0]=r; + if (r>0) x->len=(sx|1); + } + y->len|=sy; + MR_OUT + return; + } + if (y!=z) zero(z); + d=normalise(_MIPP_ y,y); + check=mr_mip->check; + mr_mip->check=OFF; +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH + if (d!=1) mr_pmul(_MIPP_ w0,d,w0); + ldy=y->w[y0-1]; + sdy=y->w[y0-2]; + w0g=w0->w; yg=y->w; + for (k=w00-1;k>=y0-1;k--) + { /* long division */ +#ifdef INLINE_ASM +#if INLINE_ASM == 1 +#ifdef MR_LMM + ASM push ds + ASM lds bx,DWORD PTR w0g +#else + ASM mov bx,w0g +#endif + ASM mov si,k + ASM shl si,1 + ASM add bx,si + ASM mov dx,[bx+2] + ASM mov ax,[bx] + ASM cmp dx,ldy + ASM jne tcl8 + ASM mov di,0xffff + ASM mov si,ax + ASM add si,ldy + ASM jc tcl12 + ASM jmp tcl10 + tcl8: + ASM div WORD PTR ldy + ASM mov di,ax + ASM mov si,dx + tcl10: + ASM mov ax,sdy + ASM mul di + ASM cmp dx,si + ASM jb tcl12 + ASM jne tcl11 + ASM cmp ax,[bx-2] + ASM jbe tcl12 + tcl11: + ASM dec di + ASM add si,ldy + ASM jnc tcl10 + tcl12: + ASM mov attemp,di +#ifdef MR_LMM + ASM pop ds +#endif +#endif +/* NOTE push and pop of esi/edi should not be necessary - Borland C bug * + * These pushes are needed here even if register variables are disabled */ +#if INLINE_ASM == 2 + ASM push esi + ASM push edi +#ifdef MR_LMM + ASM push ds + ASM lds bx,DWORD PTR w0g +#else + ASM mov bx,w0g +#endif + ASM mov si,k + ASM shl si,2 + ASM add bx,si + ASM mov edx,[bx+4] + ASM mov eax,[bx] + ASM cmp edx,ldy + ASM jne tcl8 + ASM mov edi,0xffffffff + ASM mov esi,eax + ASM add esi,ldy + ASM jc tcl12 + ASM jmp tcl10 + tcl8: + ASM div DWORD PTR ldy + ASM mov edi,eax + ASM mov esi,edx + tcl10: + ASM mov eax,sdy + ASM mul edi + ASM cmp edx,esi + ASM jb tcl12 + ASM jne tcl11 + ASM cmp eax,[bx-4] + ASM jbe tcl12 + tcl11: + ASM dec edi + ASM add esi,ldy + ASM jnc tcl10 + tcl12: + ASM mov attemp,edi +#ifdef MR_LMM + ASM pop ds +#endif + ASM pop edi + ASM pop esi +#endif +#if INLINE_ASM == 3 + ASM push esi + ASM push edi + ASM mov ebx,w0g + ASM mov esi,k + ASM shl esi,2 + ASM add ebx,esi + ASM mov edx,[ebx+4] + ASM mov eax,[ebx] + ASM cmp edx,ldy + ASM jne tcl8 + ASM mov edi,0xffffffff + ASM mov esi,eax + ASM add esi,ldy + ASM jc tcl12 + ASM jmp tcl10 + tcl8: + ASM div DWORD PTR ldy + ASM mov edi,eax + ASM mov esi,edx + tcl10: + ASM mov eax,sdy + ASM mul edi + ASM cmp edx,esi + ASM jb tcl12 + ASM jne tcl11 + ASM cmp eax,[ebx-4] + ASM jbe tcl12 + tcl11: + ASM dec edi + ASM add esi,ldy + ASM jnc tcl10 + tcl12: + ASM mov attemp,edi + ASM pop edi + ASM pop esi +#endif +#if INLINE_ASM == 4 + ASM ( + "movl %1,%%ebx\n" + "movl %2,%%esi\n" + "shll $2,%%esi\n" + "addl %%esi,%%ebx\n" + "movl 4(%%ebx),%%edx\n" + "movl (%%ebx),%%eax\n" + "cmpl %3,%%edx\n" + "jne tcl8\n" + "movl $0xffffffff,%%edi\n" + "movl %%eax,%%esi\n" + "addl %3,%%esi\n" + "jc tcl12\n" + "jmp tcl10\n" + "tcl8:\n" + "divl %3\n" + "movl %%eax,%%edi\n" + "movl %%edx,%%esi\n" + "tcl10:\n" + "movl %4,%%eax\n" + "mull %%edi\n" + "cmpl %%esi,%%edx\n" + "jb tcl12\n" + "jne tcl11\n" + "cmpl -4(%%ebx),%%eax\n" + "jbe tcl12\n" + "tcl11:\n" + "decl %%edi\n" + "addl %3,%%esi\n" + "jnc tcl10\n" + "tcl12:\n" + "movl %%edi,%0\n" + :"=m"(attemp) + :"m"(w0g),"m"(k),"m"(ldy),"m"(sdy) + :"eax","edi","esi","ebx","ecx","edx","memory" + ); +#endif +#endif +#ifndef INLINE_ASM + carry=0; + if (w0->w[k+1]==ldy) /* guess next quotient digit */ + { + attemp=(mr_small)(-1); + ra=ldy+w0->w[k]; + if (raw[k]; + dble.h[MR_TOP]=w0->w[k+1]; + attemp=(mr_small)(dble.d/ldy); + ra=(mr_small)(dble.d-(mr_large)attemp*ldy); + } +#else + else attemp=muldvm(w0->w[k+1],w0->w[k],ldy,&ra); +#endif + while (carry==0) + { +#ifdef MR_NOASM + dble.d=(mr_large)attemp*sdy; + r=dble.h[MR_BOT]; + tst=dble.h[MR_TOP]; +#else + tst=muldvd(sdy,attemp,(mr_small)0,&r); +#endif + if (tst< ra || (tst==ra && r<=w0->w[k-1])) break; + attemp--; /* refine guess */ + ra+=ldy; + if (ra0) + { /* do partial subtraction */ + borrow=0; + /* inline - substitutes for loop below */ +#ifdef INLINE_ASM +#if INLINE_ASM == 1 + ASM cld + ASM mov cx,y0 + ASM mov si,m + ASM shl si,1 + ASM mov di,attemp +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les bx,DWORD PTR w0g + ASM add bx,si + ASM sub bx,2 + ASM lds si,DWORD PTR yg +#else + ASM mov bx,w0g + ASM add bx,si + ASM sub bx,2 + ASM mov si,yg +#endif + ASM push bp + ASM xor bp,bp + + tcl3: + ASM lodsw + ASM mul di + ASM add ax,bp + ASM adc dx,0 + ASM inc bx + ASM inc bx +#ifdef MR_LMM + ASM sub es:[bx],ax +#else + ASM sub [bx],ax +#endif + ASM adc dx,0 + ASM mov bp,dx + ASM loop tcl3 + + ASM mov ax,bp + ASM pop bp +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif + ASM mov borrow,ax +#endif +/* NOTE push and pop of esi/edi should not be necessary - Borland C bug * + * These pushes are needed here even if register variables are disabled */ +#if INLINE_ASM == 2 + ASM push esi + ASM push edi + ASM cld + ASM mov cx,y0 + ASM mov si,m + ASM shl si,2 + ASM mov edi,attemp +#ifdef MR_LMM + ASM push ds + ASM push es + ASM les bx,DWORD PTR w0g + ASM add bx,si + ASM sub bx,4 + ASM lds si,DWORD PTR yg +#else + ASM mov bx,w0g + ASM add bx,si + ASM sub bx,4 + ASM mov si,yg +#endif + ASM push ebp + ASM xor ebp,ebp + + tcl3: + ASM lodsd + ASM mul edi + ASM add eax,ebp + ASM adc edx,0 + ASM add bx,4 +#ifdef MR_LMM + ASM sub es:[bx],eax +#else + ASM sub [bx],eax +#endif + ASM adc edx,0 + ASM mov ebp,edx + ASM loop tcl3 + + ASM mov eax,ebp + ASM pop ebp +#ifdef MR_LMM + ASM pop es + ASM pop ds +#endif + ASM mov borrow,eax + ASM pop edi + ASM pop esi +#endif +#if INLINE_ASM == 3 + ASM push esi + ASM push edi + ASM mov ecx,y0 + ASM mov esi,m + ASM shl esi,2 + ASM mov edi,attemp + ASM mov ebx,w0g + ASM add ebx,esi + ASM mov esi,yg + ASM sub ebx,esi + ASM sub ebx,4 + ASM push ebp + ASM xor ebp,ebp + + tcl3: + ASM mov eax,[esi] + ASM add esi,4 + ASM mul edi + ASM add eax,ebp + ASM mov ebp,[esi+ebx] + ASM adc edx,0 + ASM sub ebp,eax + ASM adc edx,0 + ASM mov [esi+ebx],ebp + ASM dec ecx + ASM mov ebp,edx + ASM jnz tcl3 + + ASM mov eax,ebp + ASM pop ebp + ASM mov borrow,eax + ASM pop edi + ASM pop esi +#endif +#if INLINE_ASM == 4 + ASM ( + "movl %1,%%ecx\n" + "movl %2,%%esi\n" + "shll $2,%%esi\n" + "movl %3,%%edi\n" + "movl %4,%%ebx\n" + "addl %%esi,%%ebx\n" + "movl %5,%%esi\n" + "subl %%esi,%%ebx\n" + "subl $4,%%ebx\n" + "pushl %%ebp\n" + "xorl %%ebp,%%ebp\n" + "tcl3:\n" + "movl (%%esi),%%eax\n" + "addl $4,%%esi\n" + "mull %%edi\n" + "addl %%ebp,%%eax\n" + "movl (%%esi,%%ebx),%%ebp\n" + "adcl $0,%%edx\n" + "subl %%eax,%%ebp\n" + "adcl $0,%%edx\n" + "movl %%ebp,(%%esi,%%ebx)\n" + "decl %%ecx\n" + "movl %%edx,%%ebp\n" + "jnz tcl3\n" + + "movl %%ebp,%%eax\n" + "popl %%ebp\n" + "movl %%eax,%0\n" + + :"=m"(borrow) + :"m"(y0),"m"(m),"m"(attemp),"m"(w0g),"m"(yg) + :"eax","edi","esi","ebx","ecx","edx","memory" + ); +#endif +#endif +#ifndef INLINE_ASM + for (i=0;iw[i]+borrow; + dig=dble.h[MR_BOT]; + borrow=dble.h[MR_TOP]; +#else + borrow=muldvd(attemp,y->w[i],borrow,&dig); +#endif + if (w0->w[m+i]w[m+i]-=dig; + } +#endif + + if (w0->w[k+1]w[k+1]=0; + carry=0; + for (i=0;iw[m+i]+y->w[i]+carry; + if (psum>y->w[i]) carry=0; + if (psumw[i]) carry=1; + w0->w[m+i]=psum; + } + attemp--; /* ... and adjust guess */ + } + else w0->w[k+1]-=borrow; + } + if (k==w00-1 && attemp==0) w00--; + else if (y!=z) z->w[m]=attemp; + } +#endif +#ifndef MR_SIMPLE_BASE + } + else + { /* have to do it the hard way */ + if (d!=1) mr_pmul(_MIPP_ w0,d,w0); + ldy=y->w[y0-1]; + sdy=y->w[y0-2]; + + for (k=w00-1;k>=y0-1;k--) + { /* long division */ + + + if (w0->w[k+1]==ldy) /* guess next quotient digit */ + { + attemp=mr_mip->base-1; + ra=ldy+w0->w[k]; + } +#ifdef MR_NOASM + else + { + dbled=(mr_large)w0->w[k+1]*mr_mip->base+w0->w[k]; + attemp=(mr_small)MR_LROUND(dbled/ldy); + ra=(mr_small)(dbled-(mr_large)attemp*ldy); + } +#else + else attemp=muldiv(w0->w[k+1],mr_mip->base,w0->w[k],ldy,&ra); +#endif + while (rabase) + { +#ifdef MR_NOASM + dbled=(mr_large)sdy*attemp; +#ifdef MR_FP_ROUNDING + tst=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); +#else +#ifndef MR_FP + if (mr_mip->base==mr_mip->base2) + tst=(mr_small)(dbled>>mr_mip->lg2b); + else +#endif + tst=(mr_small)MR_LROUND(dbled/mr_mip->base); +#endif + r=(mr_small)(dbled-(mr_large)tst*mr_mip->base); +#else +#ifdef MR_FP_ROUNDING + tst=imuldiv(sdy,attemp,(mr_small)0,mr_mip->base,mr_mip->inverse_base,&r); +#else + tst=muldiv(sdy,attemp,(mr_small)0,mr_mip->base,&r); +#endif +#endif + if (tst< ra || (tst==ra && r<=w0->w[k-1])) break; + attemp--; /* refine guess */ + ra+=ldy; + } + m=k-y0+1; + if (attemp>0) + { /* do partial subtraction */ + borrow=0; + for (i=0;iw[i]+borrow; +#ifdef MR_FP_ROUNDING + borrow=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); +#else +#ifndef MR_FP + if (mr_mip->base==mr_mip->base2) + borrow=(mr_small)(dbled>>mr_mip->lg2b); + else +#endif + borrow=(mr_small)MR_LROUND(dbled/mr_mip->base); +#endif + dig=(mr_small)(dbled-(mr_large)borrow*mr_mip->base); +#else +#ifdef MR_FP_ROUNDING + borrow=imuldiv(attemp,y->w[i],borrow,mr_mip->base,mr_mip->inverse_base,&dig); +#else + borrow=muldiv(attemp,y->w[i],borrow,mr_mip->base,&dig); +#endif +#endif + if (w0->w[m+i]w[m+i]+=(mr_mip->base-dig); + } + else w0->w[m+i]-=dig; + } + if (w0->w[k+1]w[k+1]=0; + carry=0; + for (i=0;iw[m+i]+y->w[i]+carry; + carry=0; + if (psum>=mr_mip->base) + { + carry=1; + psum-=mr_mip->base; + } + w0->w[m+i]=psum; + } + attemp--; /* ... and adjust guess */ + } + else + w0->w[k+1]-=borrow; + } + if (k==w00-1 && attemp==0) w00--; + else if (y!=z) z->w[m]=attemp; + } + } +#endif + if (y!=z) z->len=((w00-y0+1)|sz); /* set sign and length of result */ + + w0->len=y0; + + mr_lzero(y); + mr_lzero(z); + + if (x!=z) + { + mr_lzero(w0); +#ifdef MR_FP_ROUNDING + if (d!=1) mr_sdiv(_MIPP_ w0,d,mr_invert(d),x); +#else + if (d!=1) mr_sdiv(_MIPP_ w0,d,x); +#endif + else copy(w0,x); + if (x->len!=0) x->len|=sx; + } +#ifdef MR_FP_ROUNDING + if (d!=1) mr_sdiv(_MIPP_ y,d,mr_invert(d),y); +#else + if (d!=1) mr_sdiv(_MIPP_ y,d,y); +#endif + y->len|=sy; + mr_mip->check=check; + + MR_OUT +} + +BOOL divisible(_MIPD_ big x,big y) +{ /* returns y|x, that is TRUE if y divides x exactly */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(87) + + copy (x,mr_mip->w0); + divide(_MIPP_ mr_mip->w0,y,y); + + MR_OUT + if (size(mr_mip->w0)==0) return TRUE; + else return FALSE; +} + +void mad(_MIPD_ big x,big y,big z,big w,big q,big r) +{ /* Multiply, Add and Divide; q=(x*y+z)/w remainder r * + * returns remainder only if w=q, quotient only if q=r * + * add done only if x, y and z are distinct. */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + BOOL check; + if (mr_mip->ERNUM) return; + + MR_IN(24) + if (w==r) + { + mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + MR_OUT + return; + } + check=mr_mip->check; + mr_mip->check=OFF; /* turn off some error checks */ + + multiply(_MIPP_ x,y,mr_mip->w0); + if (x!=z && y!=z) add(_MIPP_ mr_mip->w0,z,mr_mip->w0); + + divide(_MIPP_ mr_mip->w0,w,q); + if (q!=r) copy(mr_mip->w0,r); + mr_mip->check=check; + MR_OUT +} + diff --git a/miracl/source/mrarth3.c b/miracl/source/mrarth3.c new file mode 100644 index 0000000..0f3d1e7 --- /dev/null +++ b/miracl/source/mrarth3.c @@ -0,0 +1,231 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL arithmetic routines 3 - simple powers and roots + * mrarth3.c + */ + +#include +#include "miracl.h" + +void expint(_MIPD_ int b,int n,big x) +{ /* sets x=b^n */ + unsigned int bit,un; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + convert(_MIPP_ 1,x); + if (n==0) return; + + MR_IN(50) + + if (n<0) + { + mr_berror(_MIPP_ MR_ERR_NEG_POWER); + MR_OUT + return; + } + if (b==2) expb2(_MIPP_ n,x); + else + { + bit=1; + un=(unsigned int)n; + while (un>=bit) bit<<=1; + bit>>=1; + while (bit>0) + { /* ltr method */ + multiply(_MIPP_ x,x,x); + if ((bit&un)!=0) premult(_MIPP_ x,b,x); + bit>>=1; + } + } + MR_OUT +} + +void power(_MIPD_ big x,long n,big z,big w) +{ /* raise big number to int power w=x^n * + * (mod z if z and w distinct) */ + mr_small norm; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + copy(x,mr_mip->w5); + zero(w); + if(mr_mip->ERNUM || size(mr_mip->w5)==0) return; + convert(_MIPP_ 1,w); + if (n==0L) return; + + MR_IN(17) + + if (n<0L) + { + mr_berror(_MIPP_ MR_ERR_NEG_POWER); + MR_OUT + return; + } + + if (w==z) forever + { /* "Russian peasant" exponentiation */ + if (n%2!=0L) + multiply(_MIPP_ w,mr_mip->w5,w); + n/=2L; + if (mr_mip->ERNUM || n==0L) break; + multiply(_MIPP_ mr_mip->w5,mr_mip->w5,mr_mip->w5); + } + else + { + norm=normalise(_MIPP_ z,z); + divide(_MIPP_ mr_mip->w5,z,z); + forever + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + if (n%2!=0L) mad(_MIPP_ w,mr_mip->w5,mr_mip->w5,z,z,w); + n/=2L; + if (mr_mip->ERNUM || n==0L) break; + mad(_MIPP_ mr_mip->w5,mr_mip->w5,mr_mip->w5,z,z,mr_mip->w5); + } + if (norm!=1) + { +#ifdef MR_FP_ROUNDING + mr_sdiv(_MIPP_ z,norm,mr_invert(norm),z); +#else + mr_sdiv(_MIPP_ z,norm,z); +#endif + divide(_MIPP_ w,z,z); + } + } + + MR_OUT +} + +BOOL nroot(_MIPD_ big x,int n,big w) +{ /* extract lower approximation to nth root * + * w=x^(1/n) returns TRUE for exact root * + * uses Newtons method */ + int sx,dif,s,p,d,lg2,lgx,rem; + BOOL full; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + if (size(x)==0 || n==1) + { + copy(x,w); + return TRUE; + } + + MR_IN(16) + + if (n<1) mr_berror(_MIPP_ MR_ERR_BAD_ROOT); + sx=exsign(x); + if (n%2==0 && sx==MINUS) mr_berror(_MIPP_ MR_ERR_NEG_ROOT); + if (mr_mip->ERNUM) + { + MR_OUT + return FALSE; + } + insign(PLUS,x); + lgx=logb2(_MIPP_ x); + if (n>=lgx) + { /* root must be 1 */ + insign(sx,x); + convert(_MIPP_ sx,w); + MR_OUT + if (lgx==1) return TRUE; + else return FALSE; + } + expb2(_MIPP_ 1+(lgx-1)/n,mr_mip->w2); /* guess root as 2^(log2(x)/n) */ + s=(-(((int)x->len-1)/n)*n); + mr_shift(_MIPP_ mr_mip->w2,s/n,mr_mip->w2); + lg2=logb2(_MIPP_ mr_mip->w2)-1; + full=FALSE; + if (s==0) full=TRUE; + d=0; + p=1; + while (!mr_mip->ERNUM) + { /* Newtons method */ + copy(mr_mip->w2,mr_mip->w3); + mr_shift(_MIPP_ x,s,mr_mip->w4); + mr_mip->check=OFF; + power(_MIPP_ mr_mip->w2,n-1,mr_mip->w6,mr_mip->w6); + mr_mip->check=ON; + divide(_MIPP_ mr_mip->w4,mr_mip->w6,mr_mip->w2); + rem=size(mr_mip->w4); + subtract(_MIPP_ mr_mip->w2,mr_mip->w3,mr_mip->w2); + dif=size(mr_mip->w2); + subdiv(_MIPP_ mr_mip->w2,n,mr_mip->w2); + add(_MIPP_ mr_mip->w2,mr_mip->w3,mr_mip->w2); + p*=2; + if(plg2b) continue; + if (full && mr_abs(dif)w2,1,mr_mip->w2); + mr_mip->check=OFF; + power(_MIPP_ mr_mip->w2,n,mr_mip->w6,mr_mip->w6); + mr_mip->check=ON; + dif=mr_compare(x,mr_mip->w6); + } + copy(mr_mip->w2,w); + insign(sx,w); + insign(sx,x); + MR_OUT + if (rem==0 && dif==0) return TRUE; + else return FALSE; + } + else + { /* adjust precision */ + d*=2; + if (d==0) d=1; + s+=d*n; + if (s>=0) + { + d-=s/n; + s=0; + full=TRUE; + } + mr_shift(_MIPP_ mr_mip->w2,d,mr_mip->w2); + } + p/=2; + } + MR_OUT + return FALSE; +} + diff --git a/miracl/source/mrbits.c b/miracl/source/mrbits.c new file mode 100644 index 0000000..29126ba --- /dev/null +++ b/miracl/source/mrbits.c @@ -0,0 +1,245 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL bit manipulation routines + * mrbits.c + */ + +#include +#include "miracl.h" + +#ifdef MR_FP +#include +#endif + +int logb2(_MIPD_ big x) +{ /* returns number of bits in x */ + int xl,lg2; + mr_small top; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM || size(x)==0) return 0; + + MR_IN(49) + + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + xl=(int)(x->len&MR_OBITS); + lg2=mr_mip->lg2b*(xl-1); + top=x->w[xl-1]; + while (top>=1) + { + lg2++; + top/=2; + } + +#ifndef MR_ALWAYS_BINARY + } + else + { + copy(x,mr_mip->w0); + insign(PLUS,mr_mip->w0); + lg2=0; + while (mr_mip->w0->len>1) + { +#ifdef MR_FP_ROUNDING + mr_sdiv(_MIPP_ mr_mip->w0,mr_mip->base2,mr_invert(mr_mip->base2),mr_mip->w0); +#else + mr_sdiv(_MIPP_ mr_mip->w0,mr_mip->base2,mr_mip->w0); +#endif + lg2+=mr_mip->lg2b; + } + + while (mr_mip->w0->w[0]>=1) + { + lg2++; + mr_mip->w0->w[0]/=2; + } + } +#endif + MR_OUT + return lg2; +} + +void sftbit(_MIPD_ big x,int n,big z) +{ /* shift x by n bits */ + int m; + mr_small sm; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + copy(x,z); + if (n==0) return; + + MR_IN(47) + + m=mr_abs(n); + sm=mr_shiftbits((mr_small)1,m%mr_mip->lg2b); + if (n>0) + { /* shift left */ + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + mr_shift(_MIPP_ z,n/mr_mip->lg2b,z); + mr_pmul(_MIPP_ z,sm,z); +#ifndef MR_ALWAYS_BINARY + } + else + { + expb2(_MIPP_ m,mr_mip->w1); + multiply(_MIPP_ z,mr_mip->w1,z); + } +#endif + } + else + { /* shift right */ + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + mr_shift(_MIPP_ z,n/mr_mip->lg2b,z); +#ifdef MR_FP_ROUNDING + mr_sdiv(_MIPP_ z,sm,mr_invert(sm),z); +#else + mr_sdiv(_MIPP_ z,sm,z); +#endif + +#ifndef MR_ALWAYS_BINARY + } + else + { + expb2(_MIPP_ m,mr_mip->w1); + divide(_MIPP_ z,mr_mip->w1,z); + } +#endif + } + MR_OUT +} + +void expb2(_MIPD_ int n,big x) +{ /* sets x=2^n */ + int r,p; +#ifndef MR_ALWAYS_BINARY + int i; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + convert(_MIPP_ 1,x); + if (n==0) return; + + MR_IN(149) + + if (n<0) + { + mr_berror(_MIPP_ MR_ERR_NEG_POWER); + MR_OUT + return; + } + r=n/mr_mip->lg2b; + p=n%mr_mip->lg2b; + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + mr_shift(_MIPP_ x,r,x); + x->w[x->len-1]=mr_shiftbits(x->w[x->len-1],p); +#ifndef MR_ALWAYS_BINARY + } + else + { + for (i=1;i<=r;i++) + mr_pmul(_MIPP_ x,mr_mip->base2,x); + mr_pmul(_MIPP_ x,mr_shiftbits((mr_small)1,p),x); + } +#endif + MR_OUT +} + +#ifndef MR_NO_RAND + +void bigbits(_MIPD_ int n,big x) +{ /* sets x as random < 2^n */ + mr_small r; + mr_lentype wlen; +#ifdef MR_FP + mr_small dres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zero(x); + if (mr_mip->ERNUM || n<=0) return; + + MR_IN(150) + + expb2(_MIPP_ n,mr_mip->w1); + wlen=mr_mip->w1->len; + do + { + r=brand(_MIPPO_ ); + if (mr_mip->base==0) x->w[x->len++]=r; + else x->w[x->len++]=MR_REMAIN(r,mr_mip->base); + } while (x->lenbase==mr_mip->base2) + { +#endif + + x->w[wlen-1]=MR_REMAIN(x->w[wlen-1],mr_mip->w1->w[wlen-1]); + mr_lzero(x); + +#ifndef MR_ALWAYS_BINARY + } + else + { + divide(_MIPP_ x,mr_mip->w1,mr_mip->w1); + } +#endif + + MR_OUT +} + +#endif diff --git a/miracl/source/mrbrick.c b/miracl/source/mrbrick.c new file mode 100644 index 0000000..eb9e41d --- /dev/null +++ b/miracl/source/mrbrick.c @@ -0,0 +1,219 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * Module to implement Comb method for fast + * computation of g^x mod n, for fixed g and n, using precomputation. + * This idea can be used to substantially speed up certain phases + * of the Digital Signature Standard (DSS) for example. + * + * See "Handbook of Applied Cryptography", CRC Press, 2001 + */ + +#include +#include "miracl.h" + +#ifndef MR_STATIC + +BOOL brick_init(_MIPD_ brick *b,big g,big n,int window,int nb) +{ /* Uses Montgomery arithmetic internally * + * g is the fixed base for exponentiation * + * n is the fixed modulus * + * nb is the maximum number of bits in the exponent */ + + int i,j,k,t,bp,len,bptr,is; + big *table; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (nb<2 || window<1 || window>nb || mr_mip->ERNUM) return FALSE; + t=MR_ROUNDUP(nb,window); + if (t<2) return FALSE; + + MR_IN(109) + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base != mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return FALSE; + } +#endif + + b->window=window; + b->max=nb; + table=(big *)mr_alloc(_MIPP_ (1<n=mirvar(_MIPP_ 0); + copy(n,b->n); + prepare_monty(_MIPP_ n); + nres(_MIPP_ g,mr_mip->w1); + convert(_MIPP_ 1,mr_mip->w2); + nres(_MIPP_ mr_mip->w2,mr_mip->w2); + + table[0]=mirvar(_MIPP_ 0); + copy(mr_mip->w2,table[0]); + table[1]=mirvar(_MIPP_ 0); + copy(mr_mip->w1,table[1]); + for (j=0;jw1,mr_mip->w1,mr_mip->w1); + + k=1; + for (i=2;i<(1<w1,table[i]); + + for (j=0;jw1,mr_mip->w1,mr_mip->w1); + continue; + } + bp=1; + copy(mr_mip->w2,table[i]); + for (j=0;jlen; + bptr=0; + b->table=(mr_small *)mr_alloc(_MIPP_ len*(1<table[bptr++]=table[i]->w[j]; + } + mirkill(table[i]); + } + + mr_free(table); + + MR_OUT + return TRUE; +} + +void brick_end(brick *b) +{ + mirkill(b->n); + mr_free(b->table); +} + +#else + +/* use precomputated table in ROM - see ebrick2.c for example of how to create such a table, and ecdh.c + for an example of use */ + +void brick_init(brick *b,const mr_small *table,big n,int window,int nb) +{ + b->table=table; + b->n=n; + b->window=window; + b->max=nb; +} + +#endif + +void pow_brick(_MIPD_ brick *b,big e,big w) +{ + int i,j,t,len,promptr,maxsize; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (size(e)<0) mr_berror(_MIPP_ MR_ERR_NEG_POWER); + t=MR_ROUNDUP(b->max,b->window); + + MR_IN(110) + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base != mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return; + } +#endif + + if (logb2(_MIPP_ e) > b->max) + { + mr_berror(_MIPP_ MR_ERR_EXP_TOO_BIG); + MR_OUT + return; + } + + prepare_monty(_MIPP_ b->n); + j=recode(_MIPP_ e,t,b->window,t-1); + + len=b->n->len; + maxsize=(1<window)*len; + + promptr=j*len; + init_big_from_rom(mr_mip->w1,len,b->table,maxsize,&promptr); + + for (i=t-2;i>=0;i--) + { + j=recode(_MIPP_ e,t,b->window,i); + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w1); + if (j>0) + { + promptr=j*len; + init_big_from_rom(mr_mip->w2,len,b->table,maxsize,&promptr); + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); + } + } + redc(_MIPP_ mr_mip->w1,w); + MR_OUT +} diff --git a/miracl/source/mrbuild.c b/miracl/source/mrbuild.c new file mode 100644 index 0000000..fbf340a --- /dev/null +++ b/miracl/source/mrbuild.c @@ -0,0 +1,176 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL flash number builder: uses generator of + * regular continued fraction expansion to create + * a flash number, rounded if necessary. + * mrbuild.c + */ + +#include "miracl.h" + +#ifdef MR_FLASH + +void build(_MIPD_ flash x,int (*gen)(_MIPT_ big,int)) +{ /* Build x from its regular c.f. * + * generated by gen() */ + mr_small ex1,ex2,ex,st,sr; + int a,b,c,d,rm,q,n,prc,lw2,lw4,lz; + BOOL finoff,last; + big t; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(48) + + zero(mr_mip->w1); + convert(_MIPP_ 1,mr_mip->w2); + convert(_MIPP_ 1,mr_mip->w3); + zero(mr_mip->w4); + finoff=FALSE; + last=FALSE; + n=0; + q=(*gen)(_MIPP_ x,n); /* Note - first quotient may be zero */ + ex=mr_mip->base-1; + if (mr_mip->nib==mr_mip->workprec) prc=mr_mip->nib; + else prc=mr_mip->workprec+1; + while (!mr_mip->ERNUM && q>=0) + { + if (q==MR_TOOBIG || n==0 || finoff) + { + if (q!=MR_TOOBIG) convert(_MIPP_ q,x); + else last=FALSE; + mr_mip->check=OFF; + multiply(_MIPP_ mr_mip->w2,x,mr_mip->w0); + subtract(_MIPP_ mr_mip->w1,mr_mip->w0,mr_mip->w7); + mr_mip->check=ON; + if ((int)(mr_mip->w7->len&MR_OBITS)>mr_mip->nib) break; + copy(mr_mip->w7,mr_mip->w1); + t=mr_mip->w1,mr_mip->w1=mr_mip->w2,mr_mip->w2=t; /* swap(w1,w2) */ + mr_mip->check=OFF; + multiply(_MIPP_ mr_mip->w4,x,mr_mip->w0); + subtract(_MIPP_ mr_mip->w3,mr_mip->w0,mr_mip->w7); + mr_mip->check=ON; + if ((int)(mr_mip->w7->len&MR_OBITS)>mr_mip->nib) + { /* oops! */ + fpack(_MIPP_ mr_mip->w1,mr_mip->w4,x); + negify(x,x); + mr_mip->EXACT=FALSE; + MR_OUT + return; + } + copy(mr_mip->w7,mr_mip->w3); + t=mr_mip->w3,mr_mip->w3=mr_mip->w4,mr_mip->w4=t; /* swap(w3,w4) */ + n++; + } + lw2=(int)(mr_mip->w2->len&MR_OBITS); + lw4=(int)(mr_mip->w4->len&MR_OBITS); + lz=lw2+lw4; + if (lz > prc) break; /* too big - exit */ + if (last) + { + if (finoff) break; + finoff=TRUE; + q=(*gen)(_MIPP_ x,n); + continue; + } + if (lz>=prc-1) + { /* nearly finished - so be careful not to overshoot */ + if (mr_mip->base==0) + { +#ifndef MR_NOFULLWIDTH + st=mr_mip->w2->w[lw2-1]+1; + if (st==0) ex1=1; + else ex1=muldvm((mr_small)1,(mr_small)0,st,&sr); + st=mr_mip->w4->w[lw4-1]+1; + if (st==0) ex2=1; + else ex2=muldvm((mr_small)1,(mr_small)0,st,&sr); +#endif + } + else + { + ex1=mr_mip->base/(mr_mip->w2->w[lw2-1]+1); + ex2=mr_mip->base/(mr_mip->w4->w[lw4-1]+1); + } + if (ex2>ex1) ex=ex1,ex1=ex2,ex2=ex; + if (lz==prc) ex=ex2; + else ex=ex1; + last=TRUE; + } + a=1; + b=0; + c=0; + d=1; + forever + { + q=(*gen)(_MIPP_ x,n); + if (q<0 || q>=MR_TOOBIG/mr_abs(d)) + { /* there could be more.... *** V3.21 mod *** */ + last=FALSE; + break; + } + rm=b-q*d; + b=d; + d=rm; + rm=a-q*c; + a=c; + c=rm; + n++; + if ((mr_small)(mr_abs(c-d))>ex) break; + } + premult(_MIPP_ mr_mip->w1,c,mr_mip->w7); + premult(_MIPP_ mr_mip->w1,a,mr_mip->w1); + premult(_MIPP_ mr_mip->w2,b,mr_mip->w0); + premult(_MIPP_ mr_mip->w2,d,mr_mip->w2); + add(_MIPP_ mr_mip->w1,mr_mip->w0,mr_mip->w1); + add(_MIPP_ mr_mip->w2,mr_mip->w7,mr_mip->w2); + premult(_MIPP_ mr_mip->w3,c,mr_mip->w7); + premult(_MIPP_ mr_mip->w3,a,mr_mip->w3); + premult(_MIPP_ mr_mip->w4,b,mr_mip->w0); + premult(_MIPP_ mr_mip->w4,d,mr_mip->w4); + add(_MIPP_ mr_mip->w3,mr_mip->w0,mr_mip->w3); + add(_MIPP_ mr_mip->w4,mr_mip->w7,mr_mip->w4); + } + if (fit(mr_mip->w2,mr_mip->w4,mr_mip->nib)) fpack(_MIPP_ mr_mip->w2,mr_mip->w4,x); + else fpack(_MIPP_ mr_mip->w1,mr_mip->w3,x); + negify (x,x); + if (q!=(-1)) mr_mip->EXACT=FALSE; + MR_OUT +} + +#endif + diff --git a/miracl/source/mrcomba.tpl b/miracl/source/mrcomba.tpl new file mode 100644 index 0000000..a4d8ce5 --- /dev/null +++ b/miracl/source/mrcomba.tpl @@ -0,0 +1,1548 @@ +/* + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +*/ +/* + * MIRACL Comba's method for ultimate speed modular multiplication + * mrcomba.tpl + * + * See "Exponentiation Cryptosystems on the IBM PC", IBM Systems + * Journal Vol. 29 No. 4 1990. Comba's method has been extended to + * implement Montgomery reduction. + * + * Here the inner loops of the basic multiplication, squaring and + * Montgomery's redc() functions are completely unravelled, and + * reorganised for maximum possible speed. + * + * This approach is recommended for maximum speed where parameters + * are fixed and compute resources are constrained. The processor must + * support an unsigned multiply instruction, and should have a carry flag. + * + * This file is a template. To fill in the gaps and create mrcomba.c, + * you must run the mex.c program to insert the C or assembly language + * macros from the appropriate .mcs file. For use with C MR_NOASM must + * be defined in mirdef.h + * + * This method would appear to be particularly useful for implementing + * fast Elliptic Curve Cryptosystems over GF(p) and fast 1024-bit RSA + * decryption. + * + * The #define MR_COMBA in mirdef.h determines the FIXED size of + * modulus to be used. This *must* be determined at compile time. + * + * Note that this module can generate a *lot* of code for large values + * of MR_COMBA. This should have a maximum value of 8-16. Any larger + * that and you should define MR_KCM instead - see mrkcm.tpl + * + * Note that on some processors it is *VITAL* that arrays be aligned on + * 4-byte boundaries + * + * **** This code does not like -fomit-frame-pointer using GCC *********** + * + */ + +#include "miracl.h" + +#ifdef MR_COMBA +#if INLINE_ASM == 1 +#define N 2 +#define POINTER WORD PTR +#define PBP bp +#define PBX bx +#define PSI si +#define PDI di +#define DSI si +#define DDI di +#define DBP bp +#define DAX ax +#define DCX cx +#define DDX dx +#endif + +#if INLINE_ASM == 2 +#define N 4 +#define POINTER DWORD PTR +#define PBP bp +#define PBX bx +#define PSI si +#define PDI di +#define DSI esi +#define DDI edi +#define DBP ebp +#define DAX eax +#define DCX ecx +#define DDX edx +#endif + +#if INLINE_ASM == 3 +#define N 4 +#define POINTER DWORD PTR +#define PBP ebp +#define PBX ebx +#define PSI esi +#define PDI edi +#define DSI esi +#define DDI edi +#define DBP ebp +#define DAX eax +#define DCX ecx +#define DDX edx +#endif + +/* NOTE! z must be distinct from x and y */ + +void comba_mult(big x,big y,big z) +{ /* comba multiplier */ + int i; + mr_small *a,*b,*c; + +#ifdef MR_WIN64 + mr_small lo,hi,sumlo,sumhi,extra; +#endif +#ifdef MR_ITANIUM + register mr_small lo1,hi1,lo2,hi2,sumlo,sumhi,extra,ma,mb; +#else +#ifdef MR_NOASM + #ifdef mr_qltype + mr_large pp1; + mr_vlarge sum; + #else + register mr_small extra,s0,s1; + mr_large pp1,pp2,sum; + #endif +#endif +#endif + + for (i=2*MR_COMBA;i<(int)(z->len&MR_OBITS);i++) z->w[i]=0; + + z->len=2*MR_COMBA; + a=x->w; b=y->w; c=z->w; +/*** MULTIPLY ***/ /* multiply a by b, result in c */ + if (z->w[2*MR_COMBA-1]==0) mr_lzero(z); +} + +/* NOTE! z and x must be distinct */ + +void comba_square(big x,big z) +{ /* super comba squarer */ + int i; + mr_small *a,*c; + +#ifdef MR_WIN64 + mr_small lo,hi,sumlo,sumhi,extra,cy; +#endif +#ifdef MR_ITANIUM + register mr_small lo1,hi1,lo2,hi2,sumlo,sumhi,extra,ma,mb; +#endif +#ifdef MR_NOASM + #ifdef mr_qltype + mr_large pp1; + mr_vlarge sum; + #else + register mr_small extra,s0,s1; + mr_large pp1,pp2,sum; + #endif +#endif + + for (i=2*MR_COMBA;i<(int)(z->len&MR_OBITS);i++) z->w[i]=0; + + z->len=2*MR_COMBA; + a=x->w; c=z->w; +/*** SQUARE ***/ /* squares a, result in b */ + if (z->w[2*MR_COMBA-1]==0) mr_lzero(z); +} + +/* NOTE! t and z must be distinct! */ + +void comba_redc(_MIPD_ big t,big z) +{ /* super comba Montgomery redc() function */ + mr_small carry,su; +#ifdef MR_ITANIUM + register mr_small lo1,hi1,lo2,hi2,sumlo,sumhi,extra,ma,mb,sp,u; +#endif +#ifdef MR_WIN64 + mr_small lo,hi,sumlo,sumhi,extra,ma,mb,u; +#endif +#ifdef MR_NOASM + mr_large u; +#ifndef MR_SPECIAL + #ifdef mr_qltype + register mr_small sp; + mr_large pp1; + mr_vlarge sum; + #else + register mr_small sp,extra,s0,s1; + mr_large pp1,pp2,sum; + #endif +#endif +#endif + + unsigned int i; + big w,modulus; + mr_small *a,*b; +#ifndef MR_SPECIAL + BOOL need_subtract; + mr_small ndash; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + +#ifdef MR_SPECIAL + + +/* !!! Implement here a "special" fast method for modular reduction, + for a particular modulus. Implemented here for 2^192-2^64-1 + and 2^224-2^96+1 on a 32 bit processor. + See for example "Software Implementation of the NIST Elliptic + Curves Over Prime Fields", Brown et al., Report #36, 2000 available + from www.cacr.math.uwaterloo.ca + + The generated code can be manually optimised further..... +*/ + int overshoot; + mr_small k[MR_COMBA],sn,tt,v; +#ifdef MR_PSEUDO_MERSENNE_142 + mr_small sh,sl; +#endif + mr_small *c; + + modulus=mr_mip->modulus; + for (i=MR_COMBA;i<(int)(z->len&MR_OBITS);i++) z->w[i]=0; + /* zero(z); */ + z->len=MR_COMBA; + +#ifdef MR_PSEUDO_MERSENNE_142 + +#if MIRACL==32 + +/* special code for 2^142-111 */ + + sn=111; + sh=t->w[4]>>14; + t->w[4]&=0x3FFF; + sl=t->w[5]>>14; + t->w[5]<<=18; t->w[5]|=sh; + sh=t->w[6]>>14; + t->w[6]<<=18; t->w[6]|=sl; + sl=t->w[7]>>14; + t->w[7]<<=18; t->w[7]|=sh; + sh=t->w[8]>>14; + t->w[8]<<=18; t->w[8]|=sl; + t->w[9]=sh; + + a=&(t->w[5]); + b=k; + c=z->w; + +/*** PMULT ***/ + + a=c; + k[0]=(c[4]>>14)*111; + c[4]&=0x3FFF; + +/*** INCREMENT ***/ + b=t->w; + +/*** INCREMENT ***/ + b=modulus->w; + + while (z->w[4]>>14) + { +/*** DECREMENT ***/ + } + + if (z->w[MR_COMBA-1]>=modulus->w[MR_COMBA-1]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + +#endif + +#if MIRACL==64 + + sn=111; + sh=t->w[2]>>14; + t->w[2]&=0x3FFF; + sl=t->w[3]>>14; + t->w[3]<<=50; t->w[3]|=sh; + sh=t->w[4]>>14; + t->w[4]<<=50; t->w[4]|=sl; + t->w[5]=sh; + + a=&(t->w[3]); + b=k; + c=z->w; + +/*** PMULT ***/ + + a=c; + k[0]=(c[2]>>14)*111; + c[2]&=0x3FFF; + +/*** INCREMENT ***/ + b=t->w; + +/*** INCREMENT ***/ + b=modulus->w; + + while (z->w[2]>>14) + { +/*** DECREMENT ***/ + } + + if (z->w[MR_COMBA-1]>=modulus->w[MR_COMBA-1]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + + +#endif + +#endif + +#ifdef MR_PSEUDO_MERSENNE + + sn=(mr_small)0-modulus->w[0]; /* Modulus is 2^{MIRACL*MR_COMBA}-c. Here we calculate c */ + +/* .. where c MUST be a word sized ... */ + + a=&(t->w[MR_COMBA]); + b=k; + c=z->w; + +/*** PMULT ***/ + + a=c; + +/*** INCREMENT ***/ + overshoot=carry; + b=t->w; + +/*** INCREMENT ***/ + overshoot+=carry; + + b=modulus->w; + while(overshoot>0) + { +/*** DECREMENT ***/ + overshoot-=carry; + } + if (z->w[MR_COMBA-1]>=modulus->w[MR_COMBA-1]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + +#endif + +#ifdef MR_GENERALIZED_MERSENNE + +#if MIRACL==64 + + #if MR_COMBA == 3 +/* Special Code for 2^192-2^64-1 - assuming 64-bit processor */ + + a=t->w; b=k; c=z->w; + k[0]=k[1]=a[3]; k[2]=0; + +/*** ADDITION ***/ + overshoot=carry; + a=c; c=t->w; + k[0]=0;k[1]=k[2]=c[4]; + +/*** INCREMENT ***/ + overshoot+=carry; + k[0]=k[1]=k[2]=c[5]; + +/*** INCREMENT ***/ + overshoot+=carry; + b=modulus->w; + while(overshoot>0) + { +/*** DECREMENT ***/ + overshoot-=carry; + } + if (z->w[MR_COMBA-1]>=modulus->w[MR_COMBA-1]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + + #endif + + #if MR_COMBA == 2 +/* Special code for 2^127-1 - for 64-bit processor */ + + a=t->w; + k[0]=a[2]; k[1]=a[3]; + a=b=k; + +/*** INCREMENT ***/ + + a=t->w; + k[0]+=(a[1]>>63); k[1]|=(a[1]&0x8000000000000000); + + c=z->w; + +/*** ADDITION ***/ + + a=z->w; + b=modulus->w; + + if (z->w[1]>=modulus->w[1]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + + #endif + + #if MR_COMBA == 9 + +/* Special Code for 2^521-1 - assuming 64-bit processor */ + +/* split t into 521-bit halves, low half in a, high half in b */ + + a=t->w; b=k; c=z->w; + + for (i=0;i<=8;i++) + b[i]=(a[i+8]>>9)|(a[i+9]<<55); + + b[8]|=(-(a[8]>>9)<<9); /* clever stuff! Set top part of b[8] to minus * + * top part of a[8]. When added they cancel out */ + +/*** ADDITION ***/ + /* ignore carry=1 */ + a=z->w; + b=modulus->w; + + if (z->w[MR_COMBA-1]>=modulus->w[MR_COMBA-1]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + #endif + + +#endif + + +#if MIRACL==8 + + #if MR_COMBA==32 + + a=t->w; b=k; c=z->w; + k[0]=k[1]=k[2]=k[3]=k[4]=k[5]=k[6]=k[7]=k[8]=k[9]=k[10]=k[11]=0; + k[12]=a[44]; k[13]=a[45]; k[14]=a[46]; k[15]=a[47]; + k[16]=a[48]; k[17]=a[49]; k[18]=a[50]; k[19]=a[51]; + k[20]=a[52]; k[21]=a[53]; k[22]=a[54]; k[23]=a[55]; + k[24]=a[56]; k[25]=a[57]; k[26]=a[58]; k[27]=a[59]; + k[28]=a[60]; k[29]=a[61]; k[30]=a[62]; k[31]=a[63]; + +/*** ADDITION ***/ + overshoot=carry; + a=c; c=t->w; + +/*** INCREMENT ***/ + overshoot+=carry; + + + k[0]=k[1]=k[2]=k[3]=k[4]=k[5]=k[6]=k[7]=k[8]=k[9]=k[10]=k[11]=0; + k[12]=c[48]; k[13]=c[49]; k[14]=c[50]; k[15]=c[51]; + k[16]=c[52]; k[17]=c[53]; k[18]=c[54]; k[19]=c[55]; + k[20]=c[56]; k[21]=c[57]; k[22]=c[58]; k[23]=c[59]; + k[24]=c[60]; k[25]=c[61]; k[26]=c[62]; k[27]=c[63]; + k[28]=k[29]=k[30]=k[31]=0; + + +/*** INCREMENT ***/ + overshoot+=carry; + +/*** INCREMENT ***/ + overshoot+=carry; + + k[0]=c[32]; k[1]=c[33]; k[2]=c[34]; k[3]=c[35]; + k[4]=c[36]; k[5]=c[37]; k[6]=c[38]; k[7]=c[39]; + k[8]=c[40]; k[9]=c[41]; k[10]=c[42]; k[11]=c[43]; + k[12]=k[13]=k[14]=k[15]=k[16]=k[17]=k[18]=k[19]=k[20]=k[21]=k[22]=k[23]=0; + k[24]=c[56]; k[25]=c[57]; k[26]=c[58]; k[27]=c[59]; + k[28]=c[60]; k[29]=c[61]; k[30]=c[62]; k[31]=c[63]; + + +/*** INCREMENT ***/ + overshoot+=carry; + + k[0]=c[36]; k[1]=c[37]; k[2]=c[38]; k[3]=c[39]; + k[4]=c[40]; k[5]=c[41]; k[6]=c[42]; k[7]=c[43]; + k[8]=c[44]; k[9]=c[45]; k[10]=c[46]; k[11]=c[47]; + k[12]=c[52]; k[13]=c[53]; k[14]=c[54]; k[15]=c[55]; + k[16]=c[56]; k[17]=c[57]; k[18]=c[58]; k[19]=c[59]; + k[20]=c[60]; k[21]=c[61]; k[22]=c[62]; k[23]=c[63]; + k[24]=c[52]; k[25]=c[53]; k[26]=c[54]; k[27]=c[55]; + k[28]=c[32]; k[29]=c[33]; k[30]=c[34]; k[31]=c[35]; + +/*** INCREMENT ***/ + overshoot+=carry; + + k[0]=c[44]; k[1]=c[45]; k[2]=c[46]; k[3]=c[47]; + k[4]=c[48]; k[5]=c[49]; k[6]=c[50]; k[7]=c[51]; + k[8]=c[52]; k[9]=c[53]; k[10]=c[54]; k[11]=c[55]; + k[12]=k[13]=k[14]=k[15]=k[16]=k[17]=k[18]=k[19]=k[20]=k[21]=k[22]=k[23]=0; + k[24]=c[32]; k[25]=c[33]; k[26]=c[34]; k[27]=c[35]; + k[28]=c[40]; k[29]=c[41]; k[30]=c[42]; k[31]=c[43]; + + +/*** DECREMENT ***/ + overshoot-=carry; + + k[0]=c[48]; k[1]=c[49]; k[2]=c[50]; k[3]=c[51]; + k[4]=c[52]; k[5]=c[53]; k[6]=c[54]; k[7]=c[55]; + k[8]=c[56]; k[9]=c[57]; k[10]=c[58]; k[11]=c[59]; + k[12]=c[60]; k[13]=c[61]; k[14]=c[62]; k[15]=c[63]; + k[16]=k[17]=k[18]=k[19]=k[20]=k[21]=k[22]=k[23]=0; + k[24]=c[36]; k[25]=c[37]; k[26]=c[38]; k[27]=c[39]; + k[28]=c[44]; k[29]=c[45]; k[30]=c[46]; k[31]=c[47]; + + +/*** DECREMENT ***/ + overshoot-=carry; + + k[0]=c[52]; k[1]=c[53]; k[2]=c[54]; k[3]=c[55]; + k[4]=c[56]; k[5]=c[57]; k[6]=c[58]; k[7]=c[59]; + k[8]=c[60]; k[9]=c[61]; k[10]=c[62]; k[11]=c[63]; + k[12]=c[32]; k[13]=c[33]; k[14]=c[34]; k[15]=c[35]; + k[16]=c[36]; k[17]=c[37]; k[18]=c[38]; k[19]=c[39]; + k[20]=c[40]; k[21]=c[41]; k[22]=c[42]; k[23]=c[43]; + k[24]=k[25]=k[26]=k[27]=0; + k[28]=c[48]; k[29]=c[49]; k[30]=c[50]; k[31]=c[51]; + + +/*** DECREMENT ***/ + overshoot-=carry; + + k[0]=c[56]; k[1]=c[57]; k[2]=c[58]; k[3]=c[59]; + k[4]=c[60]; k[5]=c[61]; k[6]=c[62]; k[7]=c[63]; + k[8]=k[9]=k[10]=k[11]=0; + k[12]=c[36]; k[13]=c[37]; k[14]=c[38]; k[15]=c[39]; + k[16]=c[40]; k[17]=c[41]; k[18]=c[42]; k[19]=c[43]; + k[20]=c[44]; k[21]=c[45]; k[22]=c[46]; k[23]=c[47]; + k[24]=k[25]=k[26]=k[27]=0; + k[28]=c[52]; k[29]=c[53]; k[30]=c[54]; k[31]=c[55]; + + +/*** DECREMENT ***/ + overshoot-=carry; + + b=modulus->w; + while (overshoot>0) + { +/*** DECREMENT ***/ + overshoot-=carry; + } + while (overshoot<0) + { +/*** INCREMENT ***/ + overshoot+=carry; + } + if (z->w[MR_COMBA-1]>=modulus->w[MR_COMBA-1]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + + #endif + + #if MR_COMBA == 16 + +/* Special code for 2^127-1 - for 8-bit processor */ + + a=t->w; + k[0]=a[16]; k[1]=a[17]; k[2]=a[18]; k[3]=a[19]; + k[4]=a[20]; k[5]=a[21]; k[6]=a[22]; k[7]=a[23]; + k[8]=a[24]; k[9]=a[25]; k[10]=a[26]; k[11]=a[27]; + k[12]=a[28]; k[13]=a[29]; k[14]=a[30]; k[15]=a[31]; + + a=b=k; + +/*** DOUBLEIT ***/ + + a=t->w; + k[0]+=(a[15]>>7); k[15]|=(a[15]&0x80); + + c=z->w; + +/*** ADDITION ***/ + + a=z->w; + b=modulus->w; + +/* if MSB is 1, try and deal with it here */ + + tt=(mr_small)(z->w[15]>>M1); + v=z->w[0]+tt; + if (v>=z->w[0]) + { + z->w[15]-=(mr_small)(tt<w[0]=v; + } + +/* This is probably not going to happen now... */ + + if (z->w[15]>=modulus->w[15]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + + #endif + + #if MR_COMBA==20 + + /* 2^160-2^112+2^64+1 */ + +/* faster way - keep a[20] to a[39] in registers r2-r21. +*/ + + a=t->w; b=k; c=z->w; + + k[0]=k[8]=a[38]; k[2]=k[4]=k[6]=k[10]=k[12]=0; k[14]=a[20]; k[16]=a[22]; k[18]=a[24]; + k[1]=k[9]=a[39]; k[3]=k[5]=k[7]=k[11]=k[13]=0; k[15]=a[21]; k[17]=a[23]; k[19]=a[25]; + +/*** ADDITION ***/ + overshoot=carry; + a=c; c=t->w; + k[0]=k[2]=k[4]=k[6]=0; k[8]=k[14]=k[16]=c[34]; k[10]=c[36]; k[12]=c[24]; k[18]=0; + k[1]=k[3]=k[5]=k[7]=0; k[9]=k[15]=k[17]=c[35]; k[11]=c[37]; k[13]=c[25]; k[19]=0; + +/*** DECREMENT ***/ + overshoot-=carry; + k[4]=c[24]; k[6]=k[12]=k[14]=c[32]; k[0]=k[8]=c[20]; k[2]=k[10]=c[22]; k[16]=k[18]=c[36]; + k[5]=c[25]; k[7]=k[13]=k[15]=c[33]; k[1]=k[9]=c[21]; k[3]=k[11]=c[23]; k[17]=k[19]=c[37]; + +/*** DECREMENT ***/ + overshoot-=carry; + k[0]=k[6]=k[8]=c[26]; k[4]=k[10]=k[12]=c[30]; k[2]=k[14]=k[16]=k[18]=0; + k[1]=k[7]=k[9]=c[27]; k[5]=k[11]=k[13]=c[31]; k[3]=k[15]=k[17]=k[19]=0; + +/*** DECREMENT ***/ + overshoot-=carry; + k[2]=k[8]=k[10]=c[28]; k[0]=k[4]=k[6]=k[16]=0; k[12]=k[14]=k[18]=c[38]; + k[3]=k[9]=k[11]=c[29]; k[1]=k[5]=k[7]=k[17]=0; k[13]=k[15]=k[19]=c[39]; + +/*** DECREMENT ***/ + overshoot-=carry; + + b=modulus->w; + while(overshoot>0) + { +/*** DECREMENT ***/ + overshoot-=carry; + } + while (overshoot<0) + { +/*** INCREMENT ***/ + overshoot+=carry; + } + + if (z->w[MR_COMBA-1]>=modulus->w[MR_COMBA-1]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + + #endif +#endif + +#if MIRACL==16 + #if MR_COMBA==10 + + /* 2^160-2^112+2^64+1 */ + + a=t->w; b=k; c=z->w; + k[0]=k[4]=a[19]; k[1]=k[2]=k[3]=k[5]=k[6]=0; k[7]=a[10]; k[8]=a[11]; k[9]=a[12]; + +/*** ADDITION ***/ + overshoot=carry; + a=c; c=t->w; + k[0]=k[1]=k[2]=k[3]=0; k[4]=k[7]=k[8]=c[17]; k[5]=c[18]; k[6]=c[12]; k[9]=0; + +/*** DECREMENT ***/ + overshoot-=carry; + k[2]=c[12]; k[3]=k[6]=k[7]=c[16]; k[0]=k[4]=c[10]; k[1]=k[5]=c[11]; k[8]=k[9]=c[18]; + +/*** DECREMENT ***/ + overshoot-=carry; + k[0]=k[3]=k[4]=c[13]; k[2]=k[5]=k[6]=c[15]; k[1]=k[7]=k[8]=k[9]=0; + +/*** DECREMENT ***/ + overshoot-=carry; + k[1]=k[4]=k[5]=c[14]; k[0]=k[2]=k[3]=k[8]=0; k[6]=k[7]=k[9]=c[19]; + +/*** DECREMENT ***/ + overshoot-=carry; + + b=modulus->w; + while(overshoot>0) + { +/*** DECREMENT ***/ + overshoot-=carry; + } + while (overshoot<0) + { +/*** INCREMENT ***/ + overshoot+=carry; + } + + if (z->w[MR_COMBA-1]>=modulus->w[MR_COMBA-1]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + #endif +#endif + +#if MIRACL==32 + +#if MR_COMBA == 8 +#ifdef MR_NOFULLWIDTH + +/* Modulus is 2^255-19 - Experimental - not tested! */ + +w->w=&(t->w[10]); +w->len=9; +premult(_MIPP_ w,608,w); +incr(_MIPP_ w,19*(t->w[9]>>21),w); +t->w[9]&=(1<<21)-1; +t->len++; +z->len=10; +for (i=0;i<10;i++) z->w[i]=t->w[i]; +comba_sub(z,w,z); + + +#endif +#endif + + #if MR_COMBA == 4 + +/* Special code for 2^127-1 - for 32-bit processor */ + + a=t->w; + k[0]=a[4]; k[1]=a[5]; k[2]=a[6]; k[3]=a[7]; + a=b=k; + +/*** DOUBLEIT ***/ + + a=t->w; + k[0]+=(a[3]>>31); k[3]|=(a[3]&0x80000000); + + c=z->w; + +/*** ADDITION ***/ + + a=z->w; + b=modulus->w; + + if (z->w[3]>=modulus->w[3]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + + #endif + + #if MR_COMBA == 6 + +/* Special Code for 2^192-2^64-1 - assuming 32-bit processor */ + + a=t->w; b=k; c=z->w; + k[0]=k[2]=a[6]; k[1]=k[3]=a[7]; k[4]=k[5]=0; + +/*** ADDITION ***/ + overshoot=carry; + a=c; c=t->w; + k[0]=k[1]=0; k[2]=k[4]=c[8]; k[3]=k[5]=c[9]; + +/*** INCREMENT ***/ + overshoot+=carry; + k[0]=k[2]=k[4]=c[10]; k[1]=k[3]=k[5]=c[11]; + +/*** INCREMENT ***/ + overshoot+=carry; + b=modulus->w; + while(overshoot>0) + { +/*** DECREMENT ***/ + overshoot-=carry; + } + if (z->w[MR_COMBA-1]>=modulus->w[MR_COMBA-1]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + + #endif + + #if MR_COMBA == 7 +/* Special Code for 2^224-2^96+1 - assuming 32-bit processor */ + + a=t->w; b=k; c=z->w; + k[0]=k[1]=k[2]=0; k[3]=a[7]; k[4]=a[8]; k[5]=a[9]; k[6]=a[10]; + +/*** ADDITION ***/ + overshoot=carry; + a=c; c=t->w; + k[0]=k[1]=k[2]=k[6]=0; k[3]=c[11]; k[4]=c[12]; k[5]=c[13]; + +/*** INCREMENT ***/ + overshoot+=carry; + k[0]=c[7]; k[1]=c[8]; k[2]=c[9]; k[3]=c[10]; k[4]=c[11]; k[5]=c[12]; k[6]=c[13]; + +/*** DECREMENT ***/ + overshoot-=carry; + k[0]=c[11]; k[1]=c[12]; k[2]=c[13]; k[3]=k[4]=k[5]=k[6]=0; + +/*** DECREMENT ***/ + overshoot-=carry; + b=modulus->w; + while (overshoot>0) + { +/*** DECREMENT ***/ + overshoot-=carry; + } + while (overshoot<0) + { +/*** INCREMENT ***/ + overshoot+=carry; + } + if (z->w[MR_COMBA-1]>=modulus->w[MR_COMBA-1]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + + #endif + + #if MR_COMBA == 8 + #ifndef MR_NOFULLWIDTH + + a=t->w; b=k; c=z->w; + k[0]=k[1]=k[2]=0; k[3]=a[11]; k[4]=a[12]; k[5]=a[13]; k[6]=a[14]; k[7]=a[15]; + +/*** ADDITION ***/ + overshoot=carry; + a=c; c=t->w; + +/*** INCREMENT ***/ + overshoot+=carry; + + k[0]=k[1]=k[2]=0; k[3]=c[12]; k[4]=c[13]; k[5]=c[14]; k[6]=c[15]; k[7]=0; + +/*** INCREMENT ***/ + overshoot+=carry; + +/*** INCREMENT ***/ + overshoot+=carry; + + k[0]=c[8]; k[1]=c[9]; k[2]=c[10]; k[3]=k[4]=k[5]=0; k[6]=c[14]; k[7]=c[15]; + +/*** INCREMENT ***/ + overshoot+=carry; + + k[0]=c[9]; k[1]=c[10]; k[2]=c[11]; k[3]=c[13]; k[4]=c[14]; k[5]=c[15]; k[6]=c[13]; k[7]=c[8]; + +/*** INCREMENT ***/ + overshoot+=carry; + + k[0]=c[11]; k[1]=c[12]; k[2]=c[13]; k[3]=k[4]=k[5]=0; k[6]=c[8]; k[7]=c[10]; + +/*** DECREMENT ***/ + overshoot-=carry; + + k[0]=c[12]; k[1]=c[13]; k[2]=c[14]; k[3]=c[15]; k[4]=k[5]=0; k[6]=c[9]; k[7]=c[11]; + +/*** DECREMENT ***/ + overshoot-=carry; + + k[0]=c[13]; k[1]=c[14]; k[2]=c[15]; k[3]=c[8]; k[4]=c[9]; k[5]=c[10]; k[6]=0; k[7]=c[12]; + +/*** DECREMENT ***/ + overshoot-=carry; + + k[0]=c[14]; k[1]=c[15]; k[2]=0; k[3]=c[9]; k[4]=c[10]; k[5]=c[11]; k[6]=0; k[7]=c[13]; + +/*** DECREMENT ***/ + overshoot-=carry; + + b=modulus->w; + while (overshoot>0) + { +/*** DECREMENT ***/ + overshoot-=carry; + } + while (overshoot<0) + { +/*** INCREMENT ***/ + overshoot+=carry; + } + if (z->w[MR_COMBA-1]>=modulus->w[MR_COMBA-1]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + + #endif + #endif + + #if MR_COMBA == 12 + #ifndef MR_NOFULLWIDTH + +/* NIST P-384 curve */ + + a=t->w; b=k; c=z->w; + k[0]=k[1]=k[2]=k[3]=0; k[4]=a[21]; k[5]=a[22]; k[6]=a[23]; k[7]=k[8]=k[9]=k[10]=k[11]=0; + +/*** ADDITION ***/ + overshoot=carry; + a=c; c=t->w; + +/*** INCREMENT ***/ + overshoot+=carry; + + k[0]=c[12]; k[1]=c[13]; k[2]=c[14]; k[3]=c[15]; k[4]=c[16]; k[5]=c[17]; k[6]=c[18]; k[7]=c[19]; k[8]=c[20]; k[9]=c[21]; k[10]=c[22]; k[11]=c[23]; + +/*** INCREMENT ***/ + overshoot+=carry; + + k[0]=c[21]; k[1]=c[22]; k[2]=c[23]; k[3]=c[12]; k[4]=c[13]; k[5]=c[14]; k[6]=c[15]; k[7]=c[16]; k[8]=c[17]; k[9]=c[18]; k[10]=c[19]; k[11]=c[20]; + +/*** INCREMENT ***/ + overshoot+=carry; + + k[0]=k[2]=0; k[1]=c[23]; k[3]=c[20]; k[4]=c[12]; k[5]=c[13]; k[6]=c[14]; k[7]=c[15]; k[8]=c[16]; k[9]=c[17]; k[10]=c[18]; k[11]=c[19]; + +/*** INCREMENT ***/ + overshoot+=carry; + + k[0]=k[1]=k[2]=k[3]=0; k[4]=c[20]; k[5]=c[21]; k[6]=c[22]; k[7]=c[23]; k[8]=k[9]=k[10]=k[11]=0; + +/*** INCREMENT ***/ + overshoot+=carry; + + k[0]=c[20]; k[1]=k[2]=0; k[3]=c[21]; k[4]=c[22]; k[5]=c[23]; k[6]=k[7]=k[8]=k[9]=k[10]=k[11]=0; + +/*** INCREMENT ***/ + overshoot+=carry; + + k[0]=c[23]; k[1]=c[12]; k[2]=c[13]; k[3]=c[14]; k[4]=c[15]; k[5]=c[16]; k[6]=c[17]; k[7]=c[18]; k[8]=c[19]; k[9]=c[20]; k[10]=c[21]; k[11]=c[22]; + +/*** DECREMENT ***/ + overshoot-=carry; + + k[0]=0; k[1]=c[20]; k[2]=c[21]; k[3]=c[22]; k[4]=c[23]; k[5]=k[6]=k[7]=k[8]=k[9]=k[10]=k[11]=0; + +/*** DECREMENT ***/ + overshoot-=carry; + + k[0]=k[1]=k[2]=0; k[3]=k[4]=c[23]; k[5]=k[6]=k[7]=k[8]=k[9]=k[10]=k[11]=0; + +/*** DECREMENT ***/ + overshoot-=carry; + + b=modulus->w; + while (overshoot>0) + { +/*** DECREMENT ***/ + overshoot-=carry; + } + while (overshoot<0) + { +/*** INCREMENT ***/ + overshoot+=carry; + } + if (z->w[MR_COMBA-1]>=modulus->w[MR_COMBA-1]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + + #endif + #endif + + + #if MR_COMBA == 17 + +/* Special Code for 2^521-1 - assuming 32-bit processor */ + +/* split t into 521-bit halves, low half in a, high half in b */ + + a=t->w; b=k; c=z->w; + + for (i=0;i<=16;i++) + b[i]=(a[i+16]>>9)|(a[i+17]<<23); + + b[16]|=(-(a[16]>>9)<<9); /* clever stuff! Set top part of b[16] to minus * + * top part of a[16]. When added they cancel out */ + +/*** ADDITION ***/ + /* ignore carry=1 */ + a=z->w; + b=modulus->w; + + if (z->w[MR_COMBA-1]>=modulus->w[MR_COMBA-1]) + { + if (mr_compare(z,modulus)>=0) + { +/*** DECREMENT ***/ + } + } + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + #endif + #endif + #endif +#else + modulus=mr_mip->modulus; + ndash=mr_mip->ndash; + w=mr_mip->w0; + if (t!=w) copy(t,w); + w->len=2*MR_COMBA+1; + a=w->w; b=modulus->w; + +/*** REDC ***/ /* reduces a mod b */ + + for (i=MR_COMBA;i<(int)(z->len&MR_OBITS);i++) z->w[i]=0; + + z->len=MR_COMBA; + for (i=0;iw[i]=w->w[i+MR_COMBA]; + + need_subtract=FALSE; + + if (w->w[MR_COMBA+MR_COMBA]!=0) + { + need_subtract=TRUE; + } + else + { + if (z->w[MR_COMBA-1]!=0) + { + if (z->w[MR_COMBA-1]>modulus->w[MR_COMBA-1]) need_subtract=TRUE; + else + { + if (z->w[MR_COMBA-1]==modulus->w[MR_COMBA-1]) + { + if (mr_compare(z,modulus)>=0) need_subtract=TRUE; + } + } + } + else mr_lzero(z); + } + + if (need_subtract) + { + a=z->w; b=modulus->w; +/*** DECREMENT ***/ + z->len=MR_COMBA; + if (z->w[MR_COMBA-1]==0) mr_lzero(z); + } + +#endif +} + +#ifdef MR_SPECIAL +#ifdef MR_GENERALIZED_MERSENNE +#if MIRACL*MR_COMBA == 128 +#define MR_FAST_MOD_ADD 2 +#endif +#endif +#endif + +#ifdef MR_SPECIAL +#ifdef MR_PSEUDO_MERSENNE +#define MR_FAST_MOD_ADD 1 +#define MR_OP(c) ( ((mr_utype)((c)<>M1) +#endif +#endif + +void comba_modadd(_MIPD_ big x,big y,big w) +{ /* fast modular addition */ + unsigned int i; + big modulus; + BOOL dodec; + mr_small *a,*b,*c; + mr_small carry,su; +#ifdef MR_WIN64 + mr_small ma,mb,u; +#endif +#ifdef MR_ITANIUM + mr_small ma,mb,u; +#endif +#ifdef MR_NOASM + mr_large u; +#endif + +#ifdef MR_FAST_MOD_ADD + mr_small sc,t,v; +#endif + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + modulus=mr_mip->modulus; + if (w!=x && w!=y) + { + for (i=MR_COMBA;i<(w->len&MR_OBITS);i++) w->w[i]=0; + /* zero(w); */ + } + + a=x->w; b=y->w; c=w->w; +/*** ADDITION ***/ /* add a and b, result in c */ + w->len=MR_COMBA; + +#ifdef MR_FAST_MOD_ADD + +#if MR_FAST_MOD_ADD == 1 + + sc=(mr_small)0-modulus->w[0]; /* Modulus is 2^{MIRACL*MR_COMBA}-c. Here we calculate c */ + t=MR_OP(carry)≻ + v=w->w[0]+t; + if (v>=w->w[0]) + { + w->w[0]=v; + carry=0; + } + +#endif + +#if MR_FAST_MOD_ADD == 2 + + t=(mr_small)(w->w[MR_COMBA-1]>>M1); + v=w->w[0]+t; + if (v>=w->w[0]) + { + w->w[MR_COMBA-1]-=(mr_small)(t<w[0]=v; + carry=0; + } + +#endif + +#endif + +/* if sum is greater than modulus a decrement will be required */ + + dodec=FALSE; + if (carry) dodec=TRUE; /* possible misprediction here */ + else + { + if (w->w[MR_COMBA-1]>modulus->w[MR_COMBA-1]) dodec=TRUE; /* possible misprediction here */ + else + { + if (w->w[MR_COMBA-1]==modulus->w[MR_COMBA-1]) /* this will be very rare, so easily predicted */ + { /* trying to avoid calling this slow function */ + if (mr_compare(w,modulus)>=0) dodec=TRUE; /* do full comparison */ + } + } + } + + if (dodec) /* prediction here correlated to earlier predictions, so should predict nicely */ + { + a=w->w; b=modulus->w; +/*** DECREMENT ***/ /* decrement b from a */ + } + + if (w->w[MR_COMBA-1]==0) mr_lzero(w); + +} + +void comba_add(big x,big y,big w) +{ /* fast addition */ + unsigned int i; + mr_small *a,*b,*c; + mr_small carry,su; +#ifdef MR_WIN64 + mr_small ma,mb,u; +#endif +#ifdef MR_ITANIUM + mr_small ma,mb,u; +#endif +#ifdef MR_NOASM + mr_large u; +#endif + + if (w!=x && w!=y) + { + for (i=MR_COMBA;i<(w->len&MR_OBITS);i++) w->w[i]=0; + /* zero(w); */ + } + + a=x->w; b=y->w; c=w->w; +/*** ADDITION ***/ /* add a and b, result in c */ + + w->len=MR_COMBA; + if (w->w[MR_COMBA-1]==0) mr_lzero(w); +} + +void comba_modsub(_MIPD_ big x,big y,big w) +{ /* fast modular subtraction */ + unsigned int i; + big modulus; + mr_small *a,*b,*c; + mr_small carry,su; +#ifdef MR_WIN64 + mr_small ma,mb,u; +#endif +#ifdef MR_ITANIUM + mr_small ma,u; +#endif +#ifdef MR_NOASM + mr_large u; +#endif +#ifdef MR_FAST_MOD_ADD + mr_small sc,t,v; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + modulus=mr_mip->modulus; + if (x!=w && y!=w) + { + for (i=MR_COMBA;i<(w->len&MR_OBITS);i++) w->w[i]=0; + /* zero(w); */ + } + + a=x->w; b=y->w; c=w->w; +/*** SUBTRACTION ***/ + +#ifdef MR_FAST_MOD_ADD + +#if MR_FAST_MOD_ADD == 1 + + sc=(mr_small)0-modulus->w[0]; /* Modulus is 2^{MIRACL*MR_COMBA}-c. Here we calculate c */ + t=MR_OP(carry)≻ + v=w->w[0]-t; + if (v<=w->w[0]) + { + w->w[0]=v; + carry=0; + } + +#endif + +#if MR_FAST_MOD_ADD == 2 + + t=(w->w[MR_COMBA-1]>>M1); + v=w->w[0]-t; + if (v<=w->w[0]) + { + w->w[MR_COMBA-1]-=(t<w[0]=v; + carry=0; + } + +#endif + +#endif + + if (carry) + { + a=w->w; b=modulus->w; +/*** INCREMENT ***/ /* add a and b, result in c */ + + } + w->len=MR_COMBA; + if (w->w[MR_COMBA-1]==0) mr_lzero(w); +} + +void comba_sub(big x,big y,big w) +{ /* fast subtraction */ + unsigned int i; + mr_small *a,*b,*c; + mr_small carry,su; +#ifdef MR_WIN64 + mr_small ma,mb,u; +#endif +#ifdef MR_ITANIUM + mr_small ma,u; +#endif +#ifdef MR_NOASM + mr_large u; +#endif + + if (x!=w && y!=w) + { + for (i=MR_COMBA;i<(w->len&MR_OBITS);i++) w->w[i]=0; + /* zero(w); */ + } + + a=x->w; b=y->w; c=w->w; +/*** SUBTRACTION ***/ + + w->len=MR_COMBA; + if (w->w[MR_COMBA-1]==0) mr_lzero(w); +} + +#ifndef MR_NO_LAZY_REDUCTION + +void comba_double_modadd(_MIPD_ big x,big y,big w) +{ /* fast modular addition */ + unsigned int i; + big modulus; + BOOL dodec; + mr_small *a,*b,*c; + mr_small carry,su; +#ifdef MR_WIN64 + mr_small ma,mb,u; +#endif +#ifdef MR_ITANIUM + mr_small ma,u; +#endif +#ifdef MR_NOASM + mr_large u; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + modulus=mr_mip->pR; + if (w!=x && w!=y) + { + for (i=2*MR_COMBA;i<(w->len&MR_OBITS);i++) w->w[i]=0; + /* zero(w); */ + } + + a=x->w; b=y->w; c=w->w; +/*** ADDITION2 ***/ /* add a and b, result in c */ + w->len=2*MR_COMBA; + +/* if sum is greater than modulus a decrement will be required */ + + dodec=FALSE; + if (carry) dodec=TRUE; /* possible misprediction here */ + else + { + if (w->w[2*MR_COMBA-1]>modulus->w[2*MR_COMBA-1]) dodec=TRUE; /* possible misprediction here */ + else + { + if (w->w[2*MR_COMBA-1]==modulus->w[2*MR_COMBA-1]) /* this will be very rare, so easily predicted */ + { + if (mr_compare(w,modulus)>=0) dodec=TRUE; /* do full comparison */ + } + } + } + + if (dodec) /* prediction here correlated to earlier predictions, so should predict nicely */ + { + a=&(w->w[MR_COMBA]); b=&(modulus->w[MR_COMBA]); +/*** DECREMENT ***/ /* decrement b from a */ + } + if (w->w[2*MR_COMBA-1]==0) mr_lzero(w); + +} + +void comba_double_add(big x,big y,big w) +{ /* fast modular addition */ + unsigned int i; + mr_small *a,*b,*c; + mr_small carry,su; +#ifdef MR_WIN64 + mr_small ma,mb,u; +#endif +#ifdef MR_ITANIUM + mr_small ma,u; +#endif +#ifdef MR_NOASM + mr_large u; +#endif + + if (w!=x && w!=y) + { + for (i=2*MR_COMBA;i<(w->len&MR_OBITS);i++) w->w[i]=0; + /* zero(w); */ + } + + a=x->w; b=y->w; c=w->w; +/*** ADDITION2 ***/ /* add a and b, result in c */ + w->len=2*MR_COMBA; + + if (w->w[2*MR_COMBA-1]==0) mr_lzero(w); + +} + +void comba_double_modsub(_MIPD_ big x,big y,big w) +{ /* fast modular subtraction */ + unsigned int i; + big modulus; + mr_small *a,*b,*c; + mr_small carry,su; +#ifdef MR_WIN64 + mr_small ma,mb,u; +#endif +#ifdef MR_ITANIUM + mr_small ma,u; +#endif +#ifdef MR_NOASM + mr_large u; +#endif + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + modulus=mr_mip->modulus; + if (x!=w && y!=w) + { + for (i=2*MR_COMBA;i<(w->len&MR_OBITS);i++) w->w[i]=0; + /* zero(w); */ + } + + a=x->w; b=y->w; c=w->w; +/*** SUBTRACTION2 ***/ + + if (carry) + { + a=&(w->w[MR_COMBA]); b=modulus->w; +/*** INCREMENT ***/ /* add a and b, result in c */ + + } + w->len=2*MR_COMBA; + if (w->w[2*MR_COMBA-1]==0) mr_lzero(w); +} + +void comba_double_sub(big x,big y,big w) +{ /* fast modular subtraction */ + unsigned int i; + mr_small *a,*b,*c; + mr_small carry,su; +#ifdef MR_WIN64 + mr_small ma,mb,u; +#endif +#ifdef MR_ITANIUM + mr_small ma,u; +#endif +#ifdef MR_NOASM + mr_large u; +#endif + + if (x!=w && y!=w) + { + for (i=2*MR_COMBA;i<(w->len&MR_OBITS);i++) w->w[i]=0; + /* zero(w); */ + } + + a=x->w; b=y->w; c=w->w; +/*** SUBTRACTION2 ***/ + + w->len=2*MR_COMBA; + if (w->w[2*MR_COMBA-1]==0) mr_lzero(w); +} + +#endif + +void comba_negate(_MIPD_ big x,big w) +{ /* fast modular subtraction */ + unsigned int i; + big modulus; + mr_small *a,*b,*c; + mr_small carry,su; +#ifdef MR_WIN64 + mr_small ma,mb,u; +#endif +#ifdef MR_ITANIUM + mr_small ma,u; +#endif +#ifdef MR_NOASM + mr_large u; +#endif + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + modulus=mr_mip->modulus; + if (w!=x) + { + for (i=MR_COMBA;i<(w->len&MR_OBITS);i++) w->w[i]=0; + /* zero(w); */ + } + a=modulus->w; b=x->w; c=w->w; + +/*** SUBTRACTION ***/ + + w->len=MR_COMBA; + if (w->w[MR_COMBA-1]==0) mr_lzero(w); +} + +#endif diff --git a/miracl/source/mrcomba2.tpl b/miracl/source/mrcomba2.tpl new file mode 100644 index 0000000..fc93d71 --- /dev/null +++ b/miracl/source/mrcomba2.tpl @@ -0,0 +1,100 @@ + +/* + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +*/ +/* + * MIRACL Comba's method for ultimate speed binary polynomial + * mrcomba2.tpl + * + * Here the inner loops of the basic multiplication, and squaring + * algorithms are completely unravelled, and reorganised for maximum possible speed. + * + * This approach is recommended for maximum speed where parameters + * are fixed and compute resources are constrained. The processor MUST + * support a special binary polynomial multiplication instruction + * + * This file is a template. To fill in the gaps and create mrcomba2.c, + * you must run the mex.c program to insert the C or assembly language + * macros from the appropriate .mcs file. + * + * This method would appear to be particularly useful for implementing + * fast Elliptic Curve Cryptosystems over GF(2^m) + * + * The #define MR_COMBA2 in mirdef.h determines the FIXED size of + * modulus to be used. This *must* be determined at compile time. + * + * Note that this module can generate a *lot* of code for large values + * of MR_COMBA2. This should have a maximum value of 8-20. + * + * Note that on some processors it is *VITAL* that arrays be aligned on + * 4-byte boundaries + * + * * **** This code does not like -fomit-frame-pointer using GCC *********** + * + */ + +#include "miracl.h" + +#ifdef MR_COMBA2 + +#ifdef MR_WIN64 +#if _MSC_VER>=1500 +#define MR_PCLMULQDQ +#include +#endif +#endif + +/* NOTE! z must be distinct from x and y */ + +void comba_mult2(_MIPD_ big x,big y,big z) +{ /* comba multiplier */ + int i; + mr_small *a,*b,*c; + big w; +#ifdef MR_PCLMULQDQ + __m128i m1,m2,sum; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + w=mr_mip->w0; + for (i=2*MR_COMBA2;i<(int)(w->len&MR_OBITS);i++) w->w[i]=0; + w->len=2*MR_COMBA2-1; + a=x->w; b=y->w; c=w->w; +/*** MULTIPLY2 ***/ /* multiply a by b, result in c */ + + mr_lzero(w); + if (w!=z) copy (w,z); +} + +#endif diff --git a/miracl/source/mrcore.c b/miracl/source/mrcore.c new file mode 100644 index 0000000..a2e5cc2 --- /dev/null +++ b/miracl/source/mrcore.c @@ -0,0 +1,2292 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * + * MIRACL Core module - contains initialisation code and general purpose + * utilities + * mrcore.c + * + * Space can be saved by removing unneeded functions (mr_and ?) + * + */ + +#include "miracl.h" +#include +#include + + +#ifdef MR_FP +#include +#endif + + +/*** Multi-Threaded Support ***/ + +#ifndef MR_GENERIC_MT + + #ifdef MR_OPENMP_MT + #include + +#define MR_MIP_EXISTS + + miracl *mr_mip; + #pragma omp threadprivate(mr_mip) + + miracl *get_mip() + { + return mr_mip; + } + + void mr_init_threading() + { + } + + void mr_end_threading() + { + } + + #endif + + #ifdef MR_WINDOWS_MT + #include + DWORD mr_key; + + miracl *get_mip() + { + return (miracl *)TlsGetValue(mr_key); + } + + void mr_init_threading() + { + mr_key=TlsAlloc(); + } + + void mr_end_threading() + { + TlsFree(mr_key); + } + + #endif + + #ifdef MR_UNIX_MT + #include + pthread_key_t mr_key; + + miracl *get_mip() + { + return (miracl *)pthread_getspecific(mr_key); + } + + void mr_init_threading() + { + pthread_key_create(&mr_key,(void(*)(void *))NULL); + } + + void mr_end_threading() + { + pthread_key_delete(mr_key); + } + #endif + + #ifndef MR_WINDOWS_MT + #ifndef MR_UNIX_MT + #ifndef MR_OPENMP_MT + #ifdef MR_STATIC + miracl mip; + miracl *mr_mip=&mip; + #else + miracl *mr_mip=NULL; /* MIRACL's one and only global variable */ + #endif +#define MR_MIP_EXISTS + miracl *get_mip() + { + return (miracl *)mr_mip; + } + #endif + #endif + #endif + +#ifdef MR_MIP_EXISTS + void set_mip(miracl *mip) + { + mr_mip=mip; + } +#endif + +#endif + +/* See Advanced Windows by Jeffrey Richter, Chapter 12 for methods for + creating different instances of this global for each executing thread + when using Windows '95/NT +*/ + +#ifdef MR_STATIC + +#if MIRACL==8 + +static const int mr_small_primes[]= +{2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103, +107,109,113,127,0}; + +#else + +static const int mr_small_primes[]= +{2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103, +107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211, +223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331, +337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449, +457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587, +593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709, +719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853, +857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991, +997,0}; + +#endif + +#endif + +#ifndef MR_STRIPPED_DOWN +#ifndef MR_NO_STANDARD_IO + +static char *names[] = +{(char *)"your program",(char *)"innum",(char *)"otnum",(char *)"jack",(char *)"normalise", +(char *)"multiply",(char *)"divide",(char *)"incr",(char *)"decr",(char *)"premult", +(char *)"subdiv",(char *)"fdsize",(char *)"egcd",(char *)"cbase", +(char *)"cinnum",(char *)"cotnum",(char *)"nroot",(char *)"power", +(char *)"powmod",(char *)"bigdig",(char *)"bigrand",(char *)"nxprime",(char *)"isprime", +(char *)"mirvar",(char *)"mad",(char *)"multi_inverse",(char *)"putdig", +(char *)"add",(char *)"subtract",(char *)"mirsys",(char *)"xgcd", +(char *)"fpack",(char *)"dconv",(char *)"mr_shift",(char *)"mround",(char *)"fmul", +(char *)"fdiv",(char *)"fadd",(char *)"fsub",(char *)"fcomp",(char *)"fconv", +(char *)"frecip",(char *)"fpmul",(char *)"fincr",(char *)"",(char *)"ftrunc", +(char *)"frand",(char *)"sftbit",(char *)"build",(char *)"logb2",(char *)"expint", +(char *)"fpower",(char *)"froot",(char *)"fpi",(char *)"fexp",(char *)"flog",(char *)"fpowf", +(char *)"ftan",(char *)"fatan",(char *)"fsin",(char *)"fasin",(char *)"fcos",(char *)"facos", +(char *)"ftanh",(char *)"fatanh",(char *)"fsinh",(char *)"fasinh",(char *)"fcosh", +(char *)"facosh",(char *)"flop",(char *)"gprime",(char *)"powltr",(char *)"fft_mult", +(char *)"crt_init",(char *)"crt",(char *)"otstr",(char *)"instr",(char *)"cotstr",(char *)"cinstr",(char *)"powmod2", +(char *)"prepare_monty",(char *)"nres",(char *)"redc",(char *)"nres_modmult",(char *)"nres_powmod", +(char *)"nres_moddiv",(char *)"nres_powltr",(char *)"divisible",(char *)"remain", +(char *)"fmodulo",(char *)"nres_modadd",(char *)"nres_modsub",(char *)"nres_negate", +(char *)"ecurve_init",(char *)"ecurve_add",(char *)"ecurve_mult", +(char *)"epoint_init",(char *)"epoint_set",(char *)"epoint_get",(char *)"nres_powmod2", +(char *)"nres_sqroot",(char *)"sqroot",(char *)"nres_premult",(char *)"ecurve_mult2", +(char *)"ecurve_sub",(char *)"trial_division",(char *)"nxsafeprime",(char *)"nres_lucas",(char *)"lucas", +(char *)"brick_init",(char *)"pow_brick",(char *)"set_user_function", +(char *)"nres_powmodn",(char *)"powmodn",(char *)"ecurve_multn", +(char *)"ebrick_init",(char *)"mul_brick",(char *)"epoint_norm",(char *)"nres_multi_inverse",(char *)"", +(char *)"nres_dotprod",(char *)"epoint_negate",(char *)"ecurve_multi_add", +(char *)"ecurve2_init",(char *)"",(char *)"epoint2_set",(char *)"epoint2_norm",(char *)"epoint2_get", +(char *)"epoint2_comp",(char *)"ecurve2_add",(char *)"epoint2_negate",(char *)"ecurve2_sub", +(char *)"ecurve2_multi_add",(char *)"ecurve2_mult",(char *)"ecurve2_multn",(char *)"ecurve2_mult2", +(char *)"ebrick2_init",(char *)"mul2_brick",(char *)"prepare_basis",(char *)"strong_bigrand", +(char *)"bytes_to_big",(char *)"big_to_bytes",(char *)"set_io_buffer_size", +(char *)"epoint_getxyz",(char *)"epoint_double_add",(char *)"nres_double_inverse", +(char *)"double_inverse",(char *)"epoint_x",(char *)"hamming",(char *)"expb2",(char *)"bigbits", +(char *)"nres_lazy",(char *)"zzn2_imul",(char *)"nres_double_modadd",(char *)"nres_double_modsub", +/*155*/(char *)"",(char *)"zzn2_from_int",(char *)"zzn2_negate",(char *)"zzn2_conj",(char *)"zzn2_add", +(char *)"zzn2_sub",(char *)"zzn2_smul",(char *)"zzn2_mul",(char *)"zzn2_inv",(char *)"zzn2_timesi",(char *)"zzn2_powl", +(char *)"zzn2_from_bigs",(char *)"zzn2_from_big",(char *)"zzn2_from_ints", +(char *)"zzn2_sadd",(char *)"zzn2_ssub",(char *)"zzn2_times_irp",(char *)"zzn2_div2", +(char *)"zzn3_from_int",(char *)"zzn3_from_ints",(char *)"zzn3_from_bigs", +(char *)"zzn3_from_big",(char *)"zzn3_negate",(char *)"zzn3_powq",(char *)"zzn3_init", +(char *)"zzn3_add",(char *)"zzn3_sadd",(char *)"zzn3_sub",(char *)"zzn3_ssub",(char *)"zzn3_smul", +(char *)"zzn3_imul",(char *)"zzn3_mul",(char *)"zzn3_inv",(char *)"zzn3_div2",(char *)"zzn3_timesi", +(char *)"epoint_multi_norm",(char *)"mr_jsf",(char *)"epoint2_multi_norm", +(char *)"ecn2_compare",(char *)"ecn2_norm",(char *)"ecn2_set",(char *)"zzn2_txx", +(char *)"zzn2_txd",(char *)"nres_div2",(char *)"nres_div3",(char *)"zzn2_div3", +(char *)"ecn2_setx",(char *)"ecn2_rhs",(char *)"zzn2_qr",(char *)"zzn2_sqrt",(char *)"ecn2_add",(char *)"ecn2_mul2_jsf",(char *)"ecn2_mul", +(char *)"nres_div5",(char *)"zzn2_div5",(char *)"zzn2_sqr",(char *)"ecn2_add_sub",(char *)"ecn2_psi",(char *)"invmodp", +(char *)"zzn2_multi_inverse",(char *)"ecn2_multi_norm",(char *)"ecn2_precomp",(char *)"ecn2_mul4_gls_v", +(char *)"ecn2_mul2",(char *)"ecn2_precomp_gls",(char *)"ecn2_mul2_gls", +(char *)"ecn2_brick_init",(char *)"ecn2_mul_brick_gls",(char *)"ecn2_multn",(char *)"zzn3_timesi2", +(char *)"nres_complex",(char *)"zzn4_from_int",(char *)"zzn4_negate",(char *)"zzn4_conj",(char *)"zzn4_add",(char *)"zzn4_sadd",(char *)"zzn4_sub",(char *)"zzn4_ssub",(char *)"zzn4_smul",(char *)"zzn4_sqr", +(char *)"zzn4_mul",(char *)"zzn4_inv",(char *)"zzn4_div2",(char *)"zzn4_powq",(char *)"zzn4_tx",(char *)"zzn4_imul",(char *)"zzn4_lmul",(char *)"zzn4_from_big", +(char *)"ecn2_mult4"}; + +/* 0 - 243 (244 in all) */ + +#endif +#endif + +#ifdef MR_NOASM + +/* C only versions of muldiv/muldvd/muldvd2/muldvm */ +/* Note that mr_large should be twice the size of mr_small */ + +mr_small muldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_small *rp) +{ + mr_small q; + mr_large ldres,p=(mr_large)a*b+c; + q=(mr_small)(MR_LROUND(p/m)); + *rp=(mr_small)(p-(mr_large)q*m); + return q; +} + +#ifdef MR_FP_ROUNDING + +mr_small imuldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_large im,mr_small *rp) +{ + mr_small q; + mr_large ldres,p=(mr_large)a*b+c; + q=(mr_small)MR_LROUND(p*im); + *rp=(mr_small)(p-(mr_large)q*m); + return q; +} + +#endif + +#ifndef MR_NOFULLWIDTH + +mr_small muldvm(mr_small a,mr_small c,mr_small m,mr_small *rp) +{ + mr_small q; + union doubleword dble; + dble.h[MR_BOT]=c; + dble.h[MR_TOP]=a; + + q=(mr_small)(dble.d/m); + *rp=(mr_small)(dble.d-(mr_large)q*m); + return q; +} + +mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) +{ + union doubleword dble; + dble.d=(mr_large)a*b+c; + + *rp=dble.h[MR_BOT]; + return dble.h[MR_TOP]; +} + +void muldvd2(mr_small a,mr_small b,mr_small *c,mr_small *rp) +{ + union doubleword dble; + dble.d=(mr_large)a*b+*c+*rp; + *rp=dble.h[MR_BOT]; + *c=dble.h[MR_TOP]; +} + +#endif +#endif + +#ifdef MR_NOFULLWIDTH + +/* no FULLWIDTH working, so supply dummies */ + +/* + +mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) +{ + return (mr_small)0; +} + +mr_small muldvm(mr_small a,mr_small c,mr_small m,mr_small *rp) +{ + return (mr_small)0; +} + +void muldvd2(mr_small a,mr_small b,mr_small *c,mr_small *rp) +{ +} + +*/ + +#endif + +#ifndef MR_NO_STANDARD_IO + +static void mputs(char *s) +{ /* output a string */ + int i=0; + while (s[i]!=0) fputc((int)s[i++],stdout); +} +#endif + +void mr_berror(_MIPD_ int nerr) +{ /* Big number error routine */ +#ifndef MR_STRIPPED_DOWN +int i; +#endif + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + +if (mr_mip->ERCON) +{ + mr_mip->ERNUM=nerr; + return; +} +#ifndef MR_NO_STANDARD_IO + +#ifndef MR_STRIPPED_DOWN +mputs((char *)"\nMIRACL error from routine "); +if (mr_mip->depthtrace[mr_mip->depth]]); +else mputs((char *)"???"); +fputc('\n',stdout); + +for (i=mr_mip->depth-1;i>=0;i--) +{ + mputs((char *)" called from "); + if (itrace[i]]); + else mputs((char *)"???"); + fputc('\n',stdout); +} + +switch (nerr) +{ +case 1 : +mputs((char *)"Number base too big for representation\n"); +break; +case 2 : +mputs((char *)"Division by zero attempted\n"); +break; +case 3 : +mputs((char *)"Overflow - Number too big\n"); +break; +case 4 : +mputs((char *)"Internal result is negative\n"); +break; +case 5 : +mputs((char *)"Input format error\n"); +break; +case 6 : +mputs((char *)"Illegal number base\n"); +break; +case 7 : +mputs((char *)"Illegal parameter usage\n"); +break; +case 8 : +mputs((char *)"Out of space\n"); +break; +case 9 : +mputs((char *)"Even root of a negative number\n"); +break; +case 10: +mputs((char *)"Raising integer to negative power\n"); +break; +case 11: +mputs((char *)"Attempt to take illegal root\n"); +break; +case 12: +mputs((char *)"Integer operation attempted on Flash number\n"); +break; +case 13: +mputs((char *)"Flash overflow\n"); +break; +case 14: +mputs((char *)"Numbers too big\n"); +break; +case 15: +mputs((char *)"Log of a non-positive number\n"); +break; +case 16: +mputs((char *)"Flash to double conversion failure\n"); +break; +case 17: +mputs((char *)"I/O buffer overflow\n"); +break; +case 18: +mputs((char *)"MIRACL not initialised - no call to mirsys()\n"); +break; +case 19: +mputs((char *)"Illegal modulus \n"); +break; +case 20: +mputs((char *)"No modulus defined\n"); +break; +case 21: +mputs((char *)"Exponent too big\n"); +break; +case 22: +mputs((char *)"Unsupported Feature - check mirdef.h\n"); +break; +case 23: +mputs((char *)"Specified double length type isn't double length\n"); +break; +case 24: +mputs((char *)"Specified basis is NOT irreducible\n"); +break; +case 25: +mputs((char *)"Unable to control Floating-point rounding\n"); +break; +case 26: +mputs((char *)"Base must be binary (MR_ALWAYS_BINARY defined in mirdef.h ?)\n"); +break; +case 27: +mputs((char *)"No irreducible basis defined\n"); +break; +case 28: +mputs((char *)"Composite modulus\n"); +break; +case 29: +mputs((char *)"Input/output error when reading from RNG device node\n"); +break; +default: +mputs((char *)"Undefined error\n"); +break; +} +exit(0); +#else +mputs((char *)"MIRACL error\n"); +exit(0); +#endif + +#endif +} + +#ifndef MR_STRIPPED_DOWN + +void mr_track(_MIPDO_ ) +{ /* track course of program execution * + * through the MIRACL routines */ + +#ifndef MR_NO_STANDARD_IO + + int i; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + for (i=0;idepth;i++) fputc('-',stdout); + fputc('>',stdout); + mputs(names[mr_mip->trace[mr_mip->depth]]); + fputc('\n',stdout); +#endif +} + +#endif + +#ifndef MR_NO_RAND + +mr_small brand(_MIPDO_ ) +{ /* Marsaglia & Zaman random number generator */ + int i,k; + mr_unsign32 pdiff,t; + mr_small r; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->lg2b>32) + { /* underlying type is > 32 bits. Assume <= 64 bits */ + mr_mip->rndptr+=2; + if (mr_mip->rndptrira[mr_mip->rndptr]; + r=mr_shiftbits(r,mr_mip->lg2b-32); + r+=(mr_small)mr_mip->ira[mr_mip->rndptr+1]; + return r; + } + } + else + { + mr_mip->rndptr++; + if (mr_mip->rndptrira[mr_mip->rndptr]; + } + mr_mip->rndptr=0; + for (i=0,k=NK-NJ;iira[k]; + pdiff=t - mr_mip->ira[i] - mr_mip->borrow; + if (pdiffborrow=0; + if (pdiff>t) mr_mip->borrow=1; + mr_mip->ira[i]=pdiff; + } + if (mr_mip->lg2b>32) + { /* double up */ + r=(mr_small)mr_mip->ira[0]; + r=mr_shiftbits(r,mr_mip->lg2b-32); + r+=(mr_small)mr_mip->ira[1]; + return r; + } + else return (mr_small)(mr_mip->ira[0]); +} + +void irand(_MIPD_ mr_unsign32 seed) +{ /* initialise random number system */ + int i,in; + mr_unsign32 t,m=1L; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + mr_mip->borrow=0L; + mr_mip->rndptr=0; + mr_mip->ira[0]=seed; + for (i=1;iira[in]=m; + t=m; + m=seed-m; + seed=t; + } + for (i=0;i<1000;i++) brand(_MIPPO_ ); /* "warm-up" & stir the generator */ +} + +#endif + +mr_small mr_shiftbits(mr_small x,int n) +{ +#ifdef MR_FP + int i; + mr_small dres; + if (n==0) return x; + if (n>0) + { + for (i=0;i0) x<<=n; + else x>>=(-n); + return x; +#endif + +} + +mr_small mr_setbase(_MIPD_ mr_small nb) +{ /* set base. Pack as many digits as * + * possible into each computer word */ + mr_small temp; +#ifdef MR_FP + mr_small dres; +#endif +#ifndef MR_NOFULLWIDTH + BOOL fits; + int bits; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + fits=FALSE; + bits=MIRACL; + while (bits>1) + { + bits/=2; + temp=((mr_small)1<apbase=nb; + mr_mip->pack=MIRACL/bits; + mr_mip->base=0; + return 0; + } +#endif + mr_mip->apbase=nb; + mr_mip->pack=1; + mr_mip->base=nb; +#ifdef MR_SIMPLE_BASE + return 0; +#else + if (mr_mip->base==0) return 0; + temp=MR_DIV(MAXBASE,nb); + while (temp>=nb) + { + temp=MR_DIV(temp,nb); + mr_mip->base*=nb; + mr_mip->pack++; + } +#ifdef MR_FP_ROUNDING + mr_mip->inverse_base=mr_invert(mr_mip->base); + return mr_mip->inverse_base; +#else + return 0; +#endif +#endif +} + +#ifdef MR_FLASH + +BOOL fit(big x,big y,int f) +{ /* returns TRUE if x/y would fit flash format of length f */ + int n,d; + n=(int)(x->len&(MR_OBITS)); + d=(int)(y->len&(MR_OBITS)); + if (n==1 && x->w[0]==1) n=0; + if (d==1 && y->w[0]==1) d=0; + if (n+d<=f) return TRUE; + return FALSE; +} + +#endif + +int mr_lent(flash x) +{ /* return length of big or flash in words */ + mr_lentype lx; + lx=(x->len&(MR_OBITS)); +#ifdef MR_FLASH + return (int)((lx&(MR_MSK))+((lx>>(MR_BTS))&(MR_MSK))); +#else + return (int)lx; +#endif +} + +void zero(flash x) +{ /* set big/flash number to zero */ + int i,n; + mr_small *g; + if (x==NULL) return; +#ifdef MR_FLASH + n=mr_lent(x); +#else + n=(x->len&MR_OBITS); +#endif + g=x->w; + + for (i=0;ilen=0; +} + +void uconvert(_MIPD_ unsigned int n ,big x) +{ /* convert unsigned integer n to big number format */ + int m; +#ifdef MR_FP + mr_small dres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zero(x); + if (n==0) return; + + m=0; +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH +#if MR_IBITS > MIRACL + while (n>0) + { + x->w[m++]=(mr_small)(n%((mr_small)1<<(MIRACL))); + n/=((mr_small)1<<(MIRACL)); + } +#else + x->w[m++]=(mr_small)n; +#endif +#endif +#ifndef MR_SIMPLE_BASE + } + else while (n>0) + { + x->w[m++]=MR_REMAIN((mr_small)n,mr_mip->base); + n=(unsigned int)((mr_small)n/mr_mip->base); + } +#endif + x->len=m; +} + +void tconvert(_MIPD_ mr_utype n,big x) +{ + mr_lentype s; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (n==0) {zero(x); return;} + s=0; + if (n<0) + { + s=MR_MSBIT; + n=(-n); + } + x->w[0]=n; + x->len=1; + x->len|=s; +} + +void convert(_MIPD_ int n ,big x) +{ /* convert signed integer n to big number format */ + mr_lentype s; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (n==0) {zero(x); return;} + s=0; + if (n<0) + { + s=MR_MSBIT; + n=(-n); + } + uconvert(_MIPP_ (unsigned int)n,x); + x->len|=s; +} + +#ifndef MR_STATIC +#ifdef mr_dltype + +void dlconv(_MIPD_ mr_dltype n,big x) +{ /* convert double length integer to big number format - rarely needed */ + int m; + mr_lentype s; +#ifdef MR_FP + mr_small dres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zero(x); + if (n==0) return; + s=0; + if (n<0) + { + s=MR_MSBIT; + n=(-n); + } + m=0; +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH + while (n>0) + { + x->w[m++]=(mr_small)(n%((mr_dltype)1<<(MIRACL))); + n/=((mr_dltype)1<<(MIRACL)); + } +#endif +#ifndef MR_SIMPLE_BASE + } + else while (n>0) + { + x->w[m++]=(mr_small)MR_REMAIN(n,mr_mip->base); + n/=mr_mip->base; + } +#endif + x->len=(m|s); +} + +#endif + +void ulgconv(_MIPD_ unsigned long n,big x) +{ /* convert unsigned long integer to big number format - rarely needed */ + int m; +#ifdef MR_FP + mr_small dres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zero(x); + if (n==0) return; + + m=0; +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH +#if MR_LBITS > MIRACL + while (n>0) + { + x->w[m++]=(mr_small)(n%(1L<<(MIRACL))); + n/=(1L<<(MIRACL)); + } +#else + x->w[m++]=(mr_small)n; +#endif +#endif +#ifndef MR_SIMPLE_BASE + } + else while (n>0) + { + x->w[m++]=MR_REMAIN(n,mr_mip->base); + n=(unsigned long)((mr_small)n/mr_mip->base); + } +#endif + x->len=m; +} + +void lgconv(_MIPD_ long n,big x) +{ /* convert signed long integer to big number format - rarely needed */ + mr_lentype s; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (n==0) {zero(x); return;} + s=0; + if (n<0) + { + s=MR_MSBIT; + n=(-n); + } + ulgconv(_MIPP_ (unsigned long)n,x); + + x->len|=s; +} + +flash mirvar(_MIPD_ int iv) +{ /* initialize big/flash number */ + flash x; + int align; + char *ptr; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return NULL; + MR_IN(23); + + if (!(mr_mip->active)) + { + mr_berror(_MIPP_ MR_ERR_NO_MIRSYS); + MR_OUT + return NULL; + } + +/* OK, now I control alignment.... */ + +/* Allocate space for big, the length, the pointer, and the array */ +/* Do it all in one memory allocation - this is quicker */ +/* Ensure that the array has correct alignment */ + + x=(big)mr_alloc(_MIPP_ mr_size(mr_mip->nib-1),1); + if (x==NULL) + { + MR_OUT + return x; + } + + ptr=(char *)&x->w; + align=(unsigned long)(ptr+sizeof(mr_small *))%sizeof(mr_small); + + x->w=(mr_small *)(ptr+sizeof(mr_small *)+sizeof(mr_small)-align); + + if (iv!=0) convert(_MIPP_ iv,x); + MR_OUT + return x; +} + +#endif + +flash mirvar_mem_variable(char *mem,int index,int sz) +{ + flash x; + int align; + char *ptr; + int offset,r; + +/* alignment */ + offset=0; + r=(unsigned long)mem%MR_SL; + if (r>0) offset=MR_SL-r; + + x=(big)&mem[offset+mr_size(sz)*index]; + ptr=(char *)&x->w; + align=(unsigned long)(ptr+sizeof(mr_small *))%sizeof(mr_small); + x->w=(mr_small *)(ptr+sizeof(mr_small *)+sizeof(mr_small)-align); + + return x; +} + +flash mirvar_mem(_MIPD_ char *mem,int index) +{ /* initialize big/flash number from pre-allocated memory */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return NULL; + + return mirvar_mem_variable(mem,index,mr_mip->nib-1); + +} + +void set_user_function(_MIPD_ BOOL (*user)(void)) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(111) + + if (!(mr_mip->active)) + { + mr_berror(_MIPP_ MR_ERR_NO_MIRSYS); + MR_OUT + return; + } + + mr_mip->user=user; + + MR_OUT +} + +#ifndef MR_STATIC + +#ifndef MR_SIMPLE_IO + +void set_io_buffer_size(_MIPD_ int len) +{ + int i; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (len<0) return; + MR_IN(142) + for (i=0;iIOBSIZ;i++) mr_mip->IOBUFF[i]=0; + mr_free(mr_mip->IOBUFF); + if (len==0) + { + MR_OUT + return; + } + mr_mip->IOBSIZ=len; + mr_mip->IOBUFF=(char *)mr_alloc(_MIPP_ len+1,1); + mr_mip->IOBUFF[0]='\0'; + MR_OUT +} +#endif + +#endif + +/* Initialise a big from ROM given its fixed length */ + +BOOL init_big_from_rom(big x,int len,const mr_small *rom,int romsize,int *romptr) +{ + int i; + zero(x); + x->len=len; + for (i=0;i=romsize) return FALSE; +#ifdef MR_AVR + x->w[i]=pgm_read_byte_near(&rom[*romptr]); +#else + x->w[i]=rom[*romptr]; +#endif + (*romptr)++; + } + + mr_lzero(x); + return TRUE; +} + +/* Initialise an elliptic curve point from ROM */ + +BOOL init_point_from_rom(epoint *P,int len,const mr_small *rom,int romsize,int *romptr) +{ + if (!init_big_from_rom(P->X,len,rom,romsize,romptr)) return FALSE; + if (!init_big_from_rom(P->Y,len,rom,romsize,romptr)) return FALSE; + P->marker=MR_EPOINT_NORMALIZED; + return TRUE; +} + +#ifdef MR_GENERIC_AND_STATIC +miracl *mirsys(miracl *mr_mip,int nd,mr_small nb) +#else +miracl *mirsys(int nd,mr_small nb) +#endif +{ /* Initialize MIRACL system to * + * use numbers to base nb, and * + * nd digits or (-nd) bytes long */ + +/* In these cases mr_mip is passed as the first parameter */ + +#ifdef MR_GENERIC_AND_STATIC + return mirsys_basic(mr_mip,nd,nb); +#endif + +#ifdef MR_GENERIC_MT +#ifndef MR_STATIC + miracl *mr_mip=mr_first_alloc(); + return mirsys_basic(mr_mip,nd,nb); +#endif +#endif +/* In these cases mr_mip is a "global" pointer and the mip itself is allocated from the heap. + In fact mr_mip (and mip) may be thread specific if some multi-threading scheme is implemented */ +#ifndef MR_STATIC + #ifdef MR_WINDOWS_MT + miracl *mr_mip=mr_first_alloc(); + TlsSetValue(mr_key,mr_mip); + #endif + + #ifdef MR_UNIX_MT + miracl *mr_mip=mr_first_alloc(); + pthread_setspecific(mr_key,mr_mip); + #endif + + #ifdef MR_OPENMP_MT + mr_mip=mr_first_alloc(); + #endif + + #ifndef MR_WINDOWS_MT + #ifndef MR_UNIX_MT + #ifndef MR_OPENMP_MT + mr_mip=mr_first_alloc(); + #endif + #endif + #endif +#endif + +#ifndef MR_GENERIC_MT + mr_mip=get_mip(); +#endif + return mirsys_basic(mr_mip,nd,nb); +} + +miracl *mirsys_basic(miracl *mr_mip,int nd,mr_small nb) +{ +#ifndef MR_NO_RAND + int i; +#endif + + mr_small b,nw; +#ifdef MR_FP + mr_small dres; +#endif + + if (mr_mip==NULL) return NULL; + +#ifndef MR_STRIPPED_DOWN + mr_mip->depth=0; + mr_mip->trace[0]=0; + mr_mip->depth++; + mr_mip->trace[mr_mip->depth]=29; +#endif + /* digest hardware configuration */ + +#ifdef MR_NO_STANDARD_IO + mr_mip->ERCON=TRUE; +#else + mr_mip->ERCON=FALSE; +#endif +#ifndef MR_STATIC + mr_mip->logN=0; + mr_mip->degree=0; + mr_mip->chin.NP=0; +#endif + + + mr_mip->user=NULL; + mr_mip->same=FALSE; + mr_mip->first_one=FALSE; + mr_mip->debug=FALSE; + mr_mip->AA=0; +#ifndef MR_AFFINE_ONLY + mr_mip->coord=MR_NOTSET; +#endif + +#ifdef MR_NOFULLWIDTH + if (nb==0) + { + mr_berror(_MIPP_ MR_ERR_BAD_BASE); + MR_OUT + return mr_mip; + } +#endif + +#ifndef MR_FP +#ifdef mr_dltype +#ifndef MR_NOFULLWIDTH + if (sizeof(mr_dltype)<2*sizeof(mr_utype)) + { /* double length type, isn't */ + mr_berror(_MIPP_ MR_ERR_NOT_DOUBLE_LEN); + MR_OUT + return mr_mip; + } +#endif +#endif +#endif + if (nb==1 || nb>MAXBASE) + { + mr_berror(_MIPP_ MR_ERR_BAD_BASE); + MR_OUT + return mr_mip; + } + +#ifdef MR_FP_ROUNDING + if (mr_setbase(_MIPP_ nb)==0) + { /* unable in fact to control FP rounding */ + mr_berror(_MIPP_ MR_ERR_NO_ROUNDING); + MR_OUT + return mr_mip; + } +#else + mr_setbase(_MIPP_ nb); +#endif + + b=mr_mip->base; + +#ifdef MR_SIMPLE_BASE + if (b!=0) + { + mr_berror(_MIPP_ MR_ERR_BAD_BASE); + MR_OUT + return mr_mip; + } +#endif + + mr_mip->lg2b=0; + mr_mip->base2=1; +#ifndef MR_SIMPLE_BASE + if (b==0) + { +#endif + mr_mip->lg2b=MIRACL; + mr_mip->base2=0; +#ifndef MR_SIMPLE_BASE + } + else while (b>1) + { + b=MR_DIV(b,2); + mr_mip->lg2b++; + mr_mip->base2*=2; + } +#endif + +#ifdef MR_ALWAYS_BINARY + if (mr_mip->base!=mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_BINARY); + MR_OUT + return mr_mip; + } +#endif + +/* calculate total space for bigs */ +/* + + big -> |int len|small *ptr| alignment space | size in words +1| alignment up to multiple of 4 | + + +*/ + if (nd>0) nw=MR_ROUNDUP(nd,mr_mip->pack); + else nw=MR_ROUNDUP(8*(-nd),mr_mip->lg2b); + + if (nw<1) nw=1; + mr_mip->nib=(int)(nw+1); /* add one extra word for small overflows */ + +#ifdef MR_STATIC + if (nw>MR_STATIC) + { + mr_berror(_MIPP_ MR_ERR_TOO_BIG); + MR_OUT + return mr_mip; + } +#endif + + /* mr_mip->nib=(int)(nw+1); add one extra word for small overflows */ + +#ifdef MR_FLASH + mr_mip->workprec=mr_mip->nib; + mr_mip->stprec=mr_mip->nib; + while (mr_mip->stprec>2 && mr_mip->stprec>MR_FLASH/mr_mip->lg2b) + mr_mip->stprec=(mr_mip->stprec+1)/2; + if (mr_mip->stprec<2) mr_mip->stprec=2; + +#endif + +#ifndef MR_DOUBLE_BIG + mr_mip->check=ON; +#else + mr_mip->check=OFF; +#endif + +#ifndef MR_SIMPLE_BASE +#ifndef MR_SIMPLE_IO + mr_mip->IOBASE=10; /* defaults */ +#endif +#endif + mr_mip->ERNUM=0; + + mr_mip->NTRY=6; + mr_mip->MONTY=ON; +#ifdef MR_FLASH + mr_mip->EXACT=TRUE; + mr_mip->RPOINT=OFF; +#endif +#ifndef MR_STRIPPED_DOWN + mr_mip->TRACER=OFF; +#endif + +#ifndef MR_SIMPLE_IO + mr_mip->INPLEN=0; + mr_mip->IOBSIZ=MR_DEFAULT_BUFFER_SIZE; +#endif + +#ifdef MR_STATIC + mr_mip->PRIMES=mr_small_primes; +#else + mr_mip->PRIMES=NULL; +#ifndef MR_SIMPLE_IO + mr_mip->IOBUFF=(char *)mr_alloc(_MIPP_ MR_DEFAULT_BUFFER_SIZE+1,1); +#endif +#endif +#ifndef MR_SIMPLE_IO + mr_mip->IOBUFF[0]='\0'; +#endif + mr_mip->qnr=0; + mr_mip->cnr=0; + mr_mip->TWIST=0; + mr_mip->pmod8=0; + mr_mip->pmod9=0; + +/* quick start for rng. irand(.) should be called first before serious use.. */ + +#ifndef MR_NO_RAND + mr_mip->ira[0]=0x55555555; + mr_mip->ira[1]=0x12345678; + + for (i=2;iira[i]=mr_mip->ira[i-1]+mr_mip->ira[i-2]+0x1379BDF1; + mr_mip->rndptr=NK; + mr_mip->borrow=0; +#endif + + mr_mip->nib=2*mr_mip->nib+1; +#ifdef MR_FLASH + if (mr_mip->nib!=(mr_mip->nib&(MR_MSK))) +#else + if (mr_mip->nib!=(int)(mr_mip->nib&(MR_OBITS))) +#endif + { + mr_berror(_MIPP_ MR_ERR_TOO_BIG); + mr_mip->nib=(mr_mip->nib-1)/2; + MR_OUT + return mr_mip; + } +#ifndef MR_STATIC + mr_mip->workspace=(char *)memalloc(_MIPP_ MR_SPACES); /* grab workspace */ +#else + memset(mr_mip->workspace,0,MR_BIG_RESERVE(MR_SPACES)); +#endif + + mr_mip->M=0; + mr_mip->fin=FALSE; + mr_mip->fout=FALSE; + mr_mip->active=ON; + + mr_mip->nib=(mr_mip->nib-1)/2; + +/* allocate memory for workspace variables */ + +#ifndef MR_DOUBLE_BIG + + mr_mip->w0=mirvar_mem(_MIPP_ mr_mip->workspace,0); /* double length */ + mr_mip->w1=mirvar_mem(_MIPP_ mr_mip->workspace,2); + mr_mip->w2=mirvar_mem(_MIPP_ mr_mip->workspace,3); + mr_mip->w3=mirvar_mem(_MIPP_ mr_mip->workspace,4); + mr_mip->w4=mirvar_mem(_MIPP_ mr_mip->workspace,5); + mr_mip->w5=mirvar_mem(_MIPP_ mr_mip->workspace,6); /* double length */ + mr_mip->w6=mirvar_mem(_MIPP_ mr_mip->workspace,8); /* double length */ + mr_mip->w7=mirvar_mem(_MIPP_ mr_mip->workspace,10); /* double length */ + mr_mip->w8=mirvar_mem(_MIPP_ mr_mip->workspace,12); + mr_mip->w9=mirvar_mem(_MIPP_ mr_mip->workspace,13); + mr_mip->w10=mirvar_mem(_MIPP_ mr_mip->workspace,14); + mr_mip->w11=mirvar_mem(_MIPP_ mr_mip->workspace,15); + mr_mip->w12=mirvar_mem(_MIPP_ mr_mip->workspace,16); + mr_mip->w13=mirvar_mem(_MIPP_ mr_mip->workspace,17); + mr_mip->w14=mirvar_mem(_MIPP_ mr_mip->workspace,18); + mr_mip->w15=mirvar_mem(_MIPP_ mr_mip->workspace,19); + mr_mip->sru=mirvar_mem(_MIPP_ mr_mip->workspace,20); + mr_mip->modulus=mirvar_mem(_MIPP_ mr_mip->workspace,21); + mr_mip->pR=mirvar_mem(_MIPP_ mr_mip->workspace,22); /* double length */ + mr_mip->A=mirvar_mem(_MIPP_ mr_mip->workspace,24); + mr_mip->B=mirvar_mem(_MIPP_ mr_mip->workspace,25); + mr_mip->one=mirvar_mem(_MIPP_ mr_mip->workspace,26); +#ifdef MR_KCM + mr_mip->big_ndash=mirvar_mem(_MIPP_ mr_mip->workspace,27); + mr_mip->ws=mirvar_mem(_MIPP_ mr_mip->workspace,28); + mr_mip->wt=mirvar_mem(_MIPP_ mr_mip->workspace,29); /* double length */ +#endif +#ifdef MR_FLASH +#ifdef MR_KCM + mr_mip->pi=mirvar_mem(_MIPP_ mr_mip->workspace,31); +#else + mr_mip->pi=mirvar_mem(_MIPP_ mr_mip->workspace,27); +#endif +#endif + +#else +/* w0-w7 are double normal length */ + mr_mip->w0=mirvar_mem(_MIPP_ mr_mip->workspace,0); /* quad length */ + mr_mip->w1=mirvar_mem(_MIPP_ mr_mip->workspace,4); /* double length */ + mr_mip->w2=mirvar_mem(_MIPP_ mr_mip->workspace,6); + mr_mip->w3=mirvar_mem(_MIPP_ mr_mip->workspace,8); + mr_mip->w4=mirvar_mem(_MIPP_ mr_mip->workspace,10); + mr_mip->w5=mirvar_mem(_MIPP_ mr_mip->workspace,12); /* quad length */ + mr_mip->w6=mirvar_mem(_MIPP_ mr_mip->workspace,16); /* quad length */ + mr_mip->w7=mirvar_mem(_MIPP_ mr_mip->workspace,20); /* quad length */ + mr_mip->w8=mirvar_mem(_MIPP_ mr_mip->workspace,24); + + mr_mip->w9=mirvar_mem(_MIPP_ mr_mip->workspace,25); + mr_mip->w10=mirvar_mem(_MIPP_ mr_mip->workspace,26); + mr_mip->w11=mirvar_mem(_MIPP_ mr_mip->workspace,27); + mr_mip->w12=mirvar_mem(_MIPP_ mr_mip->workspace,28); + mr_mip->w13=mirvar_mem(_MIPP_ mr_mip->workspace,29); + mr_mip->w14=mirvar_mem(_MIPP_ mr_mip->workspace,30); + mr_mip->w15=mirvar_mem(_MIPP_ mr_mip->workspace,31); + mr_mip->sru=mirvar_mem(_MIPP_ mr_mip->workspace,32); + mr_mip->modulus=mirvar_mem(_MIPP_ mr_mip->workspace,33); + mr_mip->pR=mirvar_mem(_MIPP_ mr_mip->workspace,34); /* double length */ + mr_mip->A=mirvar_mem(_MIPP_ mr_mip->workspace,36); + mr_mip->B=mirvar_mem(_MIPP_ mr_mip->workspace,37); + mr_mip->one=mirvar_mem(_MIPP_ mr_mip->workspace,38); +#ifdef MR_KCM + mr_mip->big_ndash=mirvar_mem(_MIPP_ mr_mip->workspace,39); + mr_mip->ws=mirvar_mem(_MIPP_ mr_mip->workspace,40); + mr_mip->wt=mirvar_mem(_MIPP_ mr_mip->workspace,41); /* double length */ +#endif +#ifdef MR_FLASH +#ifdef MR_KCM + mr_mip->pi=mirvar_mem(_MIPP_ mr_mip->workspace,43); +#else + mr_mip->pi=mirvar_mem(_MIPP_ mr_mip->workspace,39); +#endif +#endif + +#endif + MR_OUT + return mr_mip; +} + +#ifndef MR_STATIC + +/* allocate space for a number of bigs from the heap */ + +void *memalloc(_MIPD_ int num) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + return mr_alloc(_MIPP_ mr_big_reserve(num,mr_mip->nib-1),1); +} + +#endif + +void memkill(_MIPD_ char *mem,int len) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mem==NULL) return; + memset(mem,0,mr_big_reserve(len,mr_mip->nib-1)); +#ifndef MR_STATIC + mr_free(mem); +#endif +} + +#ifndef MR_STATIC + +void mirkill(big x) +{ /* kill a big/flash variable, that is set it to zero + and free its memory */ + if (x==NULL) return; + zero(x); + mr_free(x); +} + +#endif + +void mirexit(_MIPDO_ ) +{ /* clean up after miracl */ + + int i; +#ifdef MR_WINDOWS_MT + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_UNIX_MT + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_OPENMP_MT + miracl *mr_mip=get_mip(); +#endif + mr_mip->ERCON=FALSE; + mr_mip->active=OFF; + memkill(_MIPP_ mr_mip->workspace,MR_SPACES); +#ifndef MR_NO_RAND + for (i=0;iira[i]=0L; +#endif +#ifndef MR_STATIC +#ifndef MR_SIMPLE_IO + set_io_buffer_size(_MIPP_ 0); +#endif + if (mr_mip->PRIMES!=NULL) mr_free(mr_mip->PRIMES); +#else +#ifndef MR_SIMPLE_IO + for (i=0;i<=MR_DEFAULT_BUFFER_SIZE;i++) + mr_mip->IOBUFF[i]=0; +#endif +#endif + +#ifndef MR_STATIC + mr_free(mr_mip); +#ifdef MR_WINDOWS_MT + TlsSetValue(mr_key, NULL); /* Thank you Thales */ +#endif +#endif + +#ifndef MR_GENERIC_MT +#ifndef MR_WINDOWS_MT +#ifndef MR_UNIX_MT +#ifndef MR_STATIC + mr_mip=NULL; +#endif +#endif +#endif +#endif + +#ifdef MR_OPENMP_MT + mr_mip=NULL; +#endif + +} + +int exsign(flash x) +{ /* extract sign of big/flash number */ + if ((x->len&(MR_MSBIT))==0) return PLUS; + else return MINUS; +} + +void insign(int s,flash x) +{ /* assert sign of big/flash number */ + if (x->len==0) return; + if (s<0) x->len|=MR_MSBIT; + else x->len&=MR_OBITS; +} + +void mr_lzero(big x) +{ /* strip leading zeros from big number */ + mr_lentype s; + int m; + s=(x->len&(MR_MSBIT)); + m=(int)(x->len&(MR_OBITS)); + while (m>0 && x->w[m-1]==0) + m--; + x->len=m; + if (m>0) x->len|=s; +} + +#ifndef MR_SIMPLE_IO + +int getdig(_MIPD_ big x,int i) +{ /* extract a packed digit */ + int k; + mr_small n; +#ifdef MR_FP + mr_small dres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + i--; + n=x->w[i/mr_mip->pack]; + + if (mr_mip->pack==1) return (int)n; + k=i%mr_mip->pack; + for (i=1;i<=k;i++) + n=MR_DIV(n,mr_mip->apbase); + return (int)MR_REMAIN(n,mr_mip->apbase); +} + +int numdig(_MIPD_ big x) +{ /* returns number of digits in x */ + int nd; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (x->len==0) return 0; + + nd=(int)(x->len&(MR_OBITS))*mr_mip->pack; + while (getdig(_MIPP_ x,nd)==0) + nd--; + return nd; +} + +void putdig(_MIPD_ int n,big x,int i) +{ /* insert a digit into a packed word */ + int j,k,lx; + mr_small m,p; + mr_lentype s; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(26) + + s=(x->len&(MR_MSBIT)); + lx=(int)(x->len&(MR_OBITS)); + m=getdig(_MIPP_ x,i); + p=n; + i--; + j=i/mr_mip->pack; + k=i%mr_mip->pack; + for (i=1;i<=k;i++) + { + m*=mr_mip->apbase; + p*=mr_mip->apbase; + } + if (j>=mr_mip->nib && (mr_mip->check || j>=2*mr_mip->nib)) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + MR_OUT + return; + } + + x->w[j]=(x->w[j]-m)+p; + if (j>=lx) x->len=((j+1)|s); + mr_lzero(x); + MR_OUT +} + +#endif + +#ifndef MR_FP + +void mr_and(big x,big y,big z) +{ /* z= bitwise logical AND of x and y */ + int i,nx,ny,nz,nr; + if (x==y) + { + copy(x,z); + return; + } + +#ifdef MR_FLASH + nx=mr_lent(x); + ny=mr_lent(y); + nz=mr_lent(z); +#else + ny=(y->len&(MR_OBITS)); + nx=(x->len&(MR_OBITS)); + nz=(z->len&(MR_OBITS)); +#endif + if (nyw[i]=x->w[i]&y->w[i]; + for (i=nr;iw[i]=0; + z->len=nr; + mr_lzero(z); +} + +void mr_xor(big x,big y,big z) +{ + int i,nx,ny,nz,nr; + if (x==y) + { + copy(x,z); + return; + } + +#ifdef MR_FLASH + nx=mr_lent(x); + ny=mr_lent(y); + nz=mr_lent(z); +#else + ny=(y->len&(MR_OBITS)); + nx=(x->len&(MR_OBITS)); + nz=(z->len&(MR_OBITS)); +#endif + if (nyw[i]=x->w[i]^y->w[i]; + for (i=nr;iw[i]=0; + z->len=nr; + mr_lzero(z); +} + +#endif + +void copy(flash x,flash y) +{ /* copy x to y: y=x */ + int i,nx,ny; + mr_small *gx,*gy; + if (x==y || y==NULL) return; + + if (x==NULL) + { + zero(y); + return; + } + +#ifdef MR_FLASH + ny=mr_lent(y); + nx=mr_lent(x); +#else + ny=(y->len&(MR_OBITS)); + nx=(x->len&(MR_OBITS)); +#endif + + gx=x->w; + gy=y->w; + + for (i=nx;ilen=x->len; + +} + +void negify(flash x,flash y) +{ /* negate a big/flash variable: y=-x */ + copy(x,y); + if (y->len!=0) y->len^=MR_MSBIT; +} + +void absol(flash x,flash y) +{ /* y=abs(x) */ + copy(x,y); + y->len&=MR_OBITS; +} + +BOOL mr_notint(flash x) +{ /* returns TRUE if x is Flash */ +#ifdef MR_FLASH + if ((((x->len&(MR_OBITS))>>(MR_BTS))&(MR_MSK))!=0) return TRUE; +#endif + return FALSE; +} + +void mr_shift(_MIPD_ big x,int n,big w) +{ /* set w=x.(mr_base^n) by shifting */ + mr_lentype s; + int i,bl; + mr_small *gw=w->w; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + copy(x,w); + if (w->len==0 || n==0) return; + MR_IN(33) + + if (mr_notint(w)) mr_berror(_MIPP_ MR_ERR_INT_OP); + s=(w->len&(MR_MSBIT)); + bl=(int)(w->len&(MR_OBITS))+n; + if (bl<=0) + { + zero(w); + MR_OUT + return; + } + if (bl>mr_mip->nib && mr_mip->check) mr_berror(_MIPP_ MR_ERR_OVERFLOW); + if (mr_mip->ERNUM) + { + MR_OUT + return; + } + if (n>0) + { + for (i=bl-1;i>=n;i--) + gw[i]=gw[i-n]; + for (i=0;ilen=(bl|s); + MR_OUT +} + +int size(big x) +{ /* get size of big number; convert to * + * integer - if possible */ + int n,m; + mr_lentype s; + if (x==NULL) return 0; + s=(x->len&MR_MSBIT); + m=(int)(x->len&MR_OBITS); + if (m==0) return 0; + if (m==1 && x->w[0]<(mr_small)MR_TOOBIG) n=(int)x->w[0]; + else n=MR_TOOBIG; + if (s==MR_MSBIT) return (-n); + return n; +} + +int mr_compare(big x,big y) +{ /* compare x and y: =1 if x>y =-1 if xlen&MR_MSBIT); + sy=(y->len&MR_MSBIT); + if (sx==0) sig=PLUS; + else sig=MINUS; + if (sx!=sy) return sig; + m=(int)(x->len&MR_OBITS); + n=(int)(y->len&MR_OBITS); + if (m>n) return sig; + if (m0) + { /* check digit by digit */ + m--; + if (x->w[m]>y->w[m]) return sig; + if (x->w[m]w[m]) return -sig; + } + return 0; +} + +#ifdef MR_FLASH + +void fpack(_MIPD_ big n,big d,flash x) +{ /* create floating-slash number x=n/d from * + * big integer numerator and denominator */ + mr_lentype s; + int i,ld,ln; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(31) + + ld=(int)(d->len&MR_OBITS); + if (ld==0) mr_berror(_MIPP_ MR_ERR_FLASH_OVERFLOW); + if (ld==1 && d->w[0]==1) ld=0; + if (x==d) mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + if (mr_notint(n) || mr_notint(d)) mr_berror(_MIPP_ MR_ERR_INT_OP); + s=(n->len&MR_MSBIT); + ln=(int)(n->len&MR_OBITS); + if (ln==1 && n->w[0]==1) ln=0; + if ((ld+ln>mr_mip->nib) && (mr_mip->check || ld+ln>2*mr_mip->nib)) + mr_berror(_MIPP_ MR_ERR_FLASH_OVERFLOW); + if (mr_mip->ERNUM) + { + MR_OUT + return; + } + copy(n,x); + if (n->len==0) + { + MR_OUT + return; + } + s^=(d->len&MR_MSBIT); + if (ld==0) + { + if (x->len!=0) x->len|=s; + MR_OUT + return; + } + for (i=0;iw[ln+i]=d->w[i]; + x->len=(s|(ln+((mr_lentype)ld<ERNUM) return; + if (mr_notint(x)) + { + s=(x->len&MR_MSBIT); + ly=(x->len&MR_OBITS); + ln=(int)(ly&MR_MSK); + if (ln==0) + { + if(s==MR_MSBIT) convert(_MIPP_ (-1),y); + else convert(_MIPP_ 1,y); + return; + } + ld=(int)((ly>>MR_BTS)&MR_MSK); + if (x!=y) + { + for (i=0;iw[i]=x->w[i]; + for (i=ln;iw[i]=0; + } + else for (i=0;iw[ln+i]=0; + y->len=(ln|s); + } + else copy(x,y); +} + +void denom(_MIPD_ flash x,big y) +{ /* extract denominator of x */ + int i,ln,ld; + mr_lentype ly; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + if (!mr_notint(x)) + { + convert(_MIPP_ 1,y); + return; + } + ly=(x->len&MR_OBITS); + ln=(int)(ly&MR_MSK); + ld=(int)((ly>>MR_BTS)&MR_MSK); + for (i=0;iw[i]=x->w[ln+i]; + if (x==y) for (i=0;iw[ld+i]=0; + else for (i=ld;iw[i]=0; + y->len=ld; +} + +#endif + +unsigned int igcd(unsigned int x,unsigned int y) +{ /* integer GCD, returns GCD of x and y */ + unsigned int r; + if (y==0) return x; + while ((r=x%y)!=0) + x=y,y=r; + return y; +} + +unsigned long lgcd(unsigned long x,unsigned long y) +{ /* long GCD, returns GCD of x and y */ + unsigned long r; + if (y==0) return x; + while ((r=x%y)!=0) + x=y,y=r; + return y; +} + +unsigned int isqrt(unsigned int num,unsigned int guess) +{ /* square root of an integer */ + unsigned int sqr; + unsigned int oldguess=guess; + if (num==0) return 0; + if (num<4) return 1; + + for (;;) + { /* Newtons iteration */ + /* sqr=guess+(((num/guess)-guess)/2); */ + sqr=((num/guess)+guess)/2; + if (sqr==guess || sqr==oldguess) + { + if (sqr*sqr>num) sqr--; + return sqr; + } + oldguess=guess; + guess=sqr; + } +} + +unsigned long mr_lsqrt(unsigned long num,unsigned long guess) +{ /* square root of a long */ + unsigned long sqr; + unsigned long oldguess=guess; + if (num==0) return 0; + if (num<4) return 1; + + for (;;) + { /* Newtons iteration */ + /* sqr=guess+(((num/guess)-guess)/2); */ + sqr=((num/guess)+guess)/2; + if (sqr==guess || sqr==oldguess) + { + if (sqr*sqr>num) sqr--; + return sqr; + } + oldguess=guess; + guess=sqr; + } +} + +mr_small sgcd(mr_small x,mr_small y) +{ /* integer GCD, returns GCD of x and y */ + mr_small r; +#ifdef MR_FP + mr_small dres; +#endif + if (y==(mr_small)0) return x; + while ((r=MR_REMAIN(x,y))!=(mr_small)0) + x=y,y=r; + return y; +} + +/* routines to support sliding-windows exponentiation * + * in various contexts */ + +int mr_testbit(_MIPD_ big x,int n) +{ /* return value of n-th bit of big */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_FP + mr_small m,a,dres; + m=mr_shiftbits((mr_small)1,n%mr_mip->lg2b); + + a=x->w[n/mr_mip->lg2b]; + + a=MR_DIV(a,m); + + if ((MR_DIV(a,2.0)*2.0) != a) return 1; +#else + if ((x->w[n/mr_mip->lg2b] & ((mr_small)1<<(n%mr_mip->lg2b))) >0) return 1; +#endif + return 0; +} + +void mr_addbit(_MIPD_ big x,int n) +{ /* add 2^n to positive x - where you know that bit is zero. Use with care! */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + mr_lentype m=n/mr_mip->lg2b; + x->w[m]+=mr_shiftbits((mr_small)1,n%mr_mip->lg2b); + if (x->lenlen=m+1; +} + +int recode(_MIPD_ big e,int t,int w,int i) +{ /* recode exponent for Comb method */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + int j,r; + r=0; + for (j=w-1;j>=0;j--) + { + r<<=1; + r|=mr_testbit(_MIPP_ e,i+j*t); + } + return r; +} + +int mr_window(_MIPD_ big x,int i,int *nbs,int * nzs,int window_size) +{ /* returns sliding window value, max. of 5 bits, * + * (Note from version 5.23 this can be changed by * + * setting parameter window_size. This can be * + * a useful space-saver) starting at i-th bit of big x. * + * nbs is number of bits processed, nzs is the number of * + * additional trailing zeros detected. Returns valid bit * + * pattern 1x..x1 with no two adjacent 0's. So 10101 * + * will return 21 with nbs=5, nzs=0. 11001 will return 3,* + * with nbs=2, nzs=2, having stopped after the first 11..*/ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + int j,r,w; + w=window_size; + +/* check for leading 0 bit */ + + *nbs=1; + *nzs=0; + if (!mr_testbit(_MIPP_ x,i)) return 0; + +/* adjust window size if not enough bits left */ + + if (i-w+1<0) w=i+1; + + r=1; + for (j=i-1;j>i-w;j--) + { /* accumulate bits. Abort if two 0's in a row */ + (*nbs)++; + r*=2; + if (mr_testbit(_MIPP_ x,j)) r+=1; + if (r%4==0) + { /* oops - too many zeros - shorten window */ + r/=4; + *nbs-=2; + *nzs=2; + break; + } + } + if (r%2==0) + { /* remove trailing 0 */ + r/=2; + *nzs=1; + (*nbs)--; + } + return r; +} + +int mr_window2(_MIPD_ big x,big y,int i,int *nbs,int *nzs) +{ /* two bit window for double exponentiation */ + int r,w; + BOOL a,b,c,d; + w=2; + *nbs=1; + *nzs=0; + +/* check for two leading 0's */ + a=mr_testbit(_MIPP_ x,i); b=mr_testbit(_MIPP_ y,i); + + if (!a && !b) return 0; + if (i<1) w=1; + + if (a) + { + if (b) r=3; + else r=2; + } + else r=1; + if (w==1) return r; + + c=mr_testbit(_MIPP_ x,i-1); d=mr_testbit(_MIPP_ y,i-1); + + if (!c && !d) + { + *nzs=1; + return r; + } + + *nbs=2; + r*=4; + if (c) + { + if (d) r+=3; + else r+=2; + } + else r+=1; + return r; +} + +int mr_naf_window(_MIPD_ big x,big x3,int i,int *nbs,int *nzs,int store) +{ /* returns sliding window value, using fractional windows * + * where "store" precomputed values are precalulated and * + * stored. Scanning starts at the i-th bit of x. nbs is * + * the number of bits processed. nzs is number of * + * additional trailing zeros detected. x and x3 (which is * + * 3*x) are combined to produce the NAF (non-adjacent * + * form). So if x=11011(27) and x3 is 1010001, the LSB is * + * ignored and the value 100T0T (32-4-1=27) processed, * + * where T is -1. Note x.P = (3x-x)/2.P. This value will * + * return +7, with nbs=4 and nzs=1, having stopped after * + * the first 4 bits. If it goes too far, it must backtrack * + * Note in an NAF non-zero elements are never side by side, * + * so 10T10T won't happen. NOTE: return value n zero or * + * odd, -21 <= n <= +21 */ + + int nb,j,r,biggest; + + /* get first bit */ + nb=mr_testbit(_MIPP_ x3,i)-mr_testbit(_MIPP_ x,i); + + *nbs=1; + *nzs=0; + if (nb==0) return 0; + if (i==0) return nb; + + biggest=2*store-1; + + if (nb>0) r=1; + else r=(-1); + + for (j=i-1;j>0;j--) + { + (*nbs)++; + r*=2; + nb=mr_testbit(_MIPP_ x3,j)-mr_testbit(_MIPP_ x,j); + if (nb>0) r+=1; + if (nb<0) r-=1; + if (abs(r)>biggest) break; + } + + if (r%2!=0 && j!=0) + { /* backtrack */ + if (nb>0) r=(r-1)/2; + if (nb<0) r=(r+1)/2; + (*nbs)--; + } + + while (r%2==0) + { /* remove trailing zeros */ + r/=2; + (*nzs)++; + (*nbs)--; + } + return r; +} + +/* Some general purpose elliptic curve stuff */ + +BOOL point_at_infinity(epoint *p) +{ + if (p==NULL) return FALSE; + if (p->marker==MR_EPOINT_INFINITY) return TRUE; + return FALSE; +} + +#ifndef MR_STATIC + +epoint* epoint_init(_MIPDO_ ) +{ /* initialise epoint to general point at infinity. */ + epoint *p; + char *ptr; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return NULL; + + MR_IN(96) + +/* Create space for whole structure in one heap access */ + + p=(epoint *)mr_alloc(_MIPP_ mr_esize(mr_mip->nib-1),1); + + ptr=(char *)p+sizeof(epoint); + p->X=mirvar_mem(_MIPP_ ptr,0); + p->Y=mirvar_mem(_MIPP_ ptr,1); +#ifndef MR_AFFINE_ONLY + p->Z=mirvar_mem(_MIPP_ ptr,2); +#endif + p->marker=MR_EPOINT_INFINITY; + + MR_OUT + + return p; +} + +#endif + +epoint* epoint_init_mem_variable(_MIPD_ char *mem,int index,int sz) +{ + epoint *p; + char *ptr; + int offset,r; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + offset=0; + r=(unsigned long)mem%MR_SL; + if (r>0) offset=MR_SL-r; + +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + p=(epoint *)&mem[offset+index*mr_esize_a(sz)]; + else +#endif + p=(epoint *)&mem[offset+index*mr_esize(sz)]; + + ptr=(char *)p+sizeof(epoint); + p->X=mirvar_mem_variable(ptr,0,sz); + p->Y=mirvar_mem_variable(ptr,1,sz); +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord!=MR_AFFINE) p->Z=mirvar_mem_variable(ptr,2,sz); +#endif + p->marker=MR_EPOINT_INFINITY; + return p; +} + +epoint* epoint_init_mem(_MIPD_ char *mem,int index) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return NULL; + + return epoint_init_mem_variable(_MIPP_ mem,index,mr_mip->nib-1); +} + +#ifndef MR_STATIC + +/* allocate space for a number of epoints from the heap */ + +void *ecp_memalloc(_MIPD_ int num) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + return mr_alloc(_MIPP_ mr_ecp_reserve_a(num,mr_mip->nib-1),1); + else +#endif + return mr_alloc(_MIPP_ mr_ecp_reserve(num,mr_mip->nib-1),1); +} + +#endif + +void ecp_memkill(_MIPD_ char *mem,int num) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mem==NULL) return; + +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + memset(mem,0,mr_ecp_reserve_a(num,mr_mip->nib-1)); + else +#endif + memset(mem,0,mr_ecp_reserve(num,mr_mip->nib-1)); + + +#ifndef MR_STATIC + mr_free(mem); +#endif +} + +#ifndef MR_STATIC + +void epoint_free(epoint *p) +{ /* clean up point */ + + if (p==NULL) return; + zero(p->X); + zero(p->Y); +#ifndef MR_AFFINE_ONLY + if (p->marker==MR_EPOINT_GENERAL) zero(p->Z); +#endif + mr_free(p); +} + +#endif diff --git a/miracl/source/mrcrt.c b/miracl/source/mrcrt.c new file mode 100644 index 0000000..78971ff --- /dev/null +++ b/miracl/source/mrcrt.c @@ -0,0 +1,149 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL Chinese Remainder Thereom routines (for use with big moduli) + * mrcrt.c + */ + +#include +#include "miracl.h" + +#ifndef MR_STATIC + +BOOL crt_init(_MIPD_ big_chinese *c,int r,big *moduli) +{ /* calculate CRT constants */ + int i,j,k; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (r<2 || mr_mip->ERNUM) return FALSE; + for (i=0;iM=(big *)mr_alloc(_MIPP_ r,sizeof(big)); + if (c->M==NULL) + { + mr_berror(_MIPP_ MR_ERR_OUT_OF_MEMORY); + MR_OUT + return FALSE; + } + c->C=(big *)mr_alloc(_MIPP_ r*(r-1)/2,sizeof(big)); + if (c->C==NULL) + { + mr_free(c->M); + mr_berror(_MIPP_ MR_ERR_OUT_OF_MEMORY); + MR_OUT + return FALSE; + } + c->V=(big *)mr_alloc(_MIPP_ r,sizeof(big)); + if (c->V==NULL) + { + mr_free(c->M); + mr_free(c->C); + mr_berror(_MIPP_ MR_ERR_OUT_OF_MEMORY); + MR_OUT + return FALSE; + } + for (k=0,i=0;iV[i]=mirvar(_MIPP_ 0); + c->M[i]=mirvar(_MIPP_ 0); + copy(moduli[i],c->M[i]); + for (j=0;jC[k]=mirvar(_MIPP_ 0); + invmodp(_MIPP_ c->M[j],c->M[i],c->C[k]); + } + } + c->NP=r; + MR_OUT + return TRUE; +} + +void crt_end(big_chinese *c) +{ /* clean up after CRT */ + int i,j,k; + if (c->NP<2) return; + for (k=0,i=0;iNP;i++) + { + mirkill(c->M[i]); + for (j=0;jC[k++]); + mirkill(c->V[i]); + } + mr_free(c->M); + mr_free(c->V); + mr_free(c->C); + c->NP=0; +} + +#endif + +void crt(_MIPD_ big_chinese *c,big *u,big x) +{ /* Chinese Remainder Thereom * + * Calculate x given remainders u[i] mod M[i] */ + int i,j,k; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (c->NP<2 || mr_mip->ERNUM) return; + + MR_IN(74) + + copy(u[0],c->V[0]); + for (k=0,i=1;iNP;i++) + { /* Knuth page 274 */ + subtract(_MIPP_ u[i],c->V[0],c->V[i]); + mad(_MIPP_ c->V[i],c->C[k],c->C[k],c->M[i],c->M[i],c->V[i]); + k++; + for (j=1;jV[i],c->V[j],c->V[i]); + mad(_MIPP_ c->V[i],c->C[k],c->C[k],c->M[i],c->M[i],c->V[i]); + } + if (size(c->V[i])<0) add(_MIPP_ c->V[i],c->M[i],c->V[i]); + } + zero(x); + convert(_MIPP_ 1,mr_mip->w1); + for (i=0;iNP;i++) + { + multiply(_MIPP_ mr_mip->w1,c->V[i],mr_mip->w2); + add(_MIPP_ x,mr_mip->w2,x); + multiply(_MIPP_ mr_mip->w1,c->M[i],mr_mip->w1); + } + MR_OUT +} + diff --git a/miracl/source/mrcurve.c b/miracl/source/mrcurve.c new file mode 100644 index 0000000..9090b14 --- /dev/null +++ b/miracl/source/mrcurve.c @@ -0,0 +1,2506 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL elliptic curve routines + * mrcurve.c + * + * Assumes Weierstrass equation y^2 = x^3 + Ax + B + * See IEEE P1363 Draft Standard + * + * (See below for Edwards coordinates implementation) + * + * Uses Montgomery's representation internally + * + * Works particularly well with fixed length Comba multiplier + * e.g. #define MR_COMBA 5 for 5x32 = 160 bit modulus + * on 32-bit computer + * + */ + +#include +#include "miracl.h" +#ifdef MR_STATIC +#include +#endif + +#ifndef MR_EDWARDS + +static void epoint_getrhs(_MIPD_ big x,big y) +{ /* x and y must be different */ + + /* find x^3+Ax+B */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + nres_modmult(_MIPP_ x,x,y); + + nres_modmult(_MIPP_ y,x,y); + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) + nres_modmult(_MIPP_ x,mr_mip->A,mr_mip->w1); + else + nres_premult(_MIPP_ x,mr_mip->Asize,mr_mip->w1); + nres_modadd(_MIPP_ y,mr_mip->w1,y); + if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) + nres_modadd(_MIPP_ y,mr_mip->B,y); + else + { + convert(_MIPP_ mr_mip->Bsize,mr_mip->w1); + nres(_MIPP_ mr_mip->w1,mr_mip->w1); + nres_modadd(_MIPP_ y,mr_mip->w1,y); + } +} + +#ifndef MR_NOSUPPORT_COMPRESSION + +BOOL epoint_x(_MIPD_ big x) +{ /* test if x is associated with a point on the * + * currently active curve */ + int j; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(147) + + if (x==NULL) return FALSE; + + nres(_MIPP_ x,mr_mip->w2); + epoint_getrhs(_MIPP_ mr_mip->w2,mr_mip->w3); + + if (size(mr_mip->w3)==0) + { + MR_OUT + return TRUE; + } + + redc(_MIPP_ mr_mip->w3,mr_mip->w4); + j=jack(_MIPP_ mr_mip->w4,mr_mip->modulus); + + MR_OUT + if (j==1) return TRUE; + return FALSE; +} + +#endif + +BOOL epoint_set(_MIPD_ big x,big y,int cb,epoint *p) +{ /* initialise a point on active ecurve * + * if x or y == NULL, set to point at infinity * + * if x==y, a y co-ordinate is calculated - if * + * possible - and cb suggests LSB 0/1 of y * + * (which "decompresses" y). Otherwise, check * + * validity of given (x,y) point, ignoring cb. * + * Returns TRUE for valid point, otherwise FALSE. */ + + BOOL valid; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(97) + + if (x==NULL || y==NULL) + { + copy(mr_mip->one,p->X); + copy(mr_mip->one,p->Y); + p->marker=MR_EPOINT_INFINITY; + MR_OUT + return TRUE; + } + +/* find x^3+Ax+B */ + + nres(_MIPP_ x,p->X); + + epoint_getrhs(_MIPP_ p->X,mr_mip->w3); + + valid=FALSE; + + if (x!=y) + { /* compare with y^2 */ + nres(_MIPP_ y,p->Y); + nres_modmult(_MIPP_ p->Y,p->Y,mr_mip->w1); + + if (mr_compare(mr_mip->w1,mr_mip->w3)==0) valid=TRUE; + } + else + { /* no y supplied - calculate one. Find square root */ +#ifndef MR_NOSUPPORT_COMPRESSION + + valid=nres_sqroot(_MIPP_ mr_mip->w3,p->Y); + /* check LSB - have we got the right root? */ + redc(_MIPP_ p->Y,mr_mip->w1); + if (remain(_MIPP_ mr_mip->w1,2)!=cb) + mr_psub(_MIPP_ mr_mip->modulus,p->Y,p->Y); + +#else + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return FALSE; +#endif + } + if (valid) + { + p->marker=MR_EPOINT_NORMALIZED; + MR_OUT + return TRUE; + } + + MR_OUT + return FALSE; +} + +#ifndef MR_STATIC + +void epoint_getxyz(_MIPD_ epoint *p,big x,big y,big z) +{ /* get (x,y,z) coordinates */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + MR_IN(143) + convert(_MIPP_ 1,mr_mip->w1); + if (p->marker==MR_EPOINT_INFINITY) + { +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { /* (0,1) or (0,0) = O */ +#endif + if (x!=NULL) zero(x); + if (mr_mip->Bsize==0) + { + if (y!=NULL) copy(mr_mip->w1,y); + } + else + { + if (y!=NULL) zero(y); + } +#ifndef MR_AFFINE_ONLY + } + if (mr_mip->coord==MR_PROJECTIVE) + { /* (1,1,0) = O */ + if (x!=NULL) copy(mr_mip->w1,x); + if (y!=NULL) copy(mr_mip->w1,y); + } +#endif + if (z!=NULL) zero(z); + MR_OUT + return; + } + if (x!=NULL) redc(_MIPP_ p->X,x); + if (y!=NULL) redc(_MIPP_ p->Y,y); +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { +#endif + if (z!=NULL) zero(z); +#ifndef MR_AFFINE_ONLY + } + + if (mr_mip->coord==MR_PROJECTIVE) + { + if (z!=NULL) + { + if (p->marker!=MR_EPOINT_GENERAL) copy(mr_mip->w1,z); + else redc(_MIPP_ p->Z,z); + } + } +#endif + MR_OUT + return; +} + +#endif + +int epoint_get(_MIPD_ epoint* p,big x,big y) +{ /* Get point co-ordinates in affine, normal form * + * (converted from projective, Montgomery form) * + * if x==y, supplies x only. Return value is Least * + * Significant Bit of y (useful for point compression) */ + + int lsb; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (p->marker==MR_EPOINT_INFINITY) + { + zero(x); + zero(y); + return 0; + } + if (mr_mip->ERNUM) return 0; + + MR_IN(98) + + if (!epoint_norm(_MIPP_ p)) + { /* not possible ! */ + MR_OUT + return (-1); + } + + redc(_MIPP_ p->X,x); + redc(_MIPP_ p->Y,mr_mip->w1); + + if (x!=y) copy(mr_mip->w1,y); + lsb=remain(_MIPP_ mr_mip->w1,2); + MR_OUT + return lsb; +} + +BOOL epoint_norm(_MIPD_ epoint *p) +{ /* normalise a point */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + +#ifndef MR_AFFINE_ONLY + + if (mr_mip->coord==MR_AFFINE) return TRUE; + if (p->marker!=MR_EPOINT_GENERAL) return TRUE; + + if (mr_mip->ERNUM) return FALSE; + + MR_IN(117) + + copy(mr_mip->one,mr_mip->w8); + + if (nres_moddiv(_MIPP_ mr_mip->w8,p->Z,mr_mip->w8)>1) /* 1/Z */ + { + epoint_set(_MIPP_ NULL,NULL,0,p); + mr_berror(_MIPP_ MR_ERR_COMPOSITE_MODULUS); + MR_OUT + return FALSE; + } + + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w1);/* 1/ZZ */ + nres_modmult(_MIPP_ p->X,mr_mip->w1,p->X); /* X/ZZ */ + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w8,mr_mip->w1);/* 1/ZZZ */ + nres_modmult(_MIPP_ p->Y,mr_mip->w1,p->Y); /* Y/ZZZ */ + + copy(mr_mip->one,p->Z); + + p->marker=MR_EPOINT_NORMALIZED; + MR_OUT + +#endif + + return TRUE; +} + +BOOL epoint_multi_norm(_MIPD_ int m,big *work,epoint **p) +{ /* Normalise an array of points of length mcoord==MR_AFFINE) return TRUE; + if (mr_mip->ERNUM) return FALSE; + if (m>MR_MAX_M_T_S) return FALSE; + + MR_IN(190) + + for (i=0;imarker==MR_EPOINT_NORMALIZED) w[i]=mr_mip->one; + else w[i]=p[i]->Z; + if (p[i]->marker==MR_EPOINT_INFINITY) {inf=TRUE; break;} /* whoops, one of them is point at infinity */ + } + + if (inf) + { + for (i=0;ione,p[i]->Z); + p[i]->marker=MR_EPOINT_NORMALIZED; + nres_modmult(_MIPP_ work[i],work[i],mr_mip->w1); + nres_modmult(_MIPP_ p[i]->X,mr_mip->w1,p[i]->X); /* X/ZZ */ + nres_modmult(_MIPP_ mr_mip->w1,work[i],mr_mip->w1); + nres_modmult(_MIPP_ p[i]->Y,mr_mip->w1,p[i]->Y); /* Y/ZZZ */ + } + MR_OUT +#endif + return TRUE; +} + +/* adds b+=a, d+=c, and slopes in s1 and s2 */ + +#ifndef MR_NO_ECC_MULTIADD +#ifndef MR_STATIC + +void ecurve_double_add(_MIPD_ epoint *a,epoint*b,epoint *c,epoint *d,big *s1,big *s2) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(144); + +#ifndef MR_AFFINE_ONLY + + if (mr_mip->coord==MR_AFFINE) + { +#endif + if (a->marker==MR_EPOINT_INFINITY || size(a->Y)==0) + { + *s1=NULL; + ecurve_add(_MIPP_ c,d); + *s2=mr_mip->w8; + MR_OUT + return; + } + if (b->marker==MR_EPOINT_INFINITY || size(b->Y)==0) + { + *s1=NULL; + epoint_copy(a,b); + ecurve_add(_MIPP_ c,d); + *s2=mr_mip->w8; + MR_OUT + return; + } + if (c->marker==MR_EPOINT_INFINITY || size(c->Y)==0) + { + ecurve_add(_MIPP_ a,b); + *s1=mr_mip->w8; + *s2=NULL; + MR_OUT + return; + } + if (d->marker==MR_EPOINT_INFINITY || size(d->Y)==0) + { + epoint_copy(c,d); + ecurve_add(_MIPP_ a,b); + *s1=mr_mip->w8; + *s2=NULL; + MR_OUT + return; + } + + if (a==b || (mr_compare(a->X,b->X)==0 && mr_compare(a->Y,b->Y)==0)) + { + nres_modmult(_MIPP_ a->X,a->X,mr_mip->w8); + nres_premult(_MIPP_ mr_mip->w8,3,mr_mip->w8); /* 3x^2 */ + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->A,mr_mip->w8); + else + { + convert(_MIPP_ mr_mip->Asize,mr_mip->w2); + nres(_MIPP_ mr_mip->w2,mr_mip->w2); + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w2,mr_mip->w8); + } + nres_premult(_MIPP_ a->Y,2,mr_mip->w10); + } + else + { + if (mr_compare(a->X,b->X)==0) + { + epoint_set(_MIPP_ NULL,NULL,0,b); + *s1=NULL; + ecurve_add(_MIPP_ c,d); + *s2=mr_mip->w8; + MR_OUT + return; + } + nres_modsub(_MIPP_ a->Y,b->Y,mr_mip->w8); + nres_modsub(_MIPP_ a->X,b->X,mr_mip->w10); + } + + if (c==d || (mr_compare(c->X,d->X)==0 && mr_compare(c->Y,d->Y)==0)) + { + nres_modmult(_MIPP_ c->X,c->X,mr_mip->w9); + nres_premult(_MIPP_ mr_mip->w9,3,mr_mip->w9); /* 3x^2 */ + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) + nres_modadd(_MIPP_ mr_mip->w9,mr_mip->A,mr_mip->w9); + else + { + convert(_MIPP_ mr_mip->Asize,mr_mip->w2); + nres(_MIPP_ mr_mip->w2,mr_mip->w2); + nres_modadd(_MIPP_ mr_mip->w9,mr_mip->w2,mr_mip->w9); + } + nres_premult(_MIPP_ c->Y,2,mr_mip->w11); + } + else + { + if (mr_compare(c->X,d->X)==0) + { + epoint_set(_MIPP_ NULL,NULL,0,d); + *s2=NULL; + ecurve_add(_MIPP_ a,b); + *s1=mr_mip->w8; + MR_OUT + return; + } + nres_modsub(_MIPP_ c->Y,d->Y,mr_mip->w9); + nres_modsub(_MIPP_ c->X,d->X,mr_mip->w11); + } + + nres_double_inverse(_MIPP_ mr_mip->w10,mr_mip->w10,mr_mip->w11,mr_mip->w11); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w10,mr_mip->w8); + nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); + + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w2); /* m^2 */ + nres_modsub(_MIPP_ mr_mip->w2,a->X,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w1,b->X,mr_mip->w1); + + nres_modsub(_MIPP_ b->X,mr_mip->w1,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w8,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w2,b->Y,b->Y); + copy(mr_mip->w1,b->X); + b->marker=MR_EPOINT_GENERAL; + + nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w9,mr_mip->w2); /* m^2 */ + nres_modsub(_MIPP_ mr_mip->w2,c->X,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w1,d->X,mr_mip->w1); + + nres_modsub(_MIPP_ d->X,mr_mip->w1,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w9,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w2,d->Y,d->Y); + copy(mr_mip->w1,d->X); + d->marker=MR_EPOINT_GENERAL; + + *s1=mr_mip->w8; + *s2=mr_mip->w9; +#ifndef MR_AFFINE_ONLY + } + else + { /* no speed-up */ + ecurve_add(_MIPP_ a,b); + copy(mr_mip->w8,mr_mip->w9); + *s1=mr_mip->w9; + ecurve_add(_MIPP_ c,d); + *s2=mr_mip->w8; + } +#endif + MR_OUT +} + +void ecurve_multi_add(_MIPD_ int m,epoint **x,epoint**w) +{ /* adds m points together simultaneously, w[i]+=x[i] */ + int i,*flag; + big *A,*B,*C; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(122) +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { /* this can be done faster */ +#endif + A=(big *)mr_alloc(_MIPP_ m,sizeof(big)); + B=(big *)mr_alloc(_MIPP_ m,sizeof(big)); + C=(big *)mr_alloc(_MIPP_ m,sizeof(big)); + flag=(int *)mr_alloc(_MIPP_ m,sizeof(int)); + + copy(mr_mip->one,mr_mip->w3); + + for (i=0;iX,w[i]->X)==0 && mr_compare(x[i]->Y,w[i]->Y)==0) + { /* doubling */ + if (x[i]->marker==MR_EPOINT_INFINITY || size(x[i]->Y)==0) + { + flag[i]=1; /* result is infinity */ + copy(mr_mip->w3,B[i]); + continue; + } + nres_modmult(_MIPP_ x[i]->X,x[i]->X,A[i]); + nres_premult(_MIPP_ A[i],3,A[i]); /* 3*x^2 */ + if (mr_abs(mr_mip->Asize) == MR_TOOBIG) + nres_modadd(_MIPP_ A[i],mr_mip->A,A[i]); + else + { + convert(_MIPP_ mr_mip->Asize,mr_mip->w2); + nres(_MIPP_ mr_mip->w2,mr_mip->w2); + nres_modadd(_MIPP_ A[i],mr_mip->w2,A[i]); + } /* 3*x^2+A */ + nres_premult(_MIPP_ x[i]->Y,2,B[i]); + } + else + { + if (x[i]->marker==MR_EPOINT_INFINITY) + { + flag[i]=2; /* w[i] unchanged */ + copy(mr_mip->w3,B[i]); + continue; + } + if (w[i]->marker==MR_EPOINT_INFINITY) + { + flag[i]=3; /* w[i] = x[i] */ + copy(mr_mip->w3,B[i]); + continue; + } + nres_modsub(_MIPP_ x[i]->X,w[i]->X,B[i]); + if (size(B[i])==0) + { /* point at infinity */ + flag[i]=1; /* result is infinity */ + copy(mr_mip->w3,B[i]); + continue; + } + nres_modsub(_MIPP_ x[i]->Y,w[i]->Y,A[i]); + } + } + nres_multi_inverse(_MIPP_ m,B,C); /* only one inversion needed */ + for (i=0;iw8); + + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w2); /* m^2 */ + nres_modsub(_MIPP_ mr_mip->w2,x[i]->X,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w1,w[i]->X,mr_mip->w1); + + nres_modsub(_MIPP_ w[i]->X,mr_mip->w1,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w8,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w2,w[i]->Y,w[i]->Y); + copy(mr_mip->w1,w[i]->X); + w[i]->marker=MR_EPOINT_NORMALIZED; + + mr_free(C[i]); + mr_free(B[i]); + mr_free(A[i]); + } + mr_free(flag); + mr_free(C); mr_free(B); mr_free(A); +#ifndef MR_AFFINE_ONLY + } + else + { /* no speed-up */ + for (i=0;iERNUM) return; + + if (p->marker==MR_EPOINT_INFINITY) + { /* 2 times infinity == infinity ! */ + return; + } + +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { /* 2 sqrs, 1 mul, 1 div */ +#endif + if (size(p->Y)==0) + { /* set to point at infinity */ + epoint_set(_MIPP_ NULL,NULL,0,p); + return; + } + + nres_modmult(_MIPP_ p->X,p->X,mr_mip->w8); /* w8=x^2 */ + nres_premult(_MIPP_ mr_mip->w8,3,mr_mip->w8); /* w8=3*x^2 */ + if (mr_abs(mr_mip->Asize) == MR_TOOBIG) + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->A,mr_mip->w8); + else + { + convert(_MIPP_ mr_mip->Asize,mr_mip->w2); + nres(_MIPP_ mr_mip->w2,mr_mip->w2); + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w2,mr_mip->w8); + } /* w8=3*x^2+A */ + nres_premult(_MIPP_ p->Y,2,mr_mip->w6); /* w6=2y */ + if (nres_moddiv(_MIPP_ mr_mip->w8,mr_mip->w6,mr_mip->w8)>1) + { + epoint_set(_MIPP_ NULL,NULL,0,p); + mr_berror(_MIPP_ MR_ERR_COMPOSITE_MODULUS); + return; + } + +/* w8 is slope m on exit */ + + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w2); /* w2=m^2 */ + nres_premult(_MIPP_ p->X,2,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w2,mr_mip->w1,mr_mip->w1); /* w1=m^2-2x */ + + nres_modsub(_MIPP_ p->X,mr_mip->w1,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w8,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w2,p->Y,p->Y); + copy(mr_mip->w1,p->X); + + return; +#ifndef MR_AFFINE_ONLY + } + + if (size(p->Y)==0) + { /* set to point at infinity */ + epoint_set(_MIPP_ NULL,NULL,0,p); + return; + } + + convert(_MIPP_ 1,mr_mip->w1); + if (mr_abs(mr_mip->Asize) < MR_TOOBIG) + { + if (mr_mip->Asize!=0) + { + if (p->marker==MR_EPOINT_NORMALIZED) + nres(_MIPP_ mr_mip->w1,mr_mip->w6); + else nres_modmult(_MIPP_ p->Z,p->Z,mr_mip->w6); + } + + if (mr_mip->Asize==(-3)) + { /* a is -3. Goody. 4 sqrs, 4 muls */ + nres_modsub(_MIPP_ p->X,mr_mip->w6,mr_mip->w3); + nres_modadd(_MIPP_ p->X,mr_mip->w6,mr_mip->w8); + nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w8,mr_mip->w3); + nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w3,mr_mip->w8); + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w8); + } + else + { /* a is small */ + if (mr_mip->Asize!=0) + { /* a is non zero! */ + nres_modmult(_MIPP_ mr_mip->w6,mr_mip->w6,mr_mip->w3); + nres_premult(_MIPP_ mr_mip->w3,mr_mip->Asize,mr_mip->w3); + } + nres_modmult(_MIPP_ p->X,p->X,mr_mip->w1); + nres_modadd(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w8); + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w1,mr_mip->w8); + if (mr_mip->Asize!=0) nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w8); + } + } + else + { /* a is not special */ + if (p->marker==MR_EPOINT_NORMALIZED) nres(_MIPP_ mr_mip->w1,mr_mip->w6); + else nres_modmult(_MIPP_ p->Z,p->Z,mr_mip->w6); + + nres_modmult(_MIPP_ mr_mip->w6,mr_mip->w6,mr_mip->w3); + nres_modmult(_MIPP_ mr_mip->w3,mr_mip->A,mr_mip->w3); + nres_modmult(_MIPP_ p->X,p->X,mr_mip->w1); + nres_modadd(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w8); + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w1,mr_mip->w8); + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w8); + } + +/* w8 contains numerator of slope 3x^2+A.z^4 * + * denominator is now placed in Z */ + + nres_modmult(_MIPP_ p->Y,p->Y,mr_mip->w2); + nres_modmult(_MIPP_ p->X,mr_mip->w2,mr_mip->w3); + nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w3,mr_mip->w3); + nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w3,mr_mip->w3); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,p->X); + nres_modsub(_MIPP_ p->X,mr_mip->w3,p->X); + nres_modsub(_MIPP_ p->X,mr_mip->w3,p->X); + + if (p->marker==MR_EPOINT_NORMALIZED) + copy(p->Y,p->Z); + else nres_modmult(_MIPP_ p->Z,p->Y,p->Z); + nres_modadd(_MIPP_ p->Z,p->Z,p->Z); + + nres_modadd(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w7); + nres_modmult(_MIPP_ mr_mip->w7,mr_mip->w7,mr_mip->w2); + nres_modadd(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w3,p->X,mr_mip->w3); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w3,p->Y); + nres_modsub(_MIPP_ p->Y,mr_mip->w2,p->Y); + +/* alternative method + nres_modadd(_MIPP_ p->Y,p->Y,mr_mip->w2); + + if (p->marker==MR_EPOINT_NORMALIZED) + copy(mr_mip->w2,p->Z); + + else nres_modmult(_MIPP_ mr_mip->w2,p->Z,p->Z); + + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w2); + nres_modmult(_MIPP_ p->X,mr_mip->w2,mr_mip->w3); + nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w3,p->X); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w1,p->X,p->X); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w2); + + if (remain(_MIPP_ mr_mip->w2,2)!=0) + mr_padd(_MIPP_ mr_mip->w2,mr_mip->modulus,mr_mip->w2); + subdiv(_MIPP_ mr_mip->w2,2,mr_mip->w2); + + nres_modsub(_MIPP_ mr_mip->w3,p->X,mr_mip->w3); + nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w8,mr_mip->w3); + nres_modsub(_MIPP_ mr_mip->w3,mr_mip->w2,p->Y); +*/ + +/* + +Observe that when finished w8 contains the line slope, w7 has 2y^2 and w6 has z^2 +This is useful for calculating line functions in pairings + +*/ + + p->marker=MR_EPOINT_GENERAL; + return; +#endif +} + +static BOOL ecurve_padd(_MIPD_ epoint *p,epoint *pa) +{ /* primitive add two epoints on the active ecurve - pa+=p; * + * note that if p is normalized, its Z coordinate isn't used */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { /* 1 sqr, 1 mul, 1 div */ +#endif + nres_modsub(_MIPP_ p->Y,pa->Y,mr_mip->w8); + nres_modsub(_MIPP_ p->X,pa->X,mr_mip->w6); + if (size(mr_mip->w6)==0) + { /* divide by 0 */ + if (size(mr_mip->w8)==0) + { /* should have doubled ! */ + return FALSE; + } + else + { /* point at infinity */ + epoint_set(_MIPP_ NULL,NULL,0,pa); + return TRUE; + } + } + if (nres_moddiv(_MIPP_ mr_mip->w8,mr_mip->w6,mr_mip->w8)>1) + { + epoint_set(_MIPP_ NULL,NULL,0,pa); + mr_berror(_MIPP_ MR_ERR_COMPOSITE_MODULUS); + return TRUE; + } + + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w2); /* w2=m^2 */ + nres_modsub(_MIPP_ mr_mip->w2,p->X,mr_mip->w1); /* w1=m^2-x1-x2 */ + nres_modsub(_MIPP_ mr_mip->w1,pa->X,mr_mip->w1); + + + nres_modsub(_MIPP_ pa->X,mr_mip->w1,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w8,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w2,pa->Y,pa->Y); + copy(mr_mip->w1,pa->X); + + pa->marker=MR_EPOINT_NORMALIZED; + return TRUE; +#ifndef MR_AFFINE_ONLY + } + + if (p->marker!=MR_EPOINT_NORMALIZED) + { + nres_modmult(_MIPP_ p->Z,p->Z,mr_mip->w6); + nres_modmult(_MIPP_ pa->X,mr_mip->w6,mr_mip->w1); + nres_modmult(_MIPP_ mr_mip->w6,p->Z,mr_mip->w6); + nres_modmult(_MIPP_ pa->Y,mr_mip->w6,mr_mip->w8); + } + else + { + copy(pa->X,mr_mip->w1); + copy(pa->Y,mr_mip->w8); + } + if (pa->marker==MR_EPOINT_NORMALIZED) + copy(mr_mip->one,mr_mip->w6); + else nres_modmult(_MIPP_ pa->Z,pa->Z,mr_mip->w6); + + nres_modmult(_MIPP_ p->X,mr_mip->w6,mr_mip->w4); + if (pa->marker!=MR_EPOINT_NORMALIZED) + nres_modmult(_MIPP_ mr_mip->w6,pa->Z,mr_mip->w6); + nres_modmult(_MIPP_ p->Y,mr_mip->w6,mr_mip->w5); + nres_modsub(_MIPP_ mr_mip->w1,mr_mip->w4,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w5,mr_mip->w8); + +/* w8 contains the numerator of the slope */ + + if (size(mr_mip->w1)==0) + { + if (size(mr_mip->w8)==0) + { /* should have doubled ! */ + return FALSE; + } + else + { /* point at infinity */ + epoint_set(_MIPP_ NULL,NULL,0,pa); + return TRUE; + } + } + nres_modadd(_MIPP_ mr_mip->w4,mr_mip->w4,mr_mip->w6); + nres_modadd(_MIPP_ mr_mip->w1,mr_mip->w6,mr_mip->w4); + nres_modadd(_MIPP_ mr_mip->w5,mr_mip->w5,mr_mip->w6); + nres_modadd(_MIPP_ mr_mip->w8,mr_mip->w6,mr_mip->w5); + + if (p->marker!=MR_EPOINT_NORMALIZED) + { + if (pa->marker!=MR_EPOINT_NORMALIZED) + nres_modmult(_MIPP_ pa->Z,p->Z,mr_mip->w3); + else + copy(p->Z,mr_mip->w3); + nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w1,pa->Z); + } + else + { + if (pa->marker!=MR_EPOINT_NORMALIZED) + nres_modmult(_MIPP_ pa->Z,mr_mip->w1,pa->Z); + else + copy(mr_mip->w1,pa->Z); + } + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w6); + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w6,mr_mip->w1); + nres_modmult(_MIPP_ mr_mip->w6,mr_mip->w4,mr_mip->w6); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w4); + + nres_modsub(_MIPP_ mr_mip->w4,mr_mip->w6,pa->X); + nres_modsub(_MIPP_ mr_mip->w6,pa->X,mr_mip->w6); + nres_modsub(_MIPP_ mr_mip->w6,pa->X,mr_mip->w6); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w6,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w5,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w2,mr_mip->w1,mr_mip->w5); + +/* divide by 2 */ + + nres_div2(_MIPP_ mr_mip->w5,pa->Y); + + pa->marker=MR_EPOINT_GENERAL; + return TRUE; +#endif +} + +void epoint_copy(epoint *a,epoint *b) +{ + if (a==b || b==NULL) return; + + copy(a->X,b->X); + copy(a->Y,b->Y); +#ifndef MR_AFFINE_ONLY + if (a->marker==MR_EPOINT_GENERAL) copy(a->Z,b->Z); +#endif + b->marker=a->marker; + return; +} + +BOOL epoint_comp(_MIPD_ epoint *a,epoint *b) +{ + BOOL result; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + if (a==b) return TRUE; + if (a->marker==MR_EPOINT_INFINITY) + { + if (b->marker==MR_EPOINT_INFINITY) return TRUE; + else return FALSE; + } + if (b->marker==MR_EPOINT_INFINITY) + return FALSE; + +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { +#endif + if (mr_compare(a->X,b->X)==0 && mr_compare(a->Y,b->Y)==0) result=TRUE; + else result=FALSE; + return result; +#ifndef MR_AFFINE_ONLY + } + + if (mr_mip->coord==MR_PROJECTIVE) + { + MR_IN(105) + if (a->marker!=MR_EPOINT_GENERAL) + copy(mr_mip->one,mr_mip->w1); + else copy(a->Z,mr_mip->w1); + + if (b->marker!=MR_EPOINT_GENERAL) + copy(mr_mip->one,mr_mip->w2); + else copy(b->Z,mr_mip->w2); + + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w3); /* Za*Za */ + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w4); /* Zb*Zb */ + + nres_modmult(_MIPP_ a->X,mr_mip->w4,mr_mip->w5); /* Xa*Zb*Zb */ + nres_modmult(_MIPP_ b->X,mr_mip->w3,mr_mip->w6); /* Xb*Za*Za */ + + if (mr_compare(mr_mip->w5,mr_mip->w6)!=0) result=FALSE; + else + { + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w3,mr_mip->w3); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w4,mr_mip->w4); + + nres_modmult(_MIPP_ a->Y,mr_mip->w4,mr_mip->w5); + nres_modmult(_MIPP_ b->Y,mr_mip->w3,mr_mip->w6); + + if (mr_compare(mr_mip->w5,mr_mip->w6)!=0) result=FALSE; + else result=TRUE; + } + MR_OUT + return result; + } + return FALSE; +#endif +} + +int ecurve_add(_MIPD_ epoint *p,epoint *pa) +{ /* pa=pa+p; */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return MR_OVER; + + MR_IN(94) + + if (p==pa) + { + ecurve_double(_MIPP_ pa); + MR_OUT + if (pa->marker==MR_EPOINT_INFINITY) return MR_OVER; + return MR_DOUBLE; + } + if (pa->marker==MR_EPOINT_INFINITY) + { + epoint_copy(p,pa); + MR_OUT + return MR_ADD; + } + if (p->marker==MR_EPOINT_INFINITY) + { + MR_OUT + return MR_ADD; + } + + if (!ecurve_padd(_MIPP_ p,pa)) + { + ecurve_double(_MIPP_ pa); + MR_OUT + return MR_DOUBLE; + } + MR_OUT + if (pa->marker==MR_EPOINT_INFINITY) return MR_OVER; + return MR_ADD; +} + +void epoint_negate(_MIPD_ epoint *p) +{ /* negate a point */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + if (p->marker==MR_EPOINT_INFINITY) return; + + MR_IN(121) + if (size(p->Y)!=0) mr_psub(_MIPP_ mr_mip->modulus,p->Y,p->Y); + MR_OUT +} + +int ecurve_sub(_MIPD_ epoint *p,epoint *pa) +{ + int r; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return MR_OVER; + + MR_IN(104) + + if (p==pa) + { + epoint_set(_MIPP_ NULL,NULL,0,pa); + MR_OUT + return MR_OVER; + } + if (p->marker==MR_EPOINT_INFINITY) + { + MR_OUT + return MR_ADD; + } + + epoint_negate(_MIPP_ p); + r=ecurve_add(_MIPP_ p,pa); + epoint_negate(_MIPP_ p); + + MR_OUT + return r; +} + +int ecurve_mult(_MIPD_ big e,epoint *pa,epoint *pt) +{ /* pt=e*pa; */ + int i,j,n,nb,nbs,nzs,nadds; + epoint *table[MR_ECC_STORE_N]; +#ifndef MR_AFFINE_ONLY + big work[MR_ECC_STORE_N]; +#endif + +#ifdef MR_STATIC + char mem[MR_ECP_RESERVE(MR_ECC_STORE_N)]; +#ifndef MR_AFFINE_ONLY + char mem1[MR_BIG_RESERVE(MR_ECC_STORE_N)]; +#endif +#else + char *mem; +#ifndef MR_AFFINE_ONLY + char *mem1; +#endif +#endif + +#ifndef MR_ALWAYS_BINARY + epoint *p; + int ce,ch; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(95) + if (size(e)==0) + { /* multiplied by 0 */ + epoint_set(_MIPP_ NULL,NULL,0,pt); + MR_OUT + return 0; + } + copy(e,mr_mip->w9); +/* epoint_norm(_MIPP_ pa); */ + epoint_copy(pa,pt); + + if (size(mr_mip->w9)<0) + { /* pt = -pt */ + negify(mr_mip->w9,mr_mip->w9); + epoint_negate(_MIPP_ pt); + } + + if (size(mr_mip->w9)==1) + { + MR_OUT + return 0; + } + + premult(_MIPP_ mr_mip->w9,3,mr_mip->w10); /* h=3*e */ + +#ifndef MR_STATIC +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif +#endif + +#ifdef MR_STATIC + memset(mem,0,MR_ECP_RESERVE(MR_ECC_STORE_N)); +#ifndef MR_AFFINE_ONLY + memset(mem1,0,MR_BIG_RESERVE(MR_ECC_STORE_N)); +#endif +#else + mem=(char *)ecp_memalloc(_MIPP_ MR_ECC_STORE_N); +#ifndef MR_AFFINE_ONLY + mem1=(char *)memalloc(_MIPP_ MR_ECC_STORE_N); +#endif +#endif + + for (i=0;i<=MR_ECC_STORE_N-1;i++) + { + table[i]=epoint_init_mem(_MIPP_ mem,i); +#ifndef MR_AFFINE_ONLY + work[i]=mirvar_mem(_MIPP_ mem1,i); +#endif + } + + epoint_copy(pt,table[0]); + epoint_copy(table[0],table[MR_ECC_STORE_N-1]); + ecurve_double(_MIPP_ table[MR_ECC_STORE_N-1]); + /* epoint_norm(_MIPP_ table[MR_ECC_STORE_N-1]); */ + + for (i=1;iw10); + nadds=0; + epoint_set(_MIPP_ NULL,NULL,0,pt); + for (i=nb-1;i>=1;) + { /* add/subtract */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + n=mr_naf_window(_MIPP_ mr_mip->w9,mr_mip->w10,i,&nbs,&nzs,MR_ECC_STORE_N); + for (j=0;j0) {ecurve_add(_MIPP_ table[n/2],pt); nadds++;} + if (n<0) {ecurve_sub(_MIPP_ table[(-n)/2],pt); nadds++;} + i-=nbs; + if (nzs) + { + for (j=0;jw10)-1,mr_mip->w11); + mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); + subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); + while (size(mr_mip->w11) > 1) + { /* add/subtract method */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + ecurve_double(_MIPP_ pt); + ce=mr_compare(mr_mip->w9,mr_mip->w11); /* e(i)=1? */ + ch=mr_compare(mr_mip->w10,mr_mip->w11); /* h(i)=1? */ + if (ch>=0) + { /* h(i)=1 */ + if (ce<0) {ecurve_add(_MIPP_ p,pt); nadds++;} + mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); + } + if (ce>=0) + { /* e(i)=1 */ + if (ch<0) {ecurve_sub(_MIPP_ p,pt); nadds++;} + mr_psub(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); + } + subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); + } + ecp_memkill(_MIPP_ mem,1); + } +#endif +#endif + MR_OUT + return nadds; +} + +#ifndef MR_NO_ECC_MULTIADD +#ifndef MR_STATIC + +void ecurve_multn(_MIPD_ int n,big *y,epoint **x,epoint *w) +{ /* pt=e[o]*p[0]+e[1]*p[1]+ .... e[n-1]*p[n-1] */ + int i,j,k,m,nb,ea; + epoint **G; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(114) + + m=1< nb) nb=k; + + epoint_set(_MIPP_ NULL,NULL,0,w); /* w=0 */ + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + for (i=nb-1;i>=0;i--) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + ea=0; + k=1; + for (j=0;jERNUM) return FALSE; + + if (P->marker==MR_EPOINT_GENERAL || Q->marker==MR_EPOINT_GENERAL) + { + mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + MR_OUT + return FALSE; + } + + if (mr_compare(P->X,Q->X)==0) + { /* P=Q or P=-Q - shouldn't happen */ + epoint_copy(P,PP); + ecurve_add(_MIPP_ Q,PP); + epoint_copy(P,PM); + ecurve_sub(_MIPP_ Q,PM); + + MR_OUT + return TRUE; + } + + t1= mr_mip->w10; + t2= mr_mip->w11; + lam = mr_mip->w13; + + copy(P->X,t2); + nres_modsub(_MIPP_ t2,Q->X,t2); + + redc(_MIPP_ t2,t2); + invmodp(_MIPP_ t2,mr_mip->modulus,t2); + nres(_MIPP_ t2,t2); + + nres_modadd(_MIPP_ P->X,Q->X,PP->X); + copy(PP->X,PM->X); + + copy(P->Y,t1); + nres_modsub(_MIPP_ t1,Q->Y,t1); + copy(t1,lam); + nres_modmult(_MIPP_ lam,t2,lam); + copy(lam,t1); + nres_modmult(_MIPP_ t1,t1,t1); + nres_modsub(_MIPP_ t1,PP->X,PP->X); + copy(Q->X,PP->Y); + nres_modsub(_MIPP_ PP->Y,PP->X,PP->Y); + nres_modmult(_MIPP_ PP->Y,lam,PP->Y); + nres_modsub(_MIPP_ PP->Y,Q->Y,PP->Y); + + copy(P->Y,t1); + nres_modadd(_MIPP_ t1,Q->Y,t1); + copy(t1,lam); + nres_modmult(_MIPP_ lam,t2,lam); + copy(lam,t1); + nres_modmult(_MIPP_ t1,t1,t1); + nres_modsub(_MIPP_ t1,PM->X,PM->X); + copy(Q->X,PM->Y); + nres_modsub(_MIPP_ PM->Y,PM->X,PM->Y); + nres_modmult(_MIPP_ PM->Y,lam,PM->Y); + nres_modadd(_MIPP_ PM->Y,Q->Y,PM->Y); + + PP->marker=MR_EPOINT_NORMALIZED; + PM->marker=MR_EPOINT_NORMALIZED; + + return TRUE; +} + +void ecurve_mult2(_MIPD_ big e,epoint *p,big ea,epoint *pa,epoint *pt) +{ /* pt=e*p+ea*pa; */ + int e1,h1,e2,h2,bb; + epoint *p1,*p2,*ps[2]; +#ifdef MR_STATIC + char mem[MR_ECP_RESERVE(4)]; +#else + char *mem; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return; + + MR_IN(103) + + if (size(e)==0) + { + ecurve_mult(_MIPP_ ea,pa,pt); + MR_OUT + return; + } +#ifdef MR_STATIC + memset(mem,0,MR_ECP_RESERVE(4)); +#else + mem=(char *)ecp_memalloc(_MIPP_ 4); +#endif + p2=epoint_init_mem(_MIPP_ mem,0); + p1=epoint_init_mem(_MIPP_ mem,1); + ps[0]=epoint_init_mem(_MIPP_ mem,2); + ps[1]=epoint_init_mem(_MIPP_ mem,3); + + epoint_norm(_MIPP_ pa); + epoint_copy(pa,p2); + copy(ea,mr_mip->w9); + if (size(mr_mip->w9)<0) + { /* p2 = -p2 */ + negify(mr_mip->w9,mr_mip->w9); + epoint_negate(_MIPP_ p2); + } + + epoint_norm(_MIPP_ p); + epoint_copy(p,p1); + copy(e,mr_mip->w12); + if (size(mr_mip->w12)<0) + { /* p1= -p1 */ + negify(mr_mip->w12,mr_mip->w12); + epoint_negate(_MIPP_ p1); + } + + + epoint_set(_MIPP_ NULL,NULL,0,pt); /* pt=0 */ + ecurve_add_sub(_MIPP_ p1,p2,ps[0],ps[1]); /* only one inversion! ps[0]=p1+p2, ps[1]=p1-p2 */ + + mr_jsf(_MIPP_ mr_mip->w9,mr_mip->w12,mr_mip->w10,mr_mip->w9,mr_mip->w13,mr_mip->w12); + +/* To use a simple NAF instead, substitute this for the JSF + premult(_MIPP_ mr_mip->w9,3,mr_mip->w10); 3*ea + premult(_MIPP_ mr_mip->w12,3,mr_mip->w13); 3*e +*/ + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + if (mr_compare(mr_mip->w10,mr_mip->w13)>=0) bb=logb2(_MIPP_ mr_mip->w10)-1; + else bb=logb2(_MIPP_ mr_mip->w13)-1; + + while (bb>=0) /* for the simple NAF, this should be 1 */ + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + ecurve_double(_MIPP_ pt); + + e1=h1=e2=h2=0; + if (mr_testbit(_MIPP_ mr_mip->w9,bb)) e2=1; + if (mr_testbit(_MIPP_ mr_mip->w10,bb)) h2=1; + if (mr_testbit(_MIPP_ mr_mip->w12,bb)) e1=1; + if (mr_testbit(_MIPP_ mr_mip->w13,bb)) h1=1; + + if (e1!=h1) + { + if (e2==h2) + { + if (h1==1) ecurve_add(_MIPP_ p1,pt); + else ecurve_sub(_MIPP_ p1,pt); + } + else + { + if (h1==1) + { + if (h2==1) ecurve_add(_MIPP_ ps[0],pt); + else ecurve_add(_MIPP_ ps[1],pt); + } + else + { + if (h2==1) ecurve_sub(_MIPP_ ps[1],pt); + else ecurve_sub(_MIPP_ ps[0],pt); + } + } + } + else if (e2!=h2) + { + if (h2==1) ecurve_add(_MIPP_ p2,pt); + else ecurve_sub(_MIPP_ p2,pt); + } + bb-=1; + } +#ifndef MR_ALWAYS_BINARY + } + else + { + if (mr_compare(mr_mip->w10,mr_mip->w13)>=0) + expb2(_MIPP_ logb2(_MIPP_ mr_mip->w10)-1,mr_mip->w11); + else expb2(_MIPP_ logb2(_MIPP_ mr_mip->w13)-1,mr_mip->w11); + + while (size(mr_mip->w11) > 0) /* for the NAF, this should be 1 */ + { /* add/subtract method */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + ecurve_double(_MIPP_ pt); + + e1=h1=e2=h2=0; + if (mr_compare(mr_mip->w9,mr_mip->w11)>=0) + { /* e1(i)=1? */ + e2=1; + mr_psub(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); + } + if (mr_compare(mr_mip->w10,mr_mip->w11)>=0) + { /* h1(i)=1? */ + h2=1; + mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); + } + if (mr_compare(mr_mip->w12,mr_mip->w11)>=0) + { /* e2(i)=1? */ + e1=1; + mr_psub(_MIPP_ mr_mip->w12,mr_mip->w11,mr_mip->w12); + } + if (mr_compare(mr_mip->w13,mr_mip->w11)>=0) + { /* h2(i)=1? */ + h1=1; + mr_psub(_MIPP_ mr_mip->w13,mr_mip->w11,mr_mip->w13); + } + + if (e1!=h1) + { + if (e2==h2) + { + if (h1==1) ecurve_add(_MIPP_ p1,pt); + else ecurve_sub(_MIPP_ p1,pt); + } + else + { + if (h1==1) + { + if (h2==1) ecurve_add(_MIPP_ ps[0],pt); + else ecurve_add(_MIPP_ ps[1],pt); + } + else + { + if (h2==1) ecurve_sub(_MIPP_ ps[1],pt); + else ecurve_sub(_MIPP_ ps[0],pt); + } + } + } + else if (e2!=h2) + { + if (h2==1) ecurve_add(_MIPP_ p2,pt); + else ecurve_sub(_MIPP_ p2,pt); + } + + subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); + } + } +#endif + ecp_memkill(_MIPP_ mem,4); + MR_OUT +} + +#endif + +#else + +/* Twisted Inverted Edwards curves + + * Assumes Twisted Inverted Edward's equation x^2+Ay^2 = x^2.y^2 + B + * Assumes points are not of order 2 or 4 +*/ + +static void epoint_getrhs(_MIPD_ big x,big y) +{ + /* find RHS=(x^2-B)/(x^2-A) */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + nres_modmult(_MIPP_ x,x,mr_mip->w6); + nres_modsub(_MIPP_ mr_mip->w6,mr_mip->B,y); + nres_modsub(_MIPP_ mr_mip->w6,mr_mip->A,mr_mip->w6); + + nres_moddiv(_MIPP_ y,mr_mip->w6,y); +} + +#ifndef MR_NOSUPPORT_COMPRESSION + +BOOL epoint_x(_MIPD_ big x) +{ /* test if x is associated with a point on the * + * currently active curve */ + int j; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(147) + + if (x==NULL) return FALSE; + + nres(_MIPP_ x,mr_mip->w2); + epoint_getrhs(_MIPP_ mr_mip->w2,mr_mip->w7); + + if (size(mr_mip->w7)==0) + { + MR_OUT + return TRUE; + } + + redc(_MIPP_ mr_mip->w7,mr_mip->w4); + j=jack(_MIPP_ mr_mip->w4,mr_mip->modulus); + + MR_OUT + if (j==1) return TRUE; + return FALSE; +} + +#endif + +BOOL epoint_set(_MIPD_ big x,big y,int cb,epoint *p) +{ /* initialise a point on active ecurve * + * if x or y == NULL, set to point at infinity * + * if x==y, a y co-ordinate is calculated - if * + * possible - and cb suggests LSB 0/1 of y * + * (which "decompresses" y). Otherwise, check * + * validity of given (x,y) point, ignoring cb. * + * Returns TRUE for valid point, otherwise FALSE. */ + + BOOL valid; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(97) + + if (x==NULL || y==NULL) + { + copy(mr_mip->one,p->X); + zero(p->Y); + p->marker=MR_EPOINT_INFINITY; + MR_OUT + return TRUE; + } + + valid=FALSE; + nres(_MIPP_ x,p->X); + if (x!=y) + { /* Check directly that x^2+Ay^2 == x^2.y^2+B */ + nres(_MIPP_ y,p->Y); + nres_modmult(_MIPP_ p->X,p->X,mr_mip->w1); + nres_modmult(_MIPP_ p->Y,p->Y,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w3); + nres_modadd(_MIPP_ mr_mip->w3,mr_mip->B,mr_mip->w3); + + + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->A,mr_mip->w2); + else + nres_premult(_MIPP_ mr_mip->w2,mr_mip->Asize,mr_mip->w2); + nres_modadd(_MIPP_ mr_mip->w2,mr_mip->w1,mr_mip->w2); + if (mr_compare(mr_mip->w2,mr_mip->w3)==0) valid=TRUE; + } + else + { /* find RHS */ + epoint_getrhs(_MIPP_ p->X,mr_mip->w7); + /* no y supplied - calculate one. Find square root */ +#ifndef MR_NOSUPPORT_COMPRESSION + valid=nres_sqroot(_MIPP_ mr_mip->w7,p->Y); + /* check LSB - have we got the right root? */ + redc(_MIPP_ p->Y,mr_mip->w1); + if (remain(_MIPP_ mr_mip->w1,2)!=cb) + mr_psub(_MIPP_ mr_mip->modulus,p->Y,p->Y); + +#else + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return FALSE; +#endif + } + if (valid) + { + p->marker=MR_EPOINT_NORMALIZED; + MR_OUT + return TRUE; + } + + MR_OUT + return FALSE; +} + +#ifndef MR_STATIC + +void epoint_getxyz(_MIPD_ epoint *p,big x,big y,big z) +{ /* get (x,y,z) coordinates */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + MR_IN(143) + convert(_MIPP_ 1,mr_mip->w1); + if (p->marker==MR_EPOINT_INFINITY) + { + if (x!=NULL) copy(mr_mip->w1,x); + if (y!=NULL) zero(y); + if (z!=NULL) zero(z); + MR_OUT + return; + } + if (x!=NULL) redc(_MIPP_ p->X,x); + if (y!=NULL) redc(_MIPP_ p->Y,y); + if (z!=NULL) redc(_MIPP_ p->Z,z); + + MR_OUT + return; +} + +#endif + +int epoint_get(_MIPD_ epoint* p,big x,big y) +{ /* Get point co-ordinates in affine, normal form * + * (converted from projective, Montgomery form) * + * if x==y, supplies x only. Return value is Least * + * Significant Bit of y (useful for point compression) */ + + int lsb; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (p->marker==MR_EPOINT_INFINITY) + { + zero(y); + convert(_MIPP_ 1,x); + return 0; + } + if (mr_mip->ERNUM) return 0; + + MR_IN(98) + + if (!epoint_norm(_MIPP_ p)) + { /* not possible ! */ + MR_OUT + return (-1); + } + + redc(_MIPP_ p->X,x); + redc(_MIPP_ p->Y,mr_mip->w1); + + if (x!=y) copy(mr_mip->w1,y); + lsb=remain(_MIPP_ mr_mip->w1,2); + MR_OUT + return lsb; +} + +BOOL epoint_norm(_MIPD_ epoint *p) +{ /* normalise a point */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (p->marker!=MR_EPOINT_GENERAL) return TRUE; + + if (mr_mip->ERNUM) return FALSE; + + MR_IN(117) + + copy(mr_mip->one,mr_mip->w8); + + if (nres_moddiv(_MIPP_ mr_mip->w8,p->Z,mr_mip->w8)>1) /* 1/Z */ + { + epoint_set(_MIPP_ NULL,NULL,0,p); + mr_berror(_MIPP_ MR_ERR_COMPOSITE_MODULUS); + MR_OUT + return FALSE; + } + + nres_modmult(_MIPP_ p->X,mr_mip->w8,p->X); /* X/Z */ + nres_modmult(_MIPP_ p->Y,mr_mip->w8,p->Y); /* Y/Z */ + + copy(mr_mip->one,p->Z); + + p->marker=MR_EPOINT_NORMALIZED; + MR_OUT + + return TRUE; +} + +void ecurve_double(_MIPD_ epoint *p) +{ /* double epoint on active ecurve */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + if (p->marker==MR_EPOINT_INFINITY) + { /* 2 times infinity == infinity ! */ + return; + } + nres_modadd(_MIPP_ p->X,p->Y,mr_mip->w1); + + nres_modmult(_MIPP_ p->X,p->X,p->X); /* A=X1^2 */ + nres_modmult(_MIPP_ p->Y,p->Y,p->Y); /* B=Y1^2 */ + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w1); /* (X+Y)^2 */ + nres_modsub(_MIPP_ mr_mip->w1,p->X,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w1,p->Y,mr_mip->w1); /* E=(X+Y)^2-A-B */ + + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) /* U = aB */ + nres_modmult(_MIPP_ p->Y,mr_mip->A,p->Y); + else + nres_premult(_MIPP_ p->Y,mr_mip->Asize,p->Y); + + if (p->marker!=MR_EPOINT_NORMALIZED) + nres_modmult(_MIPP_ p->Z,p->Z,p->Z); + else + copy(mr_mip->one,p->Z); + + nres_modadd(_MIPP_ p->Z,p->Z,p->Z); + if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) /* 2dZ^2 */ + nres_modmult(_MIPP_ p->Z,mr_mip->B,p->Z); + else + nres_premult(_MIPP_ p->Z,mr_mip->Bsize,p->Z); + + nres_modadd(_MIPP_ p->X,p->Y,mr_mip->w2); /* C=A+U */ + nres_modsub(_MIPP_ p->X,p->Y,mr_mip->w3); /* D=A-U */ + + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w3,p->X); /* X=C.D */ + + nres_modsub(_MIPP_ mr_mip->w2,p->Z,mr_mip->w2); /* C-2dZ^2 */ + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w1,p->Y); /* Y=E.(C-2dZ^2) */ + nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w1,p->Z); /* Z=D.E */ + + p->marker=MR_EPOINT_GENERAL; + return; +} + +static BOOL ecurve_padd(_MIPD_ epoint *p,epoint *pa) +{ /* primitive add two epoints on the active ecurve - pa+=p; * + * note that if p is normalized, its Z coordinate isn't used */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (p->marker==MR_EPOINT_INFINITY) return TRUE; + if (pa->marker==MR_EPOINT_INFINITY) + { + epoint_copy(p,pa); + return TRUE; + } + + nres_modadd(_MIPP_ p->X,p->Y,mr_mip->w1); + nres_modadd(_MIPP_ pa->X,pa->Y,mr_mip->w2); + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); /* I=(X1+Y1)(X2+Y2) */ + if (p->marker!=MR_EPOINT_NORMALIZED) + { + if (pa->marker==MR_EPOINT_NORMALIZED) + copy(p->Z,pa->Z); + else nres_modmult(_MIPP_ p->Z,pa->Z,pa->Z); /* z = A = Z1*Z2 */ + } + else + { + if (pa->marker==MR_EPOINT_NORMALIZED) copy(mr_mip->one,pa->Z); + } + + nres_modmult(_MIPP_ pa->Z,pa->Z,mr_mip->w2); /* w2 = B = dA^2 */ + if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->B,mr_mip->w2); + else + nres_premult(_MIPP_ mr_mip->w2,mr_mip->Bsize,mr_mip->w2); + nres_modmult(_MIPP_ p->X,pa->X,pa->X); /* x = C = X1*X2 */ + nres_modmult(_MIPP_ p->Y,pa->Y,pa->Y); /* y = D = Y1*Y2 */ + nres_modmult(_MIPP_ pa->X,pa->Y,mr_mip->w3); /* w3 = E = C*D */ + + nres_modsub(_MIPP_ mr_mip->w1,pa->X,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w1,pa->Y,mr_mip->w1); /* I=(X1+Y1)(X2+Y2)-C-D =X1*Y2+Y1*X2 */ + + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) /* */ + nres_modmult(_MIPP_ pa->Y,mr_mip->A,pa->Y); + else + nres_premult(_MIPP_ pa->Y,mr_mip->Asize,pa->Y); + nres_modsub(_MIPP_ pa->X,pa->Y,pa->X); /* X = H = C-aD */ + + nres_modmult(_MIPP_ pa->Z,pa->X,pa->Z); + nres_modmult(_MIPP_ pa->Z,mr_mip->w1,pa->Z); + + nres_modsub(_MIPP_ mr_mip->w3,mr_mip->w2,pa->Y); + nres_modmult(_MIPP_ pa->Y,mr_mip->w1,pa->Y); + + nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w2,mr_mip->w3); + nres_modmult(_MIPP_ pa->X,mr_mip->w3,pa->X); + + if (size(pa->Z)==0) + { + copy(mr_mip->one,pa->X); + zero(pa->Y); + pa->marker=MR_EPOINT_INFINITY; + } + else pa->marker=MR_EPOINT_GENERAL; + + return TRUE; +} + +void epoint_copy(epoint *a,epoint *b) +{ + if (a==b || b==NULL) return; + + copy(a->X,b->X); + copy(a->Y,b->Y); + copy(a->Z,b->Z); + + b->marker=a->marker; + return; +} + +BOOL epoint_comp(_MIPD_ epoint *a,epoint *b) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + if (a==b) return TRUE; + if (a->marker==MR_EPOINT_INFINITY) + { + if (b->marker==MR_EPOINT_INFINITY) return TRUE; + else return FALSE; + } + if (b->marker==MR_EPOINT_INFINITY) + return FALSE; + + MR_IN(105) + copy(a->Z,mr_mip->w1); + copy(b->Z,mr_mip->w2); + + nres_modmult(_MIPP_ a->X,b->Z,mr_mip->w1); + nres_modmult(_MIPP_ b->X,a->Z,mr_mip->w2); + + if (mr_compare(mr_mip->w1,mr_mip->w2)!=0) + { + MR_OUT + return FALSE; + } + + nres_modmult(_MIPP_ a->Y,b->Z,mr_mip->w1); + nres_modmult(_MIPP_ b->Y,a->Z,mr_mip->w2); + + if (mr_compare(mr_mip->w1,mr_mip->w2)!=0) + { + MR_OUT + return FALSE; + } + MR_OUT + return TRUE; + +} + +int ecurve_add(_MIPD_ epoint *p,epoint *pa) +{ /* pa=pa+p; */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return MR_OVER; + + MR_IN(94) + + if (p==pa) + { + ecurve_double(_MIPP_ pa); + MR_OUT + if (pa->marker==MR_EPOINT_INFINITY) return MR_OVER; + return MR_DOUBLE; + } + if (pa->marker==MR_EPOINT_INFINITY) + { + epoint_copy(p,pa); + MR_OUT + return MR_ADD; + } + if (p->marker==MR_EPOINT_INFINITY) + { + MR_OUT + return MR_ADD; + } + + if (!ecurve_padd(_MIPP_ p,pa)) + { + ecurve_double(_MIPP_ pa); + MR_OUT + return MR_DOUBLE; + } + MR_OUT + if (pa->marker==MR_EPOINT_INFINITY) return MR_OVER; + return MR_ADD; +} + +void epoint_negate(_MIPD_ epoint *p) +{ /* negate a point */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + if (p->marker==MR_EPOINT_INFINITY) return; + + MR_IN(121) + if (size(p->X)!=0) mr_psub(_MIPP_ mr_mip->modulus,p->X,p->X); + MR_OUT +} + +int ecurve_sub(_MIPD_ epoint *p,epoint *pa) +{ + int r; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return MR_OVER; + + MR_IN(104) + + if (p==pa) + { + epoint_set(_MIPP_ NULL,NULL,0,pa); + MR_OUT + return MR_OVER; + } + if (p->marker==MR_EPOINT_INFINITY) + { + MR_OUT + return MR_ADD; + } + + epoint_negate(_MIPP_ p); + r=ecurve_add(_MIPP_ p,pa); + epoint_negate(_MIPP_ p); + + MR_OUT + return r; +} + +int ecurve_mult(_MIPD_ big e,epoint *pa,epoint *pt) +{ /* pt=e*pa; */ + int i,j,n,nb,nbs,nzs,nadds; + epoint *table[MR_ECC_STORE_N]; + +#ifdef MR_STATIC + char mem[MR_ECP_RESERVE(MR_ECC_STORE_N)]; +#else + char *mem; +#endif + +#ifndef MR_ALWAYS_BINARY + epoint *p; + int ce,ch; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(95) + if (size(e)==0) + { /* multiplied by 0 */ + epoint_set(_MIPP_ NULL,NULL,0,pt); + MR_OUT + return 0; + } + copy(e,mr_mip->w9); + epoint_copy(pa,pt); + + if (size(mr_mip->w9)<0) + { /* pt = -pt */ + negify(mr_mip->w9,mr_mip->w9); + epoint_negate(_MIPP_ pt); + } + + if (size(mr_mip->w9)==1) + { + MR_OUT + return 0; + } + + premult(_MIPP_ mr_mip->w9,3,mr_mip->w10); /* h=3*e */ + +#ifndef MR_STATIC +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif +#endif + +#ifdef MR_STATIC + memset(mem,0,MR_ECP_RESERVE(MR_ECC_STORE_N)); +#else + mem=(char *)ecp_memalloc(_MIPP_ MR_ECC_STORE_N); +#endif + + for (i=0;i<=MR_ECC_STORE_N-1;i++) + table[i]=epoint_init_mem(_MIPP_ mem,i); + + epoint_copy(pt,table[0]); + epoint_copy(table[0],table[MR_ECC_STORE_N-1]); + ecurve_double(_MIPP_ table[MR_ECC_STORE_N-1]); + + for (i=1;iw10); + nadds=0; + epoint_set(_MIPP_ NULL,NULL,0,pt); + for (i=nb-1;i>=1;) + { /* add/subtract */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + n=mr_naf_window(_MIPP_ mr_mip->w9,mr_mip->w10,i,&nbs,&nzs,MR_ECC_STORE_N); + for (j=0;j0) {ecurve_add(_MIPP_ table[n/2],pt); nadds++;} + if (n<0) {ecurve_sub(_MIPP_ table[(-n)/2],pt); nadds++;} + i-=nbs; + if (nzs) + { + for (j=0;jw10)-1,mr_mip->w11); + mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); + subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); + while (size(mr_mip->w11) > 1) + { /* add/subtract method */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + ecurve_double(_MIPP_ pt); + ce=mr_compare(mr_mip->w9,mr_mip->w11); /* e(i)=1? */ + ch=mr_compare(mr_mip->w10,mr_mip->w11); /* h(i)=1? */ + if (ch>=0) + { /* h(i)=1 */ + if (ce<0) {ecurve_add(_MIPP_ p,pt); nadds++;} + mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); + } + if (ce>=0) + { /* e(i)=1 */ + if (ch<0) {ecurve_sub(_MIPP_ p,pt); nadds++;} + mr_psub(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); + } + subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); + } + ecp_memkill(_MIPP_ mem,1); + } +#endif +#endif + MR_OUT + return nadds; +} + +#ifndef MR_NO_ECC_MULTIADD +#ifndef MR_STATIC + +void ecurve_multn(_MIPD_ int n,big *y,epoint **x,epoint *w) +{ /* pt=e[0]*p[0]+e[1]*p[1]+ .... e[n-1]*p[n-1] */ + int i,j,k,m,nb,ea; + epoint **G; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(114) + + m=1< nb) nb=k; + + epoint_set(_MIPP_ NULL,NULL,0,w); /* w=0 */ + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + for (i=nb-1;i>=0;i--) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + ea=0; + k=1; + for (j=0;jmarker==MR_EPOINT_NORMALIZED) + { + if (Q->marker==MR_EPOINT_NORMALIZED) + copy(mr_mip->one,mr_mip->w1); + else copy(Q->Z,mr_mip->w1); + } + else + { + if (Q->marker==MR_EPOINT_NORMALIZED) + copy(P->Z,mr_mip->w1); + else nres_modmult(_MIPP_ P->Z,Q->Z,mr_mip->w1); /* w1 = A = Z1*Z2 */ + } + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w2); /* w2 = B = dA^2 */ + if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->B,mr_mip->w2); + else + nres_premult(_MIPP_ mr_mip->w2,mr_mip->Bsize,mr_mip->w2); + nres_modmult(_MIPP_ P->X,Q->X,mr_mip->w3); /* w3 = C = X1*X2 */ + nres_modmult(_MIPP_ P->Y,Q->Y,mr_mip->w4); /* w4 = D = Y1*Y2 */ + nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w4,mr_mip->w5); /* w5 = E = C*D */ + nres_modmult(_MIPP_ P->X,Q->Y,mr_mip->w7); /* w7 = F = X1.Y2 */ + nres_modmult(_MIPP_ Q->X,P->Y,mr_mip->w8); /* w8 = G = X2.Y1 */ + + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) /* w4 = aD */ + nres_modmult(_MIPP_ mr_mip->w4,mr_mip->A,mr_mip->w4); + else + nres_premult(_MIPP_ mr_mip->w4,mr_mip->Asize,mr_mip->w4); + +/* P+Q */ + + nres_modsub(_MIPP_ mr_mip->w3,mr_mip->w4,mr_mip->w6); /* w6 = H = C-aD */ + nres_modadd(_MIPP_ mr_mip->w7,mr_mip->w8,PP->Z); /* X1*Y2+X2*Y1 */ + nres_modadd(_MIPP_ mr_mip->w5,mr_mip->w2,PP->X); + nres_modmult(_MIPP_ PP->X,mr_mip->w6,PP->X); + nres_modsub(_MIPP_ mr_mip->w5,mr_mip->w2,PP->Y); + nres_modmult(_MIPP_ PP->Y,PP->Z,PP->Y); + nres_modmult(_MIPP_ PP->Z,mr_mip->w6,PP->Z); + nres_modmult(_MIPP_ PP->Z,mr_mip->w1,PP->Z); + + if (size(PP->Z)==0) + { + copy(mr_mip->one,PP->X); + zero(PP->Y); + PP->marker=MR_EPOINT_INFINITY; + } + else PP->marker=MR_EPOINT_GENERAL; + +/* P-Q */ + + nres_modadd(_MIPP_ mr_mip->w3,mr_mip->w4,mr_mip->w6); /* w6 = C+aD */ + nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w7,PM->Z); /* X2*Y1-X1*Y2 */ + nres_modsub(_MIPP_ mr_mip->w5,mr_mip->w2,PM->X); + nres_modmult(_MIPP_ PM->X,mr_mip->w6,PM->X); + nres_modadd(_MIPP_ mr_mip->w5,mr_mip->w2,PM->Y); + nres_modmult(_MIPP_ PM->Y,PM->Z,PM->Y); + nres_modmult(_MIPP_ PM->Z,mr_mip->w6,PM->Z); + nres_modmult(_MIPP_ PM->Z,mr_mip->w1,PM->Z); + + if (size(PM->Z)==0) + { + copy(mr_mip->one,PM->X); + zero(PM->Y); + PM->marker=MR_EPOINT_INFINITY; + } + else PM->marker=MR_EPOINT_GENERAL; + + return TRUE; +} + +void ecurve_mult2(_MIPD_ big e,epoint *p,big ea,epoint *pa,epoint *pt) +{ /* pt=e*p+ea*pa; */ + int e1,h1,e2,h2,bb; + epoint *p1,*p2,*ps[2]; +#ifdef MR_STATIC + char mem[MR_ECP_RESERVE(4)]; +#else + char *mem; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return; + + MR_IN(103) + + if (size(e)==0) + { + ecurve_mult(_MIPP_ ea,pa,pt); + MR_OUT + return; + } +#ifdef MR_STATIC + memset(mem,0,MR_ECP_RESERVE(4)); +#else + mem=(char *)ecp_memalloc(_MIPP_ 4); +#endif + p2=epoint_init_mem(_MIPP_ mem,0); + p1=epoint_init_mem(_MIPP_ mem,1); + ps[0]=epoint_init_mem(_MIPP_ mem,2); + ps[1]=epoint_init_mem(_MIPP_ mem,3); + + epoint_copy(pa,p2); + copy(ea,mr_mip->w9); + if (size(mr_mip->w9)<0) + { /* p2 = -p2 */ + negify(mr_mip->w9,mr_mip->w9); + epoint_negate(_MIPP_ p2); + } + + epoint_copy(p,p1); + copy(e,mr_mip->w12); + if (size(mr_mip->w12)<0) + { /* p1= -p1 */ + negify(mr_mip->w12,mr_mip->w12); + epoint_negate(_MIPP_ p1); + } + + epoint_set(_MIPP_ NULL,NULL,0,pt); /* pt=0 */ + ecurve_add_sub(_MIPP_ p1,p2,ps[0],ps[1]); /* ps[0]=p1+p2, ps[1]=p1-p2 */ + + mr_jsf(_MIPP_ mr_mip->w9,mr_mip->w12,mr_mip->w10,mr_mip->w9,mr_mip->w13,mr_mip->w12); + +/* To use a simple NAF instead, substitute this for the JSF + premult(_MIPP_ mr_mip->w9,3,mr_mip->w10); 3*ea + premult(_MIPP_ mr_mip->w12,3,mr_mip->w13); 3*e +*/ + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + if (mr_compare(mr_mip->w10,mr_mip->w13)>=0) bb=logb2(_MIPP_ mr_mip->w10)-1; + else bb=logb2(_MIPP_ mr_mip->w13)-1; + + while (bb>=0) /* for the simple NAF, this should be 1 */ + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + ecurve_double(_MIPP_ pt); + + e1=h1=e2=h2=0; + if (mr_testbit(_MIPP_ mr_mip->w9,bb)) e2=1; + if (mr_testbit(_MIPP_ mr_mip->w10,bb)) h2=1; + if (mr_testbit(_MIPP_ mr_mip->w12,bb)) e1=1; + if (mr_testbit(_MIPP_ mr_mip->w13,bb)) h1=1; + + if (e1!=h1) + { + if (e2==h2) + { + if (h1==1) ecurve_add(_MIPP_ p1,pt); + else ecurve_sub(_MIPP_ p1,pt); + } + else + { + if (h1==1) + { + if (h2==1) ecurve_add(_MIPP_ ps[0],pt); + else ecurve_add(_MIPP_ ps[1],pt); + } + else + { + if (h2==1) ecurve_sub(_MIPP_ ps[1],pt); + else ecurve_sub(_MIPP_ ps[0],pt); + } + } + } + else if (e2!=h2) + { + if (h2==1) ecurve_add(_MIPP_ p2,pt); + else ecurve_sub(_MIPP_ p2,pt); + } + bb-=1; + } +#ifndef MR_ALWAYS_BINARY + } + else + { + if (mr_compare(mr_mip->w10,mr_mip->w13)>=0) + expb2(_MIPP_ logb2(_MIPP_ mr_mip->w10)-1,mr_mip->w11); + else expb2(_MIPP_ logb2(_MIPP_ mr_mip->w13)-1,mr_mip->w11); + + while (size(mr_mip->w11) > 0) /* for the NAF, this should be 1 */ + { /* add/subtract method */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + ecurve_double(_MIPP_ pt); + + e1=h1=e2=h2=0; + if (mr_compare(mr_mip->w9,mr_mip->w11)>=0) + { /* e1(i)=1? */ + e2=1; + mr_psub(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); + } + if (mr_compare(mr_mip->w10,mr_mip->w11)>=0) + { /* h1(i)=1? */ + h2=1; + mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); + } + if (mr_compare(mr_mip->w12,mr_mip->w11)>=0) + { /* e2(i)=1? */ + e1=1; + mr_psub(_MIPP_ mr_mip->w12,mr_mip->w11,mr_mip->w12); + } + if (mr_compare(mr_mip->w13,mr_mip->w11)>=0) + { /* h2(i)=1? */ + h1=1; + mr_psub(_MIPP_ mr_mip->w13,mr_mip->w11,mr_mip->w13); + } + + if (e1!=h1) + { + if (e2==h2) + { + if (h1==1) ecurve_add(_MIPP_ p1,pt); + else ecurve_sub(_MIPP_ p1,pt); + } + else + { + if (h1==1) + { + if (h2==1) ecurve_add(_MIPP_ ps[0],pt); + else ecurve_add(_MIPP_ ps[1],pt); + } + else + { + if (h2==1) ecurve_sub(_MIPP_ ps[1],pt); + else ecurve_sub(_MIPP_ ps[0],pt); + } + } + } + else if (e2!=h2) + { + if (h2==1) ecurve_add(_MIPP_ p2,pt); + else ecurve_sub(_MIPP_ p2,pt); + } + + subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); + } + } +#endif + ecp_memkill(_MIPP_ mem,4); + MR_OUT +} + +#endif + +#endif diff --git a/miracl/source/mrdouble.c b/miracl/source/mrdouble.c new file mode 100644 index 0000000..f729f43 --- /dev/null +++ b/miracl/source/mrdouble.c @@ -0,0 +1,169 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL Double to Flash conversion routines - use with care + * mrdouble.c + * + */ + +#include +#include "miracl.h" + +#ifdef MR_FLASH + +#define sign(x) ((x)<0? (-1) : 1) + +static int dquot(_MIPD_ big x,int num) +{ /* generate c.f. for a double D */ + int m; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (num==0) + { + mr_mip->oldn=(-1); + if (mr_mip->base==0) mr_mip->db=pow(2.0,(double)MIRACL); + else mr_mip->db=(double)mr_mip->base; + if (mr_mip->D<1.0) + { + mr_mip->D=(1.0/mr_mip->D); + return (mr_mip->q=0); + } + } + else if (mr_mip->q<0 || num==mr_mip->oldn) return mr_mip->q; + mr_mip->oldn=num; + if (mr_mip->D==0.0) return (mr_mip->q=(-1)); + mr_mip->D=modf(mr_mip->D,&mr_mip->n); /* n is whole number part */ + m=0; /* D is fractional part (or guard digits!) */ + zero(x); + while (mr_mip->n>0.0) + { /* convert n to big */ + m++; + if (m>mr_mip->nib) return (mr_mip->q=(-2)); + mr_mip->p=mr_mip->n/mr_mip->db; + modf(mr_mip->p,&mr_mip->p); + x->w[m-1]=(mr_small)(mr_mip->n-mr_mip->db*mr_mip->p); + mr_mip->n=mr_mip->p; + } + x->len=m; + if (mr_mip->D>0.0) mr_mip->D=(1.0/mr_mip->D); + return (mr_mip->q=size(x)); +} + +void dconv(_MIPD_ double d,flash w) +{ /* convert double to rounded flash */ + int s; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(32) + + zero(w); + if (d==0.0) + { + MR_OUT + return; + } + mr_mip->D=d; + s=sign(mr_mip->D); + mr_mip->D=mr_abs(mr_mip->D); + build(_MIPP_ w,dquot); + insign(s,w); + + MR_OUT +} + +double fdsize(_MIPD_ flash w) +{ /* express flash number as double. */ + int i,s,en,ed; + double n,d,b,BIGGEST; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM || size(w)==0) return (0.0); + + MR_IN(11) + + BIGGEST=pow(2.0,(double)(1<<(MR_EBITS-4))); + mr_mip->EXACT=FALSE; + n=0.0; + d=0.0; + if (mr_mip->base==0) b=pow(2.0,(double)MIRACL); + else b=(double)mr_mip->base; + numer(_MIPP_ w,mr_mip->w1); + s=exsign(mr_mip->w1); + insign(PLUS,mr_mip->w1); + en=(int)mr_mip->w1->len; + for (i=0;iw1->w[i]+(n/b); + denom(_MIPP_ w,mr_mip->w1); + ed=(int)mr_mip->w1->len; + for (i=0;iw1->w[i]+(d/b); + n/=d; + while (en!=ed) + { + if (en>ed) + { + ed++; + if (BIGGEST/b. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * Module to implement Comb method for fast + * computation of x*G mod n, for fixed G and n, using precomputation. + * + * Elliptic curve version of mrbrick.c + * + * This idea can be used to substantially speed up certain phases + * of the Digital Signature Standard (ECS) for example. + * + * See "Handbook of Applied Cryptography" + */ + +#include +#include "miracl.h" +#ifdef MR_STATIC +#include +#endif + +#ifndef MR_STATIC + +BOOL ebrick_init(_MIPD_ ebrick *B,big x,big y,big a,big b,big n,int window,int nb) +{ /* Uses Montgomery arithmetic internally * + * (x,y) is the fixed base * + * a,b and n are parameters and modulus of the curve * + * window is the window size in bits and * + * nb is the maximum number of bits in the multiplier */ + int i,j,k,t,bp,len,bptr,is; + epoint **table; + epoint *w; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (nb<2 || window<1 || window>nb || mr_mip->ERNUM) return FALSE; + + t=MR_ROUNDUP(nb,window); + if (t<2) return FALSE; + + MR_IN(115) + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base != mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return FALSE; + } +#endif + + B->window=window; + B->max=nb; + table=(epoint **)mr_alloc(_MIPP_ (1<a=mirvar(_MIPP_ 0); + B->b=mirvar(_MIPP_ 0); + B->n=mirvar(_MIPP_ 0); + copy(a,B->a); + copy(b,B->b); + copy(n,B->n); + + ecurve_init(_MIPP_ a,b,n,MR_BEST); + w=epoint_init(_MIPPO_ ); + epoint_set(_MIPP_ x,y,0,w); + table[0]=epoint_init(_MIPPO_ ); + table[1]=epoint_init(_MIPPO_ ); + epoint_copy(w,table[1]); + for (j=0;jlen; + bptr=0; + B->table=(mr_small *)mr_alloc(_MIPP_ 2*len*(1<table[bptr++]=table[i]->X->w[j]; + } + for (j=0;jtable[bptr++]=table[i]->Y->w[j]; + } + + epoint_free(table[i]); + } + + mr_free(table); + + MR_OUT + return TRUE; +} + +void ebrick_end(ebrick *B) +{ + mirkill(B->n); + mirkill(B->b); + mirkill(B->a); + mr_free(B->table); +} + +#else + +/* use precomputated table in ROM - see romaker.c to create the table, and ecdhp.c + for an example of use */ + +void ebrick_init(ebrick *B,const mr_small* rom,big a,big b,big n,int window,int nb) +{ + B->table=rom; + B->a=a; /* just pass a pointer */ + B->b=b; + B->n=n; + B->window=window; /* 2^4=16 stored values */ + B->max=nb; +} + +#endif + +int mul_brick(_MIPD_ ebrick *B,big e,big x,big y) +{ + int i,j,t,d,len,maxsize,promptr; + epoint *w,*z; + +#ifdef MR_STATIC + char mem[MR_ECP_RESERVE(2)]; +#else + char *mem; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (size(e)<0) mr_berror(_MIPP_ MR_ERR_NEG_POWER); + t=MR_ROUNDUP(B->max,B->window); + + MR_IN(116) + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base != mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return 0; + } +#endif + + if (logb2(_MIPP_ e) > B->max) + { + mr_berror(_MIPP_ MR_ERR_EXP_TOO_BIG); + MR_OUT + return 0; + } + + ecurve_init(_MIPP_ B->a,B->b,B->n,MR_BEST); +#ifdef MR_STATIC + memset(mem,0,MR_ECP_RESERVE(2)); +#else + mem=(char *)ecp_memalloc(_MIPP_ 2); +#endif + w=epoint_init_mem(_MIPP_ mem,0); + z=epoint_init_mem(_MIPP_ mem,1); + + len=B->n->len; + maxsize=2*(1<window)*len; + + j=recode(_MIPP_ e,t,B->window,t-1); + if (j>0) + { + promptr=2*j*len; + init_point_from_rom(w,len,B->table,maxsize,&promptr); + } + for (i=t-2;i>=0;i--) + { + j=recode(_MIPP_ e,t,B->window,i); + ecurve_double(_MIPP_ w); + if (j>0) + { + promptr=2*j*len; + init_point_from_rom(z,len,B->table,maxsize,&promptr); + ecurve_add(_MIPP_ z,w); + } + } + + d=epoint_get(_MIPP_ w,x,y); +#ifndef MR_STATIC + ecp_memkill(_MIPP_ mem,2); +#else + memset(mem,0,MR_ECP_RESERVE(2)); +#endif + MR_OUT + return d; +} diff --git a/miracl/source/mrec2m.c b/miracl/source/mrec2m.c new file mode 100644 index 0000000..c60e559 --- /dev/null +++ b/miracl/source/mrec2m.c @@ -0,0 +1,2047 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL routines for implementation of Elliptic Curve Cryptography over GF(2^m) + * mrec2m.c + * + * Curve equation is Y^2 + XY = X^3 + A.X^2 + B + * where A is 0 or 1 + * + * For algorithms used, see IEEE P1363 Standard, Appendix A + * unless otherwise stated. + * + * New from version 5.1.1 - changed from IEEE to Lopez-Dahab coordinates + * See "A note on Lopez-Dahab coordinates" - Tanja Lange (eprint archive) + * (x,y,z) = (x/z,y/(z*z),1) + * + * For supersingular curves Ordinary Projective coordinates are used. + * (x,y,z) = (x/z,y/z,1) + * + * READ COMMENTS CAREFULLY FOR VARIOUS OPTIMIZATION SUGGESTIONS + * + * No assembly language used. + * + * Space can be saved by removing unneeded functions and + * deleting unrequired functionality + */ + +#include +#include "miracl.h" +#ifdef MR_STATIC +#include +#endif + +#ifndef MR_NOFULLWIDTH + /* This does not make sense using floating-point! */ + +/* Initialise with Trinomial or Pentanomial * + * t^m + t^a + 1 OR t^m + t^a +t^b + t^c + 1 * + * Set b=0 for pentanomial. a2 is usually 0 or 1 * + * m negative indicates a super-singular curve */ + +BOOL ecurve2_init(_MIPD_ int m,int a,int b,int c,big a2,big a6,BOOL check,int type) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + +/* catch some nonsense conditions */ + + if (mr_mip->ERNUM) return FALSE; + +#ifndef MR_NOKOBLITZ + mr_mip->KOBLITZ=FALSE; +#endif + +#ifndef MR_NO_SS + mr_mip->SS=FALSE; + if (m<0) + { /* its a supersingular curve! */ + mr_mip->SS=TRUE; + /* type=MR_AFFINE; always AFFINE */ + m=-m; + if (size(a2)!=1) return FALSE; + if (size(a6) >1) return FALSE; + } +#else + if (m<0) return FALSE; +#endif + if (size(a2)<0) return FALSE; + if (size(a6)<0) return FALSE; + MR_IN(123) + + if (!prepare_basis(_MIPP_ m,a,b,c,check)) + { /* unable to set the basis */ + MR_OUT + return FALSE; + } + + mr_mip->Asize=size(a2); + mr_mip->Bsize=size(a6); + +#ifndef MR_NOKOBLITZ +#ifndef MR_NO_SS + if (!mr_mip->SS && mr_mip->Bsize==1) +#else + if (mr_mip->Bsize==1) +#endif + { + if (mr_mip->Asize==0 || mr_mip->Asize==1) + { + mr_mip->KOBLITZ=TRUE; + } + } +#endif + + if (mr_mip->Asize==MR_TOOBIG) + copy(a2,mr_mip->A); + + if (mr_mip->Bsize==MR_TOOBIG) + copy(a6,mr_mip->B); + +#ifndef MR_AFFINE_ONLY + if (type==MR_BEST) mr_mip->coord=MR_PROJECTIVE; + else mr_mip->coord=type; +#else + if (type==MR_PROJECTIVE) + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); +#endif + MR_OUT + return TRUE; +} + +BOOL epoint2_set(_MIPD_ big x,big y,int cb,epoint *p) +{ /* initialise a point on active ecurve * + * if x or y == NULL, set to point at infinity * + * if x==y, a y co-ordinate is calculated - if * + * possible - and cb suggests LSB 0/1 of y/x * + * (which "decompresses" y). Otherwise, check * + * validity of given (x,y) point, ignoring cb. * + * Returns TRUE for valid point, otherwise FALSE. */ + + BOOL valid; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(125) + + if (x==NULL || y==NULL) + { + convert(_MIPP_ 1,p->X); + convert(_MIPP_ 1,p->Y); + p->marker=MR_EPOINT_INFINITY; + MR_OUT + return TRUE; + } + + valid=FALSE; + +#ifndef MR_NO_SS + if (mr_mip->SS) + { /* Super-singular - calculate x^3+x+B */ + copy (x,p->X); + modsquare2(_MIPP_ p->X,mr_mip->w5); /* w5=x^2 */ + modmult2(_MIPP_ mr_mip->w5,p->X,mr_mip->w5); /* w5=x^3 */ + add2(mr_mip->w5,p->X,mr_mip->w5); + incr2(mr_mip->w5,mr_mip->Bsize,mr_mip->w5); /* w5=x^3+x+B */ + if (x!=y) + { /* compare with y^2+y */ + copy(y,p->Y); + modsquare2(_MIPP_ p->Y,mr_mip->w1); + add2(mr_mip->w1,p->Y,mr_mip->w1); + if (mr_compare(mr_mip->w1,mr_mip->w5)==0) valid=TRUE; + } + else + { /* no y supplied - calculate one. Solve quadratic */ + valid=quad2(_MIPP_ mr_mip->w5,mr_mip->w5); + incr2(mr_mip->w5,cb^parity2(mr_mip->w5),p->Y); + } + } + else + { /* calculate x^3+Ax^2+B */ +#endif + copy(x,p->X); + + modsquare2(_MIPP_ p->X,mr_mip->w6); /* w6=x^2 */ + modmult2(_MIPP_ mr_mip->w6,p->X,mr_mip->w5); /* w5=x^3 */ + + if (mr_mip->Asize==MR_TOOBIG) + copy(mr_mip->A,mr_mip->w1); + else + convert(_MIPP_ mr_mip->Asize,mr_mip->w1); + modmult2(_MIPP_ mr_mip->w6,mr_mip->w1,mr_mip->w0); + add2(mr_mip->w5,mr_mip->w0,mr_mip->w5); + + if (mr_mip->Bsize==MR_TOOBIG) + add2(mr_mip->w5,mr_mip->B,mr_mip->w5); /* w5=x^3+Ax^2+B */ + else + incr2(mr_mip->w5,mr_mip->Bsize,mr_mip->w5); + if (x!=y) + { /* compare with y^2+xy */ + copy(y,p->Y); + modsquare2(_MIPP_ p->Y,mr_mip->w2); + modmult2(_MIPP_ p->Y,p->X,mr_mip->w1); + add2(mr_mip->w1,mr_mip->w2,mr_mip->w1); + if (mr_compare(mr_mip->w1,mr_mip->w5)==0) valid=TRUE; + } + else + { /* no y supplied - calculate one. Solve quadratic */ + if (size(p->X)==0) + { + if (mr_mip->Bsize==MR_TOOBIG) + copy(mr_mip->B,mr_mip->w1); + else convert(_MIPP_ mr_mip->Bsize,mr_mip->w1); + + sqroot2(_MIPP_ mr_mip->w1,p->Y); + valid=TRUE; + } + else + { + inverse2(_MIPP_ mr_mip->w6,mr_mip->w6); /* 1/x^2 */ + modmult2(_MIPP_ mr_mip->w5,mr_mip->w6,mr_mip->w5); + valid=quad2(_MIPP_ mr_mip->w5,mr_mip->w5); + incr2(mr_mip->w5,cb^parity2(mr_mip->w5),mr_mip->w5); + modmult2(_MIPP_ mr_mip->w5,p->X,p->Y); + } + } +#ifndef MR_NO_SS + } +#endif + if (valid) + { + p->marker=MR_EPOINT_NORMALIZED; + MR_OUT + return TRUE; + } + MR_OUT + return FALSE; +} + +BOOL epoint2_norm(_MIPD_ epoint *p) +{ /* normalise a point */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) return TRUE; + if (p->marker!=MR_EPOINT_GENERAL) return TRUE; + + if (mr_mip->ERNUM) return FALSE; + + MR_IN(126) + + if (!inverse2(_MIPP_ p->Z,mr_mip->w8)) + { + MR_OUT + return FALSE; + } + +#ifndef MR_NO_SS + if (mr_mip->SS) + { + modmult2(_MIPP_ p->X,mr_mip->w8,p->X); + modmult2(_MIPP_ p->Y,mr_mip->w8,p->Y); + } + else + { +#endif + modmult2(_MIPP_ p->X,mr_mip->w8,p->X); /* X/Z */ + modsquare2(_MIPP_ mr_mip->w8,mr_mip->w8); /* 1/ZZ */ + modmult2(_MIPP_ p->Y,mr_mip->w8,p->Y); /* Y/ZZ */ +#ifndef MR_NO_SS + } +#endif + + convert(_MIPP_ 1,p->Z); + + p->marker=MR_EPOINT_NORMALIZED; + MR_OUT +#endif + return TRUE; +} + +#ifndef MR_STATIC + +void epoint2_getxyz(_MIPD_ epoint* p,big x,big y,big z) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + convert(_MIPP_ 1,mr_mip->w1); + if (p->marker==MR_EPOINT_INFINITY) + { +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { /* (0,0) = O */ +#endif + if (x!=NULL) zero(x); + if (y!=NULL) zero(y); +#ifndef MR_AFFINE_ONLY + } + + if (mr_mip->coord==MR_PROJECTIVE) + { /* (1,1,0) = O */ + if (x!=NULL) copy(mr_mip->w1,x); + if (y!=NULL) copy(mr_mip->w1,y); + } +#endif + if (z!=NULL) zero(z); + return; + } + if (x!=NULL) copy(p->X,x); + if (y!=NULL) copy(p->Y,y); +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { +#endif + if (z!=NULL) zero(z); +#ifndef MR_AFFINE_ONLY + } + + if (mr_mip->coord==MR_PROJECTIVE) + { + if (z!=NULL) + { + if (p->marker!=MR_EPOINT_GENERAL) copy(mr_mip->w1,z); + else copy(p->Z,z); + } + } +#endif + return; +} + +#endif + +int epoint2_get(_MIPD_ epoint* p,big x,big y) +{ /* Get point co-ordinates in affine, normal form * + * (converted from projective form). If x==y, supplies * + * x only. Return value is LSB of y/x (useful for * + * point compression) */ + int lsb; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (p->marker==MR_EPOINT_INFINITY) + { + zero(x); + zero(y); + return 0; + } + if (mr_mip->ERNUM) return 0; + + MR_IN(127) + + epoint2_norm(_MIPP_ p); + + copy(p->X,x); + copy(p->Y,mr_mip->w5); + + if (x!=y) copy(mr_mip->w5,y); + if (size(x)==0) + { + MR_OUT + return 0; + } +#ifndef MR_NO_SS + if (mr_mip->SS) + { + lsb=parity2(p->Y); + } + else + { +#endif + inverse2(_MIPP_ x,mr_mip->w5); + modmult2(_MIPP_ mr_mip->w5,p->Y,mr_mip->w5); + + lsb=parity2(mr_mip->w5); +#ifndef MR_NO_SS + } +#endif + MR_OUT + return lsb; +} + +void ecurve2_double(_MIPD_ epoint *p) +{ /* double epoint on active curve */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (p->marker==MR_EPOINT_INFINITY) + { /* 2 times infinity == infinity! */ + return; + } +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { +#endif + +#ifndef MR_NO_SS + if (mr_mip->SS) + { /* super-singular */ + modsquare2(_MIPP_ p->X,p->X); + incr2(p->X,1,mr_mip->w8); + modsquare2(_MIPP_ p->X,p->X); + modsquare2(_MIPP_ p->Y,p->Y); + modsquare2(_MIPP_ p->Y,p->Y); + add2(p->Y,p->X,p->Y); /* y=x^4+y^4 */ + incr2(p->X,1,p->X); /* x=x^4+1 */ + return; + } +#endif + if (size(p->X)==0) + { /* set to point at infinity */ + epoint2_set(_MIPP_ NULL,NULL,0,p); + return; + } + + inverse2(_MIPP_ p->X,mr_mip->w8); + + modmult2(_MIPP_ mr_mip->w8,p->Y,mr_mip->w8); + add2(mr_mip->w8,p->X,mr_mip->w8); /* w8 is slope m */ + + modsquare2(_MIPP_ mr_mip->w8,mr_mip->w6); /* w6 =m^2 */ + add2(mr_mip->w6,mr_mip->w8,mr_mip->w1); + if (mr_mip->Asize==MR_TOOBIG) + add2(mr_mip->w1,mr_mip->A,mr_mip->w1); + else + incr2(mr_mip->w1,mr_mip->Asize,mr_mip->w1); /* w1 = x3 */ + + add2(p->X,mr_mip->w1,mr_mip->w6); + modmult2(_MIPP_ mr_mip->w6,mr_mip->w8,mr_mip->w6); + copy(mr_mip->w1,p->X); + add2(mr_mip->w6,mr_mip->w1,mr_mip->w6); + add2(p->Y,mr_mip->w6,p->Y); + return; +#ifndef MR_AFFINE_ONLY + } + +#ifndef MR_NO_SS + if (mr_mip->SS) + { /* super-singular */ + + modsquare2(_MIPP_ p->X,p->X); + modsquare2(_MIPP_ p->X,p->X); + modsquare2(_MIPP_ p->Y,p->Y); + modsquare2(_MIPP_ p->Y,p->Y); + if (p->marker!=MR_EPOINT_NORMALIZED) + { + modsquare2(_MIPP_ p->Z,p->Z); + modsquare2(_MIPP_ p->Z,p->Z); /* z^4 */ + add2(p->Y,p->X,p->Y); /* y^4+x^4 */ + add2(p->X,p->Z,p->X); /* z^4+z^4 */ + } + else + { + add2(p->Y,p->X,p->Y); + incr2(p->X,1,p->X); + } + + return; + } +#endif + + if (size(p->X)==0) + { /* set to infinity */ + epoint2_set(_MIPP_ NULL,NULL,0,p); + return; + } + + modsquare2(_MIPP_ p->X,mr_mip->w1); /* S=X^2 */ + add2(p->Y,mr_mip->w1,p->Y); /* U=S+Y */ + + if (p->marker!=MR_EPOINT_NORMALIZED) + { + modmult2(_MIPP_ p->X,p->Z,mr_mip->w4); /* T=X*Z */ + modsquare2(_MIPP_ mr_mip->w4,p->Z); /* Z=T*T */ + } + else + { + copy(p->X,mr_mip->w4); + copy(mr_mip->w1,p->Z); + } + + modmult2(_MIPP_ mr_mip->w4,p->Y,mr_mip->w4); /* T=U*T */ + + modsquare2(_MIPP_ p->Y,p->Y); /* U*U */ + add2(p->Y,mr_mip->w4,p->X); /* U*U+T */ + if (mr_mip->Asize>0) /* X=U*U+T+AZ */ + { + if (mr_mip->Asize>1) + { + if (mr_mip->Asize==MR_TOOBIG) + copy(mr_mip->A,p->Y); + else + convert(_MIPP_ mr_mip->Asize,p->Y); + modmult2(_MIPP_ p->Y,p->Z,p->Y); + add2(p->X,p->Y,p->X); + } + else + add2(p->X,p->Z,p->X); + } + + add2(mr_mip->w4,p->Z,mr_mip->w4); /* Z+T */ + modmult2(_MIPP_ p->X,mr_mip->w4,p->Y); + modsquare2(_MIPP_ mr_mip->w1,mr_mip->w1); /* S*S */ + modmult2(_MIPP_ mr_mip->w1,p->Z,mr_mip->w1); + add2(p->Y,mr_mip->w1,p->Y); + + p->marker=MR_EPOINT_GENERAL; +#endif +} + +static BOOL ecurve2_padd(_MIPD_ epoint *p,epoint *pa) +{ /* primitive add two epoints on the active ecurve pa+=p * + * note that if p is normalized, its Z coordinate isn't used */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { +#endif + add2(p->Y,pa->Y,mr_mip->w8); + add2(p->X,pa->X,mr_mip->w6); + if (size(mr_mip->w6)==0) + { /* divide by zero */ + if (size(mr_mip->w8)==0) + { /* should have doubled! */ + return FALSE; + } + else + { /* point at infinity */ + epoint2_set(_MIPP_ NULL,NULL,0,pa); + return TRUE; + } + } + inverse2(_MIPP_ mr_mip->w6,mr_mip->w5); + + modmult2(_MIPP_ mr_mip->w8,mr_mip->w5,mr_mip->w8); /* w8=m */ + modsquare2(_MIPP_ mr_mip->w8,mr_mip->w5); /* m^2 */ +#ifndef MR_NO_SS + if (mr_mip->SS) + { + add2(pa->X,p->X,pa->X); + add2(pa->X,mr_mip->w5,pa->X); + + add2(pa->X,p->X,pa->Y); + modmult2(_MIPP_ pa->Y,mr_mip->w8,pa->Y); + add2(pa->Y,p->Y,pa->Y); + incr2(pa->Y,1,pa->Y); + } + else + { +#endif + add2(mr_mip->w5,mr_mip->w8,mr_mip->w5); + add2(mr_mip->w5,mr_mip->w6,mr_mip->w5); + if (mr_mip->Asize==MR_TOOBIG) + add2(mr_mip->w5,mr_mip->A,mr_mip->w5); + else + incr2(mr_mip->w5,mr_mip->Asize,mr_mip->w5); /* w5=x3 */ + + add2(pa->X,mr_mip->w5,mr_mip->w6); + modmult2(_MIPP_ mr_mip->w6,mr_mip->w8,mr_mip->w6); + copy(mr_mip->w5,pa->X); + add2(mr_mip->w6,mr_mip->w5,mr_mip->w6); + add2(pa->Y,mr_mip->w6,pa->Y); +#ifndef MR_NO_SS + } +#endif + pa->marker=MR_EPOINT_NORMALIZED; + return TRUE; +#ifndef MR_AFFINE_ONLY + } +#ifndef MR_NO_SS + if (mr_mip->SS) + { /* pa+=p */ + if (p->marker!=MR_EPOINT_NORMALIZED) + { + modmult2(_MIPP_ pa->Y,p->Z,mr_mip->w4); /* w4=y1.z2 */ + modmult2(_MIPP_ pa->X,p->Z,mr_mip->w1); /* w1=x1.z2 */ + if (pa->marker==MR_EPOINT_NORMALIZED) copy(p->Z,mr_mip->w2); + else modmult2(_MIPP_ pa->Z,p->Z,mr_mip->w2); /* w2=z1.z2 */ + } + else + { + if (pa->marker==MR_EPOINT_NORMALIZED) convert(_MIPP_ 1,mr_mip->w2); + else copy(pa->Z,mr_mip->w2); + copy(pa->Y,mr_mip->w4); + copy(pa->X,mr_mip->w1); + } + + if (pa->marker!=MR_EPOINT_NORMALIZED) + { + modmult2(_MIPP_ p->Y,pa->Z,mr_mip->w8); /* w8=y2.z1 */ + modmult2(_MIPP_ p->X,pa->Z,mr_mip->w5); /* w5=x2.z1 */ + } + else + { + copy(p->Y,mr_mip->w8); + copy(p->X,mr_mip->w5); + } + + add2(mr_mip->w4,mr_mip->w8,mr_mip->w8); /* A=y2.z1+y1.z2 */ + add2(mr_mip->w1,mr_mip->w5,mr_mip->w1); /* B=x2.z1+x1.z2 */ + + + if (size(mr_mip->w1)==0) + { + if (mr_compare(mr_mip->w2,mr_mip->w8)==0) + { /* point at infinity */ + epoint2_set(_MIPP_ NULL,NULL,0,pa); + return TRUE; + } + else return FALSE; /* should have doubled */ + } + +/* + if (size(mr_mip->w8)==0) + { + if (size(mr_mip->w1)==0) + { + return FALSE; + } + else + { + epoint2_set(_MIPP_ NULL,NULL,0,pa); + return TRUE; + } + } +*/ + + modsquare2(_MIPP_ mr_mip->w1,pa->X); /* X=B^2 */ + modmult2(_MIPP_ pa->X,mr_mip->w1,pa->Z); /* Z=B^3 */ + modmult2(_MIPP_ pa->X,mr_mip->w5,pa->Y); /* Y=x2.z1.B^2 */ + + modsquare2(_MIPP_ mr_mip->w8,mr_mip->w3); /* w3=A^2 */ + modmult2(_MIPP_ mr_mip->w3,mr_mip->w2,mr_mip->w5); /* w5=A^2.z1.z2 */ + + add2(pa->Y,mr_mip->w5,pa->Y); /* Y=x2.z1.B^2 + A^2.z1.z2 */ + modmult2(_MIPP_ pa->Y,mr_mip->w8,pa->Y); /* Y=A.Y */ + modsquare2(_MIPP_ pa->X,pa->X); /* X=B^4 */ + + modmult2(_MIPP_ mr_mip->w1,mr_mip->w5,mr_mip->w8); /* w8=B*w5 */ + add2(pa->X,mr_mip->w8,pa->X); /* X finished */ + modmult2(_MIPP_ mr_mip->w4,pa->Z,mr_mip->w1); /* B^3.y1.z2 */ + add2(pa->Y,mr_mip->w1,pa->Y); + modmult2(_MIPP_ pa->Z,mr_mip->w2,pa->Z); + add2(pa->Y,pa->Z,pa->Y); + + pa->marker=MR_EPOINT_GENERAL; + return TRUE; + } +#endif + + if (p->marker!=MR_EPOINT_NORMALIZED) + { + if (pa->marker!=MR_EPOINT_NORMALIZED) + modmult2(_MIPP_ p->X,pa->Z,mr_mip->w1); /* A1=x1.z2 =w1 */ + else + copy(p->X,mr_mip->w1); + + modmult2(_MIPP_ pa->X,p->Z,pa->X); /* A2=x2.z1 =X3 */ + add2(mr_mip->w1,pa->X,mr_mip->w2); /* C= A1+A2 =w2 */ + + modsquare2(_MIPP_ mr_mip->w1,mr_mip->w3); /* B1=A1*A1 =w3 */ + modsquare2(_MIPP_ pa->X,mr_mip->w4); /* B2=A2*A2 =w4 */ + add2(mr_mip->w3,mr_mip->w4,mr_mip->w5); /* D=B1+B2 =w5 */ + + if (pa->marker!=MR_EPOINT_NORMALIZED) + { + modsquare2(_MIPP_ pa->Z,mr_mip->w6); + modmult2(_MIPP_ mr_mip->w6,p->Y,mr_mip->w6); /* E1=y1.z2^2 = w6 */ + } + else + copy(p->Y,mr_mip->w6); + + modsquare2(_MIPP_ p->Z,mr_mip->w8); + modmult2(_MIPP_ mr_mip->w8,pa->Y,mr_mip->w8); /* E2=y2.z1^2 = w8 */ + + add2(mr_mip->w3,mr_mip->w6,mr_mip->w3); /* E1+B1 = w3 */ + add2(mr_mip->w4,mr_mip->w8,mr_mip->w4); /* E2+B2 = w4 */ + + add2(mr_mip->w8,mr_mip->w6,mr_mip->w8); /* F=E1+E2 */ + + if (size(mr_mip->w2)==0) + { + if (size(mr_mip->w8)==0) + { /* should have doubled */ + return FALSE; + } + else + { + epoint2_set(_MIPP_ NULL,NULL,0,pa); + return TRUE; + } + } + + modmult2(_MIPP_ mr_mip->w8,mr_mip->w2,mr_mip->w8); /* G=CF */ + if (pa->marker!=MR_EPOINT_NORMALIZED) + modmult2(_MIPP_ pa->Z,p->Z,pa->Z); + else + copy(p->Z,pa->Z); + + modmult2(_MIPP_ pa->Z,mr_mip->w5,pa->Z); /* Z3=z1.z2.D */ + + modmult2(_MIPP_ mr_mip->w1,mr_mip->w4,mr_mip->w2); + modmult2(_MIPP_ pa->X,mr_mip->w3,pa->X); + add2(pa->X,mr_mip->w2,pa->X); /* x3 = A1(E2+B2)+A2(E1+B1) */ + + modmult2(_MIPP_ mr_mip->w1,mr_mip->w8,mr_mip->w1); /* A1*G */ + modmult2(_MIPP_ mr_mip->w6,mr_mip->w5,mr_mip->w6); /* E1*D */ + add2(mr_mip->w1,mr_mip->w6,pa->Y); + modmult2(_MIPP_ pa->Y,mr_mip->w5,pa->Y); + add2(mr_mip->w8,pa->Z,mr_mip->w8); + modmult2(_MIPP_ mr_mip->w8,pa->X,mr_mip->w8); + add2(pa->Y,mr_mip->w8,pa->Y); + } + else + { + if (pa->marker!=MR_EPOINT_NORMALIZED) + { + modsquare2(_MIPP_ pa->Z,mr_mip->w1); + modmult2(_MIPP_ mr_mip->w1,p->Y,mr_mip->w1); + add2(mr_mip->w1,pa->Y,mr_mip->w1); /* U=z2^2.y1 + y2 */ + modmult2(_MIPP_ pa->Z,p->X,mr_mip->w2); + add2(mr_mip->w2,pa->X,mr_mip->w2); /* S=z2x1+x2 */ + } + else + { + add2(p->Y,pa->Y,mr_mip->w1); + add2(p->X,pa->X,mr_mip->w2); + } + + if (size(mr_mip->w2)==0) + { + if (size(mr_mip->w1)==0) + { /* should have doubled! */ + return FALSE; + } + else + { + epoint2_set(_MIPP_ NULL,NULL,0,pa); + return TRUE; + } + } + + if (pa->marker!=MR_EPOINT_NORMALIZED) + modmult2(_MIPP_ pa->Z,mr_mip->w2,mr_mip->w3); /* T=z2.S */ + else + copy(mr_mip->w2,mr_mip->w3); + + modsquare2(_MIPP_ mr_mip->w3,pa->Z); /* z3=T^2 */ + + modmult2(_MIPP_ pa->Z,p->X,mr_mip->w4); /* V=z3.x1 */ + add2(p->X,p->Y,mr_mip->w5); /* C=x1+y1 */ + modsquare2(_MIPP_ mr_mip->w1,pa->X); + modsquare2(_MIPP_ mr_mip->w2,mr_mip->w2); /* S^2 */ + add2(mr_mip->w2,mr_mip->w1,mr_mip->w2); + if (mr_mip->Asize>0) /* T(U+S^2+BT) */ + { + if (mr_mip->Asize>1) + { + if (mr_mip->Asize==MR_TOOBIG) + copy(mr_mip->A,mr_mip->w6); + else + convert(_MIPP_ mr_mip->Asize,mr_mip->w6); + modmult2(_MIPP_ mr_mip->w6,mr_mip->w3,mr_mip->w6); + add2(mr_mip->w2,mr_mip->w6,mr_mip->w2); + } + else + add2(mr_mip->w2,mr_mip->w3,mr_mip->w2); + } + modmult2(_MIPP_ mr_mip->w2,mr_mip->w3,mr_mip->w2); + add2(pa->X,mr_mip->w2,pa->X); + + add2(mr_mip->w4,pa->X,mr_mip->w4); /* V+X */ + modmult2(_MIPP_ mr_mip->w3,mr_mip->w1,mr_mip->w3); /* T*U */ + add2(pa->Z,mr_mip->w3,pa->Y); /* Z3+T*U */ + modmult2(_MIPP_ pa->Y,mr_mip->w4,pa->Y); + modsquare2(_MIPP_ pa->Z,mr_mip->w1); + modmult2(_MIPP_ mr_mip->w1,mr_mip->w5,mr_mip->w1); /*z3^2.C */ + add2(pa->Y,mr_mip->w1,pa->Y); + } + + pa->marker=MR_EPOINT_GENERAL; + return TRUE; +#endif +} + +void epoint2_copy(epoint *a,epoint *b) +{ + if (a==b) return; + copy(a->X,b->X); + copy(a->Y,b->Y); + +#ifndef MR_AFFINE_ONLY + if (a->marker==MR_EPOINT_GENERAL) copy(a->Z,b->Z); +#endif + b->marker=a->marker; + return; +} + +BOOL epoint2_comp(_MIPD_ epoint *a,epoint *b) +{ + int ia,ib; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + if (a==b) return TRUE; + + if (a->marker==MR_EPOINT_INFINITY) + { + if (b->marker==MR_EPOINT_INFINITY) return TRUE; + else return FALSE; + } + if (b->marker==MR_EPOINT_INFINITY) + return FALSE; + + MR_IN(128) + + ia=epoint2_get(_MIPP_ a,mr_mip->w9,mr_mip->w9); + ib=epoint2_get(_MIPP_ b,mr_mip->w10,mr_mip->w10); + + MR_OUT + if (ia==ib && mr_compare(mr_mip->w9,mr_mip->w10)==0) return TRUE; + return FALSE; +} + +big ecurve2_add(_MIPD_ epoint *p,epoint *pa) +{ /* pa=pa+p; */ + /* An ephemeral pointer to the line slope is returned * + * only if curve is super-singular */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return NULL; + + MR_IN(129) + + if (p==pa) + { + ecurve2_double(_MIPP_ pa); + MR_OUT + return mr_mip->w8; + } + if (pa->marker==MR_EPOINT_INFINITY) + { + epoint2_copy(p,pa); + MR_OUT + return NULL; + } + if (p->marker==MR_EPOINT_INFINITY) + { + MR_OUT + return NULL; + } + if (!ecurve2_padd(_MIPP_ p,pa)) ecurve2_double(_MIPP_ pa); + MR_OUT + return mr_mip->w8; +} + +void epoint2_negate(_MIPD_ epoint *p) +{ /* negate a point */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + if (p->marker==MR_EPOINT_INFINITY) return; + MR_IN(130) +#ifndef MR_AFFINE_ONLY + if (p->marker==MR_EPOINT_GENERAL) + { +#ifndef MR_NO_SS + if (mr_mip->SS) + { + add2(p->Y,p->Z,p->Y); + } + else + { +#endif + modmult2(_MIPP_ p->X,p->Z,mr_mip->w1); + add2(p->Y,mr_mip->w1,p->Y); +#ifndef MR_NO_SS + } +#endif + } + else + { +#endif +#ifndef MR_NO_SS + if (mr_mip->SS) incr2(p->Y,1,p->Y); + else +#endif + add2(p->Y,p->X,p->Y); +#ifndef MR_AFFINE_ONLY + } +#endif + MR_OUT +} + +big ecurve2_sub(_MIPD_ epoint *p,epoint *pa) +{ + big r; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return NULL; + + MR_IN(131) + + if (p==pa) + { + epoint2_set(_MIPP_ NULL,NULL,0,pa); + MR_OUT + return NULL; + } + if (p->marker==MR_EPOINT_INFINITY) + { + MR_OUT + return NULL; + } + + epoint2_negate(_MIPP_ p); + r=ecurve2_add(_MIPP_ p,pa); + epoint2_negate(_MIPP_ p); + + MR_OUT + return r; +} + +#ifndef MR_NO_ECC_MULTIADD +#ifndef MR_STATIC + +void ecurve2_multi_add(_MIPD_ int m,epoint **x,epoint **w) +{ /* adds m points together simultaneously, w[i]+=x[i] */ + int i,*flag; + big *A,*B,*C; + char *mem; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(132) +#ifndef MR_NO_SS + if (mr_mip->SS) + { + for (i=0;icoord==MR_AFFINE) + { +#endif + A=(big *)mr_alloc(_MIPP_ m,sizeof(big)); + B=(big *)mr_alloc(_MIPP_ m,sizeof(big)); + C=(big *)mr_alloc(_MIPP_ m,sizeof(big)); + flag=(int *)mr_alloc(_MIPP_ m,sizeof(int)); + + convert(_MIPP_ 1,mr_mip->w3); /* unity */ + mem=(char *)memalloc(_MIPP_ 3*m); + + for (i=0;iX,w[i]->X)==0 && mr_compare(x[i]->Y,w[i]->Y)==0) + { /* doubling */ + if (x[i]->marker==MR_EPOINT_INFINITY || size(x[i]->Y)==0) + { + flag[i]=1; /* result is infinity */ + copy(mr_mip->w3,B[i]); + continue; + } + modsquare2(_MIPP_ x[i]->X,A[i]); + add2(A[i],x[i]->Y,A[i]); + copy(x[i]->X,B[i]); + } + else + { + if (x[i]->marker==MR_EPOINT_INFINITY) + { + flag[i]=2; /* w[i] unchanged */ + copy(mr_mip->w3,B[i]); + continue; + } + if (w[i]->marker==MR_EPOINT_INFINITY) + { + flag[i]=3; /* w[i]=x[i] */ + copy(mr_mip->w3,B[i]); + continue; + } + add2(x[i]->X,w[i]->X,B[i]); + if (size(B[i])==0) + { /* point at infinity */ + flag[i]=1; /* result is infinity */ + copy(mr_mip->w3,B[i]); + continue; + } + add2(x[i]->Y,w[i]->Y,A[i]); + } + } + + multi_inverse2(_MIPP_ m,B,C); /* one inversion only */ + for (i=0;iw8); + modsquare2(_MIPP_ mr_mip->w8,mr_mip->w6); /* m^2 */ + add2(mr_mip->w6,mr_mip->w8,mr_mip->w6); + add2(mr_mip->w6,x[i]->X,mr_mip->w6); + add2(mr_mip->w6,w[i]->X,mr_mip->w6); + if (mr_mip->Asize==MR_TOOBIG) + add2(mr_mip->w6,mr_mip->A,mr_mip->w6); + else + incr2(mr_mip->w6,mr_mip->Asize,mr_mip->w6); + + add2(w[i]->X,mr_mip->w6,mr_mip->w2); + modmult2(_MIPP_ mr_mip->w2,mr_mip->w8,mr_mip->w2); + add2(mr_mip->w2,mr_mip->w6,mr_mip->w2); + add2(mr_mip->w2,w[i]->Y,w[i]->Y); + copy(mr_mip->w6,w[i]->X); + + w[i]->marker=MR_EPOINT_NORMALIZED; + + } + memkill(_MIPP_ mem,3*m); + mr_free(flag); + mr_free(C); mr_free(B); mr_free(A); +#ifndef MR_AFFINE_ONLY + } + else + { /* no speed-up for projective coordinates */ + for (i=0;imarker==MR_EPOINT_INFINITY) return; + + modsquare2(_MIPP_ P->X,P->X); + modsquare2(_MIPP_ P->Y,P->Y); +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_PROJECTIVE && P->marker==MR_EPOINT_GENERAL) modsquare2(_MIPP_ P->Z,P->Z); +#endif +} + +/* creates a tnaf from a+tau.b into tm[.] */ + +static int itnaf(int mu,int a,int b,signed char *tm) +{ + int u,t,len=0; + int r0=a; + int r1=b; + + while (r0!=0 || r1!=0) + { + if ((r0%2)!=0) + { + t=(r0-2*r1)%4; if (t<0) t+=4; + u=2-t; + r0-=u; + } + else u=0; + tm[len++]=u; + t=r0; + if (mu==1) r0=r1+r0/2; + else r0=r1-r0/2; + r1=-t/2; + } + return len; +} + +/* Here we use the post-processing algorithm of Lutz and Hasan */ +/* rather than the more well known Solinas method - see */ +/* http://vlsi.uwaterloo.ca/~ahasan/web_papers/technical_reports/web_Hi_Per_ECC.pdf */ + +static int tnaf(_MIPD_ big e,big hp,big hn) +{ + int n,u,t,i,j,len,mu,count; + signed char tm[8]; + BOOL wrapped=FALSE; + int m,a; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + +#ifdef MR_STATIC + signed char tn[MIRACL*MR_STATIC+8]; +#else + signed char *tn=(signed char *)mr_alloc(_MIPP_ mr_mip->M+8,1); +#endif + + m=mr_mip->M; + a=mr_mip->Asize; + + if (a==0) mu=-1; + else mu=1; + + copy(e,mr_mip->w1); + zero(mr_mip->w2); + for (i=0;iw1)!=0 || size(mr_mip->w2)!=0) + { + if (remain(_MIPP_ mr_mip->w1,2)!=0) + { + premult(_MIPP_ mr_mip->w2,2,mr_mip->w3); + subtract(_MIPP_ mr_mip->w1,mr_mip->w3,mr_mip->w3); + t=remain(_MIPP_ mr_mip->w3,4); if (t<0) t+=4; + u=2-t; + decr(_MIPP_ mr_mip->w1,u,mr_mip->w1); + tn[i]+=u; + } + + subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w3); + if (mu>0) add(_MIPP_ mr_mip->w2,mr_mip->w3,mr_mip->w1); + else subtract(_MIPP_ mr_mip->w2,mr_mip->w3,mr_mip->w1); + negify(mr_mip->w3,mr_mip->w2); + i++; + if (i==m) + { + i=0; + wrapped=TRUE; + } + } + len=i; + count=0; + if (wrapped) forever + { + len=m; + + for (i=0;i=len) len=i+n; + i++; + } + count++; + if (count<3 && len>m) + { + for (i=m;iw3); + add(_MIPP_ hp,mr_mip->w3,hp); + } + if (tn[i]==-1) + { + expb2(_MIPP_ i,mr_mip->w3); + add(_MIPP_ hn,mr_mip->w3,hn); + } + tn[i]=0; + } + for (i=0;i<8;i++) tm[i]=0; +#ifndef MR_STATIC + mr_free(tn); +#endif + return len; +} + +#endif + +BOOL epoint2_multi_norm(_MIPD_ int m,big *work,epoint **p) +{ /* Normalise an array of points of length m<20 - requires a workspace array of length m */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + +#ifndef MR_AFFINE_ONLY + int i; + big w[MR_MAX_M_T_S]; + if (mr_mip->coord==MR_AFFINE) return TRUE; + if (mr_mip->ERNUM) return FALSE; + if (m>MR_MAX_M_T_S) return FALSE; + + MR_IN(192) + + for (i=0;imarker==MR_EPOINT_NORMALIZED) w[i]=mr_mip->one; + else w[i]=p[i]->Z; + + } + + if (!multi_inverse2(_MIPP_ m,w,work)) + { + MR_OUT + return FALSE; + } + + for (i=0;ione,p[i]->Z); + p[i]->marker=MR_EPOINT_NORMALIZED; +#ifndef MR_NO_SS + if (mr_mip->SS) + { + modmult2(_MIPP_ p[i]->X,work[i],p[i]->X); + modmult2(_MIPP_ p[i]->Y,work[i],p[i]->Y); + } + else + { +#endif + modmult2(_MIPP_ p[i]->X,work[i],p[i]->X); /* X/Z */ + modmult2(_MIPP_ work[i],work[i],mr_mip->w1); + modmult2(_MIPP_ p[i]->Y,mr_mip->w1,p[i]->Y); /* Y/ZZ */ +#ifndef MR_NO_SS + } +#endif + + } + MR_OUT +#endif + return TRUE; +} + +static void table_init(_MIPD_ epoint *g,epoint **table) +{ /* A precomputation option for the multiplication of a */ + /* fixed point, would be to precalculate and normalize */ + /* this table */ + int i,n,n3,nf,nb,t; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + +#ifndef MR_NOKOBLITZ + + if (mr_mip->KOBLITZ) + { + epoint2_copy(g,table[0]); + epoint2_copy(g,table[MR_ECC_STORE_2M-1]); + frobenius(_MIPP_ table[MR_ECC_STORE_2M-1]); + frobenius(_MIPP_ table[MR_ECC_STORE_2M-1]); + nf=2; + + for (i=1;i1) + { /* number of bits in n3 */ + t>>=1; + nb++; + } + while (nb>nf) + { /* move to next power of tau */ + frobenius(_MIPP_ table[MR_ECC_STORE_2M-1]); + nf++; + } + + n3-=(1<0) ecurve2_add(_MIPP_ table[n/2],table[i]); + else ecurve2_sub(_MIPP_ table[(-n)/2],table[i]); + } + else + { /* mostly mixed additions... */ + + if (n>0) epoint2_copy(table[n/2],table[i]); + if (n<0) + { + epoint2_copy(table[(-n)/2],table[i]); + epoint2_negate(_MIPP_ table[i]); + } + + ecurve2_add(_MIPP_ table[MR_ECC_STORE_2M-1],table[i]); + } + } + } + else + { +#endif + + epoint2_copy(g,table[0]); + epoint2_copy(g,table[MR_ECC_STORE_2M-1]); + ecurve2_double(_MIPP_ table[MR_ECC_STORE_2M-1]); + + /* epoint2_norm(_MIPP_ table[MR_ECC_STORE_2M-1]); makes additions below faster */ + for (i=1;iKOBLITZ) + { + tnaf(_MIPP_ e,hp,hn); + } + else + { +#endif + copy(e,hn); + premult(_MIPP_ hn,3,hp); + subdiv(_MIPP_ hn,2,hn); + subdiv(_MIPP_ hp,2,hp); +#ifndef MR_NOKOBLITZ + } +#endif +} + +void ecurve2_mult(_MIPD_ big e,epoint *pa,epoint *pt) +{ /* pt=e*pa; */ + int i,j,n,nb,nbs,nzs; +#ifndef MR_AFFINE_ONLY +/* int coord; */ + big work[MR_ECC_STORE_2M]; +#endif + epoint *table[MR_ECC_STORE_2M]; +#ifdef MR_STATIC + char mem[MR_ECP_RESERVE(MR_ECC_STORE_2M)]; + /* char mem[MR_ECP_RESERVE_A(MR_ECC_STORE_2M)]; Reserve space for AFFINE (x,y) only */ +#ifndef MR_AFFINE_ONLY + char mem1[MR_BIG_RESERVE(MR_ECC_STORE_2M)]; +#endif +#else + char *mem; +#ifndef MR_AFFINE_ONLY + char *mem1; +#endif +#endif +#ifndef MR_ALWAYS_BINARY + epoint *p; + int ch,ce; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(133) + + if (size(e)==0) + { /* multiplied by 0 */ + epoint2_set(_MIPP_ NULL,NULL,0,pt); + MR_OUT + return; + } + epoint2_norm(_MIPP_ pa); + epoint2_copy(pa,pt); + + copy(e,mr_mip->w9); + + if (size(mr_mip->w9)<0) + { /* pt = -pt */ + negify(mr_mip->w9,mr_mip->w9); + epoint2_negate(_MIPP_ pt); + } + + if (size(mr_mip->w9)==1) + { + MR_OUT + return; + } + + prepare_naf(_MIPP_ mr_mip->w9,mr_mip->w10,mr_mip->w9); + + if (size(mr_mip->w9)==0 && size(mr_mip->w10)==0) + { /* multiplied by 0 */ + epoint2_set(_MIPP_ NULL,NULL,0,pt); + MR_OUT + return; + } + +#ifndef MR_STATIC +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif +#endif + +#ifdef MR_STATIC + memset(mem,0,MR_ECP_RESERVE(MR_ECC_STORE_2M)); + /* memset(mem,0,MR_ECP_RESERVE_A(MR_ECC_STORE_2M)); */ +#ifndef MR_AFFINE_ONLY + memset(mem1,0,MR_BIG_RESERVE(MR_ECC_STORE_2M)); +#endif +#else + mem=(char *)ecp_memalloc(_MIPP_ MR_ECC_STORE_2M); +#ifndef MR_AFFINE_ONLY + mem1=(char *)memalloc(_MIPP_ MR_ECC_STORE_2M); +#endif +#endif + + for (i=0;i<=MR_ECC_STORE_2M-1;i++) + { + table[i]=epoint_init_mem(_MIPP_ mem,i); +#ifndef MR_AFFINE_ONLY + work[i]=mirvar_mem(_MIPP_ mem1,i); +#endif + } + + table_init(_MIPP_ pt,table); + +#ifndef MR_AFFINE_ONLY + epoint2_multi_norm(_MIPP_ MR_ECC_STORE_2M,work,table); +#endif + + nb=logb2(_MIPP_ mr_mip->w10); + + if ((n=logb2(_MIPP_ mr_mip->w9))>nb) + { + nb=n; + epoint2_negate(_MIPP_ pt); + } + epoint2_set(_MIPP_ NULL,NULL,0,pt); + + for (i=nb-1;i>=0;) + { /* add/subtract */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + n=mr_naf_window(_MIPP_ mr_mip->w9,mr_mip->w10,i,&nbs,&nzs,MR_ECC_STORE_2M); +/* printf("n= %d nbs= %d nzs= %d \n",n,nbs,nzs); */ + for (j=0;jKOBLITZ) frobenius(_MIPP_ pt); + else +#endif + ecurve2_double(_MIPP_ pt); + } + if (n>0) + ecurve2_add(_MIPP_ table[n/2],pt); + if (n<0) + ecurve2_sub(_MIPP_ table[(-n)/2],pt); + i-=nbs; + if (nzs) + { + for (j=0;jKOBLITZ) frobenius(_MIPP_ pt); + else +#endif + ecurve2_double(_MIPP_ pt); + } + i-=nzs; + } + } +/* +#ifndef MR_AFFINE_ONLY + coord=mr_mip->coord; switch to AFFINE coordinates + mr_mip->coord=MR_AFFINE; +#endif +*/ +#ifdef MR_STATIC +/* memset(mem,0,MR_ECP_RESERVE_A(MR_ECC_STORE_2M)); */ + memset(mem,0,MR_ECP_RESERVE(MR_ECC_STORE_2M)); +#else + ecp_memkill(_MIPP_ mem,MR_ECC_STORE_2M); +#endif + +#ifndef MR_AFFINE_ONLY + memkill(_MIPP_ mem1,MR_ECC_STORE_2M); +/* mr_mip->coord=coord; */ +#endif + +#ifndef MR_STATIC +#ifndef MR_ALWAYS_BINARY + } + else + { + mem=(char *)ecp_memalloc(_MIPP_ 1); + p=epoint_init_mem(_MIPP_ mem,0); + epoint2_copy(pt,p); + + expb2(_MIPP_ logb2(_MIPP_ mr_mip->w10)-1,mr_mip->w11); + mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); + subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); + while (size(mr_mip->w11) > 0) + { /* add/subtract method */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + ecurve2_double(_MIPP_ pt); + ce=mr_compare(mr_mip->w9,mr_mip->w11); /* e(i)=1? */ + ch=mr_compare(mr_mip->w10,mr_mip->w11); /* h(i)=1? */ + if (ch>=0) + { /* h(i)=1 */ + if (ce<0) ecurve2_add(_MIPP_ p,pt); + mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); + } + if (ce>=0) + { /* e(i)=1 */ + if (ch<0) ecurve2_sub(_MIPP_ p,pt); + mr_psub(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); + } + subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); + } + ecp_memkill(_MIPP_ mem,1); + } +#endif +#endif + epoint2_norm(_MIPP_ pt); + MR_OUT +} + +#ifndef MR_NO_ECC_MULTIADD +#ifndef MR_STATIC + +void ecurve2_multn(_MIPD_ int n,big *y,epoint **x,epoint *w) +{ /* pt=e[o]*p[0]+e[1]*p[1]+ .... e[n-1]*p[n-1] */ + int i,j,k,m,nb,ea; + epoint **G; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(134) + + m=1< nb) nb=k; + + epoint2_set(_MIPP_ NULL,NULL,0,w); /* w=0 */ + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + for (i=nb-1;i>=0;i--) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + ea=0; + k=1; + for (j=0;jw14; + work[1]=mr_mip->w15; +#endif + if (mr_mip->ERNUM) return; + + MR_IN(135) + + if (size(e)==0) + { + ecurve2_mult(_MIPP_ ea,pa,pt); + MR_OUT + return; + } +#ifdef MR_STATIC + memset(mem,0,MR_ECP_RESERVE(4)); +#else + mem=(char *)ecp_memalloc(_MIPP_ 4); +#endif + p2=epoint_init_mem(_MIPP_ mem,0); + p1=epoint_init_mem(_MIPP_ mem,1); + ps[0]=epoint_init_mem(_MIPP_ mem,2); + ps[1]=epoint_init_mem(_MIPP_ mem,3); + + epoint2_norm(_MIPP_ pa); + epoint2_copy(pa,p2); + copy(ea,mr_mip->w9); + if (size(mr_mip->w9)<0) + { /* p2 = -p2 */ + negify(mr_mip->w9,mr_mip->w9); + epoint2_negate(_MIPP_ p2); + } + + epoint2_norm(_MIPP_ p); + epoint2_copy(p,p1); + copy(e,mr_mip->w12); + if (size(mr_mip->w12)<0) + { /* p1= -p1 */ + negify(mr_mip->w12,mr_mip->w12); + epoint2_negate(_MIPP_ p1); + } + +#ifdef MR_NOKOBLITZ + mr_jsf(_MIPP_ mr_mip->w9,mr_mip->w12,mr_mip->w10,mr_mip->w9,mr_mip->w13,mr_mip->w12); +#else + if (mr_mip->KOBLITZ) + { + prepare_naf(_MIPP_ mr_mip->w9,mr_mip->w10,mr_mip->w9); + prepare_naf(_MIPP_ mr_mip->w12,mr_mip->w13,mr_mip->w12); + } + else + mr_jsf(_MIPP_ mr_mip->w9,mr_mip->w12,mr_mip->w10,mr_mip->w9,mr_mip->w13,mr_mip->w12); +#endif + + nb=logb2(_MIPP_ mr_mip->w10); + if ((n=logb2(_MIPP_ mr_mip->w13))>nb) nb=n; + if ((n=logb2(_MIPP_ mr_mip->w9))>nb) nb=n; + if ((n=logb2(_MIPP_ mr_mip->w12))>nb) nb=n; + + epoint2_set(_MIPP_ NULL,NULL,0,pt); /* pt=0 */ + + expb2(_MIPP_ nb-1,mr_mip->w11); + + epoint2_copy(p1,ps[0]); + ecurve2_add(_MIPP_ p2,ps[0]); /* ps=p1+p2 */ + epoint2_copy(p1,ps[1]); + ecurve2_sub(_MIPP_ p2,ps[1]); /* pd=p1-p2 */ + +#ifndef MR_AFFINE_ONLY + epoint2_multi_norm(_MIPP_ 2,work,ps); +#endif + while (size(mr_mip->w11) > 0) + { /* add/subtract method */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); +#ifndef MR_NOKOBLITZ + if (mr_mip->KOBLITZ) frobenius(_MIPP_ pt); + else +#endif + ecurve2_double(_MIPP_ pt); + + e1=h1=e2=h2=0; + if (mr_compare(mr_mip->w9,mr_mip->w11)>=0) + { /* e1(i)=1? */ + e2=1; + mr_psub(_MIPP_ mr_mip->w9,mr_mip->w11,mr_mip->w9); + } + if (mr_compare(mr_mip->w10,mr_mip->w11)>=0) + { /* h1(i)=1? */ + h2=1; + mr_psub(_MIPP_ mr_mip->w10,mr_mip->w11,mr_mip->w10); + } + if (mr_compare(mr_mip->w12,mr_mip->w11)>=0) + { /* e2(i)=1? */ + e1=1; + mr_psub(_MIPP_ mr_mip->w12,mr_mip->w11,mr_mip->w12); + } + if (mr_compare(mr_mip->w13,mr_mip->w11)>=0) + { /* h2(i)=1? */ + h1=1; + mr_psub(_MIPP_ mr_mip->w13,mr_mip->w11,mr_mip->w13); + } + + if (e1!=h1) + { + if (e2==h2) + { + if (h1==1) ecurve2_add(_MIPP_ p1,pt); + else ecurve2_sub(_MIPP_ p1,pt); + } + else + { + if (h1==1) + { + if (h2==1) ecurve2_add(_MIPP_ ps[0],pt); + else ecurve2_add(_MIPP_ ps[1],pt); + } + else + { + if (h2==1) ecurve2_sub(_MIPP_ ps[1],pt); + else ecurve2_sub(_MIPP_ ps[0],pt); + } + } + } + else if (e2!=h2) + { + if (h2==1) ecurve2_add(_MIPP_ p2,pt); + else ecurve2_sub(_MIPP_ p2,pt); + } + + subdiv(_MIPP_ mr_mip->w11,2,mr_mip->w11); + } + ecp_memkill(_MIPP_ mem,4); + + MR_OUT +} + +#endif + +/* Routines to implement comb method for fast + * computation of x*G mod n, for fixed G and n, using precomputation. + * + * Elliptic curve over GF(2^m) version of mrebrick.c + * + * This idea can be used to substantially speed up certain phases + * of the Elliptic Curve Digital Signature Standard (ECS) for example. + * + * See "Handbook of Applied Cryptography" + */ + +#ifndef MR_STATIC + +BOOL ebrick2_init(_MIPD_ ebrick2 *B,big x,big y,big a2,big a6,int m,int a,int b,int c,int window,int nb) +{ /* (x,y) is the fixed base * + * a2 and a6 the parameters of the curve * + * m, a, b, c are the m in the 2^m modulus, and a,b,c * + * are the parameters of the irreducible bases, * + * trinomial if b!=0, otherwise pentanomial * + * window is the window size in bits and * + * nb is the maximum number of bits in the multiplier */ + + int i,j,k,t,bp,len,bptr,is; + epoint **table; + epoint *w; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (nb<2 || window<1 || window>nb || mr_mip->ERNUM) return FALSE; + + t=MR_ROUNDUP(nb,window); + if (t<2) return FALSE; + + MR_IN(136) + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base != mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return FALSE; + } +#endif + + B->window=window; + B->max=nb; + table=(epoint **)mr_alloc(_MIPP_ (1<a6=mirvar(_MIPP_ 0); + copy(a6,B->a6); + B->a2=mirvar(_MIPP_ 0); + copy(a2,B->a2); + B->m=m; + B->a=a; + B->b=b; + B->c=c; + + if (!ecurve2_init(_MIPP_ m,a,b,c,a2,a6,TRUE,MR_AFFINE)) + { + MR_OUT + return FALSE; + } + + if (m<0) m=-m; /* if it is supersingular */ + + w=epoint_init(_MIPPO_ ); + epoint2_set(_MIPP_ x,y,0,w); + + table[0]=epoint_init(_MIPPO_ ); + table[1]=epoint_init(_MIPPO_ ); + epoint2_copy(w,table[1]); + for (j=0;jtable=(mr_small *)mr_alloc(_MIPP_ 2*len*(1<table[bptr++]=table[i]->X->w[j]; + for (j=0;jtable[bptr++]=table[i]->Y->w[j]; + + epoint_free(table[i]); + } + + mr_free(table); + + MR_OUT + return TRUE; +} + +void ebrick2_end(ebrick2 *B) +{ + mirkill(B->a2); + mirkill(B->a6); + mr_free(B->table); +} + +#else + +/* use precomputated table in ROM - use romaker2.c to create the table, and ecdh2m*.c + for an example of use */ + +void ebrick2_init(ebrick2 *B,const mr_small* rom,big a2,big a6,int m,int a,int b,int c,int window,int nb) +{ + B->table=rom; + B->a2=a2; /* just pass a pointer */ + B->a6=a6; + B->m=m; + B->a=a; + B->b=b; + B->c=c; + B->window=window; /* 2^4=16 stored values */ + B->max=nb; +} + +#endif + +int mul2_brick(_MIPD_ ebrick2 *B,big e,big x,big y) +{ + int i,j,t,d,m,len,maxsize,promptr; + epoint *w,*z; + +#ifdef MR_STATIC + char mem[MR_ECP_RESERVE(2)]; +#else + char *mem; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (size(e)<0) mr_berror(_MIPP_ MR_ERR_NEG_POWER); + t=MR_ROUNDUP(B->max,B->window); + + MR_IN(116) + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base != mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return 0; + } +#endif + + if (logb2(_MIPP_ e) > B->max) + { + mr_berror(_MIPP_ MR_ERR_EXP_TOO_BIG); + MR_OUT + return 0; + } + if (!ecurve2_init(_MIPP_ B->m,B->a,B->b,B->c,B->a2,B->a6,FALSE,MR_BEST)) + { + MR_OUT + return 0; + } + +#ifdef MR_STATIC + memset(mem,0,MR_ECP_RESERVE(2)); +#else + mem=(char *)ecp_memalloc(_MIPP_ 2); +#endif + w=epoint_init_mem(_MIPP_ mem,0); + z=epoint_init_mem(_MIPP_ mem,1); + + m=B->m; + if (m<0) m=-m; + + len=MR_ROUNDUP(m,MIRACL); + maxsize=2*(1<window)*len; + + j=recode(_MIPP_ e,t,B->window,t-1); + if (j>0) + { + promptr=2*j*len; + init_point_from_rom(w,len,B->table,maxsize,&promptr); + } + + for (i=t-2;i>=0;i--) + { + j=recode(_MIPP_ e,t,B->window,i); + ecurve2_double(_MIPP_ w); + if (j>0) + { + promptr=2*j*len; + init_point_from_rom(z,len,B->table,maxsize,&promptr); + ecurve2_add(_MIPP_ z,w); + } + } + + d=epoint2_get(_MIPP_ w,x,y); +#ifndef MR_STATIC + ecp_memkill(_MIPP_ mem,2); +#else + memset(mem,0,MR_ECP_RESERVE(2)); +#endif + MR_OUT + return d; +} + +#endif + + diff --git a/miracl/source/mrecn2.c b/miracl/source/mrecn2.c new file mode 100644 index 0000000..67e82c1 --- /dev/null +++ b/miracl/source/mrecn2.c @@ -0,0 +1,3428 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL E(F_p^2) support functions + * mrecn2.c + */ + +#include +#include "miracl.h" +#ifdef MR_STATIC +#include +#endif + +#ifndef MR_EDWARDS + +BOOL ecn2_iszero(ecn2 *a) +{ + if (a->marker==MR_EPOINT_INFINITY) return TRUE; + return FALSE; +} + +void ecn2_copy(ecn2 *a,ecn2 *b) +{ + zzn2_copy(&(a->x),&(b->x)); + zzn2_copy(&(a->y),&(b->y)); +#ifndef MR_AFFINE_ONLY + if (a->marker==MR_EPOINT_GENERAL) zzn2_copy(&(a->z),&(b->z)); +#endif + b->marker=a->marker; +} + +void ecn2_zero(ecn2 *a) +{ + zzn2_zero(&(a->x)); zzn2_zero(&(a->y)); +#ifndef MR_AFFINE_ONLY + if (a->marker==MR_EPOINT_GENERAL) zzn2_zero(&(a->z)); +#endif + a->marker=MR_EPOINT_INFINITY; +} + +BOOL ecn2_compare(_MIPD_ ecn2 *a,ecn2 *b) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(193) + ecn2_norm(_MIPP_ a); + ecn2_norm(_MIPP_ b); + MR_OUT + if (zzn2_compare(&(a->x),&(b->x)) && zzn2_compare(&(a->y),&(b->y)) && a->marker==b->marker) return TRUE; + return FALSE; +} + +void ecn2_norm(_MIPD_ ecn2 *a) +{ + zzn2 t; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifndef MR_AFFINE_ONLY + if (mr_mip->ERNUM) return; + if (a->marker!=MR_EPOINT_GENERAL) return; + + MR_IN(194) + + zzn2_inv(_MIPP_ &(a->z)); + + t.a=mr_mip->w3; + t.b=mr_mip->w4; + zzn2_copy(&(a->z),&t); + + zzn2_sqr(_MIPP_ &(a->z),&(a->z)); + zzn2_mul(_MIPP_ &(a->x),&(a->z),&(a->x)); + zzn2_mul(_MIPP_ &(a->z),&t,&(a->z)); + zzn2_mul(_MIPP_ &(a->y),&(a->z),&(a->y)); + zzn2_from_zzn(mr_mip->one,&(a->z)); + a->marker=MR_EPOINT_NORMALIZED; + + MR_OUT +#endif +} + +void ecn2_get(_MIPD_ ecn2 *e,zzn2 *x,zzn2 *y,zzn2 *z) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + zzn2_copy(&(e->x),x); + zzn2_copy(&(e->y),y); +#ifndef MR_AFFINE_ONLY + if (e->marker==MR_EPOINT_GENERAL) zzn2_copy(&(e->z),z); + else zzn2_from_zzn(mr_mip->one,z); +#endif +} + +void ecn2_getxy(ecn2 *e,zzn2 *x,zzn2 *y) +{ + zzn2_copy(&(e->x),x); + zzn2_copy(&(e->y),y); +} + +void ecn2_getx(ecn2 *e,zzn2 *x) +{ + zzn2_copy(&(e->x),x); +} + +void ecn2_psi(_MIPD_ zzn2 *psi,ecn2 *P) +{ /* apply GLS morphism to P */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + MR_IN(212) + ecn2_norm(_MIPP_ P); + zzn2_conj(_MIPP_ &(P->x),&(P->x)); + zzn2_conj(_MIPP_ &(P->y),&(P->y)); + zzn2_mul(_MIPP_ &(P->x),&psi[0],&(P->x)); + zzn2_mul(_MIPP_ &(P->y),&psi[1],&(P->y)); + + MR_OUT +} + +#ifndef MR_AFFINE_ONLY +void ecn2_getz(_MIPD_ ecn2 *e,zzn2 *z) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (e->marker==MR_EPOINT_GENERAL) zzn2_copy(&(e->z),z); + else zzn2_from_zzn(mr_mip->one,z); +} +#endif + +void ecn2_rhs(_MIPD_ zzn2 *x,zzn2 *rhs) +{ /* calculate RHS of elliptic curve equation */ + int twist; + zzn2 A,B; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + twist=mr_mip->TWIST; + + MR_IN(202) + + A.a=mr_mip->w10; + A.b=mr_mip->w11; + B.a=mr_mip->w12; + B.b=mr_mip->w13; + + if (mr_abs(mr_mip->Asize)Asize,&A); + else zzn2_from_zzn(mr_mip->A,&A); + + if (mr_abs(mr_mip->Bsize)Bsize,&B); + else zzn2_from_zzn(mr_mip->B,&B); + + if (twist) + { /* assume its the quartic or sextic twist, if such is possible */ + if (twist==MR_QUARTIC_M) + { + zzn2_mul(_MIPP_ &A,x,&B); + zzn2_txx(_MIPP_ &B); + } + if (twist==MR_QUARTIC_D) + { + zzn2_mul(_MIPP_ &A,x,&B); + zzn2_txd(_MIPP_ &B); + } + if (twist==MR_SEXTIC_M) + { + zzn2_txx(_MIPP_ &B); + } + if (twist==MR_SEXTIC_D) + { + zzn2_txd(_MIPP_ &B); + } + if (twist==MR_QUADRATIC) + { + zzn2_txx(_MIPP_ &B); + zzn2_txx(_MIPP_ &B); + zzn2_txx(_MIPP_ &B); + + zzn2_mul(_MIPP_ &A,x,&A); + zzn2_txx(_MIPP_ &A); + zzn2_txx(_MIPP_ &A); + zzn2_add(_MIPP_ &B,&A,&B); + + } +/* + if (mr_mip->Asize==0 || mr_mip->Bsize==0) + { + if (mr_mip->Asize==0) + { // CM Discriminant D=3 - its the sextic twist (Hope I got the right one!). This works for BN curves + zzn2_txd(_MIPP_ &B); + } + if (mr_mip->Bsize==0) + { // CM Discriminant D=1 - its the quartic twist. + zzn2_mul(_MIPP_ &A,x,&B); + zzn2_txx(_MIPP_ &B); + } + } + else + { // its the quadratic twist + + zzn2_txx(_MIPP_ &B); + zzn2_txx(_MIPP_ &B); + zzn2_txx(_MIPP_ &B); + + zzn2_mul(_MIPP_ &A,x,&A); + zzn2_txx(_MIPP_ &A); + zzn2_txx(_MIPP_ &A); + zzn2_add(_MIPP_ &B,&A,&B); + + } +*/ + } + else + { + zzn2_mul(_MIPP_ &A,x,&A); + zzn2_add(_MIPP_ &B,&A,&B); + } + + zzn2_sqr(_MIPP_ x,&A); + zzn2_mul(_MIPP_ &A,x,&A); + zzn2_add(_MIPP_ &B,&A,rhs); + + MR_OUT +} + +BOOL ecn2_set(_MIPD_ zzn2 *x,zzn2 *y,ecn2 *e) +{ + zzn2 lhs,rhs; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(195) + + lhs.a=mr_mip->w10; + lhs.b=mr_mip->w11; + rhs.a=mr_mip->w12; + rhs.b=mr_mip->w13; + + ecn2_rhs(_MIPP_ x,&rhs); + + zzn2_sqr(_MIPP_ y,&lhs); + + if (!zzn2_compare(&lhs,&rhs)) + { + MR_OUT + return FALSE; + } + + zzn2_copy(x,&(e->x)); + zzn2_copy(y,&(e->y)); + + e->marker=MR_EPOINT_NORMALIZED; + + MR_OUT + return TRUE; +} + +#ifndef MR_NOSUPPORT_COMPRESSION + + +BOOL ecn2_setx(_MIPD_ zzn2 *x,ecn2 *e) +{ + zzn2 rhs; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(201) + + rhs.a=mr_mip->w12; + rhs.b=mr_mip->w13; + + ecn2_rhs(_MIPP_ x,&rhs); + if (!zzn2_iszero(&rhs)) + { + if (!zzn2_qr(_MIPP_ &rhs)) + { + MR_OUT + return FALSE; + } + zzn2_sqrt(_MIPP_ &rhs,&rhs); + } + + zzn2_copy(x,&(e->x)); + zzn2_copy(&rhs,&(e->y)); + + e->marker=MR_EPOINT_NORMALIZED; + + MR_OUT + return TRUE; +} + +#endif + +#ifndef MR_AFFINE_ONLY +void ecn2_setxyz(_MIPD_ zzn2 *x,zzn2 *y,zzn2 *z,ecn2 *e) +{ + zzn2_copy(x,&(e->x)); + zzn2_copy(y,&(e->y)); + zzn2_copy(z,&(e->z)); + + + if (zzn2_isunity(_MIPP_ z)) e->marker=MR_EPOINT_NORMALIZED; + else e->marker=MR_EPOINT_GENERAL; +} +#endif + +/* Normalise an array of points of length mcoord==MR_AFFINE) return TRUE; + if (mr_mip->ERNUM) return FALSE; + if (m>MR_MAX_M_T_S) return FALSE; + + MR_IN(215) + + one.a=mr_mip->w12; + one.b=mr_mip->w13; + t.a=mr_mip->w14; + t.b=mr_mip->w15; + + zzn2_from_int(_MIPP_ 1,&one); + + for (i=0;imarker!=MR_EPOINT_INFINITY) + zzn2_negate(_MIPP_ &(w->y),&(w->y)); +} + +BOOL ecn2_add2(_MIPD_ ecn2 *Q,ecn2 *P,zzn2 *lam,zzn2 *ex1) +{ + BOOL Doubling; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + Doubling=ecn2_add3(_MIPP_ Q,P,lam,ex1,NULL); + + return Doubling; +} + +BOOL ecn2_add1(_MIPD_ ecn2 *Q,ecn2 *P,zzn2 *lam) +{ + BOOL Doubling; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + Doubling=ecn2_add3(_MIPP_ Q,P,lam,NULL,NULL); + + return Doubling; +} + +BOOL ecn2_add(_MIPD_ ecn2 *Q,ecn2 *P) +{ + BOOL Doubling; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zzn2 lam; + + lam.a = mr_mip->w14; + lam.b = mr_mip->w15; + + Doubling=ecn2_add3(_MIPP_ Q,P,&lam,NULL,NULL); + + return Doubling; +} + +BOOL ecn2_sub(_MIPD_ ecn2 *Q,ecn2 *P) +{ + BOOL Doubling; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zzn2 lam; + + lam.a = mr_mip->w14; + lam.b = mr_mip->w15; + + ecn2_negate(_MIPP_ Q,Q); + + Doubling=ecn2_add3(_MIPP_ Q,P,&lam,NULL,NULL); + + ecn2_negate(_MIPP_ Q,Q); + + return Doubling; +} + +BOOL ecn2_add_sub(_MIPD_ ecn2 *P,ecn2 *Q,ecn2 *PP,ecn2 *PM) +{ /* PP=P+Q, PM=P-Q. Assumes P and Q are both normalized, and P!=Q */ + #ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zzn2 t1,t2,lam; + + if (mr_mip->ERNUM) return FALSE; + + if (P->marker==MR_EPOINT_GENERAL || Q->marker==MR_EPOINT_GENERAL) + { /* Sorry, some restrictions.. */ + mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + MR_OUT + return FALSE; + } + + if (zzn2_compare(&(P->x),&(Q->x))) + { /* P=Q or P=-Q - shouldn't happen */ + ecn2_copy(P,PP); + ecn2_add(_MIPP_ Q,PP); + ecn2_copy(P,PM); + ecn2_sub(_MIPP_ Q,PM); + + MR_OUT + return TRUE; + } + + t1.a = mr_mip->w8; + t1.b = mr_mip->w9; + t2.a = mr_mip->w10; + t2.b = mr_mip->w11; + lam.a = mr_mip->w12; + lam.b = mr_mip->w13; + + zzn2_copy(&(P->x),&t2); + zzn2_sub(_MIPP_ &t2,&(Q->x),&t2); + zzn2_inv(_MIPP_ &t2); /* only one inverse required */ + zzn2_add(_MIPP_ &(P->x),&(Q->x),&(PP->x)); + zzn2_copy(&(PP->x),&(PM->x)); + + zzn2_copy(&(P->y),&t1); + zzn2_sub(_MIPP_ &t1,&(Q->y),&t1); + zzn2_copy(&t1,&lam); + zzn2_mul(_MIPP_ &lam,&t2,&lam); + zzn2_copy(&lam,&t1); + zzn2_sqr(_MIPP_ &t1,&t1); + zzn2_sub(_MIPP_ &t1,&(PP->x),&(PP->x)); + zzn2_copy(&(Q->x),&(PP->y)); + zzn2_sub(_MIPP_ &(PP->y),&(PP->x),&(PP->y)); + zzn2_mul(_MIPP_ &(PP->y),&lam,&(PP->y)); + zzn2_sub(_MIPP_ &(PP->y),&(Q->y),&(PP->y)); + + zzn2_copy(&(P->y),&t1); + zzn2_add(_MIPP_ &t1,&(Q->y),&t1); + zzn2_copy(&t1,&lam); + zzn2_mul(_MIPP_ &lam,&t2,&lam); + zzn2_copy(&lam,&t1); + zzn2_sqr(_MIPP_ &t1,&t1); + zzn2_sub(_MIPP_ &t1,&(PM->x),&(PM->x)); + zzn2_copy(&(Q->x),&(PM->y)); + zzn2_sub(_MIPP_ &(PM->y),&(PM->x),&(PM->y)); + zzn2_mul(_MIPP_ &(PM->y),&lam,&(PM->y)); + zzn2_add(_MIPP_ &(PM->y),&(Q->y),&(PM->y)); + + PP->marker=MR_EPOINT_NORMALIZED; + PM->marker=MR_EPOINT_NORMALIZED; + + return TRUE; +} + +BOOL ecn2_add3(_MIPD_ ecn2 *Q,ecn2 *P,zzn2 *lam,zzn2 *ex1,zzn2 *ex2) +{ /* P+=Q */ + BOOL Doubling=FALSE; + int twist; + int iA; + zzn2 t1,t2,t3; + zzn2 Yzzz; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + t1.a = mr_mip->w8; + t1.b = mr_mip->w9; + t2.a = mr_mip->w10; + t2.b = mr_mip->w11; + t3.a = mr_mip->w12; + t3.b = mr_mip->w13; + Yzzz.a = mr_mip->w3; + Yzzz.b = mr_mip->w4; + + twist=mr_mip->TWIST; + if (mr_mip->ERNUM) return FALSE; + + if (P->marker==MR_EPOINT_INFINITY) + { + ecn2_copy(Q,P); + return Doubling; + } + if (Q->marker==MR_EPOINT_INFINITY) return Doubling; + + MR_IN(205) + + if (Q!=P && Q->marker==MR_EPOINT_GENERAL) + { /* Sorry, this code is optimized for mixed addition only */ + mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + MR_OUT + return Doubling; + } +#ifndef MR_AFFINE_ONLY + if (mr_mip->coord==MR_AFFINE) + { +#endif + if (!zzn2_compare(&(P->x),&(Q->x))) + { + zzn2_copy(&(P->y),&t1); + zzn2_sub(_MIPP_ &t1,&(Q->y),&t1); + zzn2_copy(&(P->x),&t2); + zzn2_sub(_MIPP_ &t2,&(Q->x),&t2); + zzn2_copy(&t1,lam); + zzn2_inv(_MIPP_ &t2); + zzn2_mul(_MIPP_ lam,&t2,lam); + + zzn2_add(_MIPP_ &(P->x),&(Q->x),&(P->x)); + zzn2_copy(lam,&t1); + zzn2_sqr(_MIPP_ &t1,&t1); + zzn2_sub(_MIPP_ &t1,&(P->x),&(P->x)); + + zzn2_copy(&(Q->x),&(P->y)); + zzn2_sub(_MIPP_ &(P->y),&(P->x),&(P->y)); + zzn2_mul(_MIPP_ &(P->y),lam,&(P->y)); + zzn2_sub(_MIPP_ &(P->y),&(Q->y),&(P->y)); + } + else + { + if (!zzn2_compare(&(P->y),&(Q->y)) || zzn2_iszero(&(P->y))) + { + ecn2_zero(P); + zzn2_from_int(_MIPP_ 1,lam); + MR_OUT + return Doubling; + } + zzn2_copy(&(P->x),&t1); + zzn2_copy(&(P->x),&t2); + zzn2_copy(&(P->x),lam); + zzn2_sqr(_MIPP_ lam,lam); + zzn2_add(_MIPP_ lam,lam,&t3); + zzn2_add(_MIPP_ lam,&t3,lam); + + if (mr_abs(mr_mip->Asize)Asize,&t3); + else zzn2_from_zzn(mr_mip->A,&t3); + + if (twist) + { + if (twist==MR_QUARTIC_M) + { + zzn2_txx(_MIPP_ &t3); + } + if (twist==MR_QUARTIC_D) + { + zzn2_txd(_MIPP_ &t3); + } + if (twist==MR_QUADRATIC) + { + zzn2_txx(_MIPP_ &t3); + zzn2_txx(_MIPP_ &t3); + } +/* + if (mr_mip->Bsize==0) + { // assume its the quartic twist + zzn2_txx(_MIPP_ &t3); + } + else + { + zzn2_txx(_MIPP_ &t3); + zzn2_txx(_MIPP_ &t3); + } +*/ + } + zzn2_add(_MIPP_ lam,&t3,lam); + zzn2_add(_MIPP_ &(P->y),&(P->y),&t3); + zzn2_inv(_MIPP_ &t3); + zzn2_mul(_MIPP_ lam,&t3,lam); + + zzn2_add(_MIPP_ &t2,&(P->x),&t2); + zzn2_copy(lam,&(P->x)); + zzn2_sqr(_MIPP_ &(P->x),&(P->x)); + zzn2_sub(_MIPP_ &(P->x),&t2,&(P->x)); + zzn2_sub(_MIPP_ &t1,&(P->x),&t1); + zzn2_mul(_MIPP_ &t1,lam,&t1); + zzn2_sub(_MIPP_ &t1,&(P->y),&(P->y)); + } + + P->marker=MR_EPOINT_NORMALIZED; + MR_OUT + return Doubling; +#ifndef MR_AFFINE_ONLY + } + + if (Q==P) Doubling=TRUE; + + zzn2_copy(&(Q->x),&t3); + zzn2_copy(&(Q->y),&Yzzz); + + if (!Doubling) + { + if (P->marker!=MR_EPOINT_NORMALIZED) + { + zzn2_sqr(_MIPP_ &(P->z),&t1); /* 1S */ + zzn2_mul(_MIPP_ &t3,&t1,&t3); /* 1M */ + zzn2_mul(_MIPP_ &t1,&(P->z),&t1); /* 1M */ + zzn2_mul(_MIPP_ &Yzzz,&t1,&Yzzz); /* 1M */ + } + if (zzn2_compare(&t3,&(P->x))) + { + if (!zzn2_compare(&Yzzz,&(P->y)) || zzn2_iszero(&(P->y))) + { + ecn2_zero(P); + zzn2_from_int(_MIPP_ 1,lam); + MR_OUT + return Doubling; + } + else Doubling=TRUE; + } + } + if (!Doubling) + { /* Addition */ + zzn2_sub(_MIPP_ &t3,&(P->x),&t3); + zzn2_sub(_MIPP_ &Yzzz,&(P->y),lam); + if (P->marker==MR_EPOINT_NORMALIZED) zzn2_copy(&t3,&(P->z)); + else zzn2_mul(_MIPP_ &(P->z),&t3,&(P->z)); /* 1M */ + zzn2_sqr(_MIPP_ &t3,&t1); /* 1S */ + zzn2_mul(_MIPP_ &t1,&t3,&Yzzz); /* 1M */ + zzn2_mul(_MIPP_ &t1,&(P->x),&t1); /* 1M */ + zzn2_copy(&t1,&t3); + zzn2_add(_MIPP_ &t3,&t3,&t3); + zzn2_sqr(_MIPP_ lam,&(P->x)); /* 1S */ + zzn2_sub(_MIPP_ &(P->x),&t3,&(P->x)); + zzn2_sub(_MIPP_ &(P->x),&Yzzz,&(P->x)); + zzn2_sub(_MIPP_ &t1,&(P->x),&t1); + zzn2_mul(_MIPP_ &t1,lam,&t1); /* 1M */ + zzn2_mul(_MIPP_ &Yzzz,&(P->y),&Yzzz); /* 1M */ + zzn2_sub(_MIPP_ &t1,&Yzzz,&(P->y)); + +/* + zzn2_sub(_MIPP_ &(P->x),&t3,&t1); + zzn2_sub(_MIPP_ &(P->y),&Yzzz,lam); + if (P->marker==MR_EPOINT_NORMALIZED) zzn2_copy(&t1,&(P->z)); + else zzn2_mul(_MIPP_ &(P->z),&t1,&(P->z)); + zzn2_sqr(_MIPP_ &t1,&t2); + zzn2_add(_MIPP_ &(P->x),&t3,&t3); + zzn2_mul(_MIPP_ &t3,&t2,&t3); + zzn2_sqr(_MIPP_ lam,&(P->x)); + zzn2_sub(_MIPP_ &(P->x),&t3,&(P->x)); + + zzn2_mul(_MIPP_ &t2,&t1,&t2); + zzn2_add(_MIPP_ &(P->x),&(P->x),&t1); + zzn2_sub(_MIPP_ &t3,&t1,&t3); + zzn2_mul(_MIPP_ &t3,lam,&t3); + + zzn2_add(_MIPP_ &(P->y),&Yzzz,&t1); + + zzn2_mul(_MIPP_ &t2,&t1,&t2); + zzn2_sub(_MIPP_ &t3,&t2,&(P->y)); + zzn2_div2(_MIPP_ &(P->y)); +*/ + } + else + { /* doubling */ + zzn2_sqr(_MIPP_ &(P->y),&t3); /* 1S */ + + iA=mr_mip->Asize; + if (iA!=0) + { + if (P->marker==MR_EPOINT_NORMALIZED) zzn2_from_int(_MIPP_ 1,&t1); + else zzn2_sqr(_MIPP_ &(P->z),&t1); /* 1S */ + if (ex2!=NULL) zzn2_copy(&t1,ex2); + + if (iA==-3 && twist<=MR_QUADRATIC) + { + if (twist==MR_QUADRATIC) zzn2_txx(_MIPP_ &t1); /* quadratic twist */ + zzn2_sub(_MIPP_ &(P->x),&t1,lam); + zzn2_add(_MIPP_ &t1,&(P->x),&t1); + zzn2_mul(_MIPP_ lam,&t1,lam); /* 1M */ + zzn2_add(_MIPP_ lam,lam,&t2); + zzn2_add(_MIPP_ lam,&t2,lam); + } + else + { + zzn2_sqr(_MIPP_ &(P->x),lam); /* 1S */ + zzn2_add(_MIPP_ lam,lam,&t2); + zzn2_add(_MIPP_ lam,&t2,lam); + + if (twist==MR_QUADRATIC) zzn2_txx(_MIPP_ &t1); /* quadratic twist */ + zzn2_sqr(_MIPP_ &t1,&t1); /* 1S */ + if (twist==MR_QUARTIC_M) zzn2_txx(_MIPP_ &t1); /* quartic twist */ + if (twist==MR_QUARTIC_D) zzn2_txd(_MIPP_ &t1); /* quartic twist */ + if (iA!=1) + { /* optimized for iA=1 case */ + if (iAA,&t1); + } + zzn2_add(_MIPP_ lam,&t1,lam); + } + } + else + { + zzn2_sqr(_MIPP_ &(P->x),lam); /* 1S */ + zzn2_add(_MIPP_ lam,lam,&t2); + zzn2_add(_MIPP_ lam,&t2,lam); + } + zzn2_mul(_MIPP_ &(P->x),&t3,&t1); /* 1M */ + zzn2_add(_MIPP_ &t1,&t1,&t1); + zzn2_add(_MIPP_ &t1,&t1,&t1); + zzn2_sqr(_MIPP_ lam,&(P->x)); /* 1S */ + zzn2_add(_MIPP_ &t1,&t1,&t2); + zzn2_sub(_MIPP_ &(P->x),&t2,&(P->x)); + if (P->marker==MR_EPOINT_NORMALIZED) zzn2_copy(&(P->y),&(P->z)); + else zzn2_mul(_MIPP_ &(P->z),&(P->y),&(P->z)); /* 1M */ + zzn2_add(_MIPP_ &(P->z),&(P->z),&(P->z)); + zzn2_add(_MIPP_ &t3,&t3,&t3); + if (ex1!=NULL) zzn2_copy(&t3,ex1); + zzn2_sqr(_MIPP_ &t3,&t3); /* 1S */ + zzn2_add(_MIPP_ &t3,&t3,&t3); + zzn2_sub(_MIPP_ &t1,&(P->x),&t1); + zzn2_mul(_MIPP_ lam,&t1,&(P->y)); /* 1M */ + zzn2_sub(_MIPP_ &(P->y),&t3,&(P->y)); + } + + P->marker=MR_EPOINT_GENERAL; + MR_OUT + return Doubling; +#endif +} + +/* Dahmen, Okeya and Schepers "Affine Precomputation with Sole Inversion in Elliptic Curve Cryptography" */ +/* Precomputes table into T. Assumes first P has been copied to P[0], then calculates 3P, 5P, 7P etc. into T */ + +#define MR_PRE_2 (14+4*MR_ECC_STORE_N2) + +static void ecn2_pre(_MIPD_ int sz,BOOL norm,ecn2 *PT) +{ + int twist; + int i,j; + zzn2 A,B,C,D,E,T,W; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + +#ifndef MR_STATIC + zzn2 *d=(zzn2 *)mr_alloc(_MIPP_ sz,sizeof(zzn2)); + zzn2 *e=(zzn2 *)mr_alloc(_MIPP_ sz,sizeof(zzn2)); + char *mem = (char *)memalloc(_MIPP_ 14+4*sz); +#else + zzn2 d[MR_ECC_STORE_N2],e[MR_ECC_STORE_N2]; + char mem[MR_BIG_RESERVE(MR_PRE_2)]; + memset(mem, 0, MR_BIG_RESERVE(MR_PRE_2)); +#endif + + twist=mr_mip->TWIST; + j=0; + + A.a= mirvar_mem(_MIPP_ mem, j++); + A.b= mirvar_mem(_MIPP_ mem, j++); + B.a= mirvar_mem(_MIPP_ mem, j++); + B.b= mirvar_mem(_MIPP_ mem, j++); + C.a= mirvar_mem(_MIPP_ mem, j++); + C.b= mirvar_mem(_MIPP_ mem, j++); + D.a= mirvar_mem(_MIPP_ mem, j++); + D.b= mirvar_mem(_MIPP_ mem, j++); + E.a= mirvar_mem(_MIPP_ mem, j++); + E.b= mirvar_mem(_MIPP_ mem, j++); + T.a= mirvar_mem(_MIPP_ mem, j++); + T.b= mirvar_mem(_MIPP_ mem, j++); + W.a= mirvar_mem(_MIPP_ mem, j++); + W.b= mirvar_mem(_MIPP_ mem, j++); + + for (i=0;iAsize)Asize,&A); + else zzn2_from_zzn(mr_mip->A,&A); + + if (twist) + { + if (twist==MR_QUARTIC_M) + { + zzn2_txx(_MIPP_ &A); + } + if (twist==MR_QUARTIC_D) + { + zzn2_txd(_MIPP_ &A); + } + if (twist==MR_QUADRATIC) + { + zzn2_txx(_MIPP_ &A); + zzn2_txx(_MIPP_ &A); + } +/* + if (mr_mip->Bsize==0) + { // assume its the quartic twist + zzn2_txx(_MIPP_ &A); + } + else + { + zzn2_txx(_MIPP_ &A); + zzn2_txx(_MIPP_ &A); + } +*/ + } + zzn2_add(_MIPP_ &A,&T,&A); /* 3. A=3x^2+a */ + zzn2_copy(&A,&W); + + zzn2_add(_MIPP_ &C,&C,&B); + zzn2_add(_MIPP_ &B,&C,&B); + zzn2_mul(_MIPP_ &B,&(PT[0].x),&B); /* 4. B=3C.x */ + + zzn2_sqr(_MIPP_ &A,&d[1]); + zzn2_sub(_MIPP_ &d[1],&B,&d[1]); /* 5. d_1=A^2-B */ + + zzn2_sqr(_MIPP_ &d[1],&E); /* 6. E=d_1^2 */ + + zzn2_mul(_MIPP_ &B,&E,&B); /* 7. B=E.B */ + + zzn2_sqr(_MIPP_ &C,&C); /* 8. C=C^2 */ + + zzn2_mul(_MIPP_ &E,&d[1],&D); /* 9. D=E.d_1 */ + + zzn2_mul(_MIPP_ &A,&d[1],&A); + zzn2_add(_MIPP_ &A,&C,&A); + zzn2_negate(_MIPP_ &A,&A); /* 10. A=-d_1*A-C */ + + zzn2_add(_MIPP_ &D,&D,&T); + zzn2_sqr(_MIPP_ &A,&d[2]); + zzn2_sub(_MIPP_ &d[2],&T,&d[2]); + zzn2_sub(_MIPP_ &d[2],&B,&d[2]); /* 11. d_2=A^2-2D-B */ + + if (sz>3) + { + zzn2_sqr(_MIPP_ &d[2],&E); /* 12. E=d_2^2 */ + + zzn2_add(_MIPP_ &T,&D,&T); + zzn2_add(_MIPP_ &T,&B,&T); + zzn2_mul(_MIPP_ &T,&E,&B); /* 13. B=E(B+3D) */ + + zzn2_add(_MIPP_ &A,&A,&T); + zzn2_add(_MIPP_ &C,&T,&C); + zzn2_mul(_MIPP_ &C,&D,&C); /* 14. C=D(2A+C) */ + + zzn2_mul(_MIPP_ &d[2],&E,&D); /* 15. D=E.d_2 */ + + zzn2_mul(_MIPP_ &A,&d[2],&A); + zzn2_add(_MIPP_ &A,&C,&A); + zzn2_negate(_MIPP_ &A,&A); /* 16. A=-d_2*A-C */ + + + zzn2_sqr(_MIPP_ &A,&d[3]); + zzn2_sub(_MIPP_ &d[3],&D,&d[3]); + zzn2_sub(_MIPP_ &d[3],&B,&d[3]); /* 17. d_3=A^2-D-B */ + + for (i=4;i0;i--) + { + zzn2_copy(&d[i],&B); + zzn2_mul(_MIPP_ &e[i-1],&A,&d[i]); + zzn2_mul(_MIPP_ &A,&B,&A); + } + zzn2_copy(&A,&d[0]); + + for (i=1;i=1;) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + n=mr_naf_window(_MIPP_ k,h,i,&nbs,&nzs,MR_ECC_STORE_N2); + + for (j=0;j0) {nadds++; ecn2_add(_MIPP_ &T[n/2],P);} + if (n<0) {nadds++; ecn2_sub(_MIPP_ &T[(-n)/2],P);} + i-=nbs; + if (nzs) + { + for (j=0;j0) bb=logb2(_MIPP_ e)-1; + else bb=logb2(_MIPP_ f)-1; + + ecn2_add_sub(_MIPP_ &P1,&P2,&PS,&PD); + ecn2_zero(R); + nadds=0; + + while (bb>=0) + { /* add/subtract method */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + ecn2_add(_MIPP_ R,R); + e1=h1=e2=h2=0; + + if (mr_testbit(_MIPP_ d,bb)) e2=1; + if (mr_testbit(_MIPP_ e,bb)) h2=1; + if (mr_testbit(_MIPP_ c,bb)) e1=1; + if (mr_testbit(_MIPP_ f,bb)) h1=1; + + if (e1!=h1) + { + if (e2==h2) + { + if (h1==1) {ecn2_add(_MIPP_ &P1,R); nadds++;} + else {ecn2_sub(_MIPP_ &P1,R); nadds++;} + } + else + { + if (h1==1) + { + if (h2==1) {ecn2_add(_MIPP_ &PS,R); nadds++;} + else {ecn2_add(_MIPP_ &PD,R); nadds++;} + } + else + { + if (h2==1) {ecn2_sub(_MIPP_ &PD,R); nadds++;} + else {ecn2_sub(_MIPP_ &PS,R); nadds++;} + } + } + } + else if (e2!=h2) + { + if (h2==1) {ecn2_add(_MIPP_ &P2,R); nadds++;} + else {ecn2_sub(_MIPP_ &P2,R); nadds++;} + } + bb-=1; + } + ecn2_norm(_MIPP_ R); + + MR_OUT +#ifndef MR_STATIC + memkill(_MIPP_ mem, MR_MUL2_JSF_RESERVE); +#else + memset(mem, 0, MR_BIG_RESERVE(MR_MUL2_JSF_RESERVE)); +#endif + return nadds; + +} + +/* General purpose multi-exponentiation engine, using inter-leaving algorithm. Calculate aP+bQ+cR+dS... + Inputs are divided into two groups of sizes wa<4 and wb<4. For the first group if the points are fixed the + first precomputed Table Ta[] may be taken from ROM. For the second group if the points are variable Tb[j] will + have to computed online. Each group has its own precomputed store size, sza (=8?) and szb (=20?) respectively. + The values a,b,c.. are provided in ma[] and mb[], and 3.a,3.b,3.c (as required by the NAF) are provided in + ma3[] and mb3[]. If only one group is required, set wb=0 and pass NULL pointers. + */ + +int ecn2_muln_engine(_MIPD_ int wa,int sza,int wb,int szb,big *ma,big *ma3,big *mb,big *mb3,ecn2 *Ta,ecn2 *Tb,ecn2 *R) +{ /* general purpose interleaving algorithm engine for multi-exp */ + int i,j,tba[4],pba[4],na[4],sa[4],tbb[4],pbb[4],nb[4],sb[4],nbits,nbs,nzs; + int nadds; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + ecn2_zero(R); + + nbits=0; + for (i=0;inbits) nbits=j; } + for (i=0;inbits) nbits=j; } + + nadds=0; + for (i=nbits-1;i>=1;i--) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + if (R->marker!=MR_EPOINT_INFINITY) ecn2_add(_MIPP_ R,R); + for (j=0;j0) {ecn2_add(_MIPP_ &Ta[j*sza+na[j]/2],R); nadds++;} + if (na[j]<0) {ecn2_sub(_MIPP_ &Ta[j*sza+(-na[j])/2],R); nadds++;} + } + else + { + if (na[j]>0) {ecn2_sub(_MIPP_ &Ta[j*sza+na[j]/2],R); nadds++;} + if (na[j]<0) {ecn2_add(_MIPP_ &Ta[j*sza+(-na[j])/2],R); nadds++;} + } + } + } + for (j=0;j0) {ecn2_add(_MIPP_ &Tb[j*szb+nb[j]/2],R); nadds++;} + if (nb[j]<0) {ecn2_sub(_MIPP_ &Tb[j*szb+(-nb[j])/2],R); nadds++;} + } + else + { + if (nb[j]>0) {ecn2_sub(_MIPP_ &Tb[j*szb+nb[j]/2],R); nadds++;} + if (nb[j]<0) {ecn2_add(_MIPP_ &Tb[j*szb+(-nb[j])/2],R); nadds++;} + } + } + } + } + ecn2_norm(_MIPP_ R); + return nadds; +} + +/* Routines to support Galbraith, Lin, Scott (GLS) method for ECC */ +/* requires an endomorphism psi */ + +/* *********************** */ + +/* Precompute T - first half from i.P, second half from i.psi(P) */ + +void ecn2_precomp_gls(_MIPD_ int sz,BOOL norm,ecn2 *P,zzn2 *psi,ecn2 *T) +{ + int i,j; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + j=0; + + MR_IN(219) + + ecn2_norm(_MIPP_ P); + ecn2_copy(P,&T[0]); + + ecn2_pre(_MIPP_ sz,norm,T); /* precompute table */ + + for (i=sz;inb || mr_mip->ERNUM) return FALSE; + + t=MR_ROUNDUP(nb,window); + + if (t<2) return FALSE; + + MR_IN(221) + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base != mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return FALSE; + } +#endif + + B->window=window; + B->max=nb; + table=(ecn2 *)mr_alloc(_MIPP_ (1<a=mirvar(_MIPP_ 0); + B->b=mirvar(_MIPP_ 0); + B->n=mirvar(_MIPP_ 0); + copy(a,B->a); + copy(b,B->b); + copy(n,B->n); + + ecurve_init(_MIPP_ a,b,n,MR_AFFINE); + mr_mip->TWIST=MR_QUADRATIC; + + w.x.a=mirvar(_MIPP_ 0); + w.x.b=mirvar(_MIPP_ 0); + w.y.a=mirvar(_MIPP_ 0); + w.y.b=mirvar(_MIPP_ 0); + w.marker=MR_EPOINT_INFINITY; + ecn2_set(_MIPP_ x,y,&w); + + table[0].x.a=mirvar(_MIPP_ 0); + table[0].x.b=mirvar(_MIPP_ 0); + table[0].y.a=mirvar(_MIPP_ 0); + table[0].y.b=mirvar(_MIPP_ 0); + table[0].marker=MR_EPOINT_INFINITY; + table[1].x.a=mirvar(_MIPP_ 0); + table[1].x.b=mirvar(_MIPP_ 0); + table[1].y.a=mirvar(_MIPP_ 0); + table[1].y.b=mirvar(_MIPP_ 0); + table[1].marker=MR_EPOINT_INFINITY; + + ecn2_copy(&w,&table[1]); + for (j=0;jlen; + bptr=0; + B->table=(mr_small *)mr_alloc(_MIPP_ 4*len*(1<table[bptr++]=table[i].x.a->w[j]; + for (j=0;jtable[bptr++]=table[i].x.b->w[j]; + + for (j=0;jtable[bptr++]=table[i].y.a->w[j]; + for (j=0;jtable[bptr++]=table[i].y.b->w[j]; + + mr_free(table[i].x.a); + mr_free(table[i].x.b); + mr_free(table[i].y.a); + mr_free(table[i].y.b); + } + + mr_free(table); + + MR_OUT + return TRUE; +} + +void ecn2_brick_end(ebrick *B) +{ + mirkill(B->n); + mirkill(B->b); + mirkill(B->a); + mr_free(B->table); +} + +#else + +/* use precomputated table in ROM */ + +void ecn2_brick_init(ebrick *B,const mr_small* rom,big a,big b,big n,int window,int nb) +{ + B->table=rom; + B->a=a; /* just pass a pointer */ + B->b=b; + B->n=n; + B->window=window; /* 2^4=16 stored values */ + B->max=nb; +} + +#endif + +/* +void ecn2_mul_brick(_MIPD_ ebrick *B,big e,zzn2 *x,zzn2 *y) +{ + int i,j,t,len,maxsize,promptr; + ecn2 w,z; + +#ifdef MR_STATIC + char mem[MR_BIG_RESERVE(10)]; +#else + char *mem; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (size(e)<0) mr_berror(_MIPP_ MR_ERR_NEG_POWER); + t=MR_ROUNDUP(B->max,B->window); + + MR_IN(116) + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base != mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return; + } +#endif + + if (logb2(_MIPP_ e) > B->max) + { + mr_berror(_MIPP_ MR_ERR_EXP_TOO_BIG); + MR_OUT + return; + } + + ecurve_init(_MIPP_ B->a,B->b,B->n,MR_BEST); + mr_mip->TWIST=MR_QUADRATIC; + +#ifdef MR_STATIC + memset(mem,0,MR_BIG_RESERVE(10)); +#else + mem=memalloc(_MIPP_ 10); +#endif + + w.x.a=mirvar_mem(_MIPP_ mem, 0); + w.x.b=mirvar_mem(_MIPP_ mem, 1); + w.y.a=mirvar_mem(_MIPP_ mem, 2); + w.y.b=mirvar_mem(_MIPP_ mem, 3); + w.z.a=mirvar_mem(_MIPP_ mem, 4); + w.z.b=mirvar_mem(_MIPP_ mem, 5); + w.marker=MR_EPOINT_INFINITY; + z.x.a=mirvar_mem(_MIPP_ mem, 6); + z.x.b=mirvar_mem(_MIPP_ mem, 7); + z.y.a=mirvar_mem(_MIPP_ mem, 8); + z.y.b=mirvar_mem(_MIPP_ mem, 9); + z.marker=MR_EPOINT_INFINITY; + + len=B->n->len; + maxsize=4*(1<window)*len; + + for (i=t-1;i>=0;i--) + { + j=recode(_MIPP_ e,t,B->window,i); + ecn2_add(_MIPP_ &w,&w); + if (j>0) + { + promptr=4*j*len; + init_big_from_rom(z.x.a,len,B->table,maxsize,&promptr); + init_big_from_rom(z.x.b,len,B->table,maxsize,&promptr); + init_big_from_rom(z.y.a,len,B->table,maxsize,&promptr); + init_big_from_rom(z.y.b,len,B->table,maxsize,&promptr); + z.marker=MR_EPOINT_NORMALIZED; + ecn2_add(_MIPP_ &z,&w); + } + } + ecn2_norm(_MIPP_ &w); + ecn2_getxy(&w,x,y); +#ifndef MR_STATIC + memkill(_MIPP_ mem,10); +#else + memset(mem,0,MR_BIG_RESERVE(10)); +#endif + MR_OUT +} +*/ + +void ecn2_mul_brick_gls(_MIPD_ ebrick *B,big *e,zzn2 *psi,zzn2 *x,zzn2 *y) +{ + int i,j,k,t,len,maxsize,promptr,se[2]; + ecn2 w,z; + +#ifdef MR_STATIC + char mem[MR_BIG_RESERVE(10)]; +#else + char *mem; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + for (k=0;k<2;k++) se[k]=exsign(e[k]); + + t=MR_ROUNDUP(B->max,B->window); + + MR_IN(222) + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base != mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return; + } +#endif + + if (logb2(_MIPP_ e[0])>B->max || logb2(_MIPP_ e[1])>B->max) + { + mr_berror(_MIPP_ MR_ERR_EXP_TOO_BIG); + MR_OUT + return; + } + + ecurve_init(_MIPP_ B->a,B->b,B->n,MR_BEST); + mr_mip->TWIST=MR_QUADRATIC; + +#ifdef MR_STATIC + memset(mem,0,MR_BIG_RESERVE(10)); +#else + mem=(char *)memalloc(_MIPP_ 10); +#endif + + z.x.a=mirvar_mem(_MIPP_ mem, 0); + z.x.b=mirvar_mem(_MIPP_ mem, 1); + z.y.a=mirvar_mem(_MIPP_ mem, 2); + z.y.b=mirvar_mem(_MIPP_ mem, 3); + z.marker=MR_EPOINT_INFINITY; + + w.x.a=mirvar_mem(_MIPP_ mem, 4); + w.x.b=mirvar_mem(_MIPP_ mem, 5); + w.y.a=mirvar_mem(_MIPP_ mem, 6); + w.y.b=mirvar_mem(_MIPP_ mem, 7); +#ifndef MR_AFFINE_ONLY + w.z.a=mirvar_mem(_MIPP_ mem, 8); + w.z.b=mirvar_mem(_MIPP_ mem, 9); +#endif + w.marker=MR_EPOINT_INFINITY; + + len=B->n->len; + maxsize=4*(1<window)*len; + + for (i=t-1;i>=0;i--) + { + ecn2_add(_MIPP_ &w,&w); + for (k=0;k<2;k++) + { + j=recode(_MIPP_ e[k],t,B->window,i); + if (j>0) + { + promptr=4*j*len; + init_big_from_rom(z.x.a,len,B->table,maxsize,&promptr); + init_big_from_rom(z.x.b,len,B->table,maxsize,&promptr); + init_big_from_rom(z.y.a,len,B->table,maxsize,&promptr); + init_big_from_rom(z.y.b,len,B->table,maxsize,&promptr); + z.marker=MR_EPOINT_NORMALIZED; + if (k==1) ecn2_psi(_MIPP_ psi,&z); + if (se[k]==PLUS) ecn2_add(_MIPP_ &z,&w); + else ecn2_sub(_MIPP_ &z,&w); + } + } + } + ecn2_norm(_MIPP_ &w); + ecn2_getxy(&w,x,y); +#ifndef MR_STATIC + memkill(_MIPP_ mem,10); +#else + memset(mem,0,MR_BIG_RESERVE(10)); +#endif + MR_OUT +} + +#else + +/* Now for curves in Inverted Twisted Edwards Form */ + +BOOL ecn2_iszero(ecn2 *a) +{ + if (a->marker==MR_EPOINT_INFINITY) return TRUE; + return FALSE; +} + +void ecn2_copy(ecn2 *a,ecn2 *b) +{ + zzn2_copy(&(a->x),&(b->x)); + zzn2_copy(&(a->y),&(b->y)); + if (a->marker==MR_EPOINT_GENERAL) zzn2_copy(&(a->z),&(b->z)); + b->marker=a->marker; +} + +void ecn2_zero(ecn2 *a) +{ + zzn2_zero(&(a->x)); + zzn2_zero(&(a->y)); + if (a->marker==MR_EPOINT_GENERAL) zzn2_zero(&(a->z)); + a->marker=MR_EPOINT_INFINITY; +} + +BOOL ecn2_compare(_MIPD_ ecn2 *a,ecn2 *b) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(193) + ecn2_norm(_MIPP_ a); + ecn2_norm(_MIPP_ b); + MR_OUT + if (zzn2_compare(&(a->x),&(b->x)) && zzn2_compare(&(a->y),&(b->y)) && a->marker==b->marker) return TRUE; + return FALSE; +} + +void ecn2_norm(_MIPD_ ecn2 *a) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return; + if (a->marker!=MR_EPOINT_GENERAL) return; + + MR_IN(194) + + zzn2_inv(_MIPP_ &(a->z)); + + zzn2_mul(_MIPP_ &(a->x),&(a->z),&(a->x)); + zzn2_mul(_MIPP_ &(a->y),&(a->z),&(a->y)); + zzn2_from_zzn(mr_mip->one,&(a->z)); + a->marker=MR_EPOINT_NORMALIZED; + + MR_OUT + +} + +void ecn2_get(_MIPD_ ecn2 *e,zzn2 *x,zzn2 *y,zzn2 *z) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + zzn2_copy(&(e->x),x); + zzn2_copy(&(e->y),y); + if (e->marker==MR_EPOINT_GENERAL) zzn2_copy(&(e->z),z); + else zzn2_from_zzn(mr_mip->one,z); +} + +void ecn2_getxy(ecn2 *e,zzn2 *x,zzn2 *y) +{ + zzn2_copy(&(e->x),x); + zzn2_copy(&(e->y),y); +} + +void ecn2_getx(ecn2 *e,zzn2 *x) +{ + zzn2_copy(&(e->x),x); +} + +void ecn2_getz(_MIPD_ ecn2 *e,zzn2 *z) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (e->marker==MR_EPOINT_GENERAL) zzn2_copy(&(e->z),z); + else zzn2_from_zzn(mr_mip->one,z); +} + +void ecn2_psi(_MIPD_ zzn2 *psi,ecn2 *P) +{ /* apply GLS morphism to P */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + MR_IN(212) + zzn2_conj(_MIPP_ &(P->x),&(P->x)); + zzn2_conj(_MIPP_ &(P->y),&(P->y)); + if (P->marker==MR_EPOINT_GENERAL) + zzn2_conj(_MIPP_ &(P->z),&(P->z)); + zzn2_mul(_MIPP_ &(P->x),&psi[0],&(P->x)); + + MR_OUT +} +/* +static void out_zzn2(zzn2 *x) +{ + redc(x->a,x->a); + redc(x->b,x->b); + cotnum(x->a,stdout); + cotnum(x->b,stdout); + nres(x->a,x->a); + nres(x->b,x->b); +} +*/ + +/* find RHS=(x^2-B)/(x^2-A) */ + +void ecn2_rhs(_MIPD_ zzn2 *x,zzn2 *rhs) +{ /* calculate RHS of elliptic curve equation */ + int twist; + zzn2 A,B; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + twist=mr_mip->TWIST; + + MR_IN(202) + + A.a=mr_mip->w8; + A.b=mr_mip->w9; + B.a=mr_mip->w10; + B.b=mr_mip->w11; + + zzn2_from_zzn(mr_mip->A,&A); + zzn2_from_zzn(mr_mip->B,&B); + + if (twist==MR_QUADRATIC) + { /* quadratic twist */ + zzn2_txx(_MIPP_ &A); + zzn2_txx(_MIPP_ &B); + } + + zzn2_sqr(_MIPP_ x,rhs); + + zzn2_sub(_MIPP_ rhs,&B,&B); + + zzn2_sub(_MIPP_ rhs,&A,&A); + + zzn2_inv(_MIPP_ &A); + zzn2_mul(_MIPP_ &A,&B,rhs); + + MR_OUT +} + +BOOL ecn2_set(_MIPD_ zzn2 *x,zzn2 *y,ecn2 *e) +{ + zzn2 lhs,rhs; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(195) + + lhs.a=mr_mip->w12; + lhs.b=mr_mip->w13; + rhs.a=mr_mip->w14; + rhs.b=mr_mip->w15; + + ecn2_rhs(_MIPP_ x,&rhs); + + zzn2_sqr(_MIPP_ y,&lhs); + + if (!zzn2_compare(&lhs,&rhs)) + { + MR_OUT + return FALSE; + } + + zzn2_copy(x,&(e->x)); + zzn2_copy(y,&(e->y)); + + e->marker=MR_EPOINT_NORMALIZED; + + MR_OUT + return TRUE; +} + +#ifndef MR_NOSUPPORT_COMPRESSION + +BOOL ecn2_setx(_MIPD_ zzn2 *x,ecn2 *e) +{ + zzn2 rhs; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(201) + + rhs.a=mr_mip->w12; + rhs.b=mr_mip->w13; + + ecn2_rhs(_MIPP_ x,&rhs); + + if (!zzn2_iszero(&rhs)) + { + if (!zzn2_qr(_MIPP_ &rhs)) + { + MR_OUT + return FALSE; + } + zzn2_sqrt(_MIPP_ &rhs,&rhs); + } + + zzn2_copy(x,&(e->x)); + zzn2_copy(&rhs,&(e->y)); + + e->marker=MR_EPOINT_NORMALIZED; + + MR_OUT + return TRUE; +} + +#endif + +void ecn2_setxyz(zzn2 *x,zzn2 *y,zzn2 *z,ecn2 *e) +{ + zzn2_copy(x,&(e->x)); + zzn2_copy(y,&(e->y)); + zzn2_copy(z,&(e->z)); + e->marker=MR_EPOINT_GENERAL; +} + +/* Normalise an array of points of length mERNUM) return FALSE; + if (m>MR_MAX_M_T_S) return FALSE; + + MR_IN(215) + + one.a=mr_mip->w12; + one.b=mr_mip->w13; + + zzn2_from_zzn(mr_mip->one,&one); + + for (i=0;ione,&(p[i].z)); + } + MR_OUT + + return TRUE; +} + +BOOL ecn2_add(_MIPD_ ecn2 *Q,ecn2 *P) +{ /* P+=Q */ + BOOL Doubling=FALSE; + int twist; + zzn2 t2,t3,t4; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + t2.a = mr_mip->w8; + t2.b = mr_mip->w9; + t3.a = mr_mip->w10; + t3.b = mr_mip->w11; + t4.a = mr_mip->w12; + t4.b = mr_mip->w13; + + twist=mr_mip->TWIST; + if (mr_mip->ERNUM) return FALSE; + + if (P->marker==MR_EPOINT_INFINITY) + { + ecn2_copy(Q,P); + return Doubling; + } + if (Q->marker==MR_EPOINT_INFINITY) return Doubling; + + if (Q==P) + { + Doubling=TRUE; + if (P->marker==MR_EPOINT_INFINITY) + { /* 2 times infinity == infinity ! */ + return Doubling; + } + } + + MR_IN(205) + + if (!Doubling) + { /* Addition */ + zzn2_add(_MIPP_ &(Q->x),&(Q->y),&t2); + zzn2_add(_MIPP_ &(P->x),&(P->y),&t4); + zzn2_mul(_MIPP_ &t4,&t2,&t4); /* I = t4 = (x1+y1)(x2+y2) */ + if (Q->marker!=MR_EPOINT_NORMALIZED) + { + if (P->marker==MR_EPOINT_NORMALIZED) + zzn2_copy(&(Q->z),&(P->z)); + else + zzn2_mul(_MIPP_ &(Q->z),&(P->z),&(P->z)); /* Z = z1*z2 */ + } + else + { + if (P->marker==MR_EPOINT_NORMALIZED) + zzn2_from_zzn(mr_mip->one,&(P->z)); + } + zzn2_sqr(_MIPP_ &(P->z),&t2); /* P->z = z1.z2 */ + if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) + zzn2_smul(_MIPP_ &t2,mr_mip->B,&t2); + else + zzn2_imul(_MIPP_ &t2,mr_mip->Bsize,&t2); + if (twist==MR_QUADRATIC) zzn2_txx(_MIPP_ &t2); /* B = t2 = d*A^2 */ + zzn2_mul(_MIPP_ &(P->x),&(Q->x),&(P->x)); /* X = x1*x2 */ + zzn2_mul(_MIPP_ &(P->y),&(Q->y),&(P->y)); /* Y = y1*y2 */ + zzn2_sub(_MIPP_ &t4,&(P->x),&t4); + zzn2_sub(_MIPP_ &t4,&(P->y),&t4); /* I = (x1+y1)(x2+y2)-X-Y */ + zzn2_mul(_MIPP_ &(P->x),&(P->y),&t3); /* E = t3 = X*Y */ + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) + zzn2_smul(_MIPP_ &(P->y),mr_mip->A,&(P->y)); + else + zzn2_imul(_MIPP_ &(P->y),mr_mip->Asize,&(P->y)); + if (twist==MR_QUADRATIC) zzn2_txx(_MIPP_ &(P->y)); /* Y=aY */ + zzn2_sub(_MIPP_ &(P->x),&(P->y),&(P->x)); /* X=X-aY */ + zzn2_mul(_MIPP_ &(P->z),&(P->x),&(P->z)); + zzn2_mul(_MIPP_ &(P->z),&t4,&(P->z)); + zzn2_sub(_MIPP_ &t3,&t2,&(P->y)); + zzn2_mul(_MIPP_ &(P->y),&t4,&(P->y)); + zzn2_add(_MIPP_ &t3,&t2,&t4); + zzn2_mul(_MIPP_ &(P->x),&t4,&(P->x)); + } + else + { /* doubling */ + zzn2_add(_MIPP_ &(P->x),&(P->y),&t2); + zzn2_sqr(_MIPP_ &t2,&t2); + zzn2_sqr(_MIPP_ &(P->x),&(P->x)); + zzn2_sqr(_MIPP_ &(P->y),&(P->y)); + zzn2_sub(_MIPP_ &t2,&(P->x),&t2); + zzn2_sub(_MIPP_ &t2,&(P->y),&t2); /* E=(X+Y)^2-X^2-Y^2 */ + + if (P->marker!=MR_EPOINT_NORMALIZED) + zzn2_sqr(_MIPP_ &(P->z),&(P->z)); + else + zzn2_from_zzn(mr_mip->one,&(P->z)); + + zzn2_add(_MIPP_ &(P->z),&(P->z),&(P->z)); + if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) + zzn2_smul(_MIPP_ &(P->z),mr_mip->B,&(P->z)); + else + zzn2_imul(_MIPP_ &(P->z),mr_mip->Bsize,&(P->z)); + if (twist==MR_QUADRATIC) zzn2_txx(_MIPP_ &(P->z)); + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) + zzn2_smul(_MIPP_ &(P->y),mr_mip->A,&(P->y)); + else + zzn2_imul(_MIPP_ &(P->y),mr_mip->Asize,&(P->y)); + if (twist==MR_QUADRATIC) zzn2_txx(_MIPP_ &(P->y)); + zzn2_add(_MIPP_ &(P->x),&(P->y),&t3); + zzn2_sub(_MIPP_ &(P->x),&(P->y),&t4); + zzn2_mul(_MIPP_ &t3,&t4,&(P->x)); + + zzn2_sub(_MIPP_ &t3,&(P->z),&t3); + zzn2_mul(_MIPP_ &t2,&t3,&(P->y)); + zzn2_mul(_MIPP_ &t2,&t4,&(P->z)); + } + + if (zzn2_iszero(&(P->z))) + { + zzn2_from_zzn(mr_mip->one,&(P->x)); + zzn2_zero(&(P->y)); + P->marker=MR_EPOINT_INFINITY; + } + else P->marker=MR_EPOINT_GENERAL; + + MR_OUT + return Doubling; +} + +void ecn2_negate(_MIPD_ ecn2 *u,ecn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + ecn2_copy(u,w); + if (w->marker!=MR_EPOINT_INFINITY) + zzn2_negate(_MIPP_ &(w->x),&(w->x)); +} + + +BOOL ecn2_sub(_MIPD_ ecn2 *Q,ecn2 *P) +{ + BOOL Doubling; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zzn2 lam; + + lam.a = mr_mip->w14; + lam.b = mr_mip->w15; + + ecn2_negate(_MIPP_ Q,Q); + + Doubling=ecn2_add(_MIPP_ Q,P); + + ecn2_negate(_MIPP_ Q,Q); + + return Doubling; +} + +/* + +BOOL ecn2_add_sub(_MIPD_ ecn2 *P,ecn2 *Q,ecn2 *PP,ecn2 *PM) +{ PP=P+Q, PM=P-Q. Assumes P and Q are both normalized, and P!=Q + #ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zzn2 t1,t2,lam; + + if (mr_mip->ERNUM) return FALSE; + + PP->marker=MR_EPOINT_NORMALIZED; + PM->marker=MR_EPOINT_NORMALIZED; + + return TRUE; +} + +*/ + +/* Precomputation of 3P, 5P, 7P etc. into PT. Assume PT[0] contains P */ + +#define MR_PRE_2 (6+2*MR_ECC_STORE_N2) + +static void ecn2_pre(_MIPD_ int sz,BOOL norm,ecn2 *PT) +{ + int i,j; + ecn2 P2; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + +#ifndef MR_STATIC + zzn2 *work=(zzn2 *)mr_alloc(_MIPP_ sz,sizeof(zzn2)); + char *mem = memalloc(_MIPP_ 6+2*sz); +#else + zzn2 work[MR_ECC_STORE_N2]; + char mem[MR_BIG_RESERVE(MR_PRE_2)]; + memset(mem, 0, MR_BIG_RESERVE(MR_PRE_2)); +#endif + j=0; + P2.x.a=mirvar_mem(_MIPP_ mem, j++); + P2.x.b=mirvar_mem(_MIPP_ mem, j++); + P2.y.a=mirvar_mem(_MIPP_ mem, j++); + P2.y.b=mirvar_mem(_MIPP_ mem, j++); + P2.z.a=mirvar_mem(_MIPP_ mem, j++); + P2.z.b=mirvar_mem(_MIPP_ mem, j++); + + for (i=0;i=1;) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + n=mr_naf_window(_MIPP_ k,h,i,&nbs,&nzs,MR_ECC_STORE_N2); + + for (j=0;j0) {nadds++; ecn2_add(_MIPP_ &T[n/2],P);} + if (n<0) {nadds++; ecn2_sub(_MIPP_ &T[(-n)/2],P);} + i-=nbs; + if (nzs) + { + for (j=0;j0) bb=logb2(_MIPP_ e)-1; + else bb=logb2(_MIPP_ f)-1; + + /*ecn2_add_sub(_MIPP_ &P1,&P2,&PS,&PD);*/ + + ecn2_copy(&P1,&PS); + ecn2_copy(&P1,&PD); + ecn2_add(_MIPP_ &P2,&PS); + ecn2_sub(_MIPP_ &P2,&PD); + + ecn2_zero(R); + nadds=0; + + while (bb>=0) + { /* add/subtract method */ + if (mr_mip->user!=NULL) (*mr_mip->user)(); + ecn2_add(_MIPP_ R,R); + e1=h1=e2=h2=0; + + if (mr_testbit(_MIPP_ d,bb)) e2=1; + if (mr_testbit(_MIPP_ e,bb)) h2=1; + if (mr_testbit(_MIPP_ c,bb)) e1=1; + if (mr_testbit(_MIPP_ f,bb)) h1=1; + + if (e1!=h1) + { + if (e2==h2) + { + if (h1==1) {ecn2_add(_MIPP_ &P1,R); nadds++;} + else {ecn2_sub(_MIPP_ &P1,R); nadds++;} + } + else + { + if (h1==1) + { + if (h2==1) {ecn2_add(_MIPP_ &PS,R); nadds++;} + else {ecn2_add(_MIPP_ &PD,R); nadds++;} + } + else + { + if (h2==1) {ecn2_sub(_MIPP_ &PD,R); nadds++;} + else {ecn2_sub(_MIPP_ &PS,R); nadds++;} + } + } + } + else if (e2!=h2) + { + if (h2==1) {ecn2_add(_MIPP_ &P2,R); nadds++;} + else {ecn2_sub(_MIPP_ &P2,R); nadds++;} + } + bb-=1; + } + ecn2_norm(_MIPP_ R); + + MR_OUT +#ifndef MR_STATIC + memkill(_MIPP_ mem, MR_MUL2_JSF_RESERVE); +#else + memset(mem, 0, MR_BIG_RESERVE(MR_MUL2_JSF_RESERVE)); +#endif + return nadds; + +} + +/* General purpose multi-exponentiation engine, using inter-leaving algorithm. Calculate aP+bQ+cR+dS... + Inputs are divided into two groups of sizes wa<4 and wb<4. For the first group if the points are fixed the + first precomputed Table Ta[] may be taken from ROM. For the second group if the points are variable Tb[j] will + have to computed online. Each group has its own precomputed store size, sza (=8?) and szb (=20?) respectively. + The values a,b,c.. are provided in ma[] and mb[], and 3.a,3.b,3.c (as required by the NAF) are provided in + ma3[] and mb3[]. If only one group is required, set wb=0 and pass NULL pointers. + */ + +int ecn2_muln_engine(_MIPD_ int wa,int sza,int wb,int szb,big *ma,big *ma3,big *mb,big *mb3,ecn2 *Ta,ecn2 *Tb,ecn2 *R) +{ /* general purpose interleaving algorithm engine for multi-exp */ + int i,j,tba[4],pba[4],na[4],sa[4],tbb[4],pbb[4],nb[4],sb[4],nbits,nbs,nzs; + int nadds; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + ecn2_zero(R); + + nbits=0; + for (i=0;inbits) nbits=j; } + for (i=0;inbits) nbits=j; } + + nadds=0; + for (i=nbits-1;i>=1;i--) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + if (R->marker!=MR_EPOINT_INFINITY) ecn2_add(_MIPP_ R,R); + for (j=0;j0) {ecn2_add(_MIPP_ &Ta[j*sza+na[j]/2],R); nadds++;} + if (na[j]<0) {ecn2_sub(_MIPP_ &Ta[j*sza+(-na[j])/2],R); nadds++;} + } + else + { + if (na[j]>0) {ecn2_sub(_MIPP_ &Ta[j*sza+na[j]/2],R); nadds++;} + if (na[j]<0) {ecn2_add(_MIPP_ &Ta[j*sza+(-na[j])/2],R); nadds++;} + } + } + } + for (j=0;j0) {ecn2_add(_MIPP_ &Tb[j*szb+nb[j]/2],R); nadds++;} + if (nb[j]<0) {ecn2_sub(_MIPP_ &Tb[j*szb+(-nb[j])/2],R); nadds++;} + } + else + { + if (nb[j]>0) {ecn2_sub(_MIPP_ &Tb[j*szb+nb[j]/2],R); nadds++;} + if (nb[j]<0) {ecn2_add(_MIPP_ &Tb[j*szb+(-nb[j])/2],R); nadds++;} + } + } + } + } + ecn2_norm(_MIPP_ R); + return nadds; +} + +/* Routines to support Galbraith, Lin, Scott (GLS) method for ECC */ +/* requires an endomorphism psi */ + +/* *********************** */ + +/* Precompute T - first half from i.P, second half from i.psi(P) */ +/* norm=TRUE if the table is to be normalised - which it should be */ +/* if it is to be calculated off-line */ + +void ecn2_precomp_gls(_MIPD_ int sz,BOOL norm,ecn2 *P,zzn2 *psi,ecn2 *T) +{ + int i,j; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + j=0; + + MR_IN(219) + + ecn2_norm(_MIPP_ P); + ecn2_copy(P,&T[0]); + + ecn2_pre(_MIPP_ sz,norm,T); /* precompute table */ + for (i=sz;inb || mr_mip->ERNUM) return FALSE; + + t=MR_ROUNDUP(nb,window); + if (t<2) return FALSE; + + MR_IN(221) + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base != mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return FALSE; + } +#endif + + B->window=window; + B->max=nb; + table=mr_alloc(_MIPP_ (1<a=mirvar(_MIPP_ 0); + B->b=mirvar(_MIPP_ 0); + B->n=mirvar(_MIPP_ 0); + copy(a,B->a); + copy(b,B->b); + copy(n,B->n); + + ecurve_init(_MIPP_ a,b,n,MR_BEST); + mr_mip->TWIST=MR_QUADRATIC; + + w.x.a=mirvar(_MIPP_ 0); + w.x.b=mirvar(_MIPP_ 0); + w.y.a=mirvar(_MIPP_ 0); + w.y.b=mirvar(_MIPP_ 0); + w.z.a=mirvar(_MIPP_ 0); + w.z.b=mirvar(_MIPP_ 0); + + w.marker=MR_EPOINT_INFINITY; + ecn2_set(_MIPP_ x,y,&w); + + table[0].x.a=mirvar(_MIPP_ 0); + table[0].x.b=mirvar(_MIPP_ 0); + table[0].y.a=mirvar(_MIPP_ 0); + table[0].y.b=mirvar(_MIPP_ 0); + table[0].z.a=mirvar(_MIPP_ 0); + table[0].z.b=mirvar(_MIPP_ 0); + table[0].marker=MR_EPOINT_INFINITY; + table[1].x.a=mirvar(_MIPP_ 0); + table[1].x.b=mirvar(_MIPP_ 0); + table[1].y.a=mirvar(_MIPP_ 0); + table[1].y.b=mirvar(_MIPP_ 0); + table[1].z.a=mirvar(_MIPP_ 0); + table[1].z.b=mirvar(_MIPP_ 0); + table[1].marker=MR_EPOINT_INFINITY; + + ecn2_copy(&w,&table[1]); + for (j=0;jlen; + bptr=0; + B->table=mr_alloc(_MIPP_ 4*len*(1<table[bptr++]=table[i].x.a->w[j]; + for (j=0;jtable[bptr++]=table[i].x.b->w[j]; + + for (j=0;jtable[bptr++]=table[i].y.a->w[j]; + for (j=0;jtable[bptr++]=table[i].y.b->w[j]; + + mr_free(table[i].x.a); + mr_free(table[i].x.b); + mr_free(table[i].y.a); + mr_free(table[i].y.b); + mr_free(table[i].z.a); + mr_free(table[i].z.b); + } + + mr_free(table); + + MR_OUT + return TRUE; +} + +void ecn2_brick_end(ebrick *B) +{ + mirkill(B->n); + mirkill(B->b); + mirkill(B->a); + mr_free(B->table); +} + +#else + +/* use precomputated table in ROM */ + +void ecn2_brick_init(ebrick *B,const mr_small* rom,big a,big b,big n,int window,int nb) +{ + B->table=rom; + B->a=a; /* just pass a pointer */ + B->b=b; + B->n=n; + B->window=window; /* 2^4=16 stored values */ + B->max=nb; +} + +#endif + +/* +void ecn2_mul_brick(_MIPD_ ebrick *B,big e,zzn2 *x,zzn2 *y) +{ + int i,j,t,len,maxsize,promptr; + ecn2 w,z; + +#ifdef MR_STATIC + char mem[MR_BIG_RESERVE(10)]; +#else + char *mem; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (size(e)<0) mr_berror(_MIPP_ MR_ERR_NEG_POWER); + t=MR_ROUNDUP(B->max,B->window); + + MR_IN(116) + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base != mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return; + } +#endif + + if (logb2(_MIPP_ e) > B->max) + { + mr_berror(_MIPP_ MR_ERR_EXP_TOO_BIG); + MR_OUT + return; + } + + ecurve_init(_MIPP_ B->a,B->b,B->n,MR_BEST); + mr_mip->TWIST=MR_QUADRATIC; + +#ifdef MR_STATIC + memset(mem,0,MR_BIG_RESERVE(10)); +#else + mem=memalloc(_MIPP_ 10); +#endif + + w.x.a=mirvar_mem(_MIPP_ mem, 0); + w.x.b=mirvar_mem(_MIPP_ mem, 1); + w.y.a=mirvar_mem(_MIPP_ mem, 2); + w.y.b=mirvar_mem(_MIPP_ mem, 3); + w.z.a=mirvar_mem(_MIPP_ mem, 4); + w.z.b=mirvar_mem(_MIPP_ mem, 5); + w.marker=MR_EPOINT_INFINITY; + z.x.a=mirvar_mem(_MIPP_ mem, 6); + z.x.b=mirvar_mem(_MIPP_ mem, 7); + z.y.a=mirvar_mem(_MIPP_ mem, 8); + z.y.b=mirvar_mem(_MIPP_ mem, 9); + z.marker=MR_EPOINT_INFINITY; + + len=B->n->len; + maxsize=4*(1<window)*len; + + for (i=t-1;i>=0;i--) + { + j=recode(_MIPP_ e,t,B->window,i); + ecn2_add(_MIPP_ &w,&w); + if (j>0) + { + promptr=4*j*len; + init_big_from_rom(z.x.a,len,B->table,maxsize,&promptr); + init_big_from_rom(z.x.b,len,B->table,maxsize,&promptr); + init_big_from_rom(z.y.a,len,B->table,maxsize,&promptr); + init_big_from_rom(z.y.b,len,B->table,maxsize,&promptr); + z.marker=MR_EPOINT_NORMALIZED; + ecn2_add(_MIPP_ &z,&w); + } + } + ecn2_norm(_MIPP_ &w); + ecn2_getxy(&w,x,y); +#ifndef MR_STATIC + memkill(_MIPP_ mem,10); +#else + memset(mem,0,MR_BIG_RESERVE(10)); +#endif + MR_OUT +} +*/ + +void ecn2_mul_brick_gls(_MIPD_ ebrick *B,big *e,zzn2 *psi,zzn2 *x,zzn2 *y) +{ + int i,j,k,t,len,maxsize,promptr,se[2]; + ecn2 w,z; + +#ifdef MR_STATIC + char mem[MR_BIG_RESERVE(10)]; +#else + char *mem; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + for (k=0;k<2;k++) se[k]=exsign(e[k]); + + t=MR_ROUNDUP(B->max,B->window); + + MR_IN(222) + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base != mr_mip->base2) + { + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); + MR_OUT + return; + } +#endif + + if (logb2(_MIPP_ e[0])>B->max || logb2(_MIPP_ e[1])>B->max) + { + mr_berror(_MIPP_ MR_ERR_EXP_TOO_BIG); + MR_OUT + return; + } + + ecurve_init(_MIPP_ B->a,B->b,B->n,MR_BEST); + mr_mip->TWIST=MR_QUADRATIC; + +#ifdef MR_STATIC + memset(mem,0,MR_BIG_RESERVE(10)); +#else + mem=memalloc(_MIPP_ 10); +#endif + + z.x.a=mirvar_mem(_MIPP_ mem, 0); + z.x.b=mirvar_mem(_MIPP_ mem, 1); + z.y.a=mirvar_mem(_MIPP_ mem, 2); + z.y.b=mirvar_mem(_MIPP_ mem, 3); + z.marker=MR_EPOINT_INFINITY; + + w.x.a=mirvar_mem(_MIPP_ mem, 4); + w.x.b=mirvar_mem(_MIPP_ mem, 5); + w.y.a=mirvar_mem(_MIPP_ mem, 6); + w.y.b=mirvar_mem(_MIPP_ mem, 7); + w.z.a=mirvar_mem(_MIPP_ mem, 8); + w.z.b=mirvar_mem(_MIPP_ mem, 9); + w.marker=MR_EPOINT_INFINITY; + + len=B->n->len; + maxsize=4*(1<window)*len; + + for (i=t-1;i>=0;i--) + { + ecn2_add(_MIPP_ &w,&w); + for (k=0;k<2;k++) + { + j=recode(_MIPP_ e[k],t,B->window,i); + if (j>0) + { + promptr=4*j*len; + init_big_from_rom(z.x.a,len,B->table,maxsize,&promptr); + init_big_from_rom(z.x.b,len,B->table,maxsize,&promptr); + init_big_from_rom(z.y.a,len,B->table,maxsize,&promptr); + init_big_from_rom(z.y.b,len,B->table,maxsize,&promptr); + z.marker=MR_EPOINT_NORMALIZED; + if (k==1) ecn2_psi(_MIPP_ psi,&z); + if (se[k]==PLUS) ecn2_add(_MIPP_ &z,&w); + else ecn2_sub(_MIPP_ &z,&w); + } + } + } + ecn2_norm(_MIPP_ &w); + ecn2_getxy(&w,x,y); +#ifndef MR_STATIC + memkill(_MIPP_ mem,10); +#else + memset(mem,0,MR_BIG_RESERVE(10)); +#endif + MR_OUT +} + +#endif + +#ifndef MR_NO_ECC_MULTIADD + +void ecn2_mult4(_MIPD_ big *e,ecn2 *P,ecn2 *R) +{ /* R=e[0]*P[0]+e[1]*P[1]+ .... e[n-1]*P[n-1] */ + int i,j,k,l,nb,ea,c; + ecn2 G[16]; + zzn2 work[16]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 120); +#else + char mem[MR_BIG_RESERVE(120)]; + memset(mem, 0, MR_BIG_RESERVE(120)); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(243) + + l=0; + for (k=1;k<16;k++) + { + G[k].x.a=mirvar_mem(_MIPP_ mem, l++); + G[k].x.b=mirvar_mem(_MIPP_ mem, l++); + G[k].y.a=mirvar_mem(_MIPP_ mem, l++); + G[k].y.b=mirvar_mem(_MIPP_ mem, l++); + G[k].z.a=mirvar_mem(_MIPP_ mem, l++); + G[k].z.b=mirvar_mem(_MIPP_ mem, l++); + G[k].marker=MR_EPOINT_INFINITY; + + i=k; j=1; c=0; while (i>=(2*j)) {j*=2; c++;} + if (i>j) ecn2_copy(&G[i-j],&G[k]); + ecn2_add(_MIPP_ &P[c],&G[k]); + } + + for (i=0;i<15;i++) + { + work[i].a=mirvar_mem(_MIPP_ mem, l++); + work[i].b=mirvar_mem(_MIPP_ mem, l++); + } + + ecn2_multi_norm(_MIPP_ 15,work,&G[1]); + + nb=0; + for (j=0;j<4;j++) if ((k=logb2(_MIPP_ e[j])) > nb) nb=k; + + ecn2_zero(R); + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + for (i=nb-1;i>=0;i--) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + ea=0; + k=1; + for (j=0;j<4;j++) + { + if (mr_testbit(_MIPP_ e[j],i)) ea+=k; + k<<=1; + } + ecn2_add(_MIPP_ R,R); + if (ea!=0) ecn2_add(_MIPP_ &G[ea],R); + } +#ifndef MR_ALWAYS_BINARY + } + else mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); +#endif +#ifndef MR_STATIC + memkill(_MIPP_ mem,120); +#else + memset(mem, 0, MR_BIG_RESERVE(120)); +#endif + + MR_OUT +} + +#ifndef MR_STATIC + +void ecn2_multn(_MIPD_ int n,big *e,ecn2 *P,ecn2 *R) +{ /* R=e[0]*P[0]+e[1]*P[1]+ .... e[n-1]*P[n-1] */ + int i,j,k,l,nb,ea,c; + int m=1<ERNUM) return; + + MR_IN(223) + + G= (ecn2 *)mr_alloc(_MIPP_ m,sizeof(ecn2)); + work=(zzn2 *)mr_alloc(_MIPP_ m,sizeof(zzn2)); + + l=0; + for (k=1;k=(2*j)) {j*=2; c++;} + if (i>j) ecn2_copy(&G[i-j],&G[k]); + ecn2_add(_MIPP_ &P[c],&G[k]); + } + + for (i=0;i nb) nb=k; + + ecn2_zero(R); + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + for (i=nb-1;i>=0;i--) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + ea=0; + k=1; + for (j=0;j. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL fast fourier multiplication routine, using 3 prime method. + * mrfast.c - only faster for very high precision multiplication + * of numbers > about 4096 bits (see below) + * See "The Fast Fourier Transform in a Finite Field" by J.M. Pollard, + * Mathematics of Computation, Vol. 25, No. 114, April 1971, pp365-374 + * Also Knuth Vol. 2, Chapt. 4.3.3 + * + * Takes time preportional to 9+15N+9N.lg(N) to multiply two different + * N digit numbers. This reduces to 6+18N+6N.lg(N) when squaring. + * The classic method takes N.N and N(N+1)/2 respectively + * + * Fast Polynomial arithmetic + * + * See "A New Polynomial Factorisation Algorithm and its Implementation" + * by Victor Shoup, Jl. Symbolic Computation 1996 + * Uses FFT method for fast arithmetic of large degree polynomials + * + */ + +#include +#include "miracl.h" + +#ifdef MR_FP +#include +#endif + +#ifdef MR_WIN64 +#include +#endif + +#ifndef MR_STATIC + +static mr_utype twop(int n) +{ /* 2^n */ +#ifdef MR_FP + int i; +#endif + mr_utype r=1; + if (n==0) return r; +#ifdef MR_FP + for (i=0;icheck=OFF; + multiply(_MIPP_ m1,m2,mr_mip->w5); + premult(_MIPP_ mr_mip->w5,2*newn+1,mr_mip->w5); + kk=mr_shiftbits((mr_small)1,MIRACL-2-logn); + if (mr_mip->base!=0) while (4*kk*newn>mr_mip->base) kk=mr_shiftbits(kk,-1); + + pr=0; + while (size(mr_mip->w5)>0) + { /* find out how many primes will be needed */ + do + { + kk--; + p=kk*newn+1; + } while(spmd((mr_small)2,(mr_small)(p-1),p)!=1); +#ifdef MR_FP_ROUNDING + mr_sdiv(_MIPP_ mr_mip->w5,p,mr_invert(p),mr_mip->w5); +#else + mr_sdiv(_MIPP_ mr_mip->w5,p,mr_mip->w5); +#endif + pr++; + } + mr_mip->check=ON; +/* if nothing has changed, don't recalculate */ + if (logn<=mr_mip->logN && pr==mr_mip->nprimes) return pr; + fft_reset(_MIPPO_ ); + + + mr_mip->prime=(mr_utype *)mr_alloc(_MIPP_ pr,sizeof(mr_utype)); + mr_mip->inverse=(mr_utype *)mr_alloc(_MIPP_ pr,sizeof(mr_utype)); + mr_mip->roots=(mr_utype**)mr_alloc(_MIPP_ pr,sizeof(mr_utype *)); + mr_mip->t= (mr_utype **)mr_alloc(_MIPP_ pr,sizeof(mr_utype *)); + mr_mip->cr=(mr_utype *)mr_alloc(_MIPP_ pr,sizeof(mr_utype)); + mr_mip->wa=(mr_utype *)mr_alloc(_MIPP_ newn,sizeof(mr_utype)); + mr_mip->wb=(mr_utype *)mr_alloc(_MIPP_ newn,sizeof(mr_utype)); + mr_mip->wc=(mr_utype *)mr_alloc(_MIPP_ newn,sizeof(mr_utype)); + + kk=mr_shiftbits((mr_small)1,MIRACL-2-logn); + if (mr_mip->base!=0) while (4*kk*newn>mr_mip->base) kk=mr_shiftbits(kk,-1); + for (i=0;iroots[i]=(mr_utype *)mr_alloc(_MIPP_ newn,sizeof(mr_utype)); + mr_mip->t[i]=(mr_utype *)mr_alloc(_MIPP_ newn,sizeof(mr_utype)); + + do + { + kk--; + p=kk*newn+1; + } while(spmd((mr_small)2,(mr_small)(p-1),p)!=1); + + proot=p-1; + for (j=1;jroots[i][0]=proot; /* build residue table */ + for (j=1;jroots[i][j]=smul(mr_mip->roots[i][j-1],proot,p); + mr_mip->inverse[i]=invers((mr_small)newn,p); + mr_mip->prime[i]=p; + } + + mr_mip->logN=logn; + + mr_mip->nprimes=pr; +/* set up chinese remainder structure */ + if (cr) + if (!scrt_init(_MIPP_ &mr_mip->chin,pr,mr_mip->prime)) fft_reset(_MIPPO_ ); + return pr; +} + +void fft_reset(_MIPDO_ ) +{ /* reclaim any space used by FFT */ + int i; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->degree!=0) + { /* clear any precomputed tables */ + for (i=0;inprimes;i++) + { + mr_free(mr_mip->s1[i]); + mr_free(mr_mip->s2[i]); + } + mr_free(mr_mip->s1); + mr_free(mr_mip->s2); + mr_mip->degree=0; + } + + if (mr_mip->logN!=0) + { /* clear away old stuff */ + for (i=0;inprimes;i++) + { + mr_free(mr_mip->roots[i]); + mr_free(mr_mip->t[i]); + } + mr_free(mr_mip->wa); + mr_free(mr_mip->wb); + mr_free(mr_mip->wc); + mr_free(mr_mip->cr); + mr_free(mr_mip->t); + mr_free(mr_mip->roots); + mr_free(mr_mip->inverse); + mr_free(mr_mip->prime); + mr_mip->nprimes=0; + mr_mip->logN=0; + mr_mip->same=FALSE; + } +/* clear CRT structure */ + if (mr_mip->chin.NP!=0) scrt_end(&mr_mip->chin); +} + +void mr_dif_fft(_MIPD_ int logn,int pr,mr_utype *data) +{ /* decimate-in-frequency fourier transform */ + int mmax,m,j,k,istep,i,ii,jj,newn,offset; + mr_utype w,temp,prime,*roots; +#ifdef MR_NOASM + mr_large dble,ldres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_FP_ROUNDING + mr_large iprime; +#endif + prime=mr_mip->prime[pr]; + roots=mr_mip->roots[pr]; +#ifdef MR_FP_ROUNDING + iprime=mr_invert(prime); +#endif + + newn=(1<logN-logn); + mmax=newn; + for (k=0;k>=1; + ii=newn; + jj=newn/istep; + ii-=jj; + for (i=0;i=prime) data[i]-=prime; + data[j]=temp; + } + for (m=1;m=prime) data[i]-=prime; + +#ifdef MR_NOASM + dble=(mr_large)w*temp; +#ifdef MR_FP_ROUNDING + data[j]=(mr_utype)(dble-(mr_large)prime*MR_LROUND(dble*iprime)); +#else + data[j]=(mr_utype)(dble-(mr_large)prime*MR_LROUND(dble/prime)); +#endif +#else +#ifdef MR_FP_ROUNDING + imuldiv(w,temp,(mr_small)0,prime,iprime,(mr_small *)&data[j]); +#else + muldiv(w,temp,(mr_small)0,prime,(mr_small *)&data[j]); +#endif +#endif + } +#endif + } + } +} + +void mr_dit_fft(_MIPD_ int logn,int pr,mr_utype *data) +{ /* decimate-in-time inverse fourier transform */ + int mmax,m,j,k,i,istep,ii,jj,newn,offset; + mr_utype w,temp,prime,*roots; +#ifdef MR_NOASM + mr_large dble,ldres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_FP_ROUNDING + mr_large iprime; +#endif + prime=mr_mip->prime[pr]; + roots=mr_mip->roots[pr]; + offset=(mr_mip->logN-logn); +#ifdef MR_FP_ROUNDING + iprime=mr_invert(prime); +#endif + newn=(1<=prime) data[i]-=prime; + } + for (m=1;m=prime) data[i]-=prime; + } +#endif + } + mmax=istep; + } +} + +static void modxn_1(_MIPD_ int n,int deg,big *x) +{ /* set X (of degree deg) =X mod x^n-1 = X%x^n + X/x^n */ + int i; + for (i=0;n+i<=deg;i++) + { + nres_modadd(_MIPP_ x[i],x[n+i],x[i]); + zero(x[n+i]); + } +} + +BOOL mr_poly_rem(_MIPD_ int dg,big *G,big *R) +{ /* G is a polynomial of degree dg - G is overwritten */ + int i,j,newn,logn,np,n; + mr_utype p,inv,fac; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_FP_ROUNDING + mr_large ip; +#endif + + n=mr_mip->degree; /* degree of modulus */ + if (n==0) return FALSE; /* the preset tables have been destroyed */ + np=mr_mip->nprimes; + + newn=1; logn=0; + while (2*n>newn) { newn<<=1; logn++; } + + for (i=0;iprime[i]; +#ifdef MR_FP_ROUNDING + ip=mr_invert(p); + for (j=n;j<=dg;j++) + mr_mip->t[i][j-n]=mr_sdiv(_MIPP_ G[j],p,ip,mr_mip->w1); +#else + for (j=n;j<=dg;j++) + mr_mip->t[i][j-n]=mr_sdiv(_MIPP_ G[j],p,mr_mip->w1); +#endif + for (j=dg-n+1;jt[i][j]=0; + mr_dif_fft(_MIPP_ logn,i,mr_mip->t[i]); + for (j=0;jt[i][j],mr_mip->s1[i][j],(mr_small)0,p,ip,(mr_small *)&mr_mip->t[i][j]); +#else + muldiv(mr_mip->t[i][j],mr_mip->s1[i][j],(mr_small)0,p,(mr_small *)&mr_mip->t[i][j]); +#endif + mr_dit_fft(_MIPP_ logn,i,mr_mip->t[i]); + inv=mr_mip->inverse[i]; + if (mr_mip->logN > logn) + { /* adjust 1/N log p for N/2, N/4 etc */ + fac=twop(mr_mip->logN-logn); + inv=smul(fac,inv,p); + } + for (j=0;jt[i][j+n-1],inv,(mr_small)0,p,ip,(mr_small *)&mr_mip->t[i][j+n-1]); +#else + muldiv(mr_mip->t[i][j+n-1],inv,(mr_small)0,p,(mr_small *)&mr_mip->t[i][j+n-1]); +#endif + } + + mr_mip->check=OFF; + mr_shift(_MIPP_ mr_mip->modulus,(int)mr_mip->modulus->len,mr_mip->w6); + /* w6 = N.R */ + for (j=0;jcr[i]=mr_mip->t[i][j+n-1]; + scrt(_MIPP_ &mr_mip->chin,mr_mip->cr,mr_mip->w7); + divide(_MIPP_ mr_mip->w7,mr_mip->w6,mr_mip->w6); /* R[j] may be too big for redc */ + redc(_MIPP_ mr_mip->w7,R[j]); + } + mr_mip->check=ON; + + for (i=0;iprime[i]; +#ifdef MR_FP_ROUNDING + ip=mr_invert(p); + for (j=0;jt[i][j]=mr_sdiv(_MIPP_ R[j],p,ip,mr_mip->w1); +#else + for (j=0;jt[i][j]=mr_sdiv(_MIPP_ R[j],p,mr_mip->w1); +#endif + for (j=n;j<1+newn/2;j++) mr_mip->t[i][j]=0; + + mr_dif_fft(_MIPP_ logn-1,i,mr_mip->t[i]); /* Note: Half size */ + for (j=0;jt[i][j],mr_mip->s2[i][j],(mr_small)0,p,ip,(mr_small *)&mr_mip->t[i][j]); +#else + muldiv(mr_mip->t[i][j],mr_mip->s2[i][j],(mr_small)0,p,(mr_small *)&mr_mip->t[i][j]); +#endif + mr_dit_fft(_MIPP_ logn-1,i,mr_mip->t[i]); + + inv=mr_mip->inverse[i]; + if (mr_mip->logN > logn-1) + { + fac=twop(mr_mip->logN-logn+1); + inv=smul(fac,inv,p); + } + for (j=0;jt[i][j],inv,(mr_small)0,p,ip,(mr_small *)&mr_mip->t[i][j]); +#else + muldiv(mr_mip->t[i][j],inv,(mr_small)0,p,(mr_small *)&mr_mip->t[i][j]); +#endif + } + + modxn_1(_MIPP_ newn/2,dg,G); /* G=G mod 2^x - 1 */ + + mr_mip->check=OFF; + mr_shift(_MIPP_ mr_mip->modulus,(int)mr_mip->modulus->len,mr_mip->w6); + /* w6 = N.R */ + for (j=0;jcr[i]=mr_mip->t[i][j]; + scrt(_MIPP_ &mr_mip->chin,mr_mip->cr,mr_mip->w7); + divide(_MIPP_ mr_mip->w7,mr_mip->w6,mr_mip->w6); /* R[j] may be too big for redc */ + redc(_MIPP_ mr_mip->w7,R[j]); + nres_modsub(_MIPP_ G[j],R[j],R[j]); + + } + mr_mip->check=ON; + + return TRUE; +} + +void mr_polymod_set(_MIPD_ int n, big *rf,big *f) +{ /* n is degree of f */ + int i,j,np,newn,logn,degree; + mr_utype p; + big *F; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_FP_ROUNDING + mr_large ip; +#endif + degree=2*n; + newn=1; logn=0; + while (degree>newn) { newn<<=1; logn++; } + + if (mr_mip->degree!=0) + { + for (i=0;inprimes;i++) + { + mr_free(mr_mip->s1[i]); + mr_free(mr_mip->s2[i]); + } + mr_free(mr_mip->s1); + mr_free(mr_mip->s2); + } + + if (mr_mip->logNmodulus,mr_mip->modulus,TRUE); + else np=mr_mip->nprimes; + + mr_mip->degree=n; + mr_mip->s1=(mr_utype **)mr_alloc(_MIPP_ np,sizeof(mr_utype *)); + mr_mip->s2=(mr_utype **)mr_alloc(_MIPP_ np,sizeof(mr_utype *)); + + F=(big *)mr_alloc(_MIPP_ n+1,sizeof(big)); + for (i=0;i<=n;i++) + { + F[i]=mirvar(_MIPP_ 0); + if (f[i]!=NULL) copy(f[i],F[i]); + } + + modxn_1(_MIPP_ newn/2,n,F); + + for (i=0;is1[i]=(mr_utype *)mr_alloc(_MIPP_ newn,sizeof(mr_utype)); + mr_mip->s2[i]=(mr_utype *)mr_alloc(_MIPP_ 1+newn/2,sizeof(mr_utype)); + + p=mr_mip->prime[i]; +#ifdef MR_FP_ROUNDING + ip=mr_invert(p); +#endif + for (j=0;js1[i][j]=0; +#ifdef MR_FP_ROUNDING + else mr_mip->s1[i][j]=mr_sdiv(_MIPP_ rf[j],p,ip,mr_mip->w1); +#else + else mr_mip->s1[i][j]=mr_sdiv(_MIPP_ rf[j],p,mr_mip->w1); +#endif + } + mr_dif_fft(_MIPP_ logn,i,mr_mip->s1[i]); + + for (j=0;j<=n;j++) +#ifdef MR_FP_ROUNDING + mr_mip->s2[i][j]=mr_sdiv(_MIPP_ F[j],p,ip,mr_mip->w1); +#else + mr_mip->s2[i][j]=mr_sdiv(_MIPP_ F[j],p,mr_mip->w1); +#endif + mr_dif_fft(_MIPP_ logn-1,i,mr_mip->s2[i]); + } + for (i=0;i<=n;i++) mr_free(F[i]); + mr_free(F); +} + +int mr_ps_zzn_mul(_MIPD_ int deg,big *x,big *y,big *z) +{ + int i,j,newn,logn,np; + mr_utype inv,p,fac; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_FP_ROUNDING + mr_large ip; +#endif + newn=1; logn=0; + while (2*deg>newn) { newn <<=1; logn++; } + if (mr_mip->logNmodulus,mr_mip->modulus,TRUE); + else np=mr_mip->nprimes; + + for (i=0;iprime[i]; +#ifdef MR_FP_ROUNDING + ip=mr_invert(p); +#endif + for (j=0;jwa[j]=0; +#ifdef MR_FP_ROUNDING + else mr_mip->wa[j]=mr_sdiv(_MIPP_ x[j],p,ip,mr_mip->w1); +#else + else mr_mip->wa[j]=mr_sdiv(_MIPP_ x[j],p,mr_mip->w1); +#endif + } + for (j=deg;jwa[j]=0; + + mr_dif_fft(_MIPP_ logn,i,mr_mip->wa); + for (j=0;jt[i][j]=0; +#ifdef MR_FP_ROUNDING + else mr_mip->t[i][j]=mr_sdiv(_MIPP_ y[j],p,ip,mr_mip->w1); +#else + else mr_mip->t[i][j]=mr_sdiv(_MIPP_ y[j],p,mr_mip->w1); +#endif + } + for (j=deg;jt[i][j]=0; + mr_dif_fft(_MIPP_ logn,i,mr_mip->t[i]); + /* multiply FFTs */ + for (j=0;jwa[j],mr_mip->t[i][j],(mr_small)0,p,ip,(mr_small *)&mr_mip->t[i][j]); +#else + muldiv(mr_mip->wa[j],mr_mip->t[i][j],(mr_small)0,p,(mr_small *)&mr_mip->t[i][j]); +#endif + mr_dit_fft(_MIPP_ logn,i,mr_mip->t[i]); /* np*N*lgN */ + + inv=mr_mip->inverse[i]; + if (mr_mip->logN > logn) + { + fac=twop(mr_mip->logN-logn); + inv=smul(fac,inv,p); + } + for (j=0;jt[i][j],inv,(mr_small)0,p,ip,(mr_small *)&mr_mip->t[i][j]); +#else + muldiv(mr_mip->t[i][j],inv,(mr_small)0,p,(mr_small *)&mr_mip->t[i][j]); +#endif + } + mr_mip->check=OFF; + mr_shift(_MIPP_ mr_mip->modulus,(int)mr_mip->modulus->len,mr_mip->w6); + for (j=0;jcr[i]=mr_mip->t[i][j]; + scrt(_MIPP_ &mr_mip->chin,mr_mip->cr,mr_mip->w7); + divide(_MIPP_ mr_mip->w7,mr_mip->w6,mr_mip->w6); + redc(_MIPP_ mr_mip->w7,z[j]); + } + mr_mip->check=ON; + return np; +} + +int mr_ps_big_mul(_MIPD_ int deg,big *x,big *y,big *z) +{ /* Multiply two power series with large integer parameters */ + int i,j,newn,logn,np; + mr_utype inv,p,fac; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_FP_ROUNDING + mr_large ip; +#endif + newn=1; logn=0; + while (2*deg>newn) { newn <<=1; logn++; } + + zero(mr_mip->w2); + zero(mr_mip->w4); + +/* find biggest element in each series */ + for (i=0;iw3); + if (mr_compare(mr_mip->w3,mr_mip->w2)>0) copy(mr_mip->w3,mr_mip->w2); + } + if (y[i]!=NULL) + { + absol(y[i],mr_mip->w3); + if (mr_compare(mr_mip->w3,mr_mip->w4)>0) copy(mr_mip->w3,mr_mip->w4); + } + } + premult(_MIPP_ mr_mip->w4,2,mr_mip->w4); /* range is +ve and -ve */ + /* so extra factor of 2 included */ + + np=mr_fft_init(_MIPP_ logn,mr_mip->w4,mr_mip->w2,TRUE); + convert(_MIPP_ 1,mr_mip->w3); +/* compute coefficients modulo fft primes */ + for (i=0;iprime[i]; +#ifdef MR_FP_ROUNDING + ip=mr_invert(p); +#endif + mr_pmul(_MIPP_ mr_mip->w3,p,mr_mip->w3); + for (j=0;jwa[j]=0; + else + { + if (size(x[j])>=0) + { + copy(x[j],mr_mip->w1); +#ifdef MR_FP_ROUNDING + mr_mip->wa[j]=mr_sdiv(_MIPP_ mr_mip->w1,p,ip,mr_mip->w1); +#else + mr_mip->wa[j]=mr_sdiv(_MIPP_ mr_mip->w1,p,mr_mip->w1); +#endif + } + else + { + negify(x[j],mr_mip->w1); +#ifdef MR_FP_ROUNDING + mr_mip->wa[j]=p-mr_sdiv(_MIPP_ mr_mip->w1,p,ip,mr_mip->w1); +#else + mr_mip->wa[j]=p-mr_sdiv(_MIPP_ mr_mip->w1,p,mr_mip->w1); +#endif + } + } + } + for (j=deg;jwa[j]=0; + + mr_dif_fft(_MIPP_ logn,i,mr_mip->wa); + for (j=0;jt[i][j]=0; + else + { + if (size(y[j])>=0) + { + copy(y[j],mr_mip->w1); +#ifdef MR_FP_ROUNDING + mr_mip->t[i][j]=mr_sdiv(_MIPP_ mr_mip->w1,p,ip,mr_mip->w1); +#else + mr_mip->t[i][j]=mr_sdiv(_MIPP_ mr_mip->w1,p,mr_mip->w1); +#endif + } + else + { + negify(y[j],mr_mip->w1); +#ifdef MR_FP_ROUNDING + mr_mip->t[i][j]=p-mr_sdiv(_MIPP_ mr_mip->w1,p,ip,mr_mip->w1); +#else + mr_mip->t[i][j]=p-mr_sdiv(_MIPP_ mr_mip->w1,p,mr_mip->w1); +#endif + } + } + } + for (j=deg;jt[i][j]=0; + mr_dif_fft(_MIPP_ logn,i,mr_mip->t[i]); + /* multiply FFTs */ + for (j=0;jwa[j],mr_mip->t[i][j],(mr_small)0,p,ip,(mr_small *)&mr_mip->t[i][j]); +#else + muldiv(mr_mip->wa[j],mr_mip->t[i][j],(mr_small)0,p,(mr_small *)&mr_mip->t[i][j]); +#endif + mr_dit_fft(_MIPP_ logn,i,mr_mip->t[i]); /* np*N*lgN */ + + inv=mr_mip->inverse[i]; + if (mr_mip->logN > logn) + { + fac=twop(mr_mip->logN-logn); + inv=smul(fac,inv,p); + } + for (j=0;jt[i][j],inv,(mr_small)0,p,ip,(mr_small *)&mr_mip->t[i][j]); +#else + muldiv(mr_mip->t[i][j],inv,(mr_small)0,p,(mr_small *)&mr_mip->t[i][j]); +#endif + } + /* w3 is product of chinese primes */ + decr(_MIPP_ mr_mip->w3,1,mr_mip->w4); + subdiv(_MIPP_ mr_mip->w4,2,mr_mip->w4); /* find mid-point of range */ + + for (j=0;jcr[i]=mr_mip->t[i][j]; + scrt(_MIPP_ &mr_mip->chin,mr_mip->cr,z[j]); /* N*3*np*np/2 */ + if (mr_compare(z[j],mr_mip->w4)>=0) + { /* In higher half of range, so number is negative */ + subtract(_MIPP_ mr_mip->w3,z[j],z[j]); + negify(z[j],z[j]); + } + } /* np*np*N/4 */ + return np; +} + +int mr_poly_mul(_MIPD_ int degx,big *x,int degy,big *y,big *z) +{ /* Multiply two polynomials. The big arrays are of size degree */ + int i,j,newn,logn,np,degree; + mr_utype inv,p,fac; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_FP_ROUNDING + mr_large ip; +#endif + degree=degx+degy; + if (x==y) + { + mr_poly_sqr(_MIPP_ degx,x,z); + return degree; + } + newn=1; logn=0; + while (degree+1>newn) { newn<<=1; logn++; } + + if (mr_mip->logNmodulus,mr_mip->modulus,TRUE); + else np=mr_mip->nprimes; + +/* compute coefficients modulo fft primes */ + for (i=0;iprime[i]; +#ifdef MR_FP_ROUNDING + ip=mr_invert(p); +#endif + for (j=0;j<=degx;j++) + { + if (x[j]==NULL) mr_mip->wa[j]=0; +#ifdef MR_FP_ROUNDING + else mr_mip->wa[j]=mr_sdiv(_MIPP_ x[j],p,ip,mr_mip->w1); /* np*np*N/2 muldivs */ +#else + else mr_mip->wa[j]=mr_sdiv(_MIPP_ x[j],p,mr_mip->w1); /* np*np*N/2 muldivs */ +#endif + } + for (j=degx+1;jwa[j]=0; + mr_dif_fft(_MIPP_ logn,i,mr_mip->wa); /* np*N*lgN */ + + for (j=0;j<=degy;j++) + { + if (y[j]==NULL) mr_mip->t[i][j]=0; +#ifdef MR_FP_ROUNDING + else mr_mip->t[i][j]=mr_sdiv(_MIPP_ y[j],p,ip,mr_mip->w1); /* np*np*N/2 */ +#else + else mr_mip->t[i][j]=mr_sdiv(_MIPP_ y[j],p,mr_mip->w1); /* np*np*N/2 */ +#endif + } + for (j=degy+1;jt[i][j]=0; + mr_dif_fft(_MIPP_ logn,i,mr_mip->t[i]); /* np*N*lgN */ + + /* multiply FFTs */ + for (j=0;jwa[j],mr_mip->t[i][j],(mr_small)0,p,ip,(mr_small *)&mr_mip->t[i][j]); +#else + muldiv(mr_mip->wa[j],mr_mip->t[i][j],(mr_small)0,p,(mr_small *)&mr_mip->t[i][j]); +#endif + mr_dit_fft(_MIPP_ logn,i,mr_mip->t[i]); /* np*N*lgN */ + + inv=mr_mip->inverse[i]; + if (mr_mip->logN > logn) + { + fac=twop(mr_mip->logN-logn); + inv=smul(fac,inv,p); + } + for (j=0;j<=degree;j++) /* np*N */ +#ifdef MR_FP_ROUNDING + imuldiv(mr_mip->t[i][j],inv,(mr_small)0,p,ip,(mr_small *)&mr_mip->t[i][j]); +#else + muldiv(mr_mip->t[i][j],inv,(mr_small)0,p,(mr_small *)&mr_mip->t[i][j]); +#endif + } + mr_mip->check=OFF; + mr_shift(_MIPP_ mr_mip->modulus,(int)mr_mip->modulus->len,mr_mip->w6); + /* w6 = N.R */ + for (j=0;j<=degree;j++) + { + for (i=0;icr[i]=mr_mip->t[i][j]; + scrt(_MIPP_ &mr_mip->chin,mr_mip->cr,mr_mip->w7); /* N*3*np*np/2 */ + divide(_MIPP_ mr_mip->w7,mr_mip->w6,mr_mip->w6); /* z[j] may be too big for redc */ + redc(_MIPP_ mr_mip->w7,z[j]); + } /* np*np*N/4 */ + mr_mip->check=ON; + return degree; +} + +int mr_poly_sqr(_MIPD_ int degx,big *x,big *z) +{ /* Multiply two polynomials. The big arrays are of size degree */ + int i,j,newn,logn,np,degree; + mr_utype inv,p,fac; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_FP_ROUNDING + mr_large ip; +#endif + degree=2*degx; + newn=1; logn=0; + while (degree+1>newn) { newn<<=1; logn++; } + + if (mr_mip->logNmodulus,mr_mip->modulus,TRUE); + else np=mr_mip->nprimes; + +/* compute coefficients modulo fft primes */ + for (i=0;iprime[i]; +#ifdef MR_FP_ROUNDING + ip=mr_invert(p); +#endif + for (j=0;j<=degx;j++) + { + if (x[j]==NULL) mr_mip->t[i][j]=0; +#ifdef MR_FP_ROUNDING + else mr_mip->t[i][j]=mr_sdiv(_MIPP_ x[j],p,ip,mr_mip->w1); +#else + else mr_mip->t[i][j]=mr_sdiv(_MIPP_ x[j],p,mr_mip->w1); +#endif + } + for (j=degx+1;jt[i][j]=0; + mr_dif_fft(_MIPP_ logn,i,mr_mip->t[i]); + + /* multiply FFTs */ + for (j=0;jt[i][j],mr_mip->t[i][j],(mr_small)0,p,ip,(mr_small *)&mr_mip->t[i][j]); +#else + muldiv(mr_mip->t[i][j],mr_mip->t[i][j],(mr_small)0,p,(mr_small *)&mr_mip->t[i][j]); +#endif + mr_dit_fft(_MIPP_ logn,i,mr_mip->t[i]); + + inv=mr_mip->inverse[i]; + if (mr_mip->logN > logn) + { /* adjust 1/N log p for smaller N */ + fac=twop(mr_mip->logN-logn); + inv=smul(fac,inv,p); + } + for (j=0;j<=degree;j++) +#ifdef MR_FP_ROUNDING + imuldiv(mr_mip->t[i][j],inv,(mr_small)0,p,ip,(mr_small *)&mr_mip->t[i][j]); +#else + muldiv(mr_mip->t[i][j],inv,(mr_small)0,p,(mr_small *)&mr_mip->t[i][j]); +#endif + } + mr_mip->check=OFF; + mr_shift(_MIPP_ mr_mip->modulus,(int)mr_mip->modulus->len,mr_mip->w6); + /* w6 = N.R */ + for (j=0;j<=degree;j++) + { /* apply CRT to each column */ + for (i=0;icr[i]=mr_mip->t[i][j]; + + scrt(_MIPP_ &mr_mip->chin,mr_mip->cr,mr_mip->w7); + divide(_MIPP_ mr_mip->w7,mr_mip->w6,mr_mip->w6); /* z[j] may be too big for redc */ + redc(_MIPP_ mr_mip->w7,z[j]); + } + mr_mip->check=ON; + + return degree; +} + +static BOOL init_it(_MIPD_ int logn) +{ /* find primes, table of roots, inverses etc for new N */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + +#ifdef MR_ITANIUM + mr_small tm; +#endif +#ifdef MR_WIN64 + mr_small tm; +#endif + + zero(mr_mip->w15); + mr_mip->w15->len=2; mr_mip->w15->w[0]=0; mr_mip->w15->w[1]=1; + + if (mr_fft_init(_MIPP_ logn,mr_mip->w15,mr_mip->w15,FALSE)!=3) return FALSE; + + mr_mip->const1=invers(mr_mip->prime[0],mr_mip->prime[1]); + mr_mip->const2=invers(mr_mip->prime[0],mr_mip->prime[2]); + mr_mip->const3=invers(mr_mip->prime[1],mr_mip->prime[2]); + if (mr_mip->base==0) + { +#ifndef MR_NOFULLWIDTH + mr_mip->msw=muldvd(mr_mip->prime[0],mr_mip->prime[1],(mr_small)0,&mr_mip->lsw); +#endif + } + else mr_mip->msw=muldiv(mr_mip->prime[0],mr_mip->prime[1],(mr_small)0,mr_mip->base,&mr_mip->lsw); + mr_mip->logN=logn; + return TRUE; +} + +BOOL fastmultop(_MIPD_ int n,big x,big y,big z) +{ /* only return top n words... assumes x and y are n in length */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + int len; + mr_mip->check=OFF; + fft_mult(_MIPP_ x,y,mr_mip->w0); + mr_mip->check=ON; + len=mr_lent(mr_mip->w0); + mr_shift(_MIPP_ mr_mip->w0,n-len,mr_mip->w0); + copy(mr_mip->w0,z); + if (len<2*n) return TRUE; + return FALSE; +} + +void fft_mult(_MIPD_ big x,big y,big z) +{ /* "fast" O(n.log n) multiplication */ + int i,pr,xl,yl,zl,newn,logn; + mr_small v1,v2,v3,ic,c1,c2,p,fac,inv; + +#ifdef MR_ITANIUM + mr_small tm; +#endif +#ifdef MR_WIN64 + mr_small tm; +#endif +#ifdef MR_FP + mr_small dres; +#endif + mr_lentype sz; + mr_utype *w[3],*wptr,*dptr,*d0,*d1,*d2,t; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_FP_ROUNDING + mr_large ip; +#endif + if (mr_mip->ERNUM) return; + if (y->len==0 || x->len==0) + { + zero(z); + return; + } + + MR_IN(72) + + if (mr_notint(x) || mr_notint(y)) + { + mr_berror(_MIPP_ MR_ERR_INT_OP); + MR_OUT + return; + } + sz=((x->len&MR_MSBIT)^(y->len&MR_MSBIT)); + xl=(int)(x->len&MR_OBITS); + yl=(int)(y->len&MR_OBITS); + zl=xl+yl; + if (xl<512 || yl<512) /* should be 512 */ + { /* not worth it! */ + multiply(_MIPP_ x,y,z); + MR_OUT + return; + } + if (zl>mr_mip->nib && mr_mip->check) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + MR_OUT + return; + } + newn=1; logn=0; + while (zl>newn) { newn<<=1; logn++;} + if (logn>mr_mip->logN) /* 2^(N+1) settings can be used for 2^N */ + { /* numbers too big for current settings */ + if (!init_it(_MIPP_ logn)) + { + mr_berror(_MIPP_ MR_ERR_OUT_OF_MEMORY); + MR_OUT + return; + } + } + if (newn>2*mr_mip->nib) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + MR_OUT + return; + } + + d0=mr_mip->t[0]; d1=mr_mip->t[1]; d2=mr_mip->t[2]; + w[0]=mr_mip->wa; w[1]=mr_mip->wb; w[2]=mr_mip->wc; + + fac=twop(mr_mip->logN-logn); + + for (pr=0;pr<3;pr++) + { /* multiply mod each prime */ + p=mr_mip->prime[pr]; + inv=mr_mip->inverse[pr]; +#ifdef MR_FP_ROUNDING + ip=mr_invert(p); +#endif + if (fac!=1) inv=smul(fac,inv,p); /* adjust 1/N mod p */ + + dptr=mr_mip->t[pr]; + wptr=w[pr]; + + for (i=0;iw[i],p); + for (i=xl;isame || !mr_mip->first_one) + { + for (i=0;iw[i],p); + for (i=yl;iprime[1]; + muldiv(t,mr_mip->const1,(mr_small)0,mr_mip->prime[1],(mr_small *)&d1[i]); + } + if (pr==2) + { + t=d2[i]-d0[i]; + while (t<0) t+=mr_mip->prime[2]; + muldiv(t,mr_mip->const2,(mr_small)0,mr_mip->prime[2],(mr_small *)&t); + t-=d1[i]; + while (t<0) t+=mr_mip->prime[2]; + muldiv(t,mr_mip->const3,(mr_small)0,mr_mip->prime[2],(mr_small *)&d2[i]); + } + } + } + + mr_mip->first_one=TRUE; + + zero(z); + c1=c2=0; + if (mr_mip->base==0) for (i=0;iprime[0],v1,&v1); + c1+=v1; + if (c1lsw,v3,c1,&z->w[i]); + c2=muldvd(mr_mip->msw,v3,ic,&c1); + c1+=v2; + if (c1prime[0],v1+c1,mr_mip->base,mr_mip->inverse_base,&v1); + ic=c2+imuldiv(mr_mip->lsw,v3,v1,mr_mip->base,mr_mip->inverse_base,&z->w[i]); + c2=imuldiv(mr_mip->msw,v3,v2+ic,mr_mip->base,mr_mip->inverse_base,&c1); +#else + v2=muldiv(v2,mr_mip->prime[0],(mr_small)(v1+c1),mr_mip->base,&v1); + ic=c2+muldiv(mr_mip->lsw,v3,v1,mr_mip->base,&z->w[i]); + c2=muldiv(mr_mip->msw,v3,(mr_small)(v2+ic),mr_mip->base,&c1); +#endif + } + z->len=(sz|zl); /* set length and sign of result */ + mr_lzero(z); + MR_OUT +} + +#endif + +/* +main() +{ + big x,y,z,w; + int i,j,k; + miracl *mip=mirsys(1024,0); + x=mirvar(0); + y=mirvar(0); + z=mirvar(0); + w=mirvar(0); + + mip->IOBASE=16; + bigbits(512*MIRACL,x); + bigbits(512*MIRACL,y); + + + multiply(x,x,z); + + cotnum(z,stdout); + + fft_mult(x,x,w); + + cotnum(w,stdout); + if (mr_compare(z,w)!=0) printf("Problems\n"); + +} +*/ diff --git a/miracl/source/mrflash.c b/miracl/source/mrflash.c new file mode 100644 index 0000000..ffdb51c --- /dev/null +++ b/miracl/source/mrflash.c @@ -0,0 +1,340 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL floating-Slash arithmetic + * mrflash.c + */ + +#include "miracl.h" + +#ifdef MR_FLASH + +void flop(_MIPD_ flash x,flash y,int *op,flash z) +{ /* Do basic flash operation - depending on * + * op[]. Performs operations of the form + + A.f1(x,y) + B.f2(x,y) + ------------------- + C.f3(x,y) + D.f4(x,y) + + * Four functions f(x,y) are supported and * + * coded thus * + * 00 - Nx.Ny * + * 01 - Nx.Dy * + * 10 - Dx.Ny * + * 11 - Dx.Dy * + * where Nx is numerator of x, Dx denominator * + * of x, etc. * + * op[0] contains the codes for f1-f4 in last * + * eight bits = 00000000f1f2f3f4 * + * op[1], op[2], op[3], op[4] contain the * + * single precision multipliers A, B, C, D */ + int i,code; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(69) + numer(_MIPP_ x,mr_mip->w1); + denom(_MIPP_ x,mr_mip->w2); + numer(_MIPP_ y,mr_mip->w3); + denom(_MIPP_ y,mr_mip->w4); + + mr_mip->check=OFF; + for (i=1;i<=4;i++) + { + zero(mr_mip->w0); + if (op[i]==0) continue; + code=(op[0]>>(2*(4-i)))&3; + switch (code) + { + case 0 : if (x==y) multiply(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w0); + else multiply(_MIPP_ mr_mip->w1,mr_mip->w3,mr_mip->w0); + break; + case 1 : multiply(_MIPP_ mr_mip->w1,mr_mip->w4,mr_mip->w0); + break; + case 2 : multiply(_MIPP_ mr_mip->w2,mr_mip->w3,mr_mip->w0); + break; + case 3 : if(x==y) multiply(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w0); + else multiply(_MIPP_ mr_mip->w2,mr_mip->w4,mr_mip->w0); + break; + } + premult(_MIPP_ mr_mip->w0,op[i],mr_mip->w0); + switch (i) + { + case 1 : copy(mr_mip->w0,mr_mip->w5); + break; + case 2 : add(_MIPP_ mr_mip->w5,mr_mip->w0,mr_mip->w5); + break; + case 3 : copy(mr_mip->w0,mr_mip->w6); + break; + case 4 : add(_MIPP_ mr_mip->w6,mr_mip->w0,mr_mip->w6); + break; + } + } + mr_mip->check=ON; + mround(_MIPP_ mr_mip->w5,mr_mip->w6,z); + MR_OUT +} + +void fmul(_MIPD_ flash x,flash y,flash z) +{ /* Flash multiplication - z=x*y */ + int op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(35) + op[0]=0x0C; + op[1]=op[3]=1; + op[2]=op[4]=0; + flop(_MIPP_ x,y,op,z); + MR_OUT +} + +void fdiv(_MIPD_ flash x,flash y,flash z) +{ /* Flash divide - z=x/y */ + int op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(36) + op[0]=0x48; + op[1]=op[3]=1; + op[2]=op[4]=0; + flop(_MIPP_ x,y,op,z); + MR_OUT +} + +void fadd(_MIPD_ flash x,flash y,flash z) +{ /* Flash add - z=x+y */ + int op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(37) + op[0]=0x6C; + op[1]=op[2]=op[3]=1; + op[4]=0; + flop(_MIPP_ x,y,op,z); + MR_OUT +} + +void fsub(_MIPD_ flash x,flash y,flash z) +{ /* Flash subtract - z=x-y */ + int op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(38) + op[0]=0x6C; + op[1]=op[3]=1; + op[2]=(-1); + op[4]=0; + flop(_MIPP_ x,y,op,z); + MR_OUT +} + +int fcomp(_MIPD_ flash x,flash y) +{ /* compares two Flash numbers * + * returns -1 if y>x; +1 if x>y; 0 if x=y */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(39) + numer(_MIPP_ x,mr_mip->w1); + denom(_MIPP_ y,mr_mip->w2); + mr_mip->check=OFF; + multiply(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w5); + numer(_MIPP_ y,mr_mip->w1); + denom(_MIPP_ x,mr_mip->w2); + multiply(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w0); + mr_mip->check=ON; + MR_OUT + return (mr_compare(mr_mip->w5,mr_mip->w0)); +} + +void ftrunc(_MIPD_ flash x,big y,flash z) +{ /* sets y=int(x), z=rem(x) - returns * + * y only for ftrunc(x,y,y) */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(45) + numer(_MIPP_ x,mr_mip->w1); + denom(_MIPP_ x,mr_mip->w2); + divide(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w3); + copy(mr_mip->w3,y); + if (y!=z) fpack(_MIPP_ mr_mip->w1,mr_mip->w2,z); + MR_OUT +} + +void fmodulo(_MIPD_ flash x,flash y,flash z) +{ /* sets z=x mod y */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(89) + fdiv(_MIPP_ x,y,mr_mip->w8); + ftrunc(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w8); + fmul(_MIPP_ mr_mip->w8,y,mr_mip->w8); + fsub(_MIPP_ x,mr_mip->w8,z); + MR_OUT +} + +void fconv(_MIPD_ int n,int d,flash x) +{ /* convert simple fraction n/d to Flash form */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(40) + if (d<0) + { + d=(-d); + n=(-n); + } + convert(_MIPP_ n,mr_mip->w5); + convert(_MIPP_ d,mr_mip->w6); + fpack(_MIPP_ mr_mip->w5,mr_mip->w6,x); + MR_OUT +} + +void frecip(_MIPD_ flash x,flash y) +{ /* set y=1/x */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(41) + + numer(_MIPP_ x,mr_mip->w1); + denom(_MIPP_ x,mr_mip->w2); + fpack(_MIPP_ mr_mip->w2,mr_mip->w1,y); + + MR_OUT +} + +void fpmul(_MIPD_ flash x,int n,int d,flash y) +{ /* multiply x by small fraction n/d - y=x*n/d */ + int r,g; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + if (n==0 || size(x)==0) + { + zero(y); + return; + } + if (n==d) + { + copy(x,y); + return; + } + + MR_IN(42) + + if (d<0) + { + d=(-d); + n=(-n); + } + numer(_MIPP_ x,mr_mip->w1); + denom(_MIPP_ x,mr_mip->w2); + r=subdiv(_MIPP_ mr_mip->w1,d,mr_mip->w3); + g=igcd(d,r); + r=subdiv(_MIPP_ mr_mip->w2,n,mr_mip->w3); + g*=igcd(n,r); + mr_mip->check=OFF; + premult(_MIPP_ mr_mip->w1,n,mr_mip->w5); + premult(_MIPP_ mr_mip->w2,d,mr_mip->w6); + subdiv(_MIPP_ mr_mip->w5,g,mr_mip->w5); + subdiv(_MIPP_ mr_mip->w6,g,mr_mip->w6); + mr_mip->check=ON; + if (fit(mr_mip->w5,mr_mip->w6,mr_mip->nib)) + fpack(_MIPP_ mr_mip->w5,mr_mip->w6,y); + else + mround(_MIPP_ mr_mip->w5,mr_mip->w6,y); + MR_OUT +} + +void fincr(_MIPD_ flash x,int n,int d,flash y) +{ /* increment x by small fraction n/d - y=x+(n/d) */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(43) + + if (d<0) + { + d=(-d); + n=(-n); + } + numer(_MIPP_ x,mr_mip->w1); + denom(_MIPP_ x,mr_mip->w2); + mr_mip->check=OFF; + premult(_MIPP_ mr_mip->w1,d,mr_mip->w5); + premult(_MIPP_ mr_mip->w2,d,mr_mip->w6); + premult(_MIPP_ mr_mip->w2,n,mr_mip->w0); + add(_MIPP_ mr_mip->w5,mr_mip->w0,mr_mip->w5); + mr_mip->check=ON; + if (d==1 && fit(mr_mip->w5,mr_mip->w6,mr_mip->nib)) + fpack(_MIPP_ mr_mip->w5,mr_mip->w6,y); + else + mround(_MIPP_ mr_mip->w5,mr_mip->w6,y); + MR_OUT +} + +#endif + diff --git a/miracl/source/mrflsh1.c b/miracl/source/mrflsh1.c new file mode 100644 index 0000000..ae031bf --- /dev/null +++ b/miracl/source/mrflsh1.c @@ -0,0 +1,226 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL flash roots and powers + * mrflsh1.c + */ + +#include +#include "miracl.h" + +#ifdef MR_FLASH + +static int quad(_MIPD_ big w,int n) +{ /* generator for C.F. of square root of small integer */ + int t; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (n==0) + { + mr_mip->oldn=(-1); + mr_mip->b=2*mr_mip->RD; + mr_mip->c=mr_mip->b; + mr_mip->a=1; + mr_mip->d=mr_mip->RS; + mr_mip->r=mr_mip->RD; + if (mr_mip->r>=MR_TOOBIG) + { + convert(_MIPP_ mr_mip->r,w); + return MR_TOOBIG; + } + return (mr_mip->r); + } + else if (n==mr_mip->oldn) return (mr_mip->r); + t=mr_mip->a; + mr_mip->a=mr_mip->r*(mr_mip->c-mr_mip->b)+mr_mip->d; + mr_mip->d=t; + mr_mip->r=mr_mip->b/mr_mip->a; + mr_mip->c=mr_mip->b; + mr_mip->b=2*mr_mip->RD-mr_mip->b%mr_mip->a; + mr_mip->oldn=n; + if (mr_mip->r>=MR_TOOBIG) + { + convert(_MIPP_ mr_mip->r,w); + return (MR_TOOBIG); + } + return mr_mip->r; +} + +void fpower(_MIPD_ flash x,int n,flash w) +{ /* raise floating-slash number to integer power w=x^n */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,mr_mip->w8); + zero(w); + if (mr_mip->ERNUM || size(mr_mip->w8)==0) return; + convert(_MIPP_ 1,w); + if (n==0) return; + + MR_IN(51) + + if (n<0) + { + n=(-n); + frecip(_MIPP_ mr_mip->w8,mr_mip->w8); + } + if (n==1) + { + copy(mr_mip->w8,w); + MR_OUT + return; + } + forever + { + if (n%2!=0) fmul(_MIPP_ w,mr_mip->w8,w); + n/=2; + if (mr_mip->ERNUM || n==0) break; + fmul(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w8); + } + MR_OUT +} + +BOOL froot(_MIPD_ flash x,int n,flash w) +{ /* extract nth root of x - w=x^(1/n) using Newtons method */ + BOOL minus,rn,rm,hack; + int nm,dn,s,op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,w); + if (mr_mip->ERNUM || n==1) return TRUE; + if (n==(-1)) + { + frecip(_MIPP_ w,w); + return TRUE; + } + + MR_IN(52) + + minus=FALSE; + if (n<0) + { + minus=TRUE; + n=(-n); + } + s=exsign(w); + if (n%2==0 && s==MINUS) + { + mr_berror(_MIPP_ MR_ERR_NEG_ROOT); + MR_OUT + return FALSE; + } + insign(PLUS,w); + numer(_MIPP_ w,mr_mip->w8); + denom(_MIPP_ w,mr_mip->w9); + rn=nroot(_MIPP_ mr_mip->w8,n,mr_mip->w8); + rm=nroot(_MIPP_ mr_mip->w9,n,mr_mip->w9); + if (rn && rm) + { + fpack(_MIPP_ mr_mip->w8,mr_mip->w9,w); + if (minus) frecip(_MIPP_ w,w); + insign(s,w); + MR_OUT + return TRUE; + } + nm=size(mr_mip->w8); + dn=size(mr_mip->w9); + if (n==2 && ((nmw8,mr_mip->w8,mr_mip->w8); + numer(_MIPP_ w,mr_mip->w7); + subtract(_MIPP_ mr_mip->w7,mr_mip->w8,mr_mip->w8); + mr_mip->RS=(int)(mr_mip->w8->w[0]+mr_mip->base*mr_mip->w8->w[1]); + mr_mip->RD=nm; + build(_MIPP_ mr_mip->w8,quad); + } + if (!rm && dnw9,mr_mip->w9,mr_mip->w9); + denom(_MIPP_ w,mr_mip->w7); + subtract(_MIPP_ mr_mip->w7,mr_mip->w9,mr_mip->w9); + mr_mip->RS=(int)(mr_mip->w9->w[0]+mr_mip->base*mr_mip->w9->w[2]); + mr_mip->RD=dn; + build(_MIPP_ mr_mip->w9,quad); + } + if (size(mr_mip->w9)==1) copy(mr_mip->w8,w); + else fdiv(_MIPP_ mr_mip->w8,mr_mip->w9,w); + if (minus) frecip(_MIPP_ w,w); + insign(s,w); + MR_OUT + return FALSE; + } + hack=FALSE; + if (mr_lent(w)<=2) + { /* for 'simple' w only */ + hack=TRUE; + fpi(_MIPP_ mr_mip->pi); + fpmul(_MIPP_ mr_mip->pi,1,3,mr_mip->w10); + fpower(_MIPP_ mr_mip->w10,n,mr_mip->w10); + fmul(_MIPP_ w,mr_mip->w10,w); + } + op[0]=0x6C; /* set up for [(n-1).x+y]/n */ + op[1]=n-1; + op[2]=1; + op[3]=n; + op[4]=0; + mr_mip->workprec=mr_mip->stprec; + dconv(_MIPP_ pow(fdsize(_MIPP_ w),1.0/(double)n),mr_mip->w10); + while (mr_mip->workprec!=mr_mip->nib) + { /* Newtons iteration w10=(w/w10^(n-1)+(n-1)*w10)/n */ + if (mr_mip->workprecnib) mr_mip->workprec*=2; + if (mr_mip->workprec>=mr_mip->nib) mr_mip->workprec=mr_mip->nib; + else if (mr_mip->workprec*2>mr_mip->nib) mr_mip->workprec=(mr_mip->nib+1)/2; + fpower(_MIPP_ mr_mip->w10,n-1,mr_mip->w9); + fdiv(_MIPP_ w,mr_mip->w9,mr_mip->w9); + flop(_MIPP_ mr_mip->w10,mr_mip->w9,op,mr_mip->w10); + } + copy(mr_mip->w10,w); + op[0]=0x48; + op[1]=3; + op[3]=1; + op[2]=op[4]=0; + if (hack) flop(_MIPP_ w,mr_mip->pi,op,w); + if (minus) frecip(_MIPP_ w,w); + insign(s,w); + MR_OUT + return FALSE; +} + +#endif + diff --git a/miracl/source/mrflsh2.c b/miracl/source/mrflsh2.c new file mode 100644 index 0000000..294834d --- /dev/null +++ b/miracl/source/mrflsh2.c @@ -0,0 +1,229 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL flash exponential and logs + * mrflsh2.c + */ + +#include +#include "miracl.h" + +#ifdef MR_FLASH + +static int expon(_MIPD_ big w,int n) +{ /* generator for C.F. of e */ + if (n==0) return 2; + if (n%3==2) return 2*(n/3)+2; + else return 1; +} + +void fexp(_MIPD_ flash x,flash y) +{ /* calculates y=exp(x) */ + int i,n,nsq,m,sqrn,op[5]; + BOOL minus,rem; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + if (size(x)==0) + { + convert(_MIPP_ 1,y); + return; + } + copy(x,y); + + MR_IN(54) + + minus=FALSE; + if (size(y)<0) + { + minus=TRUE; + negify(y,y); + } + ftrunc(_MIPP_ y,y,mr_mip->w9); + n=size(y); + if (n==MR_TOOBIG) + { + mr_berror(_MIPP_ MR_ERR_FLASH_OVERFLOW); + MR_OUT + return; + } + if (n==0) convert(_MIPP_ 1,y); + else + { + build(_MIPP_ y,expon); + if (minus) + { /* underflow to zero - bit of a bodge */ + rem=mr_mip->ERCON; + mr_mip->ERCON=TRUE; + fpower(_MIPP_ y,n,y); + mr_mip->ERCON=rem; + if (mr_mip->ERNUM) + { + mr_mip->ERNUM=0; + zero(y); + MR_OUT + return; + } + } + else fpower(_MIPP_ y,n,y); + } + if (size(mr_mip->w9)==0) + { + if (minus) frecip(_MIPP_ y,y); + MR_OUT + return; + } + sqrn=isqrt(mr_mip->lg2b*mr_mip->workprec,mr_mip->lg2b); + nsq=0; + copy(mr_mip->w9,mr_mip->w8); + frecip(_MIPP_ mr_mip->w9,mr_mip->w9); + ftrunc(_MIPP_ mr_mip->w9,mr_mip->w9,mr_mip->w9); + m=logb2(_MIPP_ mr_mip->w9); + if (mw9); + fdiv(_MIPP_ mr_mip->w8,mr_mip->w9,mr_mip->w8); + } + zero(mr_mip->w10); + op[0]=0x4B; /* set up for x/(C+y) */ + op[1]=1; + op[2]=0; + for (m=sqrn;m>0;m--) + { /* Unwind C.F. expansion for exp(x)-1 */ + if (m%2==0) op[4]=2,op[3]=1; + else op[4]=m,op[3]=(-1); + flop(_MIPP_ mr_mip->w8,mr_mip->w10,op,mr_mip->w10); + } + op[0]=0x2C; /* set up for (x+2).y */ + op[1]=op[3]=1; + op[2]=2; + op[4]=0; + for (i=0;iw10,mr_mip->w10,op,mr_mip->w10); + } + op[2]=1; + flop(_MIPP_ mr_mip->w10,y,op,y); + if (minus) frecip(_MIPP_ y,y); + MR_OUT +} + +void flog(_MIPD_ flash x,flash y) +{ /* calculate y=log(x) to base e */ + BOOL hack; + int op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,y); + if (mr_mip->ERNUM) return; + if (size(y)==1) + { + zero(y); + return; + } + + MR_IN(55) + + if (size(y)<=0) + { + mr_berror(_MIPP_ MR_ERR_NEG_LOG); + MR_OUT + return; + } + hack=FALSE; + if (mr_lent(y)<=2) + { /* for 'simple' values of y */ + hack=TRUE; + build(_MIPP_ mr_mip->w11,expon); + fdiv(_MIPP_ y,mr_mip->w11,y); + } + op[0]=0x68; + op[1]=op[3]=1; + op[2]=(-1); + op[4]=0; + mr_mip->workprec=mr_mip->stprec; + dconv(_MIPP_ log(fdsize(_MIPP_ y)),mr_mip->w11); + while (mr_mip->workprec!=mr_mip->nib) + { /* Newtons iteration w11=w11+(y-exp(w11))/exp(w11) */ + if (mr_mip->workprecnib) mr_mip->workprec*=2; + if (mr_mip->workprec>=mr_mip->nib) mr_mip->workprec=mr_mip->nib; + else if (mr_mip->workprec*2>mr_mip->nib) mr_mip->workprec=(mr_mip->nib+1)/2; + fexp(_MIPP_ mr_mip->w11,mr_mip->w12); + flop(_MIPP_ y,mr_mip->w12,op,mr_mip->w12); + fadd(_MIPP_ mr_mip->w12,mr_mip->w11,mr_mip->w11); + } + copy(mr_mip->w11,y); + if (hack) fincr(_MIPP_ y,1,1,y); + MR_OUT +} + +void fpowf(_MIPD_ flash x,flash y,flash z) +{ /* raise flash number to flash power * + * z=x^y -> z=exp(y.log(x)) */ + int n; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(56) + + n=size(y); + if (mr_abs(n)w13); + n=size(mr_mip->w13); + if (mr_abs(n)w13,z); + fexp(_MIPP_ z,z); + MR_OUT +} + +#endif + diff --git a/miracl/source/mrflsh3.c b/miracl/source/mrflsh3.c new file mode 100644 index 0000000..d6b1f6f --- /dev/null +++ b/miracl/source/mrflsh3.c @@ -0,0 +1,322 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL flash trig. + * mrflsh3.c + */ + +#include +#include "miracl.h" + +#ifdef MR_FLASH + +#define TAN 1 +#define SIN 2 +#define COS 3 + +static int norm(_MIPD_ int type,flash y) +{ /* convert y to first quadrant angle * + * and return sign of result */ + int s; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + s=PLUS; + if (size(y)<0) + { + negify(y,y); + if (type!=COS) s=(-s); + } + fpi(_MIPP_ mr_mip->pi); + fpmul(_MIPP_ mr_mip->pi,1,2,mr_mip->w8); + if (fcomp(_MIPP_ y,mr_mip->w8)<=0) return s; + fpmul(_MIPP_ mr_mip->pi,2,1,mr_mip->w8); + if (fcomp(_MIPP_ y,mr_mip->w8)>0) + { /* reduce mod 2.pi */ + fdiv(_MIPP_ y,mr_mip->w8,mr_mip->w9); + ftrunc(_MIPP_ mr_mip->w9,mr_mip->w9,mr_mip->w9); + fmul(_MIPP_ mr_mip->w9,mr_mip->w8,mr_mip->w9); + fsub(_MIPP_ y,mr_mip->w9,y); + } + if (fcomp(_MIPP_ y,mr_mip->pi)>0) + { /* if greater than pi */ + fsub(_MIPP_ y,mr_mip->pi,y); + if (type!=TAN) s=(-s); + } + fpmul(_MIPP_ mr_mip->pi,1,2,mr_mip->w8); + if (fcomp(_MIPP_ y,mr_mip->w8)>0) + { /* if greater than pi/2 */ + fsub(_MIPP_ mr_mip->pi,y,y); + if (type!=SIN) s=(-s); + } + return s; +} + +static int tan1(_MIPD_ big w,int n) +{ /* generator for C.F. of tan(1) */ + if (n==0) return 1; + if (n%2==1) return 2*(n/2)+1; + else return 1; +} + +void ftan(_MIPD_ flash x,flash y) +{ /* calculates y=tan(x) */ + int i,n,nsq,m,sqrn,sgn,op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,y); + if (mr_mip->ERNUM || size(y)==0) return; + + MR_IN(57) + + sgn=norm(_MIPP_ TAN,y); + ftrunc(_MIPP_ y,y,mr_mip->w10); + n=size(y); + if (n!=0) build(_MIPP_ y,tan1); + if (size(mr_mip->w10)==0) + { + insign(sgn,y); + MR_OUT + return; + } + sqrn=isqrt(mr_mip->lg2b*mr_mip->workprec,mr_mip->lg2b); + nsq=0; + copy(mr_mip->w10,mr_mip->w8); + frecip(_MIPP_ mr_mip->w10,mr_mip->w10); + ftrunc(_MIPP_ mr_mip->w10,mr_mip->w10,mr_mip->w10); + m=logb2(_MIPP_ mr_mip->w10); + if (mw10); + fdiv(_MIPP_ mr_mip->w8,mr_mip->w10,mr_mip->w8); + } + zero(mr_mip->w10); + fmul(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w9); + negify(mr_mip->w9,mr_mip->w9); + op[0]=0x4B; /* set up for x/(y+C) */ + op[1]=op[3]=1; + op[2]=0; + for (m=sqrn;m>1;m--) + { /* Unwind C.F for tan(x)=z/(1-z^2/(3-z^2/(5-...)))))) */ + op[4]=2*m-1; + flop(_MIPP_ mr_mip->w9,mr_mip->w10,op,mr_mip->w10); + } + op[4]=1; + flop(_MIPP_ mr_mip->w8,mr_mip->w10,op,mr_mip->w10); + op[0]=0x6C; /* set up for tan(x+y)=tan(x)+tan(y)/(1-tan(x).tan(y)) */ + op[1]=op[2]=op[3]=1; + op[4]=(-1); + for (i=0;iw10,mr_mip->w10,op,mr_mip->w10); + } + flop(_MIPP_ y,mr_mip->w10,op,y); + insign(sgn,y); + MR_OUT +} + +void fatan(_MIPD_ flash x,flash y) +{ /* calculate y=atan(x) */ + int s,c,op[5]; + BOOL inv,hack; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,y); + if (mr_mip->ERNUM || size(y)==0) return; + + MR_IN(58) + + s=exsign(y); + insign(PLUS,y); + inv=FALSE; + fpi(_MIPP_ mr_mip->pi); + fconv(_MIPP_ 1,1,mr_mip->w11); + c=fcomp(_MIPP_ y,mr_mip->w11); + if (c==0) + { /* atan(1)=pi/4 */ + fpmul(_MIPP_ mr_mip->pi,1,4,y); + insign(s,y); + MR_OUT + return; + } + if (c>0) + { /* atan(x)=pi/2 - atan(1/x) for x>1 */ + inv=TRUE; + frecip(_MIPP_ y,y); + } + hack=FALSE; + if (mr_lent(y)<=2) + { /* for 'simple' values of y */ + hack=TRUE; + fconv(_MIPP_ 3,1,mr_mip->w11); + froot(_MIPP_ mr_mip->w11,2,mr_mip->w11); + op[0]=0xC6; + op[2]=op[3]=op[4]=1; + op[1]=(-1); + flop(_MIPP_ y,mr_mip->w11,op,y); + } + op[0]=0x4B; + op[1]=op[3]=op[4]=1; + op[2]=0; + mr_mip->workprec=mr_mip->stprec; + dconv(_MIPP_ atan(fdsize(_MIPP_ y)),mr_mip->w11); + while (mr_mip->workprec!=mr_mip->nib) + { /* Newtons iteration w11=w11+(y-tan(w11))/(tan(w11)^2+1) */ + if (mr_mip->workprecnib) mr_mip->workprec*=2; + if (mr_mip->workprec>=mr_mip->nib) mr_mip->workprec=mr_mip->nib; + else if (mr_mip->workprec*2>mr_mip->nib) mr_mip->workprec=(mr_mip->nib+1)/2; + ftan(_MIPP_ mr_mip->w11,mr_mip->w12); + fsub(_MIPP_ y,mr_mip->w12,mr_mip->w8); + fmul(_MIPP_ mr_mip->w12,mr_mip->w12,mr_mip->w12); + flop(_MIPP_ mr_mip->w8,mr_mip->w12,op,mr_mip->w12); /* w12=w8/(w12+1) */ + fadd(_MIPP_ mr_mip->w12,mr_mip->w11,mr_mip->w11); + } + copy(mr_mip->w11,y); + op[0]=0x6C; + op[1]=op[3]=6; + op[2]=1; + op[4]=0; + if (hack) flop(_MIPP_ y,mr_mip->pi,op,y); + op[1]=(-2); + op[3]=2; + if (inv) flop(_MIPP_ y,mr_mip->pi,op,y); + insign(s,y); + MR_OUT +} + +void fsin(_MIPD_ flash x,flash y) +{ /* calculate y=sin(x) */ + int sgn,op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,y); + if (mr_mip->ERNUM || size(y)==0) return; + + MR_IN(59) + sgn=norm(_MIPP_ SIN,y); + fpmul(_MIPP_ y,1,2,y); + ftan(_MIPP_ y,y); + op[0]=0x6C; + op[1]=op[2]=op[3]=op[4]=1; + flop(_MIPP_ y,y,op,y); + insign(sgn,y); + MR_OUT +} + +void fasin(_MIPD_ flash x,flash y) +{ /* calculate y=asin(x) */ + int s,op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,y); + if (mr_mip->ERNUM || size(y)==0) return; + + MR_IN(60) + s=exsign(y); + insign(PLUS,y); + op[0]=0x3C; + op[1]=(-1); + op[2]=op[3]=1; + op[4]=0; + flop(_MIPP_ y,y,op,mr_mip->w11); /* mr_w11 = -(y.y-1) */ + froot(_MIPP_ mr_mip->w11,2,mr_mip->w11); + if (size(mr_mip->w11)==0) + { + fpi(_MIPP_ mr_mip->pi); + fpmul(_MIPP_ mr_mip->pi,1,2,y); + } + else + { + fdiv(_MIPP_ y,mr_mip->w11,y); + fatan(_MIPP_ y,y); + } + insign(s,y); + MR_OUT +} + +void fcos(_MIPD_ flash x,flash y) +{ /* calculate y=cos(x) */ + int sgn,op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,y); + if (mr_mip->ERNUM || size(y)==0) + { + convert(_MIPP_ 1,y); + return; + } + + MR_IN(61) + sgn=norm(_MIPP_ COS,y); + fpmul(_MIPP_ y,1,2,y); + ftan(_MIPP_ y,y); + op[0]=0x33; + op[1]=op[3]=op[4]=1; + op[2]=(-1); + flop(_MIPP_ y,y,op,y); + insign(sgn,y); + MR_OUT +} + +void facos(_MIPD_ flash x,flash y) +{ /* calculate y=acos(x) */ + int op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(62) + + fasin(_MIPP_ x,y); + fpi(_MIPP_ mr_mip->pi); + op[0]=0x6C; + op[1]=(-2); + op[2]=1; + op[3]=2; + op[4]=0; + flop(_MIPP_ y,mr_mip->pi,op,y); /* y = pi/2 - y */ + MR_OUT +} + +#endif + diff --git a/miracl/source/mrflsh4.c b/miracl/source/mrflsh4.c new file mode 100644 index 0000000..acacd9c --- /dev/null +++ b/miracl/source/mrflsh4.c @@ -0,0 +1,156 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL flash hyperbolic trig. + * mrflsh4.c + */ + +#include "miracl.h" + +#ifdef MR_FLASH + +void ftanh(_MIPD_ flash x,flash y) +{ /* calculates y=tanh(x) */ + int op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,y); + if (mr_mip->ERNUM || size(y)==0) return; + + MR_IN(63) + fexp(_MIPP_ y,y); + op[0]=0x33; + op[1]=op[3]=op[4]=1; + op[2]=(-1); + flop(_MIPP_ y,y,op,y); + MR_OUT +} + +void fatanh(_MIPD_ flash x,flash y) +{ /* calculate y=atanh(x) */ + int op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,y); + if (mr_mip->ERNUM || size(y)==0) return; + + MR_IN(64) + fconv(_MIPP_ 1,1,mr_mip->w11); + op[0]=0x66; + op[1]=op[2]=op[3]=1; + op[4]=(-1); + flop(_MIPP_ mr_mip->w11,y,op,y); + flog(_MIPP_ y,y); + fpmul(_MIPP_ y,1,2,y); + MR_OUT +} + +void fsinh(_MIPD_ flash x,flash y) +{ /* calculate y=sinh(x) */ + int op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,y); + if (mr_mip->ERNUM || size(y)==0) return; + + MR_IN(65) + fexp(_MIPP_ y,y); + op[0]=0xC6; + op[2]=op[3]=op[4]=1; + op[1]=(-1); + flop(_MIPP_ y,y,op,y); + MR_OUT +} + +void fasinh(_MIPD_ flash x,flash y) +{ /* calculate y=asinh(x) */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,y); + if (mr_mip->ERNUM || size(y)==0) return; + + MR_IN(66) + fmul(_MIPP_ y,y,mr_mip->w11); + fincr(_MIPP_ mr_mip->w11,1,1,mr_mip->w11); + froot(_MIPP_ mr_mip->w11,2,mr_mip->w11); + fadd(_MIPP_ y,mr_mip->w11,y); + flog(_MIPP_ y,y); + MR_OUT +} + +void fcosh(_MIPD_ flash x,flash y) +{ /* calculate y=cosh(x) */ + int op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,y); + if (mr_mip->ERNUM || size(y)==0) + { + convert(_MIPP_ 1,y); + return; + } + + MR_IN(67) + fexp(_MIPP_ y,y); + op[0]=0xC6; + op[1]=op[2]=op[3]=op[4]=1; + flop(_MIPP_ y,y,op,y); + MR_OUT +} + +void facosh(_MIPD_ flash x,flash y) +{ /* calculate y=acosh(x) */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,y); + if (mr_mip->ERNUM) return; + + MR_IN(68) + fmul(_MIPP_ y,y,mr_mip->w11); + fincr(_MIPP_ mr_mip->w11,(-1),1,mr_mip->w11); + froot(_MIPP_ mr_mip->w11,2,mr_mip->w11); + fadd(_MIPP_ y,mr_mip->w11,y); + flog(_MIPP_ y,y); + MR_OUT +} + +#endif + diff --git a/miracl/source/mrfpe.c b/miracl/source/mrfpe.c new file mode 100644 index 0000000..46536c5 --- /dev/null +++ b/miracl/source/mrfpe.c @@ -0,0 +1,688 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * Implementation of BPS Format Preserving Encryption + * + * See "BPS: a Format Preserving Encryption Proposal" by E. Brier, T. Peyrin and J. Stern + * + * http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/bps/bps-spec.pdf + * + * Uses AES internally + * + * Author: M. Scott 2012/2015 + */ + +#include +#include "miracl.h" + +/* Define FPE_TEST to activate test main program and run test vectors */ +/* Link with mraes.c */ +/* gcc -O2 mrfpe.c mraes.c -o mrfpe.exe */ +/* #define FPE_TEST */ + +#define UINT32 mr_unsign32 /* 32-bit unsigned type */ +#define W 8 /* recommended number of rounds */ +#define BLOCK_SIZE 16 /* 16 Byte Blocks - AES */ +#define ENCRYPT 0 +#define DECRYPT 1 + +static void unpack(UINT32 a,MR_BYTE *b) +{ /* unpack bytes from a word */ + b[0]=MR_TOBYTE(a); + b[1]=MR_TOBYTE(a>>8); + b[2]=MR_TOBYTE(a>>16); + b[3]=MR_TOBYTE(a>>24); +} + +/* Little Endian */ + +static int to_base_256(char *x,int len,int s,MR_BYTE *y) +{ /* x[] of length len to base s is converted to byte array y[] of length BLOCK_SIZE */ + int i,j,m; + UINT32 c; + + for (i=0;i=0;j--) + { /* multiply by s */ + c=x[j]; + for (i=0;i>=8; + } + if (c>0) {m++; y[m-1]=c;} + } + + return m; +} + +/* Find max_b for chosen cipher and number base */ + +static int maxb(int s) +{ + MR_BYTE y[BLOCK_SIZE]; + int i,m,n,c; + if (s==2) return 192; + m=1; y[0]=1; + for (n=0;;n++) + { + c=0; + for (i=0;i>=8; + } + if (c>0) {m++; y[m-1]=c;} + if (m==13) break; /* greater than 2^96 for AES */ + } + return 2*n; +} + +static void from_base_256(int addsub,MR_BYTE *y,int len,int s,char *x) +{ /* y[] of length BLOCK_SIZE is added to or subtracted from base s array x[] of length len. */ + int i,m,n; + UINT32 c,d; + + m=BLOCK_SIZE; + n=0; c=0; + forever + { + while (m>0 && y[m-1]==0) m--; + d=0; + for (i=m-1;i>=0;i--) + { /* divide y by s */ + d=(d<<8)+y[i]; + y[i]=d/s; + d%=s; + } + if (addsub==ENCRYPT) + { /* ADD */ + d+=c+x[n]; c=0; + if ((int)d>=s) + {c=1; x[n]=d-s;} + else x[n]=d; + } + else + { /* SUB */ + d+=c; c=0; + if ((UINT32)x[n]>=d) x[n]-=d; + else + {x[n]+=(s-d); c=1;} + } + n++; + if (n>=len) break; + } +} + +/* AES instance must be initialised and passed */ +/* Format Preserving Encryption/Decryption routine */ +/* Array x of length len to base s is encrypted/decrypted in place */ + +static void BC(int crypt,char *x,int len,int s,aes *a,UINT32 TL,UINT32 TR) +{ + int i,j; + char *left,*right; + MR_BYTE buff[BLOCK_SIZE]; + int l,r; + l=r=len/2; + if (len%2==1) l++; + + left=&x[0]; right=&x[l]; + + for (i=0;i=mb) + { + if (i!=0) for (j=c;j. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL flash random number routine + * mrfrnd.c + */ + +#include "miracl.h" + +#ifdef MR_FP +#include +#endif + +#ifdef MR_FLASH + +#ifndef MR_NO_RAND + +void frand(_MIPD_ flash x) +{ /* generates random flash number 0ERNUM) return; + + MR_IN(46) + + zero(mr_mip->w6); + mr_mip->w6->len=mr_mip->nib; + for (i=0;inib;i++) + { /* generate a full width random number */ + if (mr_mip->base==0) mr_mip->w6->w[i]=brand(_MIPPO_ ); + else mr_mip->w6->w[i]=MR_REMAIN(brand(_MIPPO_ ),mr_mip->base); + } + mr_mip->check=OFF; + bigrand(_MIPP_ mr_mip->w6,mr_mip->w5); + mr_mip->check=ON; + mround(_MIPP_ mr_mip->w5,mr_mip->w6,x); + + MR_OUT +} + +#endif + +#endif + diff --git a/miracl/source/mrgcd.c b/miracl/source/mrgcd.c new file mode 100644 index 0000000..7406796 --- /dev/null +++ b/miracl/source/mrgcd.c @@ -0,0 +1,163 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL Greatest Common Divisor module. + * mrgcd.c + */ + +#include "miracl.h" + +#ifdef MR_FP +#include +#endif + +int egcd(_MIPD_ big x,big y,big z) +{ /* greatest common divisor z=gcd(x,y) by Euclids * + * method using Lehmers algorithm for big numbers */ + int q,r,a,b,c,d,n; + mr_small sr,m,sm; + mr_small u,v,lq,lr; +#ifdef MR_FP + mr_small dres; +#endif + big t; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(12) + + copy(x,mr_mip->w1); + copy(y,mr_mip->w2); + insign(PLUS,mr_mip->w1); + insign(PLUS,mr_mip->w2); + a=b=c=d=0; + while (size(mr_mip->w2)!=0) + { + /* printf("a= %d b= %d c= %d d=%d\n",a,b,c,d); */ + if (b==0) + { /* update w1 and w2 */ + divide(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w2); + t=mr_mip->w1,mr_mip->w1=mr_mip->w2,mr_mip->w2=t; /* swap(w1,w2) */ + } + else + { + premult(_MIPP_ mr_mip->w1,c,z); + premult(_MIPP_ mr_mip->w1,a,mr_mip->w1); + premult(_MIPP_ mr_mip->w2,b,mr_mip->w0); + premult(_MIPP_ mr_mip->w2,d,mr_mip->w2); + add(_MIPP_ mr_mip->w1,mr_mip->w0,mr_mip->w1); + add(_MIPP_ mr_mip->w2,z,mr_mip->w2); + } + if (mr_mip->ERNUM || size(mr_mip->w2)==0) break; + n=(int)mr_mip->w1->len; + if (mr_mip->w2->len==1) + { /* special case if mr_mip->w2 is now small */ + sm=mr_mip->w2->w[0]; +#ifdef MR_FP_ROUNDING + sr=mr_sdiv(_MIPP_ mr_mip->w1,sm,mr_invert(sm),mr_mip->w1); +#else + sr=mr_sdiv(_MIPP_ mr_mip->w1,sm,mr_mip->w1); +#endif + if (sr==0) + { + copy(mr_mip->w2,mr_mip->w1); + break; + } + zero(mr_mip->w1); + mr_mip->w1->len=1; + mr_mip->w1->w[0]=sr; + while ((sr=MR_REMAIN(mr_mip->w2->w[0],mr_mip->w1->w[0]))!=0) + mr_mip->w2->w[0]=mr_mip->w1->w[0],mr_mip->w1->w[0]=sr; + break; + } + a=1; + b=0; + c=0; + d=1; + m=mr_mip->w1->w[n-1]+1; + /* printf("m= %d\n",m); */ +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH + if (m==0) + { + u=mr_mip->w1->w[n-1]; + v=mr_mip->w2->w[n-1]; + } + else + { + /* printf("w1[n-1]= %d w1[n-2]= %d\n", mr_mip->w1->w[n-1],mr_mip->w1->w[n-2]); + printf("w2[n-1]= %d w2[n-2]= %d\n", mr_mip->w2->w[n-1],mr_mip->w2->w[n-2]);*/ + u=muldvm(mr_mip->w1->w[n-1],mr_mip->w1->w[n-2],m,&sr); + v=muldvm(mr_mip->w2->w[n-1],mr_mip->w2->w[n-2],m,&sr); + } +#endif +#ifndef MR_SIMPLE_BASE + } + else + { + u=muldiv(mr_mip->w1->w[n-1],mr_mip->base,mr_mip->w1->w[n-2],m,&sr); + v=muldiv(mr_mip->w2->w[n-1],mr_mip->base,mr_mip->w2->w[n-2],m,&sr); + } +#endif + /* printf("u= %d v= %d\n",u,v);*/ + + forever + { /* work only with most significant piece */ + if (((v+c)==0) || ((v+d)==0)) break; + lq=MR_DIV((u+a),(v+c)); + if (lq!=MR_DIV((u+b),(v+d))) break; + if (lq>=(mr_small)(MR_TOOBIG/mr_abs(d))) break; + q=(int)lq; + r=a-q*c; + a=c; + c=r; + r=b-q*d; + b=d; + d=r; + lr=u-lq*v; + u=v; + v=lr; + } + } + copy(mr_mip->w1,z); + MR_OUT + return (size(mr_mip->w1)); +} + diff --git a/miracl/source/mrgcm.c b/miracl/source/mrgcm.c new file mode 100644 index 0000000..ad64c58 --- /dev/null +++ b/miracl/source/mrgcm.c @@ -0,0 +1,328 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * Implementation of the AES-GCM Encryption/Authentication + * + * Some restrictions.. + * 1. Only for use with AES + * 2. Returned tag is always 128-bits. Truncate at your own risk. + * 3. The order of function calls must follow some rules + * + * Typical sequence of calls.. + * 1. call gcm_init + * 2. call gcm_add_header any number of times, as long as length of header is multiple of 16 bytes (block size) + * 3. call gcm_add_header one last time with any length of header + * 4. call gcm_add_cipher any number of times, as long as length of cipher/plaintext is multiple of 16 bytes + * 5. call gcm_add_cipher one last time with any length of cipher/plaintext + * 6. call gcm_finish to extract the tag. + * + * See http://www.mindspring.com/~dmcgrew/gcm-nist-6.pdf + */ + +#include +#include +#include "miracl.h" + +#define NB 4 +#define MR_WORD mr_unsign32 + +static MR_WORD pack(const MR_BYTE *b) +{ /* pack bytes into a 32-bit Word */ + return ((MR_WORD)b[0]<<24)|((MR_WORD)b[1]<<16)|((MR_WORD)b[2]<<8)|(MR_WORD)b[3]; +} + +static void unpack(MR_WORD a,MR_BYTE *b) +{ /* unpack bytes from a word */ + b[3]=MR_TOBYTE(a); + b[2]=MR_TOBYTE(a>>8); + b[1]=MR_TOBYTE(a>>16); + b[0]=MR_TOBYTE(a>>24); +} + +static void precompute(gcm *g,MR_BYTE *H) +{ /* precompute small 2k bytes gf2m table of x^n.H */ + int i,j; + MR_WORD *last,*next,b; + + for (i=j=0;itable[0][i]=pack((MR_BYTE *)&H[j]); + + for (i=1;i<128;i++) + { + next=g->table[i]; last=g->table[i-1]; b=0; + for (j=0;j>1; b=last[j]<<31;} + if (b) next[0]^=0xE1000000; /* irreducible polynomial */ + } +} + +static void gf2mul(gcm *g) +{ /* gf2m mul - Z=H*X mod 2^128 */ + int i,j,m,k; + MR_WORD P[4]; + MR_BYTE b; + + P[0]=P[1]=P[2]=P[3]=0; + j=8; m=0; + for (i=0;i<128;i++) + { + b=(g->stateX[m]>>(--j))&1; + if (b) for (k=0;ktable[i][k]; + if (j==0) + { + j=8; m++; + if (m==16) break; + } + } + for (i=j=0;istateX[j]); +} + +static void gcm_wrap(gcm *g) +{ /* Finish off GHASH */ + int i,j; + MR_WORD F[4]; + MR_BYTE L[16]; + +/* convert lengths from bytes to bits */ + F[0]=(g->lenA[0]<<3)|(g->lenA[1]&0xE0000000)>>29; + F[1]=g->lenA[1]<<3; + F[2]=(g->lenC[0]<<3)|(g->lenC[1]&0xE0000000)>>29; + F[3]=g->lenC[1]<<3; + for (i=j=0;istateX[i]^=L[i]; + gf2mul(g); +} + +void gcm_init(gcm* g,int nk,char *key,int niv,char *iv) +{ /* iv size niv is usually 12 bytes (96 bits). AES key size nk can be 16,24 or 32 bytes */ + int i; + MR_BYTE H[16]; + for (i=0;i<16;i++) {H[i]=0; g->stateX[i]=0;} + + aes_init(&(g->a),MR_ECB,nk,key,iv); + aes_ecb_encrypt(&(g->a),H); /* E(K,0) */ + precompute(g,H); + + g->lenA[0]=g->lenC[0]=g->lenA[1]=g->lenC[1]=0; + if (niv==12) + { + for (i=0;i<12;i++) g->a.f[i]=iv[i]; + unpack((MR_WORD)1,(MR_BYTE *)&(g->a.f[12])); /* initialise IV */ + for (i=0;i<16;i++) g->Y_0[i]=g->a.f[i]; + } + else + { + g->status=GCM_ACCEPTING_CIPHER; + gcm_add_cipher(g,0,iv,niv,NULL); /* GHASH(H,0,IV) */ + gcm_wrap(g); + for (i=0;i<16;i++) {g->a.f[i]=g->stateX[i];g->Y_0[i]=g->a.f[i];g->stateX[i]=0;} + g->lenA[0]=g->lenC[0]=g->lenA[1]=g->lenC[1]=0; + } + g->status=GCM_ACCEPTING_HEADER; +} + +BOOL gcm_add_header(gcm* g,char *header,int len) +{ /* Add some header. Won't be encrypted, but will be authenticated. len is length of header */ + int i,j=0; + if (g->status!=GCM_ACCEPTING_HEADER) return FALSE; + + while (jstateX[i]^=header[j++]; + g->lenA[1]++; if (g->lenA[1]==0) g->lenA[0]++; + } + gf2mul(g); + } + if (len%16!=0) g->status=GCM_ACCEPTING_CIPHER; + return TRUE; +} + +BOOL gcm_add_cipher(gcm *g,int mode,char *plain,int len,char *cipher) +{ /* Add plaintext to extract ciphertext, or visa versa, depending on mode. len is length of plaintext/ciphertext. Note this file combines GHASH() functionality with encryption/decryption */ + int i,j=0; + MR_WORD counter; + MR_BYTE B[16]; + if (g->status==GCM_ACCEPTING_HEADER) g->status=GCM_ACCEPTING_CIPHER; + if (g->status!=GCM_ACCEPTING_CIPHER) return FALSE; + + while (ja.f[12])); + counter++; + unpack(counter,(MR_BYTE *)&(g->a.f[12])); /* increment counter */ + for (i=0;i<16;i++) B[i]=g->a.f[i]; + aes_ecb_encrypt(&(g->a),B); /* encrypt it */ + } + for (i=0;i<16 && jstateX[i]^=plain[j++]; + else + { + if (mode==GCM_ENCRYPTING) cipher[j]=plain[j]^B[i]; + g->stateX[i]^=cipher[j]; + if (mode==GCM_DECRYPTING) plain[j]=cipher[j]^B[i]; + j++; + /*if (mode==GCM_ENCRYPTING) cipher[j]=plain[j]^B[i]; + if (mode==GCM_DECRYPTING) plain[j]=cipher[j]^B[i]; + g->stateX[i]^=cipher[j++]; */ + } + g->lenC[1]++; if (g->lenC[1]==0) g->lenC[0]++; + } + gf2mul(g); + } + if (len%16!=0) g->status=GCM_NOT_ACCEPTING_MORE; + return TRUE; +} + +void gcm_finish(gcm *g,char *tag) +{ /* Finish off GHASH and extract tag (MAC) */ + int i; + + gcm_wrap(g); + +/* extract tag */ + if (tag!=NULL) + { + aes_ecb_encrypt(&(g->a),g->Y_0); /* E(K,Y0) */ + for (i=0;i<16;i++) g->Y_0[i]^=g->stateX[i]; + for (i=0;i<16;i++) {tag[i]=g->Y_0[i];g->Y_0[i]=g->stateX[i]=0;} + } + g->status=GCM_FINISHED; + aes_end(&(g->a)); +} + +/* +// Compile with +// cl /O2 mrgcm.c mraes.c + +static void hex2bytes(char *hex,char *bin) +{ + int i; + char v; + int len=strlen(hex); + for (i = 0; i < len/2; i++) { + char c = hex[2*i]; + if (c >= '0' && c <= '9') { + v = c - '0'; + } else if (c >= 'A' && c <= 'F') { + v = c - 'A' + 10; + } else if (c >= 'a' && c <= 'f') { + v = c - 'a' + 10; + } else { + v = 0; + } + v <<= 4; + c = hex[2*i + 1]; + if (c >= '0' && c <= '9') { + v += c - '0'; + } else if (c >= 'A' && c <= 'F') { + v += c - 'A' + 10; + } else if (c >= 'a' && c <= 'f') { + v += c - 'a' + 10; + } else { + v = 0; + } + bin[i] = v; + } +} + +int main() +{ + int i; + + char* KT="feffe9928665731c6d6a8f9467308308"; + char* MT="d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39"; + char* HT="feedfacedeadbeeffeedfacedeadbeefabaddad2"; +// char* NT="cafebabefacedbaddecaf888"; +// Tag should be 5bc94fbc3221a5db94fae95ae7121a47 + char* NT="9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b"; +// Tag should be 619cc5aefffe0bfa462af43c1699d050 + + + int len=strlen(MT)/2; + int lenH=strlen(HT)/2; + int lenK=strlen(KT)/2; + int lenIV=strlen(NT)/2; + + char T[16]; // Tag + char K[32]; // AES Key + char H[64]; // Header - to be included in Authentication, but not encrypted + char N[100]; // IV - Initialisation vector + char M[100]; // Plaintext to be encrypted/authenticated + char C[100]; // Ciphertext + char P[100]; // Recovered Plaintext + + gcm g; + + hex2bytes(MT, M); + hex2bytes(HT, H); + hex2bytes(NT, N); + hex2bytes(KT, K); + + printf("Plaintext=\n"); + for (i=0;i. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL routines for arithmetic over GF(2^m), + * mrgf2m.c + * + * For algorithms used, see IEEE P1363 Standard, Appendix A + * unless otherwise stated. + * + * The time-critical routines are the multiplication routine multiply2() + * and (for AFFINE co-ordinates), the modular inverse routine inverse2() + * and the routines it calls. + * + * READ COMMENTS CAREFULLY FOR VARIOUS OPTIMIZATION SUGGESTIONS + * + * No assembly language used. + * + * Use utility irp.cpp to generate optimal code for function reduce2(.) below + * + * Space can be saved by removing unneeded functions and + * deleting unrequired functionality. + * For example in reduce2(.) remove code for those irreducible polynomials + * which will not be used by your code. + */ + +#include +#include "miracl.h" +#ifdef MR_STATIC +#include +#endif + +#ifdef MR_COUNT_OPS +extern int fpm2,fpi2; +#endif + +/* must use /arch:SSE2 in compilation */ + +#ifdef _M_IX86_FP +#if _M_IX86_FP >= 2 +#define MR_SSE2_INTRINSICS +#endif +#endif + +/* must use -msse2 in compilation */ + +#ifdef __SSE2__ +#define MR_SSE2_INTRINSICS +#endif + +#ifdef MR_SSE2_INTRINSICS + #ifdef __GNUC__ + #include + #else + #include + #endif + + #if MIRACL==64 + #define MR_SSE2_64 +/* Can use SSE2 registers for 64-bit manipulations */ + #endif + +#endif + +#ifndef MR_NOFULLWIDTH + /* This does not make sense using floating-point! */ + +/* This is extremely time-critical, and expensive */ + +/* Some experimental MMX code for x86-32. Seems to be slower than the standard code (on a PIV anyway).. */ + +#ifdef MR_MMX_x86_32 + +#ifdef __GNUC__ + #include +#else + #include +#endif + +static mr_small mr_mul2(mr_small a,mr_small b,mr_small *r) +{ + __m64 rg,tt[4]; + mr_small q; + + tt[0]=_m_from_int(0); + tt[1]=_m_from_int(a); + tt[2]=_m_psllqi(tt[1],1); + tt[3]=_m_pxor(tt[1],tt[2]); + + rg=tt[b&3]; + rg=_m_pxor(rg,_m_psllqi(tt[(b>>2)&3],2)); + rg=_m_pxor(rg,_m_psllqi(tt[(b>>4)&3],4)); + rg=_m_pxor(rg,_m_psllqi(tt[(b>>6)&3],6)); + rg=_m_pxor(rg,_m_psllqi(tt[(b>>8)&3],8)); + rg=_m_pxor(rg,_m_psllqi(tt[(b>>10)&3],10)); + rg=_m_pxor(rg,_m_psllqi(tt[(b>>12)&3],12)); + rg=_m_pxor(rg,_m_psllqi(tt[(b>>14)&3],14)); + rg=_m_pxor(rg,_m_psllqi(tt[(b>>16)&3],16)); + rg=_m_pxor(rg,_m_psllqi(tt[(b>>18)&3],18)); + rg=_m_pxor(rg,_m_psllqi(tt[(b>>20)&3],20)); + rg=_m_pxor(rg,_m_psllqi(tt[(b>>22)&3],22)); + rg=_m_pxor(rg,_m_psllqi(tt[(b>>24)&3],24)); + rg=_m_pxor(rg,_m_psllqi(tt[(b>>26)&3],26)); + rg=_m_pxor(rg,_m_psllqi(tt[(b>>28)&3],28)); + rg=_m_pxor(rg,_m_psllqi(tt[(b>>30)],30)); + + *r=_m_to_int(rg); + q=_m_to_int(_m_psrlqi(rg,32)); + + return q; +} + +#else + +/* This might be faster on a 16-bit processor with no variable shift instructions. + The line w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); is just a 1-bit right shift on + the hi|lo value - should be really fast in assembly language + +unsigned short mr_mul2(unsigned short x,unsigned short y,unsigned short *r) +{ + unsigned short lo,hi,bit,w; + hi=0; + lo=x; + bit=-(lo&1); + lo>>=1; + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + hi^=(y&bit); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<15); + + *r=lo; + return hi; +} + +*/ + + +/* This might be faster on an 8-bit processor with no variable shift instructions. + The line w=hi&1; hi>>=1; lo>>=1; lo|=(w<<7); is just a 1-bit right shift on + the hi|lo value - should be really fast in assembly language + +unsigned char mr_mul2(unsigned char x,unsigned char y,unsigned char *r) +{ + unsigned char lo,hi,bit,w; + hi=0; + lo=x; + bit=-(lo&1); + lo>>=1; + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<7); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<7); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<7); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<7); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<7); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<7); + + hi^=(y&bit); bit=-(lo&1); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<7); + + hi^=(y&bit); + w=hi&1; hi>>=1; lo>>=1; lo|=(w<<7); + + *r=lo; + return hi; +} + +*/ + +/* wouldn't it be nice if instruction sets supported a + one cycle "carry-free" multiplication instruction ... + The SmartMips does - its called maddp */ + +#ifndef MR_COMBA2 + +#if MIRACL==8 + +/* maybe use a small precomputed look-up table? */ + +static mr_small mr_mul2(mr_small a,mr_small b,mr_small *r) +{ + static const mr_small look[256]= + {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, + 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30, + 0,3,6,5,12,15,10,9,24,27,30,29,20,23,18,17, + 0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60, + 0,5,10,15,20,17,30,27,40,45,34,39,60,57,54,51, + 0,6,12,10,24,30,20,18,48,54,60,58,40,46,36,34, + 0,7,14,9,28,27,18,21,56,63,54,49,36,35,42,45, + 0,8,16,24,32,40,48,56,64,72,80,88,96,104,112,120, + 0,9,18,27,36,45,54,63,72,65,90,83,108,101,126,119, + 0,10,20,30,40,34,60,54,80,90,68,78,120,114,108,102, + 0,11,22,29,44,39,58,49,88,83,78,69,116,127,98,105, + 0,12,24,20,48,60,40,36,96,108,120,116,80,92,72,68, + 0,13,26,23,52,57,46,35,104,101,114,127,92,81,70,75, + 0,14,28,18,56,54,36,42,112,126,108,98,72,70,84,90, + 0,15,30,17,60,51,34,45,120,119,102,105,68,75,90,85 + }; + + mr_small x1,y0,m,p,q; + x1=a&0xf0; + y0=b&0x0f; + a<<=4; + b>>=4; + + p=look[(a|y0)]; + q=look[(x1|b)]; + + m=look[a^b^x1^y0]^p^q; /* Karatsuba! */ + + p^=(m<<4); + q^=(m>>4); + + *r=p; + return q; +} + +#else + +#ifdef MR_SSE2_64 + +static mr_small mr_mul2(mr_small a,mr_small b,mr_small *r) +{ + int i,j; + __m128i pp,tt[16],m; + + m=_mm_set_epi32(0,0,0xf0<<24,0); + + tt[0]=_mm_setzero_si128(); + tt[1]=_mm_loadl_epi64((__m128i *)&a); + tt[2]=_mm_xor_si128(_mm_slli_epi64(tt[1],1),_mm_srli_epi64( _mm_slli_si128(_mm_and_si128(m ,tt[1]),1) ,7)); + tt[4]=_mm_xor_si128(_mm_slli_epi64(tt[1],2),_mm_srli_epi64( _mm_slli_si128(_mm_and_si128(m ,tt[1]),1) ,6)); + tt[8]=_mm_xor_si128(_mm_slli_epi64(tt[1],3),_mm_srli_epi64( _mm_slli_si128(_mm_and_si128(m ,tt[1]),1) ,5)); + tt[3]=_mm_xor_si128(tt[1],tt[2]); + tt[5]=_mm_xor_si128(tt[1],tt[4]); + tt[6]=_mm_xor_si128(tt[2],tt[4]); + tt[7]=_mm_xor_si128(tt[6],tt[1]); + tt[9]=_mm_xor_si128(tt[8],tt[1]); + tt[10]=_mm_xor_si128(tt[8],tt[2]); + tt[11]=_mm_xor_si128(tt[10],tt[1]); + tt[12]=_mm_xor_si128(tt[8],tt[4]); + tt[13]=_mm_xor_si128(tt[12],tt[1]); + tt[14]=_mm_xor_si128(tt[8],tt[6]); + tt[15]=_mm_xor_si128(tt[14],tt[1]); + +/* Thanks to Darrel Hankerson, who pointed out an optimization for this code ... */ + + i=(int)(b&0xF); j=(int)((b>>4)&0xF); + pp=_mm_xor_si128(tt[i], _mm_or_si128(_mm_slli_epi64(tt[j],4), + _mm_srli_epi64(_mm_slli_si128(tt[j],8), 60)) ); + i=(int)((b>>8)&0xF); j=(int)((b>>12)&0xF); + + pp=_mm_xor_si128(pp, _mm_slli_si128( _mm_xor_si128(tt[i], + _mm_or_si128(_mm_slli_epi64(tt[j],4), + _mm_srli_epi64(_mm_slli_si128(tt[j],8), 60)) + ) ,1) ); + i=(int)((b>>16)&0xF); j=(int)((b>>20)&0xF); + pp=_mm_xor_si128(pp, _mm_slli_si128(_mm_xor_si128(tt[i], + _mm_or_si128(_mm_slli_epi64(tt[j],4), + _mm_srli_epi64(_mm_slli_si128(tt[j],8), 60)) + ) ,2) ); + i=(int)((b>>24)&0xF); j=(int)((b>>28)&0xF); + pp=_mm_xor_si128(pp, _mm_slli_si128(_mm_xor_si128(tt[i], + _mm_or_si128(_mm_slli_epi64(tt[j],4), + _mm_srli_epi64(_mm_slli_si128(tt[j],8), 60)) + ) ,3) ); + i=(int)((b>>32)&0xF); j=(int)((b>>36)&0xF); + pp=_mm_xor_si128(pp, _mm_slli_si128(_mm_xor_si128(tt[i], + _mm_or_si128(_mm_slli_epi64(tt[j],4), + _mm_srli_epi64(_mm_slli_si128(tt[j],8), 60)) + ) ,4) ); + i=(int)((b>>40)&0xF); j=(int)((b>>44)&0xF); + pp=_mm_xor_si128(pp, _mm_slli_si128(_mm_xor_si128(tt[i], + _mm_or_si128(_mm_slli_epi64(tt[j],4), + _mm_srli_epi64(_mm_slli_si128(tt[j],8), 60)) + ) ,5) ); + i=(int)((b>>48)&0xF); j=(int)((b>>52)&0xF); + pp=_mm_xor_si128(pp, _mm_slli_si128(_mm_xor_si128(tt[i], + _mm_or_si128(_mm_slli_epi64(tt[j],4), + _mm_srli_epi64(_mm_slli_si128(tt[j],8), 60)) + ) ,6) ); + i=(int)((b>>56)&0xF); j=(int)(b>>60); + pp=_mm_xor_si128(pp, _mm_slli_si128(_mm_xor_si128(tt[i], + _mm_or_si128(_mm_slli_epi64(tt[j],4), + _mm_srli_epi64(_mm_slli_si128(tt[j],8), 60)) + ) ,7) ); + + *r=((unsigned long long *)&pp)[0]; + return ((unsigned long long *)&pp)[1]; +} + +#else + +static mr_small mr_mul2(mr_small a,mr_small b,mr_small *r) +{ + int k; + mr_small kb,t[16]; + mr_small x,q,p; + mr_utype tb0; +#if MIRACL > 32 + mr_utype tb1,tb2; +#endif + + kb=b; + +#if MIRACL <= 32 + t[0]=0; /* small look up table */ + t[3]=t[2]=a<<1; /* it can overflow.... */ + t[1]=t[2]>>1; + t[3]^=t[1]; + + tb0=(mr_utype)(a&TOPBIT); /* remember top bit */ + tb0>>=M1; /* all ones if top bit is one */ +#else + t[0]=0; /* larger look-up table */ + t[8]=a<<3; + t[4]=t[8]>>1; + t[2]=t[4]>>1; + t[1]=t[2]>>1; + t[3]=t[5]=t[7]=t[9]=t[11]=t[13]=t[15]=t[1]; + t[3]^=t[2]; + t[5]^=t[4]; + t[9]^=t[8]; + t[6]=t[3]<<1; + t[7]^=t[6]; + t[10]=t[5]<<1; + t[11]^=t[10]; + t[12]=t[6]<<1; + t[13]^=t[12]; + t[14]=t[7]<<1; + t[15]^=t[14]; + + tb0=(a&TOPBIT); /* remember top bits */ + tb0>>=M1; /* all bits one, if this bit is set in a */ + tb1=(a&SECBIT)<<1; + tb1>>=M1; + tb2=(a&THDBIT)<<2; + tb2>>=M1; +#endif + +#if MIRACL == 8 +#define UNWOUNDM + p=q=t[b&3]; q>>=2; + x=t[(b>>2)&3]; q^=x; p^=(x<<2); q>>=2; + x=t[(b>>4)&3]; q^=x; p^=(x<<4); q>>=2; + x=t[(b>>6)]; q^=x; p^=(x<<6); q>>=2; +#endif + +#if MIRACL == 16 +#define UNWOUNDM + p=q=t[b&3]; q>>=2; + x=t[(b>>2)&3]; q^=x; p^=(x<<2); q>>=2; + x=t[(b>>4)&3]; q^=x; p^=(x<<4); q>>=2; + x=t[(b>>6)&3]; q^=x; p^=(x<<6); q>>=2; + x=t[(b>>8)&3]; q^=x; p^=(x<<8); q>>=2; + x=t[(b>>10)&3]; q^=x; p^=(x<<10); q>>=2; + x=t[(b>>12)&3]; q^=x; p^=(x<<12); q>>=2; + x=t[(b>>14)]; q^=x; p^=(x<<14); q>>=2; +#endif + +#if MIRACL == 32 +#define UNWOUNDM + p=q=t[b&3]; q>>=2; + x=t[(b>>2)&3]; q^=x; p^=(x<<2); q>>=2; /* 8 ASM 80386 instructions */ + x=t[(b>>4)&3]; q^=x; p^=(x<<4); q>>=2; /* but only 4 ARM instructions! */ + x=t[(b>>6)&3]; q^=x; p^=(x<<6); q>>=2; + x=t[(b>>8)&3]; q^=x; p^=(x<<8); q>>=2; + x=t[(b>>10)&3]; q^=x; p^=(x<<10); q>>=2; + x=t[(b>>12)&3]; q^=x; p^=(x<<12); q>>=2; + x=t[(b>>14)&3]; q^=x; p^=(x<<14); q>>=2; + x=t[(b>>16)&3]; q^=x; p^=(x<<16); q>>=2; + x=t[(b>>18)&3]; q^=x; p^=(x<<18); q>>=2; + x=t[(b>>20)&3]; q^=x; p^=(x<<20); q>>=2; + x=t[(b>>22)&3]; q^=x; p^=(x<<22); q>>=2; + x=t[(b>>24)&3]; q^=x; p^=(x<<24); q>>=2; + x=t[(b>>26)&3]; q^=x; p^=(x<<26); q>>=2; + x=t[(b>>28)&3]; q^=x; p^=(x<<28); q>>=2; + x=t[(b>>30)]; q^=x; p^=(x<<30); q>>=2; +#endif + +#if MIRACL == 64 +#define UNWOUNDM + p=q=t[b&0xf]; q>>=4; + x=t[(b>>4)&0xf]; q^=x; p^=(x<<4); q>>=4; + x=t[(b>>8)&0xf]; q^=x; p^=(x<<8); q>>=4; + x=t[(b>>12)&0xf]; q^=x; p^=(x<<12); q>>=4; + x=t[(b>>16)&0xf]; q^=x; p^=(x<<16); q>>=4; + x=t[(b>>20)&0xf]; q^=x; p^=(x<<20); q>>=4; + x=t[(b>>24)&0xf]; q^=x; p^=(x<<24); q>>=4; + x=t[(b>>28)&0xf]; q^=x; p^=(x<<28); q>>=4; + x=t[(b>>32)&0xf]; q^=x; p^=(x<<32); q>>=4; + x=t[(b>>36)&0xf]; q^=x; p^=(x<<36); q>>=4; + x=t[(b>>40)&0xf]; q^=x; p^=(x<<40); q>>=4; + x=t[(b>>44)&0xf]; q^=x; p^=(x<<44); q>>=4; + x=t[(b>>48)&0xf]; q^=x; p^=(x<<48); q>>=4; + x=t[(b>>52)&0xf]; q^=x; p^=(x<<52); q>>=4; + x=t[(b>>56)&0xf]; q^=x; p^=(x<<56); q>>=4; + x=t[(b>>60)]; q^=x; p^=(x<<60); q>>=4; + +#endif + +#ifndef UNWOUNDM + + q=p=(mr_small)0; + for (k=0;k>=2; + p>>=2; + p|=q<>=2; + + q^=(t[b&3]); + b>>=2; + p>>=2; + p|=q<>=2; + + q^=(t[b&3]); + b>>=2; + p>>=2; + p|=q<>=2; + + q^=(t[b&3]); + b>>=2; + p>>=2; + p|=q<>=2; + } +#endif + +#if MIRACL <= 32 + p^=(tb0&(kb<>1)); /* don't break pipeline.. */ +#else + p^=(tb0&(kb<>1)); + p^=(tb1&(kb<>2)); + p^=(tb2&(kb<>3)); +#endif + + *r=p; + return q; +} + +#endif + +#endif + +#endif + +#endif + +static int numbits(big x) +{ /* return degree of x */ + mr_small *gx=x->w,bit=TOPBIT; + int m,k=x->len; + if (k==0) return 0; + m=k*MIRACL; + while (!(gx[k-1]&bit)) + { + m--; + bit>>=1; + } + return m; +} + +int degree2(big x) +{ /* returns -1 for x=0 */ + return (numbits(x)-1); +} + +/* +static int zerobits(big x) +{ + int m,n,k; + mr_small *gx,lsb,bit=1; + k=x->len; + if (k==0) return (-1); + gx=x->w; + for (m=0;mlen; + int w=m/MIRACL; + int b=m%MIRACL; + mr_small *gx=x->w; + if (k==0 || m==0) return; + if (w>0) + { + for (i=0;ilen-=w; + } + if (b!=0) + { + for (i=0;i>b)|(gx[i+1]<<(MIRACL-b)); + gx[k-w-1]>>=b; + if (gx[k-w-1]==0) x->len--; + } +} +*/ + +static void shiftleftbits(big x,int m) +{ + int i,k=x->len; + mr_small j; + int w=m/MIRACL; /* words */ + int b=m%MIRACL; /* bits */ + mr_small *gx=x->w; + if (k==0 || m==0) return; + if (w>0) + { + for (i=k+w-1;i>=w;i--) + gx[i]=gx[i-w]; + for (i=w-1;i>=0;i--) gx[i]=0; + x->len+=w; + } +/* time critical */ + if (b!=0) + { + j=gx[k+w-1]>>(MIRACL-b); + if (j!=0) + { + x->len++; + gx[k+w]=j; + } + for (i=k+w-1;i>w;i--) + { + gx[i]=(gx[i]<>(MIRACL-b)); + } + gx[w]<<=b; + } +} + +static void square2(big x,big w) +{ /* w=x*x where x can be NULL so be careful */ + int i,j,n,m; + mr_small a,t,r,*gw; + + static const mr_small look[16]= + {0,(mr_small)1<len; + if (n==0) return; + m=n+n; + w->len=m; + gw=w->w; + + for (i=n-1;i>=0;i--) + { + a=gw[i]; + +#if MIRACL == 8 +#define UNWOUNDS + gw[i+i]=look[a&0xF]; + gw[i+i+1]=look[(a>>4)]; +#endif + +#if MIRACL == 16 +#define UNWOUNDS + gw[i+i]=(look[a&0xF]>>8)|look[(a>>4)&0xF]; + gw[i+i+1]=(look[(a>>8)&0xF]>>8)|look[(a>>12)]; +#endif + +#if MIRACL == 32 +#define UNWOUNDS + gw[i+i]=(look[a&0xF]>>24)|(look[(a>>4)&0xF]>>16)|(look[(a>>8)&0xF]>>8)|look[(a>>12)&0xF]; + gw[i+i+1]=(look[(a>>16)&0xF]>>24)|(look[(a>>20)&0xF]>>16)|(look[(a>>24)&0xF]>>8)|look[(a>>28)]; +#endif + +#ifndef UNWOUNDS + + r=0; + for (j=0;j>=4; + r>>=8; + r|=t; + } + gw[i+i]=r; r=0; + + for (j=0;j>=4; + r>>=8; + r|=t; + } + gw[i+i+1]=r; + +#endif + + } + if (gw[m-1]==0) + { + w->len--; + if (gw[m-2]==0) + mr_lzero(w); + } +} + +/* Use karatsuba to multiply two polynomials with coefficients in GF(2^m) */ + +#ifndef MR_STATIC + +void karmul2_poly(_MIPD_ int n,big *t,big *x,big *y,big *z) +{ + int m,nd2,nd,md,md2; + if (n==1) + { /* finished */ + modmult2(_MIPP_ *x,*y,*z); + zero(z[1]); + return; + } + if (n==2) + { /* in-line 2x2 */ + modmult2(_MIPP_ x[0],y[0],z[0]); + modmult2(_MIPP_ x[1],y[1],z[2]); + add2(x[0],x[1],t[0]); + add2(y[0],y[1],t[1]); + modmult2(_MIPP_ t[0],t[1],z[1]); + add2(z[1],z[0],z[1]); + add2(z[1],z[2],z[1]); + zero(z[3]); + return; + } + + if (n==3) + { + modmult2(_MIPP_ x[0],y[0],z[0]); + modmult2(_MIPP_ x[1],y[1],z[2]); + modmult2(_MIPP_ x[2],y[2],z[4]); + add2(x[0],x[1],t[0]); + add2(y[0],y[1],t[1]); + modmult2(_MIPP_ t[0],t[1],z[1]); + add2(z[1],z[0],z[1]); + add2(z[1],z[2],z[1]); + add2(x[1],x[2],t[0]); + add2(y[1],y[2],t[1]); + modmult2(_MIPP_ t[0],t[1],z[3]); + add2(z[3],z[2],z[3]); + add2(z[3],z[4],z[3]); + add2(x[0],x[2],t[0]); + add2(y[0],y[2],t[1]); + modmult2(_MIPP_ t[0],t[1],t[0]); + add2(z[2],t[0],z[2]); + add2(z[2],z[0],z[2]); + add2(z[2],z[4],z[2]); + zero(z[5]); + return; + } + + if (n%2==0) + { + md=nd=n; + md2=nd2=n/2; + } + else + { + nd=n+1; + md=n-1; + nd2=nd/2; md2=md/2; + } + + for (m=0;mw0; + + if (x==NULL || y==NULL) + { + zero(w); + return; + } + if (x->len==0 || y->len==0) + { + zero(w); + return; + } + + xl=x->len; + yl=y->len; + zero(w0); + +#ifdef CLAIRE + +/* Comba method */ + + w0->len=xl+yl; + d=1+mr_mip->M/MIRACL; + hi=lo=0; + for (i=0;iw[j],y->w[i-j],&p); + hi^=q; lo^=p; + } + w0->w[i]=lo; lo=hi; hi=0; + } + for (i=d;i<2*d-1;i++) + { + for (j=i-d+1;jw[j],y->w[i-j],&p); + hi^=q; lo^=p; + } + w0->w[i]=lo; lo=hi; hi=0; + } + w0->w[2*d-1]=lo; + mr_lzero(w0); + copy(w0,w); + +#else + +/* recommended method as mr_mul2 is so slow... */ + + if (xl>=MR_KARATSUBA && yl>=MR_KARATSUBA) + { + if (xl>yl) ml=xl; + else ml=yl; + + karmul2(ml,mr_mip->w7->w,x->w,y->w,w0->w); + + mr_mip->w7->len=w0->len=2*ml+1; + mr_lzero(w0); + mr_lzero(mr_mip->w7); + copy(w0,w); + return; + } + + w0->len=xl+yl; + for (i=0;iw[i],y->w[j],&p); + w0->w[i+j]^=p; + w0->w[i+j+1]^=q; + } + } + mr_lzero(w0); + copy(w0,w); +#endif +#endif +} + +void add2(big x,big y,big z) +{ /* XOR x and y */ + int i,lx,ly,lz,lm; + mr_small *gx,*gy,*gz; + + if (x==y) + { + zero(z); + return; + } + if (y==NULL) + { + copy(x,z); + return; + } + else if (x==NULL) + { + copy(y,z); + return; + } + + if (x==z) + { + gy=y->w; gz=z->w; + ly=y->len; lz=z->len; + lm=lz; if (ly>lz) lm=ly; + for (i=0;ilen=lm; + if (gz[lm-1]==0) mr_lzero(z); + } + else + { + gx=x->w; gy=y->w; gz=z->w; + lx=x->len; ly=y->len; lz=z->len; + lm=lx; if (ly>lx) lm=ly; + + for (i=0;ilen=lm; + if (gz[lm-1]==0) mr_lzero(z); + } +} + +static void remain2(_MIPD_ big y,big x) +{ /* generic "remainder" program. x%=y */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + int my=numbits(y); + int mx=numbits(x); + while (mx>=my) + { + copy(y,mr_mip->w7); + shiftleftbits(mr_mip->w7,mx-my); + add2(x,mr_mip->w7,x); + mx=numbits(x); + } + return; +} + +void gcd2(_MIPD_ big x,big y,big g) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (size(y)==0) + { + copy(x,g); + return; + } + copy(x,mr_mip->w1); + copy(y,mr_mip->w2); + forever + { + remain2(_MIPP_ mr_mip->w2,mr_mip->w1); + if (size(mr_mip->w1)==0) break; + copy(mr_mip->w1,mr_mip->w3); + copy(mr_mip->w2,mr_mip->w1); + copy(mr_mip->w3,mr_mip->w2); + } + copy(mr_mip->w2,g); +} + + +/* See "Elliptic Curves in Cryptography", Blake, Seroussi & Smart, + Cambridge University Press, 1999, page 20, for this fast reduction + routine - algorithm II.9 */ + +void reduce2(_MIPD_ big y,big x) +{ /* reduction wrt the trinomial or pentanomial modulus * + * Note that this is linear O(n), and thus not time critical */ + int k1,k2,k3,k4,ls1,ls2,ls3,ls4,rs1,rs2,rs3,rs4,i; + int M,A,B,C; + int xl; + mr_small top,*gx,w; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (x!=y) copy(y,x); + xl=x->len; + gx=x->w; + + M=mr_mip->M; + A=mr_mip->AA; + if (A==0) + { + mr_berror(_MIPP_ MR_ERR_NO_BASIS); + return; + } + B=mr_mip->BB; + C=mr_mip->CC; + + +/* If optimizing agressively it makes sense to make this code specific to a particular field + For example code like this can be optimized for the case + m=163. Note that the general purpose code involves lots of branches - these cause breaks in + the pipeline and they are slow. Further loop unrolling would be even faster... + + Version 5.10 - optimal code for 32-bit processors and for some NIST curves added + Version 5.22 - some code for a 16-bit processor.. + + Version 5.23 - Use findbase.cpp to find "best" irreducible polynomial + Version 5.23 - Use utility irp.cpp to automatically generate optimal code for insertion here +*/ + +#if MIRACL == 8 + + if (M==163 && A==7 && B==6 && C==3) + { + for (i=xl-1;i>=21;i--) + { + w=gx[i]; gx[i]=0; + gx[i-19]^=(w>>4)^(w>>5); + gx[i-20]^=(w>>3)^(w<<4)^(w<<3)^w; + gx[i-21]^=(w<<5); + } /* XORs= 7 shifts= 6 */ + top=gx[20]>>3; + gx[0]^=top; + top<<=3; + gx[0]^=(top<<4)^(top<<3)^top; + gx[1]^=(top>>4)^(top>>5); + gx[20]^=top; + x->len=21; + if (gx[20]==0) mr_lzero(x); + return; + } + + if (M==271 && A==201) + { + for (i=xl-1;i>=34;i--) + { + w=gx[i]; gx[i]=0; + gx[i-8]^=(w>>6); + gx[i-9]^=(w<<2); + gx[i-33]^=(w>>7); + gx[i-34]^=(w<<1); + } /* XORs= 4 shifts= 4 */ + top=gx[33]>>7; + gx[0]^=top; + top<<=7; + gx[24]^=(top<<2); + gx[25]^=(top>>6); + gx[33]^=top; + x->len=34; + if (gx[33]==0) mr_lzero(x); + return; + } + + if (M==271 && A==207 && B==175 && C==111) + { + for (i=xl-1;i>=34;i--) + { + w=gx[i]; gx[i]=0; + gx[i-8]^=w; + gx[i-12]^=w; + gx[i-20]^=w; + gx[i-33]^=(w>>7); + gx[i-34]^=(w<<1); + } /* XORs= 5 shifts= 2 */ + top=gx[33]>>7; + gx[0]^=top; + top<<=7; + gx[13]^=top; + gx[21]^=top; + gx[25]^=top; + gx[33]^=top; + x->len=34; + if (gx[33]==0) mr_lzero(x); + return; + } + +#endif + +#if MIRACL == 16 + + if (M==163 && A==7 && B==6 && C==3) + { + for (i=xl-1;i>=11;i--) + { + w=gx[i]; gx[i]=0; + gx[i-10]^=(w>>3)^(w<<3)^(w<<4)^w; + gx[i-11]^=(w<<13); + gx[i-9]^=(w>>12)^(w>>13); + } + top=gx[10]>>3; + gx[0]^=top; + top<<=3; + + gx[1]^=(top>>12)^(top>>13); + gx[0]^=(top<<4)^(top<<3)^top; + + gx[10]^=top; + x->len=11; + if (gx[10]==0) mr_lzero(x); + + return; + } + + if (M==271 && A==201 && B==0) + { + for (i=xl-1;i>=17;i--) + { + w=gx[i]; gx[i]=0; + gx[i-17]^=(w<<1); + gx[i-16]^=(w>>15); + gx[i-5]^=(w<<10); + gx[i-4]^=(w>>6); + } + top=gx[16]>>15; + gx[0]^=top; + top<<=15; + gx[12]^=(top>>6); + gx[11]^=(top<<10); + + gx[16]^=top; + x->len=17; + if (gx[16]==0) mr_lzero(x); + + return; + } + + if (M==271 && A==207 && B==175 && C==111) + { + for (i=xl-1;i>=17;i--) + { + w=gx[i]; gx[i]=0; + gx[i-4]^=w; + gx[i-6]^=w; + gx[i-10]^=w; + gx[i-16]^=(w>>15); + gx[i-17]^=(w<<1); + } /* XORs= 5 shifts= 2 */ + top=gx[16]>>15; + gx[0]^=top; + top<<=15; + gx[6]^=top; + gx[10]^=top; + gx[12]^=top; + gx[16]^=top; + x->len=17; + if (gx[16]==0) mr_lzero(x); + return; + } + +#endif + +#if MIRACL == 32 + + if (M==127 && A==63) + { + for (i=xl-1;i>=4;i--) + { + w=gx[i]; gx[i]=0; + gx[i-2]^=w; + gx[i-3]^=(w>>31); + gx[i-4]^=(w<<1); + } /* XORs= 3 shifts= 2 */ + top=gx[3]>>31; gx[0]^=top; top<<=31; + gx[1]^=top; + gx[3]^=top; + x->len=4; + if (gx[3]==0) mr_lzero(x); + return; + } + + if (M==163 && A==7 && B==6 && C==3) + { + for (i=xl-1;i>=6;i--) + { + w=gx[i]; gx[i]=0; + gx[i-5]^=((w>>3)^(w<<4)^(w<<3)^w); + gx[i-6]^=(w<<29); + gx[i-4]^=((w>>28)^(w>>29)); + } + top=gx[5]>>3; + + gx[0]^=top; + top<<=3; + gx[1]^=(top>>28)^(top>>29); + gx[0]^=top^(top<<4)^(top<<3); + + gx[5]^=top; + + x->len=6; + if (gx[5]==0) mr_lzero(x); + + return; + } + + if (M==163 && A==99 && B==97 && C==3) + { + for (i=xl-1;i>=6;i--) + { + w=gx[i]; gx[i]=0; + gx[i-2]^=w^(w>>2); + gx[i-3]^=(w<<30); + gx[i-5]^=(w>>3)^w; + gx[i-6]^=(w<<29); + } + top=gx[5]>>3; + gx[0]^=top; + top<<=3; + gx[0]^=top; + gx[2]^=(top<<30); + gx[3]^=top^(top>>2); + gx[5]^=top; + x->len=6; + if (gx[5]==0) mr_lzero(x); + return; + } + + if (M==233 && A==74 && B==0) + { + for (i=xl-1;i>=8;i--) + { + w=gx[i]; gx[i]=0; + gx[i-8]^=(w<<23); + gx[i-7]^=(w>>9); + gx[i-5]^=(w<<1); + gx[i-4]^=(w>>31); + } + top=gx[7]>>9; + gx[0]^=top; + gx[2]^=(top<<10); + gx[3]^=(top>>22); + gx[7]&=0x1FF; + + x->len=8; + if (gx[7]==0) mr_lzero(x); + return; + } + + if (M==233 && A==159 && B==0) + { + for (i=xl-1;i>=8;i--) + { + w=gx[i]; gx[i]=0; + gx[i-2]^=(w>>10); + gx[i-3]^=(w<<22); + gx[i-7]^=(w>>9); + gx[i-8]^=(w<<23); + } + top=gx[7]>>9; + gx[0]^=top; + top<<=9; + gx[4]^=(top<<22); + gx[5]^=(top>>10); + gx[7]^=top; + x->len=8; + if (gx[7]==0) mr_lzero(x); + return; + } + + if (M==233 && A==201 && B==105 && C==9) + { + for (i=xl-1;i>=8;i--) + { + w=gx[i]; gx[i]=0; + gx[i-1]^=w; + gx[i-4]^=w; + gx[i-7]^=(w>>9)^w; + gx[i-8]^=(w<<23); + } + top=gx[7]>>9; + gx[0]^=top; + top<<=9; + gx[0]^=top; + gx[3]^=top; + gx[6]^=top; + gx[7]^=top; + x->len=8; + if (gx[7]==0) mr_lzero(x); + + return; + } + + if (M==103 && A==9 && B==0) + { + for (i=xl-1;i>=4;i--) + { + w=gx[i]; gx[i]=0; + gx[i-3]^=((w>>7)^(w<<2)); + gx[i-4]^=(w<<25); + gx[i-2]^=(w>>30); + } + top=gx[3]>>7; + gx[0]^=top; + top<<=7; + gx[1]^=(top>>30); + gx[0]^=(top<<2); + gx[3]^=top; + x->len=4; + if (gx[3]==0) mr_lzero(x); + + return; + } + + if (M==283 && A==12 && B==7 && C==5) + { + for (i=xl-1;i>=9;i--) + { + w=gx[i]; gx[i]=0; + gx[i-9]^=(w<<5)^(w<<10)^(w<<12)^(w<<17); + gx[i-8]^=(w>>27)^(w>>22)^(w>>20)^(w>>15); + } + + top=gx[8]>>27; + gx[0]^=top^(top<<5)^(top<<7)^(top<<12); + gx[8]&=0x7FFFFFF; + + x->len=9; + if (gx[8]==0) mr_lzero(x); + return; + } + + if (M==283 && A==249 && B==219 && C==27) + { + for (i=xl-1;i>=9;i--) + { + w=gx[i]; gx[i]=0; + gx[i-1]^=(w>>2); + gx[i-2]^=(w<<30)^w; + gx[i-8]^=(w>>27)^w; + gx[i-9]^=(w<<5); + } /* XORs= 6 shifts= 4 */ + top=gx[8]>>27; + gx[0]^=top; + top<<=27; + gx[0]^=top; + gx[6]^=(top<<30)^top; + gx[7]^=(top>>2); + gx[8]^=top; + x->len=9; + if (gx[8]==0) mr_lzero(x); + return; + } + + if (M==313 && A==121 && B==0) + { + for (i=xl-1;i>=10;i--) + { + w=gx[i]; gx[i]=0; + gx[i-6]^=w; + gx[i-9]^=(w>>25); + gx[i-10]^=(w<<7); + } + top=gx[9]>>25; + gx[0]^=top; + top<<=25; + gx[3]^=top; + gx[9]^=top; + x->len=10; + if (gx[9]==0) mr_lzero(x); + return; + } + + if (M==379 && A==253 && B==251 && C==59) + { + for (i=xl-1;i>=12;i--) + { + w=gx[i]; gx[i]=0; + gx[i-3]^=(w>>30); + gx[i-4]^=(w<<2)^w; + gx[i-10]^=w; + gx[i-11]^=(w>>27); + gx[i-12]^=(w<<5); + } /* XORs= 6 shifts= 4 */ + top=gx[11]>>27; gx[0]^=top; top<<=27; + gx[1]^=top; + gx[7]^=(top<<2)^top; + gx[8]^=(top>>30); + gx[11]^=top; + x->len=12; + if (gx[11]==0) mr_lzero(x); + return; + } + + if (M==571 && A==10 && B==5 && C==2) + { + for (i=xl-1;i>=18;i--) + { + w=gx[i]; gx[i]=0; + gx[i-18]^=(w<<5)^(w<<7)^(w<<10)^(w<<15); + gx[i-17]^=(w>>27)^(w>>25)^(w>>22)^(w>>17); + } + + top=gx[17]>>27; + gx[0]^=top^(top<<2)^(top<<5)^(top<<10); + gx[17]&=0x7FFFFFF; + + x->len=18; + if (gx[17]==0) mr_lzero(x); + + return; + } + + if (M==571 && A==507 && B==475 && C==417) + { + for (i=xl-1;i>=18;i--) + { + w=gx[i]; gx[i]=0; + gx[i-2]^=w; + gx[i-3]^=w; + gx[i-4]^=(w>>26); + gx[i-5]^=(w<<6); + gx[i-17]^=(w>>27); + gx[i-18]^=(w<<5); + } /* XORs= 6 shifts= 4 */ + top=gx[17]>>27; + gx[0]^=top; + top<<=27; + gx[12]^=(top<<6); + gx[13]^=(top>>26); + gx[14]^=top; + gx[15]^=top; + gx[17]^=top; + x->len=18; + if (gx[17]==0) mr_lzero(x); + return; + } + + if (M==1223 && A==255) + { + for (i=xl-1;i>=39;i--) + { + w=gx[i]; gx[i]=0; + gx[i-30]^=(w>>8); + gx[i-31]^=(w<<24); + gx[i-38]^=(w>>7); + gx[i-39]^=(w<<25); + } /* XORs= 4 shifts= 4 */ + top=gx[38]>>7; gx[0]^=top; top<<=7; + gx[7]^=(top<<24); + gx[8]^=(top>>8); + gx[38]^=top; + x->len=39; + if (gx[38]==0) mr_lzero(x); + return; + } + +#endif + +#if MIRACL == 64 + if (M==1223 && A==255) + { + for (i=xl-1;i>=20;i--) + { + w=gx[i]; gx[i]=0; + gx[i-15]^=(w>>8); + gx[i-16]^=(w<<56); + gx[i-19]^=(w>>7); + gx[i-20]^=(w<<57); + } + top=gx[19]>>7; gx[0]^=top; top<<=7; + gx[3]^=(top<<56); + gx[4]^=(top>>8); + gx[19]^=top; + x->len=20; + if (gx[19]==0) mr_lzero(x); + return; + } + + if (M==379 && A==253 && B==251 && C==59) + { + for (i=xl-1;i>=6;i--) + { + w=gx[i]; gx[i]=0; + gx[i-1]^=(w>>62); + gx[i-2]^=(w<<2)^w; + gx[i-5]^=(w>>59)^w; + gx[i-6]^=(w<<5); + } /* XORs= 6 shifts= 4 */ + top=gx[5]>>59; gx[0]^=top; top<<=59; + gx[0]^=top; + gx[3]^=(top<<2)^top; + gx[4]^=(top>>62); + gx[5]^=top; + x->len=6; + if (gx[5]==0) mr_lzero(x); + return; + } +#endif + + k3=k4=rs3=ls3=rs4=ls4=0; + k1=1+M/MIRACL; /* words from MSB to LSB */ + + if (xl<=k1) + { + if (numbits(x)<=M) return; + } + + rs1=M%MIRACL; + ls1=MIRACL-rs1; + + if (M-A < MIRACL) + { /* slow way */ + while (numbits(x)>=M+1) + { + copy(mr_mip->modulus,mr_mip->w7); + shiftleftbits(mr_mip->w7,numbits(x)-M-1); + add2(x,mr_mip->w7,x); + } + return; + } + + k2=1+(M-A)/MIRACL; /* words from MSB to bit */ + rs2=(M-A)%MIRACL; + ls2=MIRACL-rs2; + + if (B) + { /* Pentanomial */ + k3=1+(M-B)/MIRACL; + rs3=(M-B)%MIRACL; + ls3=MIRACL-rs3; + + k4=1+(M-C)/MIRACL; + rs4=(M-C)%MIRACL; + ls4=MIRACL-rs4; + } + + for (i=xl-1;i>=k1;i--) + { + w=gx[i]; gx[i]=0; + if (rs1==0) gx[i-k1+1]^=w; + else + { + gx[i-k1+1]^=(w>>rs1); + gx[i-k1]^=(w<>rs2); + gx[i-k2]^=(w<>rs3); + gx[i-k3]^=(w<>rs4); + gx[i-k4]^=(w<>rs1; + + if (top!=0) + { + gx[0]^=top; + top<<=rs1; + + if (rs2==0) gx[k1-k2]^=top; + else + { + gx[k1-k2]^=(top>>rs2); + if (k1>k2) gx[k1-k2-1]^=(top<>rs3); + if (k1>k3) gx[k1-k3-1]^=(top<>rs4); + if (k1>k4) gx[k1-k4-1]^=(top<len=k1; + if (gx[k1-1]==0) mr_lzero(x); +} + +void incr2(big x,int n,big w) +{ /* increment x by small amount */ + if (x!=w) copy(x,w); + if (n==0) return; + if (w->len==0) + { + w->len=1; + w->w[0]=n; + } + else + { + w->w[0]^=(mr_small)n; + if (w->len==1 && w->w[0]==0) w->len=0; + } +} + +void modsquare2(_MIPD_ big x,big w) +{ /* w=x*x mod f */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + square2(x,mr_mip->w0); + reduce2(_MIPP_ mr_mip->w0,mr_mip->w0); + copy(mr_mip->w0,w); +} + +/* Experimental code for GF(2^103) modular multiplication * + * Inspired by Robert Harley's ECDL code */ + +#ifdef SP103 + +#ifdef __GNUC__ +#include +#else +#include +#endif + +void modmult2(_MIPD_ big x,big y,big w) +{ + int i,j; + mr_small b; + + __m128i t[16]; + __m128i m,r,s,p,q,xe,xo; + __m64 a3,a2,a1,a0,top; + + if (x==y) + { + modsquare2(_MIPP_ x,w); + return; + } + + if (x->len==0 || y->len==0) + { + zero(w); + return; + } + +#ifdef MR_COUNT_OPS +fpm2++; +#endif + + m=_mm_set_epi32(0,0,0xff<<24,0); /* shifting mask */ + +/* precompute a small table */ + + t[0]=_mm_set1_epi32(0); + xe=_mm_set_epi32(0,x->w[2],0,x->w[0]); + xo=_mm_set_epi32(0,x->w[3],0,x->w[1]); + t[1]=_mm_xor_si128(xe,_mm_slli_si128(xo,4)); + xe=_mm_slli_epi64(xe,1); + xo=_mm_slli_epi64(xo,1); + t[2]=_mm_xor_si128(xe,_mm_slli_si128(xo,4)); + t[3]=_mm_xor_si128(t[2],t[1]); + xe=_mm_slli_epi64(xe,1); + xo=_mm_slli_epi64(xo,1); + t[4]=_mm_xor_si128(xe,_mm_slli_si128(xo,4)); + t[5]=_mm_xor_si128(t[4],t[1]); + t[6]=_mm_xor_si128(t[4],t[2]); + t[7]=_mm_xor_si128(t[4],t[3]); + xe=_mm_slli_epi64(xe,1); + xo=_mm_slli_epi64(xo,1); + t[8]=_mm_xor_si128(xe,_mm_slli_si128(xo,4)); + t[9]=_mm_xor_si128(t[8],t[1]); + t[10]=_mm_xor_si128(t[8],t[2]); + t[11]=_mm_xor_si128(t[8],t[3]); + t[12]=_mm_xor_si128(t[8],t[4]); + t[13]=_mm_xor_si128(t[8],t[5]); + t[14]=_mm_xor_si128(t[8],t[6]); + t[15]=_mm_xor_si128(t[8],t[7]); + + b=y->w[0]; + + i=b&0xf; j=(b>>4)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); /* net shift left 4 */ + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + p=q=r; q=_mm_srli_si128(q,1); + + i=(b>>8)&0xf; j=(b>>12)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,1); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + i=(b>>16)&0xf; j=(b>>20)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,2); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + i=(b>>24)&0xf; j=(b>>28); r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,3); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + b=y->w[1]; + + i=(b)&0xf; j=(b>>4)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,4); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + i=(b>>8)&0xf; j=(b>>12)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,5); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + i=(b>>16)&0xf; j=(b>>20)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,6); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + i=(b>>24)&0xf; j=(b>>28); r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,7); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + b=y->w[2]; + + i=(b)&0xf; j=(b>>4)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,8); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + i=(b>>8)&0xf; j=(b>>12)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,9); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + i=(b>>16)&0xf; j=(b>>20)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,10); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + i=(b>>24)&0xf; j=(b>>28); r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,11); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + b=y->w[3]; + + i=(b)&0xf; j=(b>>4)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,12); + p=_mm_xor_si128(p,r); + + q=_mm_srli_si128(q,4); /* only 103 bits, so we are done */ + +/* modular reduction - x^103+x^9+1 */ + + a0=_mm_movepi64_pi64(p); + a1=_mm_movepi64_pi64(_mm_srli_si128(p,8)); + a2=_mm_movepi64_pi64(q); + a3=_mm_movepi64_pi64(_mm_srli_si128(q,8)); + + a2=_m_pxor(a2,_m_psrlqi(a3,39)); + a2=_m_pxor(a2,_m_psrlqi(a3,30)); + a1=_m_pxor(a1,_m_psllqi(a3,25)); + a1=_m_pxor(a1,_m_psllqi(a3,34)); + + a1=_m_pxor(a1,_m_psrlqi(a2,39)); + a1=_m_pxor(a1,_m_psrlqi(a2,30)); + a0=_m_pxor(a0,_m_psllqi(a2,25)); + a0=_m_pxor(a0,_m_psllqi(a2,34)); + + top=_m_psrlqi(a1,39); + a0=_m_pxor(a0,top); + top=_m_psllqi(top,39); + a0=_m_pxor(a0,_m_psrlqi(top,30)); + a1=_m_pxor(a1,top); + + if (w->len>4) zero(w); + + w->w[0]=_m_to_int(a0); + a0=_m_psrlqi(a0,32); + w->w[1]=_m_to_int(a0); + w->w[2]=_m_to_int(a1); + a1=_m_psrlqi(a1,32); + w->w[3]=_m_to_int(a1); + + w->len=4; + if (w->w[3]==0) mr_lzero(w); + _m_empty(); +} + +#endif + +#ifdef SP79 + +#ifdef __GNUC__ +#include +#else +#include +#endif + +void modmult2(_MIPD_ big x,big y,big w) +{ + int i,j; + mr_small b; + + __m128i t[16]; + __m128i m,r,s,p,q,xe,xo; + __m64 a2,a1,a0,top; + + if (x==y) + { + modsquare2(_MIPP_ x,w); + return; + } +#ifdef MR_COUNT_OPS +fpm2++; +#endif + if (x->len==0 || y->len==0) + { + zero(w); + return; + } + + m=_mm_set_epi32(0,0,0xff<<24,0); /* shifting mask */ + +/* precompute a small table */ + + t[0]=_mm_set1_epi32(0); + xe=_mm_set_epi32(0,x->w[2],0,x->w[0]); + xo=_mm_set_epi32(0,0,0,x->w[1]); + t[1]=_mm_xor_si128(xe,_mm_slli_si128(xo,4)); + xe=_mm_slli_epi64(xe,1); + xo=_mm_slli_epi64(xo,1); + t[2]=_mm_xor_si128(xe,_mm_slli_si128(xo,4)); + t[3]=_mm_xor_si128(t[2],t[1]); + xe=_mm_slli_epi64(xe,1); + xo=_mm_slli_epi64(xo,1); + t[4]=_mm_xor_si128(xe,_mm_slli_si128(xo,4)); + t[5]=_mm_xor_si128(t[4],t[1]); + t[6]=_mm_xor_si128(t[4],t[2]); + t[7]=_mm_xor_si128(t[4],t[3]); + xe=_mm_slli_epi64(xe,1); + xo=_mm_slli_epi64(xo,1); + t[8]=_mm_xor_si128(xe,_mm_slli_si128(xo,4)); + t[9]=_mm_xor_si128(t[8],t[1]); + t[10]=_mm_xor_si128(t[8],t[2]); + t[11]=_mm_xor_si128(t[8],t[3]); + t[12]=_mm_xor_si128(t[8],t[4]); + t[13]=_mm_xor_si128(t[8],t[5]); + t[14]=_mm_xor_si128(t[8],t[6]); + t[15]=_mm_xor_si128(t[8],t[7]); + + b=y->w[0]; + + i=b&0xf; j=(b>>4)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); /* net shift left 4 */ + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + p=q=r; q=_mm_srli_si128(q,1); + + i=(b>>8)&0xf; j=(b>>12)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,1); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + i=(b>>16)&0xf; j=(b>>20)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,2); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + i=(b>>24)&0xf; j=(b>>28); r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,3); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + b=y->w[1]; + + i=(b)&0xf; j=(b>>4)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,4); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + i=(b>>8)&0xf; j=(b>>12)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,5); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + i=(b>>16)&0xf; j=(b>>20)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,6); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + i=(b>>24)&0xf; j=(b>>28); r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,7); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + b=y->w[2]; + + i=(b)&0xf; j=(b>>4)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,8); + p=_mm_xor_si128(p,r); q=_mm_srli_si128(q,1); + + i=(b>>8)&0xf; j=(b>>12)&0xf; r=t[j]; + s=_mm_and_si128(r,m); r=_mm_slli_epi64(r,4); + s=_mm_slli_si128(s,1); s=_mm_srli_epi64(s,4); + r=_mm_xor_si128(r,s); r=_mm_xor_si128(r,t[i]); + q=_mm_xor_si128(q,r); r=_mm_slli_si128(r,9); + p=_mm_xor_si128(p,r); + + q=_mm_srli_si128(q,7); /* only 79 bits, so we are done */ + +/* modular reduction - x^79+x^9+1 */ + + a0=_mm_movepi64_pi64(p); + a1=_mm_movepi64_pi64(_mm_srli_si128(p,8)); + a2=_mm_movepi64_pi64(q); + + a1=_m_pxor(a1,_m_psrlqi(a2,15)); + a1=_m_pxor(a1,_m_psrlqi(a2,6)); + a0=_m_pxor(a0,_m_psllqi(a2,49)); + a0=_m_pxor(a0,_m_psllqi(a2,58)); + + top=_m_psrlqi(a1,15); + a0=_m_pxor(a0,top); + top=_m_psllqi(top,15); + a0=_m_pxor(a0,_m_psrlqi(top,6)); + a1=_m_pxor(a1,top); + + w->w[2]=_m_to_int(a1); + + if (w->len>3) + { /* Yes I know its crazy, but its needed to fix the broken /O2 optimizer */ + for (i=3;ilen;i++) w->w[i]=0; + } + + w->w[0]=_m_to_int(a0); + a0=_m_psrlqi(a0,32); + w->w[1]=_m_to_int(a0); + + w->len=3; + if (w->w[2]==0) mr_lzero(w); + _m_empty(); +} + +#endif + + +#ifndef SP103 +#ifndef SP79 +/*#ifndef SP271 */ + +void modmult2(_MIPD_ big x,big y,big w) +{ /* w=x*y mod f */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (x==NULL || y==NULL) + { + zero(w); + return; + } + + if (x==y) + { + modsquare2(_MIPP_ x,w); + return; + } + + if (y->len==0) + { + zero(w); + return; + } + + if (y->len==1) + { + if (y->w[0]==1) + { + copy(x,w); + return; + } + } + +#ifdef MR_COUNT_OPS +fpm2++; +#endif + + multiply2(_MIPP_ x,y,mr_mip->w0); + reduce2(_MIPP_ mr_mip->w0,mr_mip->w0); + copy(mr_mip->w0,w); +} + +#endif +#endif +/*#endif*/ + +/* Will be *much* faster if M,A,(B and C) are all odd */ +/* This could/should be optimized for a particular irreducible polynomial and fixed A, B and C */ + +void sqroot2(_MIPD_ big x,big y) +{ + int i,M,A,B,C; + int k,n,h,s,a,aw,ab,bw,bb,cw,cb; + #if MIRACL != 32 + int mm,j; + #endif + mr_small *wk,w,we,wo; + BOOL slow; +/* Using Harley's trick */ + static const mr_small evens[16]= + {0,1,4,5,2,3,6,7,8,9,12,13,10,11,14,15}; + static const mr_small odds[16]= + {0,4,1,5,8,12,9,13,2,6,3,7,10,14,11,15}; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + M=mr_mip->M; + A=mr_mip->AA; + if (A==0) + { + mr_berror(_MIPP_ MR_ERR_NO_BASIS); + return; + } + B=mr_mip->BB; + C=mr_mip->CC; + + slow=FALSE; + if (B) + { + if (M%2!=1 || A%2!=1 || B%2!=1 || C%2!=1) slow=TRUE; + } + else + { + if (M%2!=1 || A%2!=1) slow=TRUE; + } + + if (slow) + { + copy(x,y); + for (i=1;iM;i++) + modsquare2(_MIPP_ y,y); + return; + } + + bb=cb=cw=bw=0; +/* M, A (B and C) are all odd - so use fast + Fong, Hankerson, Lopez and Menezes method */ + + if (x==y) + { + copy (x,mr_mip->w0); + wk=mr_mip->w0->w; + } + else + { + wk=x->w; + } + zero(y); + +#if MIRACL==8 + if (M==271 && A==207 && B==175 && C==111) + { + y->len=34; + for (i=0;i<34;i++) + { + n=i/2; + w=wk[i]; + + we=evens[((w&0x5)+((w&0x50)>>3))]; + wo=odds[((w&0xA)+((w&0xA0)>>5))]; + + i++; + w=wk[i]; + + we|=evens[((w&0x5)+((w&0x50)>>3))]<<4; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<4; + + y->w[n]^=we; + y->w[n+17]=wo; + + y->w[n+13]^=wo; + y->w[n+11]^=wo; + y->w[n+7]^=wo; + } + if (y->w[33]==0) mr_lzero(y); + return; + } +#endif + +#if MIRACL==32 + if (M==1223 && A==255) + { + y->len=39; + for (i=0;i<39;i++) + { + n=i/2; + w=wk[i]; + + we=evens[((w&0x5)+((w&0x50)>>3))]; + wo=odds[((w&0xA)+((w&0xA0)>>5))]; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<4; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<4; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<8; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<8; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<12; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<12; + + i++; + if (i<39) + { + w=wk[i]; + + we|=evens[((w&0x5)+((w&0x50)>>3))]<<16; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<16; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<20; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<20; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<24; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<24; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<28; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<28; + } + y->w[n]^=we; + + y->w[20+n-1]^=wo<<4; + y->w[20+n]^=wo>>28; + + y->w[n+4]^=wo; + } + if (y->w[38]==0) mr_lzero(y); + return; + } + +#endif + +#if MIRACL==64 + if (M==1223 && A==255) + { + y->len=20; + for (i=0;i<20;i++) + { + n=i/2; + w=wk[i]; + + we=evens[((w&0x5)+((w&0x50)>>3))]; + wo=odds[((w&0xA)+((w&0xA0)>>5))]; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<4; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<4; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<8; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<8; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<12; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<12; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<16; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<16; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<20; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<20; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<24; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<24; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<28; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<28; + + i++; + w=wk[i]; + + we|=evens[((w&0x5)+((w&0x50)>>3))]<<32; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<32; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<36; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<36; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<40; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<40; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<44; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<44; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<48; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<48; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<52; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<52; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<56; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<56; + w>>=8; + we|=evens[((w&0x5)+((w&0x50)>>3))]<<60; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<60; + + y->w[n]^=we; + + y->w[10+n-1]^=wo<<36; + y->w[10+n]^=wo>>28; + + y->w[n+2]^=wo; + } + if (y->w[19]==0) mr_lzero(y); + return; + } + +#endif + + k=1+(M/MIRACL); + h=(k+1)/2; + + a=(A+1)/2; + aw=a/MIRACL; + ab=a%MIRACL; + + if (B) + { + a=(B+1)/2; + bw=a/MIRACL; + bb=a%MIRACL; + + a=(C+1)/2; + cw=a/MIRACL; + cb=a%MIRACL; + } + s=h*MIRACL-1-(M-1)/2; + + y->len=k; + for (i=0;i>3))]; + wo=odds[((w&0xA)+((w&0xA0)>>5))]; + w>>=8; + + we|=evens[((w&0x5)+((w&0x50)>>3))]<<4; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<4; + w>>=8; + + we|=evens[((w&0x5)+((w&0x50)>>3))]<<8; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<8; + w>>=8; + + we|=evens[((w&0x5)+((w&0x50)>>3))]<<12; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<12; + +#else + mm=0; + we=wo=0; + for (j=0;j>3))]<>5))]<>=8; + } + +#endif + i++; + if (i>3))]<<16; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<16; + w>>=8; + + we|=evens[((w&0x5)+((w&0x50)>>3))]<<20; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<20; + w>>=8; + + we|=evens[((w&0x5)+((w&0x50)>>3))]<<24; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<24; + w>>=8; + + we|=evens[((w&0x5)+((w&0x50)>>3))]<<28; + wo|=odds[((w&0xA)+((w&0xA0)>>5))]<<28; + + +#else + for (j=0;j>3))]<>5))]<>=8; + } + +#endif + } + y->w[n]^=we; + + if (s==0) y->w[h+n]=wo; + else + { + y->w[h+n-1]^=wo<<(MIRACL-s); + y->w[h+n]^=wo>>s; /* abutt odd bits to even */ + } + if (ab==0) y->w[n+aw]^=wo; + else + { + y->w[n+aw]^=wo<w[n+aw+1]^=wo>>(MIRACL-ab); + } + if (B) + { + if (bb==0) y->w[n+bw]^=wo; + else + { + y->w[n+bw]^=wo<w[n+bw+1]^=wo>>(MIRACL-bb); + } + if (cb==0) y->w[n+cw]^=wo; + else + { + y->w[n+cw]^=wo<w[n+cw+1]^=wo>>(MIRACL-cb); + } + } + } + + if (y->w[k-1]==0) mr_lzero(y); +} + +#ifndef MR_STATIC + +void power2(_MIPD_ big x,int m,big w) +{ /* w=x^m mod f. Could be optimised a lot, but not time critical for me */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,mr_mip->w1); + + convert(_MIPP_ 1,w); + forever + { + if (m%2!=0) + modmult2(_MIPP_ w,mr_mip->w1,w); + m/=2; + if (m==0) break; + modsquare2(_MIPP_ mr_mip->w1,mr_mip->w1); + } +} + +#endif + +/* Euclidean Algorithm */ + +BOOL inverse2(_MIPD_ big x,big w) +{ + mr_small bit; + int i,j,n,n3,k,n4,mb,mw; + big t; + BOOL newword; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (size(x)==0) return FALSE; + + convert(_MIPP_ 1,mr_mip->w1); + zero(mr_mip->w2); + copy(x,mr_mip->w3); + copy(mr_mip->modulus,mr_mip->w4); + + n3=numbits(mr_mip->w3); + n4=mr_mip->M+1; + +#ifdef MR_COUNT_OPS +fpi2++; +#endif + + while (n3!=1) + { + j=n3-n4; + + if (j<0) + { + t=mr_mip->w3; mr_mip->w3=mr_mip->w4; mr_mip->w4=t; + t=mr_mip->w1; mr_mip->w1=mr_mip->w2; mr_mip->w2=t; + j=-j; n=n3; n3=n4; n4=n; + } + + mw=j/MIRACL; mb=j%MIRACL; + + if (n3w3->w[0]^=mr_mip->w4->w[0]<w3->w[0]&bit)) + { + n3--; + bit>>=1; + } + } + else + { + k=mr_mip->w3->len; + if (mb==0) + { + for (i=mw;iw3->w[i]^=mr_mip->w4->w[i-mw]; + } + else + { + mr_mip->w3->w[mw]^=mr_mip->w4->w[0]<w3->w[i]^=((mr_mip->w4->w[i-mw]<w4->w[i-mw-1]>>(MIRACL-mb))); + } + + newword=FALSE; + while (mr_mip->w3->w[k-1]==0) {k--; newword=TRUE;} + +/* + bit=mr_mip->w3->w[k-1]; + ASM mov eax,bit + ASM bsr ecx,eax + ASM mov shift,ecx + n3=(k-1)*MIRACL+shift+1; + +*/ + if (newword) + { + bit=TOPBIT; + n3=k*MIRACL; + } + else + { + n3--; + bit=((mr_small)1<<((n3-1)%MIRACL)); + } + while (!(mr_mip->w3->w[k-1]&bit)) + { + n3--; + bit>>=1; + } + + mr_mip->w3->len=k; + } + + k=mr_mip->w2->len+mw+1; + if ((int)mr_mip->w1->len>k) k=mr_mip->w1->len; + + if (mb==0) + { + for (i=mw;iw1->w[i]^=mr_mip->w2->w[i-mw]; + } + else + { + mr_mip->w1->w[mw]^=mr_mip->w2->w[0]<w1->w[i]^=((mr_mip->w2->w[i-mw]<w2->w[i-mw-1]>>(MIRACL-mb))); + } + while (mr_mip->w1->w[k-1]==0) k--; + mr_mip->w1->len=k; + } + + copy(mr_mip->w1,w); + return TRUE; +} + +/* Schroeppel, Orman, O'Malley, Spatscheck * + * "Almost Inverse" algorithm, Crypto '95 * + * More optimization here and in-lining would * + * speed up AFFINE mode. I observe that * + * pentanomials would be more efficient if C * + * were greater */ + +/* +BOOL inverse2(_MIPD_ big x,big w) +{ + mr_small lsw,*gw; + int i,n,bits,step,n3,n4,k; + int k1,k2,k3,k4,ls1,ls2,ls3,ls4,rs1,rs2,rs3,rs4; + int M,A,B,C; + big t; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (size(x)==0) return FALSE; + + M=mr_mip->M; + A=mr_mip->AA; + if (A==0) + { + mr_berror(_MIPP_ MR_ERR_NO_BASIS); + return FALSE; + } + + B=mr_mip->BB; + C=mr_mip->CC; + convert(_MIPP_ 1,mr_mip->w1); + zero(mr_mip->w2); + copy(x,mr_mip->w3); + copy(mr_mip->modulus,mr_mip->w4); + + bits=zerobits(mr_mip->w3); + shiftrightbits(mr_mip->w3,bits); + k=bits; + n3=numbits(mr_mip->w3); + n4=M+1; + + if (n3>1) forever + { + if (n3w3; mr_mip->w3=mr_mip->w4; mr_mip->w4=t; + t=mr_mip->w1; mr_mip->w1=mr_mip->w2; mr_mip->w2=t; + n=n3; n3=n4; n4=n; + } + + add2(mr_mip->w3,mr_mip->w4,mr_mip->w3); + + add2(mr_mip->w1,mr_mip->w2,mr_mip->w1); + + if (n3==n4) n3=numbits(mr_mip->w3); + bits=zerobits(mr_mip->w3); + k+=bits; + n3-=bits; + if (n3==1) break; + shiftrightbits(mr_mip->w3,bits); + shiftleftbits(mr_mip->w2,bits); + } + + copy(mr_mip->w1,w); + + if (k==0) + { + mr_lzero(w); + return TRUE; + } + step=MIRACL; + + if (Aw; + while (k>0) + { + if (k>step) n=step; + else n=k; + + if (n==MIRACL) lsw=gw[0]; + else lsw=gw[0]&(((mr_small)1<len=k1; + if (rs1==0) gw[k1-1]^=lsw; + else + { + w->len++; + gw[k1]^=(lsw>>ls1); + gw[k1-1]^=(lsw<>ls2); + gw[k2-1]^=(lsw<>ls3); + gw[k3-1]^=(lsw<>ls4); + gw[k4-1]^=(lsw<w6); + if (size(mr_mip->w6)==0) + { + mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); + return FALSE; + } + + inverse2(_MIPP_ mr_mip->w6,mr_mip->w6); /* y=1/y */ + + copy(x[m-1],mr_mip->w5); + modmult2(_MIPP_ w[m-1],mr_mip->w6,w[m-1]); + + for (i=m-2;;i--) + { + if (i==0) + { + modmult2(_MIPP_ mr_mip->w5,mr_mip->w6,w[0]); + break; + } + modmult2(_MIPP_ w[i],mr_mip->w5,w[i]); + modmult2(_MIPP_ w[i],mr_mip->w6,w[i]); + modmult2(_MIPP_ mr_mip->w5,x[i],mr_mip->w5); + } + return TRUE; +} + +#ifndef MR_STATIC + +int trace2(_MIPD_ big x) +{ + int i; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + copy(x,mr_mip->w1); + for (i=1;iM;i++) + { + modsquare2(_MIPP_ mr_mip->w1,mr_mip->w1); + add2(mr_mip->w1,x,mr_mip->w1); + } + return (int)(mr_mip->w1->w[0]&1); +} + +#endif + +#ifndef MR_NO_RAND + +void rand2(_MIPD_ big x) +{ /* random number */ + int i,k; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zero(x); + k=1+mr_mip->M/MIRACL; + x->len=k; + for (i=0;iw[i]=brand(_MIPPO_ ); + mr_lzero(x); + reduce2(_MIPP_ x,x); +} + +#endif + +int parity2(big x) +{ /* return LSB */ + if (x->len==0) return 0; + return (int)(x->w[0]%2); +} + +void halftrace2(_MIPD_ big b,big w) +{ + int i,M; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + M=mr_mip->M; + if (M%2==0) return; + + copy(b,mr_mip->w1); + copy(b,w); + + for (i=1;i<=(M-1)/2;i++) + { + modsquare2(_MIPP_ w,w); + modsquare2(_MIPP_ w,w); + add2(w,mr_mip->w1,w); + } +} + +BOOL quad2(_MIPD_ big b,big w) +{ /* Solves x^2 + x = b for a root w * + * returns TRUE if a solution exists * + * the "other" solution is w+1 */ + int i,M; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + M=mr_mip->M; + copy(b,mr_mip->w1); + if (M%2==1) halftrace2(_MIPP_ b,w); /* M is odd, so its the Half-Trace */ + + else + { + zero(mr_mip->w2); + forever + { +#ifndef MR_NO_RAND + rand2(_MIPP_ mr_mip->w2); +#else + incr(_MIPP_ mr_mip->w2,1,mr_mip->w2); +#endif + zero(w); + copy(mr_mip->w2,mr_mip->w3); + for (i=1;iw3,mr_mip->w3); + modmult2(_MIPP_ mr_mip->w3,mr_mip->w1,mr_mip->w4); + modsquare2(_MIPP_ w,w); + add2(w,mr_mip->w4,w); + add2(mr_mip->w3,mr_mip->w2,mr_mip->w3); + } + if (size(mr_mip->w3)!=0) break; + } + } + + copy(w,mr_mip->w2); + modsquare2(_MIPP_ mr_mip->w2,mr_mip->w2); + add2(mr_mip->w2,w,mr_mip->w2); + if (mr_compare(mr_mip->w1,mr_mip->w2)==0) return TRUE; + return FALSE; +} + +#ifndef MR_STATIC + +void gf2m_dotprod(_MIPD_ int n,big *x,big *y,big w) +{ /* dot product - only one reduction! */ + int i; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + mr_mip->check=OFF; + zero(mr_mip->w5); + + for (i=0;iw0); + add2(mr_mip->w5,mr_mip->w0,mr_mip->w5); + } + + reduce2(_MIPP_ mr_mip->w5,mr_mip->w5); + copy(mr_mip->w5,w); + + mr_mip->check=ON; +} + +#endif + +BOOL prepare_basis(_MIPD_ int m,int a,int b,int c,BOOL check) +{ + int i,k,sh; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + if (b==0) c=0; + if (m==mr_mip->M && a==mr_mip->AA && b==mr_mip->BB && c==mr_mip->CC) + return TRUE; /* its already prepared... */ + + MR_IN(138) + if (m <=0 || a<=0 || a>=m || b>=a) + { + mr_berror(_MIPP_ MR_ERR_BAD_MODULUS); + MR_OUT + return FALSE; + } + + mr_mip->M=m; + mr_mip->AA=a; + mr_mip->BB=0; + mr_mip->CC=0; + zero(mr_mip->modulus); + convert(_MIPP_ 1,mr_mip->one); + + k=1+m/MIRACL; + + if (k>mr_mip->nib) + { + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + MR_OUT + return FALSE; + } + + mr_mip->modulus->len=k; + sh=m%MIRACL; + mr_mip->modulus->w[k-1]=((mr_small)1<modulus->w[0]^=1; + mr_mip->modulus->w[a/MIRACL]^=((mr_small)1<<(a%MIRACL)); + if (b!=0) + { + mr_mip->BB=b; + mr_mip->CC=c; + mr_mip->modulus->w[b/MIRACL]^=((mr_small)1<<(b%MIRACL)); + mr_mip->modulus->w[c/MIRACL]^=((mr_small)1<<(c%MIRACL)); + } + + if (!check) + { + MR_OUT + return TRUE; + } + +/* check for irreducibility of basis */ + + zero(mr_mip->w4); + mr_mip->w4->len=1; + mr_mip->w4->w[0]=2; /* f(t) = t */ + for (i=1;i<=m/2;i++) + { + modsquare2(_MIPP_ mr_mip->w4,mr_mip->w4); + incr2(mr_mip->w4,2,mr_mip->w5); + gcd2(_MIPP_ mr_mip->w5,mr_mip->modulus,mr_mip->w6); + if (size(mr_mip->w6)!=1) + { + mr_berror(_MIPP_ MR_ERR_NOT_IRREDUC); + MR_OUT + return FALSE; + } + } + + MR_OUT + return TRUE; +} + +#endif diff --git a/miracl/source/mrio1.c b/miracl/source/mrio1.c new file mode 100644 index 0000000..7a55d9d --- /dev/null +++ b/miracl/source/mrio1.c @@ -0,0 +1,533 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL I/O routines 1. + * mrio1.c + */ + +#include "miracl.h" + +#ifndef MR_SIMPLE_IO + +int instr(_MIPD_ flash x,char *string) +{ /* input a big number * + * returns length in digits */ + int i,ipt,n,s,e,pads; + BOOL first_after_pad; + int ch,lc; +#ifdef MR_FLASH + BOOL frac; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(76) + + if (mr_mip->apbase==0 || mr_mip->apbase>256) + { + mr_berror(_MIPP_ MR_ERR_BASE_TOO_BIG); + MR_OUT + return 0; + } + + if (!mr_mip->active) + { + mr_berror(_MIPP_ MR_ERR_NO_MIRSYS); + MR_OUT + return 0; + } + + zero(x); + if (mr_mip->fin) string=mr_mip->IOBUFF; + if (mr_mip->INPLEN==0) + { /* inputting ASCII bytes */ + +#ifndef MR_NO_FILE_IO + + if (mr_mip->fin) + { /* read in characters */ + i=0; + do + { + ch=fgetc(mr_mip->infile); + if (ch==EOF) break; + string[i++]=ch; + + if (i>=mr_mip->IOBSIZ) + { + mr_berror(_MIPP_ MR_ERR_IO_OVERFLOW); + MR_OUT + return 0; + } + } while (ch!='\n' && ch!='\0'); + string[i]='\0'; + } + +#endif + forever + { /* get input length */ + ch=(unsigned char)string[mr_mip->INPLEN]; + if (ch=='\0') break; + if (mr_mip->apbase<=60 && ch=='\n') break; + mr_mip->INPLEN++; + if (string==mr_mip->IOBUFF && mr_mip->INPLEN>=mr_mip->IOBSIZ) + { + mr_berror(_MIPP_ MR_ERR_IO_OVERFLOW); + MR_OUT + return 0; + } + } + } + else + { /* inputting BINARY bytes */ + if (string==mr_mip->IOBUFF && mr_mip->INPLEN>=mr_mip->IOBSIZ) + { + mr_berror(_MIPP_ MR_ERR_IO_OVERFLOW); + MR_OUT + return 0; + } + +#ifndef MR_NO_FILE_IO + + if (mr_mip->fin) for(i=0;iINPLEN;i++) + { + if ((ch=fgetc(mr_mip->infile))==EOF) + { + mr_mip->INPLEN=i; + break; + } + string[i]=MR_TOBYTE(ch); + } + +#endif + + } + n=0; + s=PLUS; + e=0; +#ifdef MR_FLASH + frac=FALSE; +#endif + if (mr_mip->INPLEN>0 && mr_mip->apbase<=60) + { /* skip leading blanks and check sign */ +#ifdef MR_FLASH + if (string[mr_mip->INPLEN-1]=='/') mr_mip->INPLEN--; +#endif + while (string[e]==' ') e++; + if (string[e]=='-') + { /* check sign */ + s=MINUS; + e++; + } + if (string[e]=='+') e++; + } + + pads=0; first_after_pad=TRUE; + for (i=mr_mip->INPLEN-1;i>=e;i--) + { + ch=(unsigned char)string[i]; + if (mr_mip->apbase<=60 || mr_mip->apbase==64) + { /* check for slash or dot and convert character to number */ +#ifdef MR_FLASH + if (mr_mip->apbase<=60 && !frac) + { + if (ch=='/') + { + frac=TRUE; + copy(x,mr_mip->w0); + zero(x); + n=0; + continue; + } + if (ch=='.') + { + frac=TRUE; + zero(mr_mip->w0); + putdig(_MIPP_ 1,mr_mip->w0,n+1); + continue; + } + } +#endif + ch+=80; + if (mr_mip->apbase==64) + { /* base64 */ + if (ch<=112) continue; /* ignore white space */ + if (ch>144 && ch<171) ch-=145; + if (ch>176 && ch<203) ch-=151; + if (ch>127 && ch<138) ch-=76; + if (ch==123) ch=62; + if (ch==127) ch=63; + if (ch==141) {pads++; continue;} /* pads '=' */ + } + else + { + if (ch>127 && ch<138) ch-=128; + if (ch>144 && ch<171) ch-=135; + if (mr_mip->apbase<=16) + { + if (ch>176 && ch<203) ch-=167; + } + else + { + if (ch>176 && ch<203) ch-=141; + } + } + } + + if ((mr_small)ch>=mr_mip->apbase || pads>2) + { + mr_berror(_MIPP_ MR_ERR_BAD_FORMAT); + MR_OUT + return 0; + } + + if (pads && first_after_pad) + { /* there was padding, so adjust */ + lc=ch>>(2*pads); + first_after_pad=FALSE; + continue; + } + + n++; + if (pads) + { + putdig(_MIPP_ 0x3f&((ch<<(6-2*pads))|lc),x,n); + lc=(ch>>(2*pads)); + continue; + } + + putdig(_MIPP_ ch,x,n); + } + + if (pads && lc>0) + putdig(_MIPP_ lc,x,++n); + + ipt=mr_mip->INPLEN; + mr_mip->INPLEN=0; + insign(s,x); + mr_lzero(x); +#ifdef MR_FLASH + mr_lzero(mr_mip->w0); + if (frac) fpack(_MIPP_ x,mr_mip->w0,x); +#endif + MR_OUT + return ipt; +} + +int otstr(_MIPD_ flash x,char *string) +{ /* output a big number */ + int s,i,n,ch,rp,nd,m; + BOOL check; +#ifdef MR_FLASH + int nw,dw; +#endif + mr_lentype lx; + BOOL done; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(75) + if (mr_mip->apbase==0 || mr_mip->apbase>256) + { + mr_berror(_MIPP_ MR_ERR_BASE_TOO_BIG); + MR_OUT + return 0; + } + + if (!mr_mip->active) + { + mr_berror(_MIPP_ MR_ERR_NO_MIRSYS); + MR_OUT + return 0; + } + n=0; + s=exsign(x); + insign(PLUS,x); + lx = x->len; + if (lx==0 && mr_mip->apbase<=60) + { + +#ifndef MR_NO_FILE_IO + + if (!mr_mip->fout) + { + string[0]='0'; + string[1]='\0'; + } + else + { + fputc('0',mr_mip->otfile); + fputc('\n',mr_mip->otfile); + } +#else + string[0]='0'; + string[1]='\0'; + +#endif + MR_OUT + return 1; + } + rp=0; + if (s==MINUS && mr_mip->apbase<=60) + { +#ifndef MR_NO_FILE_IO + if (!mr_mip->fout) string[n]='-'; + else fputc('-',mr_mip->otfile); +#else + string[n]='-'; +#endif + n++; + } +#ifdef MR_FLASH + done=FALSE; + numer(_MIPP_ x,mr_mip->w6); + if (mr_mip->RPOINT) + { /* output with radix point */ + denom(_MIPP_ x,mr_mip->w5); + if (size(mr_mip->w5)>1) + { /* multiply up numerator to get full precision in * + * the output. Remember position of radix point. */ + nw=(int)(lx&MR_MSK); + dw=(int)((lx>>MR_BTS)&MR_MSK); + if (nw==0) nw++; + check=mr_mip->check; + mr_mip->check=OFF; + if (nw>dw) mr_shift(_MIPP_ mr_mip->w5,nw-dw,mr_mip->w5); + if (dw>nw) mr_shift(_MIPP_ mr_mip->w6,dw-nw,mr_mip->w6); + nd=mr_mip->nib; + if (mr_compare(mr_mip->w6,mr_mip->w5)>=0) nd--; + copy(mr_mip->w6,mr_mip->w0); + if (((int)mr_mip->w0->len+nd)>2*mr_mip->nib) nd=2*mr_mip->nib-(int)mr_mip->w0->len; + mr_shift(_MIPP_ mr_mip->w0,nd,mr_mip->w0); + divide(_MIPP_ mr_mip->w0,mr_mip->w5,mr_mip->w6); + mr_mip->check=check; + rp=mr_mip->pack*(nd+dw-nw); + } + } +#else + copy(x,mr_mip->w6); + done=TRUE; +#endif + + forever + { + nd=numdig(_MIPP_ mr_mip->w6); + m=nd; + if (mr_mip->apbase==64) + { /* add leading zeros to base64 */ + while (m%4!=0) m++; + } + if (rp>m) m=rp; + for (i=m;i>0;i--) + { + if (!mr_mip->fout && string==mr_mip->IOBUFF && n>=mr_mip->IOBSIZ-5) + { + mr_berror(_MIPP_ MR_ERR_IO_OVERFLOW); + MR_OUT + return n; + } +#ifdef MR_FLASH + if (i==rp && mr_mip->apbase<=60) + { +#ifndef MR_NO_FILE_IO + if (!mr_mip->fout) string[n]='.'; + else fputc('.',mr_mip->otfile); +#else + string[n]='.'; +#endif + n++; + } +#endif + if (i>nd && mr_mip->apbase!=64) ch='0'; + else + { + ch=getdig(_MIPP_ mr_mip->w6,i); + check=mr_mip->check; + mr_mip->check=OFF; + putdig(_MIPP_ 0,mr_mip->w6,i); + /* mr_mip->check=mr_mip->check; Nasty stupid bug! */ + mr_mip->check=check; + if (mr_mip->apbase<=60) + { /* convert number to character */ + ch+=48; + if (ch>=58) ch+=7; + if (ch>=91) ch+=6; + } + if (mr_mip->apbase==64) + { + if (ch<26) ch+=65; + if (ch>=26 && ch<52) ch+=71; + if (ch>=52 && ch<62) ch-=4; + if (ch==62) ch='+'; + if (ch==63) ch='/'; + } + } + if (iapbase<=60 && ch=='0' && size(mr_mip->w6)==0) break; +#ifndef MR_NO_FILE_IO + if (!mr_mip->fout) string[n]=MR_TOBYTE(ch); + else fputc(MR_TOBYTE(ch),mr_mip->otfile); +#else + string[n]=MR_TOBYTE(ch); +#endif + n++; + } + if (done) break; +#ifdef MR_FLASH + if (mr_mip->RPOINT) break; + denom(_MIPP_ x,mr_mip->w6); + if (size(mr_mip->w6)==1) break; + if (mr_mip->apbase<=60) + { +#ifndef MR_NO_FILE_IO + if (!mr_mip->fout) string[n]='/'; + else fputc('/',mr_mip->otfile); +#else + string[n]='/'; +#endif + n++; + } + done=TRUE; +#endif + } +/* + if (mr_mip->apbase==64) + { + while (n%3!=0) + { +#ifndef MR_NO_FILE_IO + if (!mr_mip->fout) string[n]='='; + else fputc('=',mr_mip->otfile); +#else + string[n]='='; +#endif + n++; + } + + } +*/ +/* Append a trailing 0 - it may be printable ascii text */ + +#ifndef MR_NO_FILE_IO + if (!mr_mip->fout) string[n]='\0'; + else if (mr_mip->apbase<=60 || mr_mip->apbase==64) fputc('\n',mr_mip->otfile); +#else + string[n]='\0'; +#endif + insign(s,x); + MR_OUT + return n; +} + +#ifndef MR_NO_FILE_IO + +int innum(_MIPD_ flash x,FILE *filep) +{ /* convert from string to flash x */ + int n; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(1) + + mr_mip->infile=filep; + mr_mip->fin=TRUE; + n=instr(_MIPP_ x,NULL); + mr_mip->fin=FALSE; + + MR_OUT + return n; +} + +int otnum(_MIPD_ flash x,FILE *filep) +{ /* convert flash to string */ + int n; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(2) + + mr_mip->otfile=filep; + mr_mip->fout=TRUE; + n=otstr(_MIPP_ x,NULL); + mr_mip->fout=FALSE; + + MR_OUT + return n; +} + +#endif + +#else + +#ifndef MR_FLASH +#ifndef MR_NO_STANDARD_IO +#ifndef MR_FP + +int otnum(_MIPD_ flash x,FILE *filep) +{ /* support crude hex output only */ + int i,j,ch,n; + BOOL leading=TRUE; + mr_small w; + n=0; + if (size(x)<0) fputc('-',filep); + for (i=(x->len&MR_OBITS)-1;i>=0;i--) + { + w=x->w[i]; + for (j=MIRACL-4;j>=0;j-=4) + { + ch=48+((w>>j)&0xF); + if (ch==48 && leading) continue; + leading=FALSE; + if (ch>=58) ch+=7; + fputc(MR_TOBYTE(ch),filep); + n++; + } + } + fputc('\n',filep); + return n; +} + +#endif +#endif +#endif + +#endif diff --git a/miracl/source/mrio2.c b/miracl/source/mrio2.c new file mode 100644 index 0000000..71d2198 --- /dev/null +++ b/miracl/source/mrio2.c @@ -0,0 +1,215 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL I/O routines 2. + * mrio2.c + */ + +#include "miracl.h" + +#ifndef MR_SIMPLE_BASE +#ifndef MR_SIMPLE_IO + +static void cbase(_MIPD_ big x,mr_small oldbase,big y) +{ /* change radix of x from oldbase to base */ + int i,s; + mr_small n; + BOOL done; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + if (mr_mip->base==oldbase) + { + copy(x,y); + return; + } + + MR_IN(13) + + s=exsign(x); +#ifdef MR_FLASH + numer(_MIPP_ x,mr_mip->w1); + denom(_MIPP_ x,mr_mip->w2); + done=FALSE; +#else + copy(x,mr_mip->w1); + done=TRUE; +#endif + insign(PLUS,mr_mip->w1); + + forever + { + zero(mr_mip->w6); + convert(_MIPP_ 1,mr_mip->w0); + + for (i=0;i<(int)mr_mip->w1->len;i++) + { /* this is a bit slow - but not time critical */ + + + mr_pmul(_MIPP_ mr_mip->w0,mr_mip->w1->w[i],mr_mip->w5); + + add(_MIPP_ mr_mip->w6,mr_mip->w5,mr_mip->w6); + if (oldbase==0) + { /* bit of a frig! */ + n=mr_shiftbits(1,MIRACL/2); + mr_pmul(_MIPP_ mr_mip->w0,n,mr_mip->w0); + mr_pmul(_MIPP_ mr_mip->w0,n,mr_mip->w0); + } + else mr_pmul(_MIPP_ mr_mip->w0,oldbase,mr_mip->w0); + } + if (mr_mip->ERNUM || done) break; +#ifdef MR_FLASH + copy(mr_mip->w2,mr_mip->w1); + copy(mr_mip->w6,mr_mip->w7); + done=TRUE; +#endif + } + +#ifdef MR_FLASH + fpack(_MIPP_ mr_mip->w7,mr_mip->w6,y); +#else + copy(mr_mip->w6,y); +#endif + + insign(s,y); + MR_OUT +} + +int cinstr(_MIPD_ flash x,char *string) +{ /* input big number in base IOBASE */ + mr_small newb,oldb,b; + mr_lentype lx; + int ipt; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(78) + + newb=mr_mip->IOBASE; + oldb=mr_mip->apbase; + mr_setbase(_MIPP_ newb); /* temporarily change base ... */ + b=mr_mip->base; + mr_mip->check=OFF; + ipt=instr(_MIPP_ mr_mip->w5,string); /* ... and get number */ + + mr_mip->check=ON; + lx=(mr_mip->w5->len&MR_OBITS); +#ifdef MR_FLASH + if ((int)(lx&MR_MSK)>mr_mip->nib || (int)((lx>>MR_BTS)&MR_MSK)>mr_mip->nib) +#else + if ((int)lx>mr_mip->nib) +#endif + { /* numerator or denominator too big */ + mr_berror(_MIPP_ MR_ERR_OVERFLOW); + MR_OUT + return 0; + } + mr_setbase(_MIPP_ oldb); /* restore original base */ + + cbase(_MIPP_ mr_mip->w5,b,x); + + MR_OUT + return ipt; +} + +int cotstr(_MIPD_ flash x,char *string) +{ /* output a big number in base IOBASE */ + mr_small newb,oldb,b; + int ipt; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(77) + newb=mr_mip->IOBASE; + oldb=mr_mip->apbase; + b=mr_mip->base; + mr_setbase(_MIPP_ newb); /* temporarily change base ... */ + mr_mip->check=OFF; + + cbase(_MIPP_ x,b,mr_mip->w5); /* number may get bigger ! */ + mr_mip->check=ON; + + ipt=otstr(_MIPP_ mr_mip->w5,string); /*..... and output number */ + zero(mr_mip->w5); + mr_setbase(_MIPP_ oldb); + MR_OUT + return ipt; +} + +#ifndef MR_NO_FILE_IO + +int cinnum(_MIPD_ flash x,FILE *filep) +{ /* convert from string to flash x */ + int n; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(14) + mr_mip->infile=filep; + mr_mip->fin=TRUE; + n=cinstr(_MIPP_ x,NULL); + mr_mip->fin=FALSE; + MR_OUT + return n; +} + +int cotnum(_MIPD_ flash x,FILE *filep) +{ /* convert flash to string */ + int n; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(15) + mr_mip->otfile=filep; + mr_mip->fout=TRUE; + n=cotstr(_MIPP_ x,NULL); + mr_mip->fout=FALSE; + MR_OUT + return n; +} + +#endif + +#endif +#endif diff --git a/miracl/source/mrjack.c b/miracl/source/mrjack.c new file mode 100644 index 0000000..bc3b445 --- /dev/null +++ b/miracl/source/mrjack.c @@ -0,0 +1,342 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL Jacobi symbol routine + * mrjack.c + * + * See "A binary algorithm for the Jacobi symbol" + * Shallit and Sorenson + */ +#include +#include "miracl.h" + +int jack(_MIPD_ big a,big n) +{ /* find jacobi symbol (a/n), for positive odd n */ + big w; + int nm8,onm8,t; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM || size(a)==0 || size(n) <1) return 0; + MR_IN(3) + + t=1; + copy(n,mr_mip->w2); + nm8=remain(_MIPP_ mr_mip->w2,8); + if (nm8%2==0) + { + MR_OUT + return 0; + } + + if (size(a)<0) + { + if (nm8%4==3) t=-1; + negify(a,mr_mip->w1); + } + else copy(a,mr_mip->w1); + + while (size(mr_mip->w1)!=0) + { + while (remain(_MIPP_ mr_mip->w1,2)==0) + { + subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1); + if (nm8==3 || nm8==5) t=-t; + } + if (mr_compare(mr_mip->w1,mr_mip->w2)<0) + { + onm8=nm8; + w=mr_mip->w1; mr_mip->w1=mr_mip->w2; mr_mip->w2=w; + nm8=remain(_MIPP_ mr_mip->w2,8); + if (onm8%4==3 && nm8%4==3) t=-t; + } + mr_psub(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); + subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1); + + if (nm8==3 || nm8==5) t=-t; + } + + MR_OUT + if (size(mr_mip->w2)==1) return t; + return 0; +} + +/* + * See "Efficient Algorithms for Computing the Jacobi Symbol" + * Eikenberry & Sorenson + * + * Its turns out this is slower than the binary method above for reasonable sizes + * of parameters (and takes up a lot more space!) + + +#ifdef MR_FP +#include +#endif + + +static void rfind(mr_small u,mr_small v,mr_small k,mr_small sk,mr_utype *a,mr_utype *b) +{ + mr_utype x2,y2,r; + mr_small w,q,x1,y1,sr; +#ifdef MR_FP + mr_small dres; +#endif + + w=invers(v,k); + w=smul(u,w,k); + + x1=k; x2=0; + y1=w; y2=1; + +// NOTE: x1 and y1 are always +ve. x2 and y2 are always small + + while (y1>=sk) + { +#ifndef MR_NOFULLWIDTH + if (x1==0) q=muldvm((mr_small)1,(mr_small)0,y1,&sr); + else +#endif + q=MR_DIV(x1,y1); + r= x1-q*y1; x1=y1; y1=r; + sr=x2-q*y2; x2=y2; y2=sr; + } + if (y2>=0) { *a=y2; *b=0-y1; } + else { *a=-y2; *b=y1; } +} + +int jack(_MIPD_ big U,big V) +{ // find jacobi symbol for U wrt V. Only defined for + // positive V, V odd. Otherwise returns 0 + int i,e,r,m,t,v8,u4; + mr_utype a,b; + mr_small u,v,d,g,k,sk,s; +#ifdef MR_FP + mr_small dres; +#endif + big w; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_FP_ROUNDING + mr_large ik,id; +#endif + if (mr_mip->ERNUM || size(U)==0 || size(V) <1) return 0; + copy(U,mr_mip->w1); + copy(V,mr_mip->w2); + a=0; + MR_IN(3) + + if (remain(_MIPP_ mr_mip->w2,2)==0) + { // V is even + MR_OUT + return 0; + } + + if (mr_mip->base!=0) + { + k=1; + for (m=1;;m++) + { + k*=2; + if (k==MAXBASE) break; + } + if (m%2==1) {m--; k=MR_DIV(k,2);} +#ifdef MR_FP_ROUNDING + ik=mr_invert(k); +#endif + } + else + { + m=MIRACL; + k=0; + } + r=m/2; + sk=1; + for (i=0;iw2,8); + + while (!mr_mip->ERNUM && size(mr_mip->w1)!=0) + { + if (size(mr_mip->w1)<0) + { + negify(mr_mip->w1,mr_mip->w1); + if (v8%4==3) t=-t; + } + + do { // oddify + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + if (mr_mip->base==k) u=mr_mip->w1->w[0]; + else u=MR_REMAIN(mr_mip->w1->w[0],k); +#ifndef MR_ALWAYS_BINARY + } + +#ifdef MR_FP_ROUNDING + else u=mr_sdiv(_MIPP_ mr_mip->w1,k,ik,mr_mip->w3); +#else + else u=mr_sdiv(_MIPP_ mr_mip->w1,k,mr_mip->w3); +#endif + +#endif + if (u==0) {s=k; e=0;} + else + { + s=1; e=0; + while (MR_REMAIN(u,2)==0) {s*=2; e++; u=MR_DIV(u,2);} + } + if (s==mr_mip->base) mr_shift(_MIPP_ mr_mip->w1,-1,mr_mip->w1); +#ifdef MR_FP_ROUNDING + else if (s>1) + { + mr_sdiv(_MIPP_ mr_mip->w1,s,mr_invert(s),mr_mip->w1); + } +#else + else if (s>1) mr_sdiv(_MIPP_ mr_mip->w1,s,mr_mip->w1); +#endif + } while (u==0); + if (e%2!=0 && (v8==3 || v8==5)) t=-t; + if (mr_compare(mr_mip->w1,mr_mip->w2)<0) + { + if (mr_mip->base==mr_mip->base2) u4=(int)MR_REMAIN(mr_mip->w1->w[0],4); + else u4=remain(_MIPP_ mr_mip->w1,4); + if (v8%4==3 && u4==3) t=-t; + w=mr_mip->w1; mr_mip->w1=mr_mip->w2; mr_mip->w2=w; + } + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + if (k==mr_mip->base) + { + u=mr_mip->w1->w[0]; + v=mr_mip->w2->w[0]; + } + else + { + u=MR_REMAIN(mr_mip->w1->w[0],k); + v=MR_REMAIN(mr_mip->w2->w[0],k); + } +#ifndef MR_ALWAYS_BINARY + } + else + { +#ifdef MR_FP_ROUNDING + u=mr_sdiv(_MIPP_ mr_mip->w1,k,ik,mr_mip->w3); + v=mr_sdiv(_MIPP_ mr_mip->w2,k,ik,mr_mip->w3); +#else + u=mr_sdiv(_MIPP_ mr_mip->w1,k,mr_mip->w3); + v=mr_sdiv(_MIPP_ mr_mip->w2,k,mr_mip->w3); +#endif + } +#endif + rfind(u,v,k,sk,&a,&b); + if (a>1) + { +#ifdef MR_FP_ROUNDING + d=mr_sdiv(_MIPP_ mr_mip->w2,a,mr_invert(a),mr_mip->w3); +#else + d=mr_sdiv(_MIPP_ mr_mip->w2,a,mr_mip->w3); +#endif + d=sgcd(d,a); + a=MR_DIV(a,d); + } + else d=1; + + if (d>1) + { +#ifdef MR_FP_ROUNDING + id=mr_invert(d); + mr_sdiv(_MIPP_ mr_mip->w2,d,id,mr_mip->w2); + u=mr_sdiv(_MIPP_ mr_mip->w1,d,id,mr_mip->w3); +#else + mr_sdiv(_MIPP_ mr_mip->w2,d,mr_mip->w2); + u=mr_sdiv(_MIPP_ mr_mip->w1,d,mr_mip->w3); +#endif + } + else u=0; + + g=a; + if (mr_mip->base==mr_mip->base2) v8=(int)MR_REMAIN(mr_mip->w2->w[0],8); + else v8=remain(_MIPP_ mr_mip->w2,8); + while (MR_REMAIN(g,2)==0) + { + g=MR_DIV(g,2); + if (v8==3 || v8==5) t=-t; + } + if (MR_REMAIN(g,4)==3 && v8%4==3) t=-t; +#ifdef MR_FP_ROUNDING + v=mr_sdiv(_MIPP_ mr_mip->w2,g,mr_invert(g),mr_mip->w3); +#else + v=mr_sdiv(_MIPP_ mr_mip->w2,g,mr_mip->w3); +#endif + t*=jac(v,g)*jac(u,d); + if (t==0) + { + MR_OUT + return 0; + } + +// printf("a= %I64d b=%I64d %d\n",a,b,(int)b); + + if (a>1) mr_pmul(_MIPP_ mr_mip->w1,a,mr_mip->w1); + if (b>=0) + mr_pmul(_MIPP_ mr_mip->w2,b,mr_mip->w3); + else + { + b=-b; + mr_pmul(_MIPP_ mr_mip->w2,b,mr_mip->w3); + negify(mr_mip->w3,mr_mip->w3); + } + // premult(_MIPP_ mr_mip->w2,(int)b,mr_mip->w3); <- nasty bug - potential loss of precision in b + add(_MIPP_ mr_mip->w1,mr_mip->w3,mr_mip->w1); + if (k==mr_mip->base) mr_shift(_MIPP_ mr_mip->w1,-1,mr_mip->w1); +#ifdef MR_FP_ROUNDING + else mr_sdiv(_MIPP_ mr_mip->w1,k,ik,mr_mip->w1); +#else + else mr_sdiv(_MIPP_ mr_mip->w1,k,mr_mip->w1); +#endif + } + MR_OUT + if (size(mr_mip->w2)==1) return t; + return 0; +} + +*/ diff --git a/miracl/source/mrkcm.tpl b/miracl/source/mrkcm.tpl new file mode 100644 index 0000000..50f54fd --- /dev/null +++ b/miracl/source/mrkcm.tpl @@ -0,0 +1,511 @@ + +/* + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +*/ +/* + * MIRACL Karatsuba method for multiprecision multiplication combined with + * Comba's method for high speed assembly language multiplication + * and Montgomery's method for modular muliplication - the KCM Method - + * together yield near optimal speed for exponentiation cryptosystems. + * + * mrkcm.tpl + * + * This approach is recommended for maximum speed where parameters + * are fixed and compute resources are constrained. The processor must + * support an unsigned multiply instruction, and should have a carry flag. + * + * This file is a template. To fill in the gaps and create mrkcm.c + * you must run the mex.c program to insert the C or assembly language + * macros from the appropriate .mcs file. For use with C, MR_NOASM must + * be defined in mirdef.h + * + * This method would appear to be particularly useful for implementing fast + * RSA/DSA/DH Cryptosystems. + * + * The #define MR_KCM in mirdef.h affects the size of modulus that can + * be used. This *must* be determined at compile time. Then any modulus + * of size in words = MR_KCM*2^n can be used. For example if MR_KCM=8 + * a modulus of size 8,16,32,64 etc can be used. So if MR_KCM = 8 on a + * 32 bit computer, then the modulus may be 256, 512, 1024, 2048 etc. + * bits in length + * + * Note that this module can generate a *lot* of code for larger values of + * MR_KCM. This should have a maximum value of 8-16. + * + * Note that on some processors it is *VITAL* that arrays be aligned on + * 4-byte boundaries + * + * Inspiration from Wei Dai is acknowledged + * + * **** This code does not like -fomit-frame-pointer using GCC *********** + * + */ + +#include "miracl.h" + +#ifdef MR_KCM + +#if INLINE_ASM == 1 +#define N 2 +#define POINTER WORD PTR +#define PBP bp +#define PBX bx +#define PCX cx +#define PSI si +#define PDI di +#define DSI si +#define DDI di +#define DBP bp +#define DAX ax +#define DBX bx +#define DCX cx +#define DDX dx +#endif + +#if INLINE_ASM == 2 +#define N 4 +#define POINTER DWORD PTR +#define PBP bp +#define PBX bx +#define PSI si +#define PDI di +#define PCX cx +#define DSI esi +#define DDI edi +#define DBP ebp +#define DAX eax +#define DBX ebx +#define DCX ecx +#define DDX edx +#endif + +#if INLINE_ASM == 3 +#define N 4 +#define POINTER DWORD PTR +#define PBP ebp +#define PBX ebx +#define PCX ecx +#define PSI esi +#define PDI edi +#define DSI esi +#define DDI edi +#define DBP ebp +#define DAX eax +#define DBX ebx +#define DCX ecx +#define DDX edx +#endif + +static void mr_comba_mul(mr_small *x,mr_small *y,mr_small *z) +{ /* multiply two arrays of length MR_KCM */ + mr_small *a,*b,*c; +#ifdef MR_WIN64 + mr_small lo,hi,sumlo,sumhi,extra; +#endif +#ifdef MR_ITANIUM + register mr_small lo1,hi1,lo2,hi2,ma,mb,sumlo,sumhi,extra; +#endif +#ifdef MR_NOASM + #ifdef mr_qltype + mr_large pp1; + mr_vlarge sum; + #else + register mr_small extra,s0,s1; + mr_large pp1,pp2,sum; + #endif +#endif + a=x; b=y; c=z; + +/*** MULTIPLY ***/ + +} + +static void mr_comba_halfm(mr_small *x,mr_small *y,mr_small *z) +{ /* multiply two arrays, but only return lower half */ + mr_small *a,*b,*c; +#ifdef MR_ITANIUM + register mr_small lo1,hi1,lo2,hi2,ma,mb,sumlo,sumhi,extra; +#endif +#ifdef MR_WIN64 + mr_small lo,hi,sumlo,sumhi,extra; +#endif +#ifdef MR_NOASM + #ifdef mr_qltype + mr_large pp1; + mr_vlarge sum; + #else + register mr_small extra,s0,s1; + mr_large pp1,pp2,sum; + #endif +#endif + a=x; b=y; c=z; + +/*** MULTUP ***/ + +} + +static void mr_comba_sqr(mr_small *x,mr_small *z) +{ /* square an array of length MR_KCM */ + mr_small *a,*c; +#ifdef MR_ITANIUM + register mr_small lo1,hi1,lo2,hi2,ma,mb,sumlo,sumhi,extra; +#endif +#ifdef MR_WIN64 + mr_small lo,hi,sumlo,sumhi,extra,cy; +#endif +#ifdef MR_NOASM + #ifdef mr_qltype + mr_large pp1; + mr_vlarge sum; + #else + register mr_small extra,s0,s1; + mr_large pp1,pp2,sum; + #endif +#endif + a=x; c=z; + +/*** SQUARE ***/ + +} + +static int mr_addn(mr_small *x,mr_small *y,mr_small *z,int n) +{ /* add two arrays of length n*MR_KCM */ + /* first some macros */ + mr_small *a,*b,*c; + mr_small carry; +#ifdef MR_ITANIUM + register mr_small ma,u; +#endif +#ifdef MR_WIN64 + mr_small ma,u; +#endif +#ifdef MR_NOASM + mr_large u; +#endif + a=x; b=y; c=z; + +/*** SUMMATION ***/ + + return (int)carry; +} + +static int mr_incn(mr_small *y,mr_small *z,int n) +{ /* add to an array of length n*MR_KCM */ + mr_small *a,*b; + mr_small carry; +#ifdef MR_WIN64 + mr_small ma,u; +#endif +#ifdef MR_ITANIUM + register mr_small ma,u; +#endif +#ifdef MR_NOASM + mr_large u; +#endif + + a=z; b=y; + +/*** INCREMENTATION */ + + return (int)carry; +} + +static int mr_decn(mr_small *y,mr_small *z,int n) +{ /* subtract from an array of length n*MR_KCM */ + mr_small *a,*b; + mr_small carry; +#ifdef MR_WIN64 + mr_small ma,u; +#endif +#ifdef MR_ITANIUM + register mr_small ma,u; +#endif +#ifdef MR_NOASM + mr_large u; +#endif + + a=z; b=y; + +/*** DECREMENTATION */ + + return (int)carry; +} + +static void mr_cpy(mr_small *x,mr_small *z,int n) +{ /* copy an array of length n*MR_KCM */ + int m; + for (m=0;mmodulus->len; + zero(mr_mip->w0); + for (i=2*ml;i<(mr_mip->wt->len&MR_OBITS);i++) mr_mip->wt->w[i]=0; + + mr_karmul(ml,mr_mip->wt->w,x->w,y->w,mr_mip->w0->w); + mr_mip->w0->len=mr_mip->wt->len=2*ml; + copy(mr_mip->w0,z); +} + +void kcm_multiply(_MIPD_ int n,big x,big y,big z) +{ /* n *must* be MR_KCM*2^m for m>=0 */ + unsigned int i; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zero(mr_mip->w0); + for (i=2*n;i<(mr_mip->wt->len&MR_OBITS);i++) mr_mip->wt->w[i]=0; + mr_karmul(n,mr_mip->wt->w,x->w,y->w,mr_mip->w0->w); + mr_mip->w0->len=mr_mip->wt->len=2*n; + copy(mr_mip->w0,z); +} + +void kcm_square(_MIPD_ int n,big x,big z) +{ /* n *must* be MR_KCM*2^m for m>=0 */ + unsigned int i; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zero(mr_mip->w0); + for (i=2*n;i<(mr_mip->wt->len&MR_OBITS);i++) mr_mip->wt->w[i]=0; + mr_karsqr(n,mr_mip->wt->w,x->w,mr_mip->w0->w); + mr_mip->w0->len=mr_mip->wt->len=2*n; + copy(mr_mip->w0,z); +} + +BOOL kcm_top(_MIPD_ int n,big x,big y,big z) +{ /* to support floating-point - see float.cpp and fmth function in big.cpp */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + unsigned int i; + int len; + zero(mr_mip->w0); + + if (ncheck=OFF; + multiply(_MIPP_ x,y,mr_mip->w0); + mr_mip->check=ON; + } + else + { + for (i=2*n;i<(mr_mip->wt->len&MR_OBITS);i++) mr_mip->wt->w[i]=0; + if (x==y) mr_karsqr(n,mr_mip->wt->w,x->w,mr_mip->w0->w); + else mr_karmul(n,mr_mip->wt->w,x->w,y->w,mr_mip->w0->w); + mr_mip->w0->len=mr_mip->wt->len=2*n; + mr_lzero(mr_mip->w0); + } + len=mr_lent(mr_mip->w0); + mr_shift(_MIPP_ mr_mip->w0,n-len,mr_mip->w0); + copy(mr_mip->w0,z); + if (len<2*n) return TRUE; + return FALSE; +} + +void kcm_sqr(_MIPD_ big x,big z) +{ /* fast karatsuba squaring */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + unsigned int i; + int ml=(int)mr_mip->modulus->len; + zero(mr_mip->w0); + for (i=2*ml;i<(mr_mip->wt->len&MR_OBITS);i++) mr_mip->wt->w[i]=0; + mr_karsqr(ml,mr_mip->wt->w,x->w,mr_mip->w0->w); + mr_mip->w0->len=mr_mip->wt->len=2*ml; + copy(mr_mip->w0,z); +} + +void kcm_redc(_MIPD_ big z,big w) +{ /* fast karatsuba Montgomery reduction */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + int m,ml=(int)mr_mip->modulus->len; + unsigned int i; + m=ml/MR_KCM; + copy(z,mr_mip->w0); + + for (i=2*ml;i<(mr_mip->wt->len&MR_OBITS);i++) mr_mip->wt->w[i]=0; + mr_cpy(&(mr_mip->w0->w[ml]),w->w,m); + + mr_karmul_lower(ml,mr_mip->wt->w,mr_mip->w0->w,mr_mip->big_ndash->w,mr_mip->ws->w); + + for (i=ml;i<(w->len&MR_OBITS);i++) w->w[i]=0; + + mr_mip->ws->len=w->len=ml; + + mr_karmul_upper(ml,mr_mip->wt->w,mr_mip->ws->w,mr_mip->modulus->w,mr_mip->w0->w); + mr_mip->w0->len=mr_mip->wt->len=2*ml; + + if (mr_decn(&(mr_mip->w0->w[ml]),w->w,m)) + mr_incn(mr_mip->modulus->w,w->w,m); + + mr_lzero(w); + +} + +#endif + diff --git a/miracl/source/mrlucas.c b/miracl/source/mrlucas.c new file mode 100644 index 0000000..0add44c --- /dev/null +++ b/miracl/source/mrlucas.c @@ -0,0 +1,157 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL methods for evaluating lucas V function + * mrlucas.c (Postl's algorithm) + */ + +#include +#include "miracl.h" + +void nres_lucas(_MIPD_ big p,big r,big vp,big v) +{ + int i,nb; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(107) + + if (size(r)==0) + { + zero(vp); + convert(_MIPP_ 2,v); + nres(_MIPP_ v,v); + MR_OUT + return; + } + if (size(r)==1 || size(r)==(-1)) + { /* note - sign of r doesn't matter */ + convert(_MIPP_ 2,vp); + nres(_MIPP_ vp,vp); + copy(p,v); + MR_OUT + return; + } + + copy(p,mr_mip->w3); + + convert(_MIPP_ 2,mr_mip->w4); + nres(_MIPP_ mr_mip->w4,mr_mip->w4); /* w4=2 */ + + copy(mr_mip->w4,mr_mip->w8); + copy(mr_mip->w3,mr_mip->w9); + + copy(r,mr_mip->w1); + insign(PLUS,mr_mip->w1); + decr(_MIPP_ mr_mip->w1,1,mr_mip->w1); + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + nb=logb2(_MIPP_ mr_mip->w1); + for (i=nb-1;i>=0;i--) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + if (mr_testbit(_MIPP_ mr_mip->w1,i)) + { + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w9,mr_mip->w8); + nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w8); + nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w9,mr_mip->w9); + nres_modsub(_MIPP_ mr_mip->w9,mr_mip->w4,mr_mip->w9); + + } + else + { + nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w8,mr_mip->w9); + nres_modsub(_MIPP_ mr_mip->w9,mr_mip->w3,mr_mip->w9); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w8); + nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w4,mr_mip->w8); + } + } + +#ifndef MR_ALWAYS_BINARY + } + else + { + expb2(_MIPP_ logb2(_MIPP_ mr_mip->w1)-1,mr_mip->w2); + + while (!mr_mip->ERNUM && size(mr_mip->w2)!=0) + { /* use binary method */ + if (mr_compare(mr_mip->w1,mr_mip->w2)>=0) + { /* vp=v*vp-p, v=v*v-2 */ + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w9,mr_mip->w8); + nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w3,mr_mip->w8); + nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w9,mr_mip->w9); + nres_modsub(_MIPP_ mr_mip->w9,mr_mip->w4,mr_mip->w9); + subtract(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); + } + else + { /* v=v*vp-p, vp=vp*vp-2 */ + nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w8,mr_mip->w9); + nres_modsub(_MIPP_ mr_mip->w9,mr_mip->w3,mr_mip->w9); + nres_modmult(_MIPP_ mr_mip->w8,mr_mip->w8,mr_mip->w8); + nres_modsub(_MIPP_ mr_mip->w8,mr_mip->w4,mr_mip->w8); + } + subdiv(_MIPP_ mr_mip->w2,2,mr_mip->w2); + } + } +#endif + + copy(mr_mip->w9,v); + if (v!=vp) copy(mr_mip->w8,vp); + MR_OUT + +} + +void lucas(_MIPD_ big p,big r,big n,big vp,big v) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(108) + prepare_monty(_MIPP_ n); + nres(_MIPP_ p,mr_mip->w3); + nres_lucas(_MIPP_ mr_mip->w3,r,mr_mip->w8,mr_mip->w9); + redc(_MIPP_ mr_mip->w9,v); + if (v!=vp) redc(_MIPP_ mr_mip->w8,vp); + MR_OUT +} + diff --git a/miracl/source/mrmonty.c b/miracl/source/mrmonty.c new file mode 100644 index 0000000..227cdf5 --- /dev/null +++ b/miracl/source/mrmonty.c @@ -0,0 +1,1414 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL Montgomery's method for modular arithmetic without division. + * mrmonty.c + * + * Programs to implement Montgomery's method + * See "Modular Multiplication Without Trial Division", Math. Comp. + * Vol 44, Number 170, April 1985, Pages 519-521 + * NOTE - there is an important correction to this paper mentioned as a + * footnote in "Speeding the Pollard and Elliptic Curve Methods", + * Math. Comput., Vol. 48, January 1987, 243-264 + * + * The advantage of this approach is that no division required in order + * to compute a modular reduction - useful if division is slow + * e.g. on a SPARC processor, or a DSP. + * + * The disadvantage is that numbers must first be converted to an internal + * "n-residue" form. + * + */ + +#include +#include "miracl.h" + +#ifdef MR_FP +#include +#endif + +#ifdef MR_WIN64 +#include +#endif + +#ifdef MR_COUNT_OPS +extern int fpc,fpa; +#endif + +#ifdef MR_CELL +extern void mod256(_MIPD_ big,big); +#endif + +void kill_monty(_MIPDO_ ) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zero(mr_mip->modulus); +#ifdef MR_KCM + zero(mr_mip->big_ndash); +#endif +} + +mr_small prepare_monty(_MIPD_ big n) +{ /* prepare Montgomery modulus */ +#ifdef MR_KCM + int nl; +#endif +#ifdef MR_PENTIUM + mr_small ndash; + mr_small base; + mr_small magic=13835058055282163712.0; + int control=0x1FFF; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return (mr_small)0; +/* Is it set-up already? */ + if (size(mr_mip->modulus)!=0) + if (mr_compare(n,mr_mip->modulus)==0) return mr_mip->ndash; + + MR_IN(80) + + if (size(n)<=2) + { + mr_berror(_MIPP_ MR_ERR_BAD_MODULUS); + MR_OUT + return (mr_small)0; + } + + zero(mr_mip->w6); + zero(mr_mip->w15); + +/* set a small negative QNR (on the assumption that n is prime!) */ +/* These defaults can be over-ridden */ + +/* Did you know that for p=2 mod 3, -3 is a QNR? */ + + mr_mip->pmod8=remain(_MIPP_ n,8); + + switch (mr_mip->pmod8) + { + case 0: + case 1: + case 2: + case 4: + case 6: + mr_mip->qnr=0; /* none defined */ + break; + case 3: + mr_mip->qnr=-1; + break; + case 5: + mr_mip->qnr=-2; + break; + case 7: + mr_mip->qnr=-1; + break; + } + mr_mip->pmod9=remain(_MIPP_ n,9); + + mr_mip->NO_CARRY=FALSE; + if (n->w[n->len-1]>>M4 < 5) mr_mip->NO_CARRY=TRUE; + +#ifdef MR_PENTIUM + +mr_mip->ACTIVE=FALSE; +if (mr_mip->base!=0) + if (MR_PENTIUM==n->len) mr_mip->ACTIVE=TRUE; + if (MR_PENTIUM<0) + { + if (n->len<=(-MR_PENTIUM)) mr_mip->ACTIVE=TRUE; + if (logb2(_MIPP_ n)%mr_mip->lg2b==0) mr_mip->ACTIVE=FALSE; + } +#endif + +#ifdef MR_DISABLE_MONTGOMERY + mr_mip->MONTY=OFF; +#else + mr_mip->MONTY=ON; +#endif + +#ifdef MR_COMBA + mr_mip->ACTIVE=FALSE; + + if (MR_COMBA==n->len && mr_mip->base==mr_mip->base2) + { + mr_mip->ACTIVE=TRUE; +#ifdef MR_SPECIAL + mr_mip->MONTY=OFF; /* "special" modulus reduction */ + +#endif /* implemented in mrcomba.c */ + } + +#endif + convert(_MIPP_ 1,mr_mip->one); + if (!mr_mip->MONTY) + { /* Montgomery arithmetic is turned off */ + copy(n,mr_mip->modulus); + mr_mip->ndash=0; + MR_OUT + return (mr_small)0; + } + +#ifdef MR_KCM + +/* test for base==0 & n->len=MR_KCM.2^x */ + + mr_mip->ACTIVE=FALSE; + if (mr_mip->base==0) + { + nl=(int)n->len; + while (nl>=MR_KCM) + { + if (nl==MR_KCM) + { + mr_mip->ACTIVE=TRUE; + break; + } + if (nl%2!=0) break; + nl/=2; + } + } + if (mr_mip->ACTIVE) + { + mr_mip->w6->len=n->len+1; + mr_mip->w6->w[n->len]=1; + if (invmodp(_MIPP_ n,mr_mip->w6,mr_mip->w14)!=1) + { /* problems */ + mr_berror(_MIPP_ MR_ERR_BAD_MODULUS); + MR_OUT + return (mr_small)0; + } + } + else + { +#endif + mr_mip->w6->len=2; + mr_mip->w6->w[0]=0; + mr_mip->w6->w[1]=1; /* w6 = base */ + mr_mip->w15->len=1; + mr_mip->w15->w[0]=n->w[0]; /* w15 = n mod base */ + if (invmodp(_MIPP_ mr_mip->w15,mr_mip->w6,mr_mip->w14)!=1) + { /* problems */ + mr_berror(_MIPP_ MR_ERR_BAD_MODULUS); + MR_OUT + return (mr_small)0; + } +#ifdef MR_KCM + } + copy(mr_mip->w14,mr_mip->big_ndash); +#endif + + mr_mip->ndash=mr_mip->base-mr_mip->w14->w[0]; /* = N' mod b */ + copy(n,mr_mip->modulus); + mr_mip->check=OFF; + mr_shift(_MIPP_ mr_mip->modulus,(int)mr_mip->modulus->len,mr_mip->pR); + mr_mip->check=ON; +#ifdef MR_PENTIUM +/* prime the FP stack */ + if (mr_mip->ACTIVE) + { + ndash=mr_mip->ndash; + base=mr_mip->base; + magic *=base; + ASM + { + finit + fldcw WORD PTR control + fld QWORD PTR ndash + fld1 + fld QWORD PTR base + fdiv + fld QWORD PTR magic + } + } +#endif + nres(_MIPP_ mr_mip->one,mr_mip->one); + MR_OUT + + return mr_mip->ndash; +} + +void nres(_MIPD_ big x,big y) +{ /* convert x to n-residue format */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(81) + + if (size(mr_mip->modulus)==0) + { + mr_berror(_MIPP_ MR_ERR_NO_MODULUS); + MR_OUT + return; + } + copy(x,y); + divide(_MIPP_ y,mr_mip->modulus,mr_mip->modulus); + if (size(y)<0) add(_MIPP_ y,mr_mip->modulus,y); + if (!mr_mip->MONTY) + { + MR_OUT + return; + } + mr_mip->check=OFF; + + mr_shift(_MIPP_ y,(int)mr_mip->modulus->len,mr_mip->w0); + divide(_MIPP_ mr_mip->w0,mr_mip->modulus,mr_mip->modulus); + mr_mip->check=ON; + copy(mr_mip->w0,y); + + MR_OUT +} + +void redc(_MIPD_ big x,big y) +{ /* Montgomery's REDC function p. 520 */ + /* also used to convert n-residues back to normal form */ + mr_small carry,delay_carry,m,ndash,*w0g,*mg; + +#ifdef MR_ITANIUM + mr_small tm; +#endif +#ifdef MR_WIN64 + mr_small tm,tr; +#endif + int i,j,rn,rn2; + big w0,modulus; +#ifdef MR_NOASM + union doubleword dble; + mr_large dbled,ldres; +#endif +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(82) + + w0=mr_mip->w0; /* get these into local variables (for inline assembly) */ + modulus=mr_mip->modulus; + ndash=mr_mip->ndash; + + copy(x,w0); + if (!mr_mip->MONTY) + { +/*#ifdef MR_CELL + mod256(_MIPP_ w0,w0); +#else */ + divide(_MIPP_ w0,modulus,modulus); +/* #endif */ + copy(w0,y); + MR_OUT + return; + } + delay_carry=0; + rn=(int)modulus->len; + rn2=rn+rn; +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH + mg=modulus->w; + w0g=w0->w; + for (i=0;iw[i],ndash,0,&m); Note that after this time */ + m=ndash*w0->w[i]; + carry=0; /* around the loop, w0[i]=0 */ + + for (j=0;jw[j]+carry+w0->w[i+j]; + w0->w[i+j]=dble.h[MR_BOT]; + carry=dble.h[MR_TOP]; +#else + muldvd2(m,modulus->w[j],&carry,&w0->w[i+j]); +#endif + } + w0->w[rn+i]+=delay_carry; + if (w0->w[rn+i]w[rn+i]+=carry; + if (w0->w[rn+i]w[i],ndash,0,mr_mip->base,mr_mip->inverse_base,&m); +#else + muldiv(w0->w[i],ndash,0,mr_mip->base,&m); +#endif + carry=0; + for (j=0;jw[j]+carry+w0->w[i+j]; +#ifdef MR_FP_ROUNDING + carry=(mr_small)MR_LROUND(dbled*mr_mip->inverse_base); +#else +#ifndef MR_FP + if (mr_mip->base==mr_mip->base2) + carry=(mr_small)(dbled>>mr_mip->lg2b); + else +#endif + carry=(mr_small)MR_LROUND(dbled/mr_mip->base); +#endif + w0->w[i+j]=(mr_small)(dbled-(mr_large)carry*mr_mip->base); +#else +#ifdef MR_FP_ROUNDING + carry=imuldiv(modulus->w[j],m,w0->w[i+j]+carry,mr_mip->base,mr_mip->inverse_base,&w0->w[i+j]); +#else + carry=muldiv(modulus->w[j],m,w0->w[i+j]+carry,mr_mip->base,&w0->w[i+j]); +#endif +#endif + } + w0->w[rn+i]+=(delay_carry+carry); + delay_carry=0; + if (w0->w[rn+i]>=mr_mip->base) + { + w0->w[rn+i]-=mr_mip->base; + delay_carry=1; + } + } +#endif + w0->w[rn2]=delay_carry; + w0->len=rn2+1; + mr_shift(_MIPP_ w0,(-rn),w0); + mr_lzero(w0); + + if (mr_compare(w0,modulus)>=0) mr_psub(_MIPP_ w0,modulus,w0); + copy(w0,y); + MR_OUT +} + +/* "Complex" method for ZZn2 squaring */ + +void nres_complex(_MIPD_ big a,big b,big r,big i) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(225) + + if (mr_mip->NO_CARRY && mr_mip->qnr==-1) + { /* if modulus is small enough we can ignore carries, and use simple addition and subtraction */ + /* recall that Montgomery reduction can cope as long as product is less than pR */ +#ifdef MR_COMBA +#ifdef MR_COUNT_OPS +fpa+=3; +#endif + if (mr_mip->ACTIVE) + { + comba_add(a,b,mr_mip->w1); + comba_add(a,mr_mip->modulus,mr_mip->w2); /* a-b is p+a-b */ + comba_sub(mr_mip->w2,b,mr_mip->w2); + comba_add(a,a,r); + } + else + { +#endif + mr_padd(_MIPP_ a,b,mr_mip->w1); + mr_padd(_MIPP_ a,mr_mip->modulus,mr_mip->w2); + mr_psub(_MIPP_ mr_mip->w2,b,mr_mip->w2); + mr_padd(_MIPP_ a,a,r); +#ifdef MR_COMBA + } +#endif + nres_modmult(_MIPP_ r,b,i); + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w2,r); + } + else + { + nres_modadd(_MIPP_ a,b,mr_mip->w1); + nres_modsub(_MIPP_ a,b,mr_mip->w2); + + if (mr_mip->qnr==-2) + nres_modsub(_MIPP_ mr_mip->w2,b,mr_mip->w2); + + nres_modmult(_MIPP_ a,b,i); + nres_modmult(_MIPP_ mr_mip->w1,mr_mip->w2,r); + + if (mr_mip->qnr==-2) + nres_modadd(_MIPP_ r,i,r); + + nres_modadd(_MIPP_ i,i,i); + } + MR_OUT +} + +#ifndef MR_NO_LAZY_REDUCTION + +/* + +Lazy reduction technique for zzn2 multiplication - competitive if Reduction is more +expensive that Multiplication. This is true for pairing-based crypto. Note that +Lazy reduction can also be used with Karatsuba! Uses w1, w2, w5, and w6. + +Reduction poly is X^2-D=0 + +(a0+a1.X).(b0+b1.X) = (a0.b0 + D.a1.b1) + (a1.b0+a0.b1).X + +Karatsuba + + (a0.b0+D.a1.b1) + ((a0+a1)(b0+b1) - a0.b0 - a1.b1).X +*/ + +void nres_lazy(_MIPD_ big a0,big a1,big b0,big b1,big r,big i) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + mr_mip->check=OFF; +#ifdef MR_COUNT_OPS +fpc+=3; +fpa+=5; +if (mr_mip->qnr==-2) fpa++; +#endif + +#ifdef MR_COMBA + if (mr_mip->ACTIVE) + { + comba_mult(a0,b0,mr_mip->w0); + comba_mult(a1,b1,mr_mip->w5); + } + else + { +#endif +#ifdef MR_KCM + if (mr_mip->ACTIVE) + { + kcm_mul(_MIPP_ a1,b1,mr_mip->w5); /* this destroys w0! */ + kcm_mul(_MIPP_ a0,b0,mr_mip->w0); + } + else + { +#endif + MR_IN(151) + multiply(_MIPP_ a0,b0,mr_mip->w0); + multiply(_MIPP_ a1,b1,mr_mip->w5); +#ifdef MR_COMBA + } +#endif +#ifdef MR_KCM + } +#endif + + if (mr_mip->NO_CARRY && mr_mip->qnr==-1) + { /* if modulus is small enough we can ignore carries, and use simple addition and subtraction */ +#ifdef MR_COMBA +#ifdef MR_COUNT_OPS +fpa+=2; +#endif + if (mr_mip->ACTIVE) + { + comba_double_add(mr_mip->w0,mr_mip->w5,mr_mip->w6); + comba_add(a0,a1,mr_mip->w1); + comba_add(b0,b1,mr_mip->w2); + } + else + { +#endif + mr_padd(_MIPP_ mr_mip->w0,mr_mip->w5,mr_mip->w6); + mr_padd(_MIPP_ a0,a1,mr_mip->w1); + mr_padd(_MIPP_ b0,b1,mr_mip->w2); +#ifdef MR_COMBA + } +#endif + } + else + { + nres_double_modadd(_MIPP_ mr_mip->w0,mr_mip->w5,mr_mip->w6); /* w6 = a0.b0+a1.b1 */ + if (mr_mip->qnr==-2) + nres_double_modadd(_MIPP_ mr_mip->w5,mr_mip->w5,mr_mip->w5); + nres_modadd(_MIPP_ a0,a1,mr_mip->w1); + nres_modadd(_MIPP_ b0,b1,mr_mip->w2); + } + nres_double_modsub(_MIPP_ mr_mip->w0,mr_mip->w5,mr_mip->w0); /* r = a0.b0+D.a1.b1 */ + +#ifdef MR_COMBA + if (mr_mip->ACTIVE) + { + comba_redc(_MIPP_ mr_mip->w0,r); + comba_mult(mr_mip->w1,mr_mip->w2,mr_mip->w0); + } + else + { +#endif +#ifdef MR_KCM + if (mr_mip->ACTIVE) + { + kcm_redc(_MIPP_ mr_mip->w0,r); + kcm_mul(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w0); + } + else + { +#endif + redc(_MIPP_ mr_mip->w0,r); + multiply(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w0); /* w0=(a0+a1)*(b0+b1) */ +#ifdef MR_COMBA + } +#endif +#ifdef MR_KCM + } +#endif + + if (mr_mip->NO_CARRY && mr_mip->qnr==-1) + { +#ifdef MR_COMBA + if (mr_mip->ACTIVE) + comba_double_sub(mr_mip->w0,mr_mip->w6,mr_mip->w0); + else +#endif + mr_psub(_MIPP_ mr_mip->w0,mr_mip->w6,mr_mip->w0); + } + else + nres_double_modsub(_MIPP_ mr_mip->w0,mr_mip->w6,mr_mip->w0); /* (a0+a1)*(b0+b1) - w6 */ + +#ifdef MR_COMBA + if (mr_mip->ACTIVE) + { + comba_redc(_MIPP_ mr_mip->w0,i); + } + else + { +#endif +#ifdef MR_KCM + if (mr_mip->ACTIVE) + { + kcm_redc(_MIPP_ mr_mip->w0,i); + } + else + { +#endif + redc(_MIPP_ mr_mip->w0,i); + MR_OUT +#ifdef MR_COMBA + } +#endif +#ifdef MR_KCM + } +#endif + + mr_mip->check=ON; + +} + +#endif + +#ifndef MR_STATIC + +void nres_dotprod(_MIPD_ int n,big *x,big *y,big w) +{ + int i; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return; + MR_IN(120) + mr_mip->check=OFF; + zero(mr_mip->w7); + for (i=0;iw0); + mr_padd(_MIPP_ mr_mip->w7,mr_mip->w0,mr_mip->w7); + } + copy(mr_mip->pR,mr_mip->w6); + /* w6 = p.R */ + divide(_MIPP_ mr_mip->w7,mr_mip->w6,mr_mip->w6); + redc(_MIPP_ mr_mip->w7,w); + + mr_mip->check=ON; + MR_OUT +} + +#endif + +void nres_negate(_MIPD_ big x, big w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (size(x)==0) + { + zero(w); + return; + } +#ifdef MR_COMBA + if (mr_mip->ACTIVE) + { + comba_negate(_MIPP_ x,w); + return; + } + else + { +#endif + if (mr_mip->ERNUM) return; + + MR_IN(92) + mr_psub(_MIPP_ mr_mip->modulus,x,w); + MR_OUT + +#ifdef MR_COMBA + } +#endif + +} + +void nres_div2(_MIPD_ big x,big w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + MR_IN(198) + copy(x,mr_mip->w1); + if (remain(_MIPP_ mr_mip->w1,2)!=0) + add(_MIPP_ mr_mip->w1,mr_mip->modulus,mr_mip->w1); + subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1); + copy(mr_mip->w1,w); + + MR_OUT +} + +void nres_div3(_MIPD_ big x,big w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + MR_IN(199) + copy(x,mr_mip->w1); + while (remain(_MIPP_ mr_mip->w1,3)!=0) + add(_MIPP_ mr_mip->w1,mr_mip->modulus,mr_mip->w1); + subdiv(_MIPP_ mr_mip->w1,3,mr_mip->w1); + copy(mr_mip->w1,w); + + MR_OUT +} + +void nres_div5(_MIPD_ big x,big w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + MR_IN(208) + copy(x,mr_mip->w1); + while (remain(_MIPP_ mr_mip->w1,5)!=0) + add(_MIPP_ mr_mip->w1,mr_mip->modulus,mr_mip->w1); + subdiv(_MIPP_ mr_mip->w1,5,mr_mip->w1); + copy(mr_mip->w1,w); + + MR_OUT +} + +/* mod pR addition and subtraction */ +#ifndef MR_NO_LAZY_REDUCTION + +void nres_double_modadd(_MIPD_ big x,big y,big w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_COMBA + + if (mr_mip->ACTIVE) + { + comba_double_modadd(_MIPP_ x,y,w); + return; + } + else + { +#endif + + if (mr_mip->ERNUM) return; + MR_IN(153) + + mr_padd(_MIPP_ x,y,w); + if (mr_compare(w,mr_mip->pR)>=0) + mr_psub(_MIPP_ w,mr_mip->pR,w); + + MR_OUT +#ifdef MR_COMBA + } +#endif +} + +void nres_double_modsub(_MIPD_ big x,big y,big w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_COMBA + + if (mr_mip->ACTIVE) + { + comba_double_modsub(_MIPP_ x,y,w); + return; + } + else + { +#endif + + if (mr_mip->ERNUM) return; + MR_IN(154) + + if (mr_compare(x,y)>=0) + mr_psub(_MIPP_ x,y,w); + else + { + mr_psub(_MIPP_ y,x,w); + mr_psub(_MIPP_ mr_mip->pR,w,w); + } + + MR_OUT +#ifdef MR_COMBA + } +#endif +} + +#endif + +void nres_modadd(_MIPD_ big x,big y,big w) +{ /* modular addition */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_COUNT_OPS +fpa++; +#endif +#ifdef MR_COMBA + + if (mr_mip->ACTIVE) + { + comba_modadd(_MIPP_ x,y,w); + return; + } + else + { +#endif + if (mr_mip->ERNUM) return; + + MR_IN(90) + mr_padd(_MIPP_ x,y,w); + if (mr_compare(w,mr_mip->modulus)>=0) mr_psub(_MIPP_ w,mr_mip->modulus,w); + + MR_OUT +#ifdef MR_COMBA + } +#endif +} + +void nres_modsub(_MIPD_ big x,big y,big w) +{ /* modular subtraction */ + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_COUNT_OPS +fpa++; +#endif +#ifdef MR_COMBA + if (mr_mip->ACTIVE) + { + comba_modsub(_MIPP_ x,y,w); + return; + } + else + { +#endif + if (mr_mip->ERNUM) return; + + MR_IN(91) + + if (mr_compare(x,y)>=0) + mr_psub(_MIPP_ x,y,w); + else + { + mr_psub(_MIPP_ y,x,w); + mr_psub(_MIPP_ mr_mip->modulus,w,w); + } + + MR_OUT +#ifdef MR_COMBA + } +#endif + +} + +int nres_moddiv(_MIPD_ big x,big y,big w) +{ /* Modular division using n-residues w=x/y mod n */ + int gcd; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(85) + + if (x==y) + { /* Illegal parameter usage */ + mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + MR_OUT + + return 0; + } + redc(_MIPP_ y,mr_mip->w6); + gcd=invmodp(_MIPP_ mr_mip->w6,mr_mip->modulus,mr_mip->w6); + + if (gcd!=1) zero(w); /* fails silently and returns 0 */ + else + { + nres(_MIPP_ mr_mip->w6,mr_mip->w6); + nres_modmult(_MIPP_ x,mr_mip->w6,w); + /* mad(_MIPP_ x,mr_mip->w6,x,mr_mip->modulus,mr_mip->modulus,w); */ + } + MR_OUT + return gcd; +} + +void nres_premult(_MIPD_ big x,int k,big w) +{ /* multiply n-residue by small ordinary integer */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + int sign=0; + if (k==0) + { + zero(w); + return; + } + if (k<0) + { + k=-k; + sign=1; + } + if (mr_mip->ERNUM) return; + + MR_IN(102) + + if (k<=6) + { + switch (k) + { + case 1: copy(x,w); + break; + case 2: nres_modadd(_MIPP_ x,x,w); + break; + case 3: + nres_modadd(_MIPP_ x,x,mr_mip->w0); + nres_modadd(_MIPP_ x,mr_mip->w0,w); + break; + case 4: + nres_modadd(_MIPP_ x,x,w); + nres_modadd(_MIPP_ w,w,w); + break; + case 5: + nres_modadd(_MIPP_ x,x,mr_mip->w0); + nres_modadd(_MIPP_ mr_mip->w0,mr_mip->w0,mr_mip->w0); + nres_modadd(_MIPP_ x,mr_mip->w0,w); + break; + case 6: + nres_modadd(_MIPP_ x,x,w); + nres_modadd(_MIPP_ w,w,mr_mip->w0); + nres_modadd(_MIPP_ w,mr_mip->w0,w); + break; + } + if (sign==1) nres_negate(_MIPP_ w,w); + MR_OUT + return; + } + + mr_pmul(_MIPP_ x,(mr_small)k,mr_mip->w0); +#ifdef MR_COMBA +#ifdef MR_SPECIAL + comba_redc(_MIPP_ mr_mip->w0,w); +#else + divide(_MIPP_ mr_mip->w0,mr_mip->modulus,mr_mip->modulus); + copy(mr_mip->w0,w); +#endif +#else + divide(_MIPP_ mr_mip->w0,mr_mip->modulus,mr_mip->modulus); + copy(mr_mip->w0,w); +#endif + + if (sign==1) nres_negate(_MIPP_ w,w); + + MR_OUT +} + +void nres_modmult(_MIPD_ big x,big y,big w) +{ /* Modular multiplication using n-residues w=x*y mod n */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if ((x==NULL || x->len==0) && x==w) return; + if ((y==NULL || y->len==0) && y==w) return; + if (y==NULL || x==NULL || x->len==0 || y->len==0) + { + zero(w); + return; + } +#ifdef MR_COUNT_OPS +fpc++; +#endif +#ifdef MR_COMBA + if (mr_mip->ACTIVE) + { + if (x==y) comba_square(x,mr_mip->w0); + else comba_mult(x,y,mr_mip->w0); + comba_redc(_MIPP_ mr_mip->w0,w); + } + else + { +#endif +#ifdef MR_KCM + if (mr_mip->ACTIVE) + { + if (x==y) kcm_sqr(_MIPP_ x,mr_mip->w0); + else kcm_mul(_MIPP_ x,y,mr_mip->w0); + kcm_redc(_MIPP_ mr_mip->w0,w); + } + else + { +#endif +#ifdef MR_PENTIUM + if (mr_mip->ACTIVE) + { + if (x==y) fastmodsquare(_MIPP_ x,w); + else fastmodmult(_MIPP_ x,y,w); + } + else + { +#endif + if (mr_mip->ERNUM) return; + + MR_IN(83) + + mr_mip->check=OFF; + multiply(_MIPP_ x,y,mr_mip->w0); + redc(_MIPP_ mr_mip->w0,w); + mr_mip->check=ON; + MR_OUT +#ifdef MR_COMBA +} +#endif +#ifdef MR_KCM +} +#endif +#ifdef MR_PENTIUM +} +#endif + +} + +/* Montgomery's trick for finding multiple * + * simultaneous modular inverses * + * Based on the observation that * + * 1/x = yz*(1/xyz) * + * 1/y = xz*(1/xyz) * + * 1/z = xy*(1/xyz) * + * Why are all of Peter Montgomery's clever * + * algorithms always described as "tricks" ??*/ + +BOOL nres_double_inverse(_MIPD_ big x,big y,big w,big z) +{ /* find y=1/x mod n and z=1/w mod n */ + /* 1/x = w/xw, and 1/w = x/xw */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + MR_IN(145) + + nres_modmult(_MIPP_ x,w,mr_mip->w6); /* xw */ + + if (size(mr_mip->w6)==0) + { + mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); + MR_OUT + return FALSE; + } + redc(_MIPP_ mr_mip->w6,mr_mip->w6); + redc(_MIPP_ mr_mip->w6,mr_mip->w6); + invmodp(_MIPP_ mr_mip->w6,mr_mip->modulus,mr_mip->w6); + + nres_modmult(_MIPP_ w,mr_mip->w6,mr_mip->w5); + nres_modmult(_MIPP_ x,mr_mip->w6,z); + copy(mr_mip->w5,y); + + MR_OUT + return TRUE; +} + +BOOL nres_multi_inverse(_MIPD_ int m,big *x,big *w) +{ /* find w[i]=1/x[i] mod n, for i=0 to m-1 * + * x and w MUST be distinct */ + int i; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (m==0) return TRUE; + if (m<0) return FALSE; + MR_IN(118) + + if (x==w) + { + mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + MR_OUT + return FALSE; + } + + if (m==1) + { + copy(mr_mip->one,w[0]); + nres_moddiv(_MIPP_ w[0],x[0],w[0]); + MR_OUT + return TRUE; + } + + convert(_MIPP_ 1,w[0]); + copy(x[0],w[1]); + for (i=2;iw6); /* y=x[0]*x[1]*x[2]....x[m-1] */ + if (size(mr_mip->w6)==0) + { + mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); + MR_OUT + return FALSE; + } + + redc(_MIPP_ mr_mip->w6,mr_mip->w6); + redc(_MIPP_ mr_mip->w6,mr_mip->w6); + + invmodp(_MIPP_ mr_mip->w6,mr_mip->modulus,mr_mip->w6); + +/* Now y=1/y */ + + copy(x[m-1],mr_mip->w5); + nres_modmult(_MIPP_ w[m-1],mr_mip->w6,w[m-1]); + + for (i=m-2;;i--) + { + if (i==0) + { + nres_modmult(_MIPP_ mr_mip->w5,mr_mip->w6,w[0]); + break; + } + nres_modmult(_MIPP_ w[i],mr_mip->w5,w[i]); + nres_modmult(_MIPP_ w[i],mr_mip->w6,w[i]); + nres_modmult(_MIPP_ mr_mip->w5,x[i],mr_mip->w5); + } + + MR_OUT + return TRUE; +} + +/* initialise elliptic curve */ + +void ecurve_init(_MIPD_ big a,big b,big p,int type) +{ /* Initialize the active ecurve * + * Asize indicate size of A * + * Bsize indicate size of B */ + int as; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(93) + +#ifndef MR_NO_SS + mr_mip->SS=FALSE; /* no special support for super-singular curves */ +#endif + + prepare_monty(_MIPP_ p); + + mr_mip->Asize=size(a); + if (mr_abs(mr_mip->Asize)==MR_TOOBIG) + { + if (mr_mip->Asize>=0) + { /* big positive number - check it isn't minus something small */ + copy(a,mr_mip->w1); + divide(_MIPP_ mr_mip->w1,p,p); + subtract(_MIPP_ p,mr_mip->w1,mr_mip->w1); + as=size(mr_mip->w1); + if (asAsize=-as; + } + } + nres(_MIPP_ a,mr_mip->A); + + mr_mip->Bsize=size(b); + if (mr_abs(mr_mip->Bsize)==MR_TOOBIG) + { + if (mr_mip->Bsize>=0) + { /* big positive number - check it isn't minus something small */ + copy(b,mr_mip->w1); + divide(_MIPP_ mr_mip->w1,p,p); + subtract(_MIPP_ p,mr_mip->w1,mr_mip->w1); + as=size(mr_mip->w1); + if (asBsize=-as; + } + } + + nres(_MIPP_ b,mr_mip->B); +#ifdef MR_EDWARDS + mr_mip->coord=MR_PROJECTIVE; /* only type supported for Edwards curves */ +#else +#ifndef MR_AFFINE_ONLY + if (type==MR_BEST) mr_mip->coord=MR_PROJECTIVE; + else mr_mip->coord=type; +#else + if (type==MR_PROJECTIVE) + mr_berror(_MIPP_ MR_ERR_NOT_SUPPORTED); +#endif +#endif + MR_OUT + return; +} diff --git a/miracl/source/mrmuldv.any b/miracl/source/mrmuldv.any new file mode 100644 index 0000000..68f3cd8 --- /dev/null +++ b/miracl/source/mrmuldv.any @@ -0,0 +1,2779 @@ +/* + * MIRACL - various implementations of routines muldiv, muldvm, muldvd + * muldvd2 and imuldiv + * mrmuldv.c + * + * THIS FILE CONTAINS MANY VERSIONS OF THESE ROUTINES + * COPY THIS FILE TO MRMULDV.C AND DELETE THOSE PARTS IRRELEVANT TO + * YOUR REQUIREMENTS. + * + * NOTE: - This file and its contents are not needed + * if MR_NOASM is defined in mirdef.h + * + * muldiv() calculates (a*b+c)/m and (a*b+c)%m as quickly as possible. Should + * ideally be written in assembly language of target machine for speed + * The problem is to avoid overflow in the calculation of the intermediate + * product a*b+c. + * + * If using a floating-point underlying type, and rounding can be + * controlled, it makes sense to pre-calculate + * the inverse of the modulus m, and multiply instead of divide + * In this situation a function imuldiv() is also needed. + * + * muldvm() and muldvd() routines are necessary to support full-width number + * base working. They are not needed if MR_NOFULLWIDTH is defined in mirdef.h. + * + * muldvm - returns (a*base+c)/m and remainder + * muldvd - returns (a*b+c)/base and remainder + * + * NOTE: New to version 4.2, new routine muldvd2() is required. + * See C version below for specification + * Versions of this are easily developed from existing muldvd() programs + * + * In most applications muldvd2() will be the time critical routine. + * + * Note that full-width base working may not be possible for all processors. + * For example it cannot be used on a VAX, or RS/6000 with mr_utypes defined + * as ints. This is because the instruction set does not support + * unsigned multiply and divide instructions. In such cases ALWAYS use a + * maximum base of MAXBASE in mirsys(), rather than 0. + * + * Since parameter passing and returning is time-consuming, these routines + * should be generated 'inline', if compiler allows it. Parameter passing + * by register will also be faster than via the stack. For even faster + * operation, use in-line assembly to speed up the inner loops of routines + * pmul(), sdiv(), multiply() and divide(). See these routines for details + * of Microsoft/Borland C inline 80x86 assembly, which gives a substantial speed-up. + * + * NOTE: All other things being equal, versions of MIRACL with 32-bit mr_utypes + * will run 3-4 times faster than versions with 16-bit mr_utypes, even for medium + * precision arithmetic, such as used in Public Key systems. + * + * Note that a portable C version of 'muldiv' may not possible with some + * 32-bit compilers if ints and longs are both 32-bits and there is no + * 64-bit type. Fortunately these days there usually is such a type - called + * perhaps long long, or maybe __int64. See also the Blakely-Sloan + * method below. In any case the portable versions may be used if mr_utypes + * are defined as shorts, usually 16 bits. This would amount however to + * using the 32-bit processor in a 16 bit mode and would be very inefficient + * - up to 4 times slower. See mirdef.haf + * + * First the standard portable versions, for use when there is a double + * length type capable of holding the product of two mr_utype types. + * For example 32 and 16 bits types respectively. + * Note that if MR_NOASM is defined in mirdef.h, these routines are + * implemented in mrcore.c, and do not need to be extracted from here. + * + * This is followed by various other assembly language implementations for + * popular processors, computers and compilers. + * + + +************************************************************** + +/* Standard C version of mrmuldv.c */ + +#include +#include "miracl.h" + +mr_small muldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_small *rp) +{ + mr_small q; + mr_large ldres,dble=(mr_large)a*b+c; + q=(mr_small)MR_LROUND(dble/m); + *rp=(mr_small)(dble-(mr_large)q*m); + return q; +} + +#ifdef MR_FP_ROUNDING + +mr_small imuldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_large im,mr_small *rp) +{ + mr_small q; + mr_large ldres,dble=(mr_large)a*b+c; + q=(mr_small)MR_LROUND(dble*im); + *rp=(mr_small)(dble-(mr_large)q*m); + return q; +} + +#endif + + +#ifndef MR_NOFULLWIDTH + +mr_small muldvm(mr_small a,mr_small c,mr_small m,mr_small *rp) +{ + mr_small q; + union doubleword dble; + dble.h[MR_BOT]=c; + dble.h[MR_TOP]=a; + q=(mr_small)(dble.d/m); + *rp=(mr_small)(dble.d-(mr_large)q*m); + return q; +} + +mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) +{ + union doubleword dble; + dble.d=(mr_large)a*b+c; + *rp=dble.h[MR_BOT]; + return dble.h[MR_TOP]; +} + +void muldvd2(mr_small a,mr_small b,mr_small *c,mr_small *rp) +{ + union doubleword dble; + dble.d=(mr_large)a*b+*c+*rp; + *rp=dble.h[MR_BOT]; + *c=dble.h[MR_TOP]; +} + +#endif + +/* version for PowerPC (64-bit G5). Use with Blakely-Sloan C versions of muldiv(.) and muldvm(.) - see below */ + +void muldvd2(mr_small a,mr_small b,mr_small *c,mr_small *rp) +{ + __asm__ __volatile__ ( + "mulld %%r16,%0,%1\n" + "mulhdu %%r17,%0,%1\n" + "ld %%r18,0(%2)\n" + "addc %%r16,%%r18,%%r16\n" + "addze %%r17,%%r17\n" + "ld %%r19,0(%3)\n" + "addc %%r16,%%r19,%%r16\n" + "addze %%r17,%%r17\n" + "std %%r16,0(%3)\n" + "std %%r17,0(%2)\n" + : + : "r"(a),"r"(b),"r"(c),"r"(rp) + : "r16","r17","r18","r19","memory" + ); + +} + +mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) +{ + mr_small q; + __asm__ __volatile__ ( + "mulld %%r16,%1,%2\n" + "mulhdu %%r17,%1,%2\n" + "addc %%r16,%3,%%r16\n" + "addze %%r17,%%r17\n" + "std %%r16,0(%4)\n" + "or %0,%%r17,%%r17\n" + : "=r"(q) + : "r"(a),"r"(b),"r"(c),"r"(rp) + : "r16","r17","memory" + ); + return q; +} + + +**************************************************************** + +// +// Version of muldiv() for use with underlying type a double +// and using the FP co-processor on a Pentium, and the gcc compiler. +// In this case MR_NOFULLWIDTH is defined. +// This is much better than compiling the above, but fprem and fdiv +// are still very slow. +// + + .file "mrmuldv.s" +.text +.globl _muldiv +_muldiv: + + pushl %ebx + + fldl 8(%esp) + fmull 16(%esp) + movl 40(%esp),%ebx + faddl 24(%esp) + fldl 32(%esp) + fld %st(1) + +// NOTE: If rounding control is possible, set rounding to "chop" +// and replace lines below with these +// In this case #define MR_FP_ROUNDING will be defined in mirdef.h +// +// fdiv %st(1),%st +// fistpq 8(%esp) +// fildq 8(%esp) +// fmul %st,%st(1) +// fxch %st(2) +// fsubp %st,%st(1) +// fstpl (%ebx) + + fprem + fstl (%ebx) + fsubrp %st,%st(2) + fdivrp %st,%st(1) + + popl %ebx + ret + +// +// If MR_FP_ROUNDING is defined, this function will be needed for Pentium +// +.globl _imuldiv +_imuldiv: + + pushl %ebx + + fldl 8(%esp) + fmull 16(%esp) + movl 52(%esp),%ebx + faddl 24(%esp) + fldl 32(%esp) + fld %st(1) + + fldt 40(%esp) + fmulp %st,%st(1) + fistpq 8(%esp) + fildq 8(%esp) + fmul %st,%st(1) + fxch %st(2) + fsubp %st,%st(1) + fstpl (%ebx) + + popl %ebx + ret + + +************************************************************************ + +/* + * Borland C++ 32-bit compiler (BCC32) version of the above. + * Uses inline assembly feature. Suitable for Win32 Apps + * Also compatible with Microsoft Visual C++ 32-bit compiler + * BUT change TBYTE to QWORD + */ +#include "mirdef.h" + +#define ASM _asm + +double muldiv(double a,double b,double c,double m,double *rp) +{ + ASM fld QWORD PTR a + ASM fmul QWORD PTR b + ASM mov ebx,DWORD PTR rp + ASM fadd QWORD PTR c + ASM fld QWORD PTR m + ASM fld st(1) + +#ifdef MR_FP_ROUNDING + ASM fdiv st,st(1) + ASM fistp QWORD PTR [ebx] + ASM fild QWORD PTR [ebx] + ASM fmul st(1),st + ASM fxch st(2) + ASM fsubrp st(1),st + ASM fstp QWORD PTR [ebx] +#else + ASM fprem + ASM fst QWORD PTR [ebx] + ASM fsubp st(2),st + ASM fdivp st(1),st +#endif +} + +#ifdef MR_FP_ROUNDING + +double imuldiv(double a,double b,double c,double m,long double im,double *rp) +{ + ASM fld QWORD PTR a + ASM fmul QWORD PTR b + ASM fld QWORD PTR m + ASM fxch st(1) + ASM fadd QWORD PTR c + ASM mov ebx,DWORD PTR rp + ASM fxch st(1) + ASM fld st(1) + + ASM fld TBYTE PTR im /* QWORD for Microsoft */ + ASM fmulp st(1),st + ASM fistp QWORD PTR [ebx] + ASM fild QWORD PTR [ebx] + ASM fmul st(1),st + ASM fxch st(2) + ASM fsubrp st(1),st + ASM fstp QWORD PTR [ebx] +} + +#endif + + +********************************************************************* + +; +; VAX11 version for Dec C compiler +; with 32 bit int using 64-bit quadword +; for the intermediate product. +; +; Use with mirdef.h32 - but define MR_NOFULLWIDTH +; Use mirsys(...,MAXBASE) instead of mirsys(...,0) in your programs. +; +; Why ...(MIRACL-2) instead of ...(MIRACL-1) ? That's a negative +; number for division by mr_base! +; +; The problem is that the emul and ediv instructions work only +; for signed types +; + .entry muldiv,0 + subl #4,sp + emul 4(ap),8(ap),12(ap),r0 ;a*b+c + ediv 16(ap),r0,r0,@20(ap) ;quo. in r0, rem. in *rp + ret + .end +; +; Fullwidth base working not possible on VAX, so no muldvm() or muldvd() +; +; + + +********************************************************************** + + +# +# Version of muldiv.c for IBM RS/6000 +# This processor has no unsigned multiply/divide +# so full-width base not possible, so no muldvm() or muldvd() +# +# Use with mirdef.h32 but define MR_NOFULLWIDTH definition. +# Use mirsys(...,MAXBASE) instead of mirsys(...,0) in your programs. +# +# Note this version was developed from very inadequate RS/6000 +# documentation. It may not be optimal, and it may not always work +# (although it works fine for me!) +# + + + .file "mrmuldv.s" + .globl .muldiv[PR] + .csect .muldiv[PR] + +# parameters are passed in registers 3,4,5,6 and 7 +# the mq register holds the low 32-bits for mul/div + + mul 3,4,3 # q=a*b + mfmq 4 # get low part from mq + a 4,5,4 # add in c + aze 3,3 # add carry to high part + mtmq 4 # move low part to mq + div 3,3,6 # q=(a*b+c)/m + mfmq 4 # get remainder + st 4,0(7) # store remainder + +# quotient is returned in register 3 + + brl + +************************************************************************ + +/* Here's another portable method which might be considered for processors + * like the VAX and RS6000. The idea is due to Peter Montgomery. */ + + #include "mirdef.h" + + typedef unsigned mr_utype uint; + + uint muldiv(a,b,c,m,rp) + uint a,b,c,m,*rp; + { + int q,r; + q=(int)(0.5+((double)a*(double)b+(double)c)/(double)m); + r=(int)(((uint)a*(uint)b+(uint)c)-(uint)m*(uint)q); + if (r < 0) + { + r+=m; + q--; + } + *rp=r; + return q; + } + +********************************************************************** + + +; +; IBM-PC versions - small memory model only +; Easily modified for other memory models +; +; For large code models (e.g. medium) +; +; change _TEXT to mrmuldv_TEXT (in three places) +; change NEAR to FAR +; change [bp+4] to [bp+6] +; change [bp+6] to [bp+8] +; change [bp+8] to [bp+10] +; change [bp+10] to [bp+12] +; change [bp+12] to [bp+14] +; +; For large data models, see Turbo C version below for required modification +; +; Microsoft C compiler V4.0+ +; Written for MS macro-assembler +; + ASSUME CS:_TEXT +_TEXT SEGMENT BYTE PUBLIC 'CODE' + + PUBLIC _muldiv +_muldiv PROC NEAR + push bp ;standard C linkage + mov bp,sp + + mov ax,[bp+4] ;get a + mul WORD PTR [bp+6] ;multiply by b + add ax,[bp+8] ;add c to low word + adc dx,0h ;add carry to high word + div WORD PTR [bp+10] ;divide by m + mov bx,[bp+12] ;get address for remainder + mov [bx],dx ;store remainder + + pop bp ;standard C return + ret ;quotient in ax + +_muldiv endP + + PUBLIC _muldvm +_muldvm PROC NEAR + push bp ;standard C linkage + mov bp,sp + + mov dx,[bp+4] ;get a + mov ax,[bp+6] ;add in c + div WORD PTR [bp+8] ;divide by m + mov bx,[bp+10] ;get address for remainder + mov [bx],dx ;store remainder + + pop bp ;standard C return + ret ;quotient in ax + +_muldvm endP + + PUBLIC _muldvd +_muldvd PROC NEAR + push bp ;standard C linkage + mov bp,sp + + mov ax,[bp+4] ;get a + mul WORD PTR [bp+6] ;multiply by b + add ax,[bp+8] ;add c to low word + adc dx,0h ;add carry to high word + mov bx,[bp+10] ;get address for remainder + mov [bx],ax ;store remainder + mov ax,dx + pop bp ;standard C return + ret ;quotient in ax + +_muldvd endP + + PUBLIC _muldvd2 +_muldvd2 PROC NEAR + push bp ;standard C linkage + mov bp,sp + push si + + mov ax,[bp+4] ;get a + mul WORD PTR [bp+6] ;multiply by b + mov bx,[bp+8] ;get address for c + add ax,[bx] ;add c + adc dx,0h ;add carry to high word + + mov si,[bp+10] ;get address for remainder + add ax,[si] ;add rp + adc dx,0h ;add carry to high word + + mov [si],ax ;store remainder + mov [bx],dx ;store carry + + pop si + pop bp ;standard C return + ret + +_muldvd2 endP + + + +_TEXT ENDS +END + + +*********************************************************************** + + +/* + * Turbo C compiler V1.5+, Turbo/Borland C++. Microsoft C/C++ + * Uses inline assembly feature + * Generates code identical to above version, and + * can be used instead. + */ + +#define ASM asm + +/* or perhaps #define ASM _asm */ + +unsigned int muldiv(a,b,c,m,rp) +unsigned int a,b,c,m,*rp; +{ + ASM mov ax,a ;/* get a */ + ASM mul WORD PTR b ;/* multiply by b */ + ASM add ax,c ;/* add c to low word */ + ASM adc dx,0h ;/* add carry to high word */ + ASM div WORD PTR m ;/* divide by m */ + ASM mov bx,rp ;/* get address for remainder */ + ASM mov [bx],dx ;/* store remainder */ +} +/* Replace last two ASM lines when using large data memory models */ +/* ASM les bx, DWORD PTR rp ; get address for remainder */ +/* ASM mov WORD PTR es:[bx],dx ; store remainder */ + +unsigned int muldvm(a,c,m,rp) +unsigned int a,c,m,*rp; +{ + ASM mov dx,a ;/* get a */ + ASM mov ax,c ;/* add in c to low word */ + ASM div WORD PTR m ;/* divide by m */ + ASM mov bx,rp ;/* get address for remainder */ + ASM mov [bx],dx ;/* store remainder */ +} +/* Replace last two ASM lines when using large data memory models */ +/* ASM les bx, DWORD PTR rp ; get address for remainder */ +/* ASM mov WORD PTR es:[bx],dx ; store remainder */ + +unsigned int muldvd(a,b,c,rp) +unsigned int a,b,c,*rp; +{ + ASM mov ax,a ;/* get a */ + ASM mul WORD PTR b ;/* multiply by b */ + ASM add ax,c ;/* add c to low word */ + ASM adc dx,0h ;/* add carry to high word */ + ASM mov bx,rp ;/* get address for remainder */ + ASM mov [bx],ax ;/* store remainder */ + ASM mov ax,dx +} +/* Replace second and third last lines if using large data memory models */ +/* ASM les bx, DWORD PTR rp ; get address for remainder */ +/* ASM mov WORD PTR es:[bx],ax ; store remainder */ + +void muldvd2(a,b,c,rp) +unsigned int a,b,*c,*rp; +{ + ASM mov ax,a ;/* get a */ + ASM mul WORD PTR b ;/* multiply by b */ + ASM mov bx,c + ASM add ax,[bx] + ASM adc dx,0h ;/* add carry to high word */ + ASM mov si,rp + ASM add ax,[si] + ASM adc dx,0h + ASM mov [si],ax + ASM mov [bx],dx +} + +/* for large memory model .... + ASM mov ax,a ;/* get a */ + ASM mul WORD PTR b ;/* multiply by b */ + ASM les bx, DWORD PTR c + ASM add ax, WORD PTR es:[bx] + ASM adc dx,0h ;/* add carry to high word */ + ASM les si,DWORD PTR rp + ASM add ax,WORD PTR es:[si] + ASM adc dx,0h + ASM mov WORD PTR es:[si],ax + ASM les bx,DWORD PTR c + ASM mov WORD PTR es:[bx],dx +*/ + + + +********************************************************************** + + +; +; IBM-PC-8087 for Microsoft C compiler V4.0+ +; with 'mr_utype' defined as 'long' (32 bit). See mirdef.hpc +; This allows IBM-PC XT to look a bit like a 32-bit computer +; (which it isn't). To make use of this option: +; +; (1) Must have 8087 Maths Co-processor (for speed and to hold 64-bit +; intermediate product). +; +; (2) Must use 'ANSI' enhanced type C compiler, e.g. Microsoft V3.0+ +; and must use header 'miracl.h' which declares function +; parameter types. +; +; Note: some compilation warnings may be generated - ignore them. +; +; Note: This is NOT, in most cases, faster, but it does allow +; very high precision calculations, e.g. 1000! +; +; Note: No versions of muldvm(), muldvd() or muldvd2() yet written for +; this method. +; + ASSUME CS:_TEXT +_TEXT SEGMENT BYTE PUBLIC 'CODE' + + PUBLIC _muldiv +_muldiv PROC NEAR + push si ;standard C linkage + push bp + mov bp,sp + + finit ;initialise 8087 + fild DWORD PTR [bp+6] ;get a + fimul DWORD PTR [bp+0ah];multiply by b + fiadd DWORD PTR [bp+0eh];add c + fild DWORD PTR [bp+12h];get m + fld st(1) ;duplicate a*b+c on stack + fprem ;get remainder + fist DWORD PTR [bp+0ah];store remainder in b + fsubr st,st(2) ;subtract rem from total + fdiv st,st(1) ;divide by m + fist DWORD PTR [bp+6] ;store quotient in a + wait + + mov si,[bp+22] ;get address for remainder + mov ax,[bp+10] + mov dx,[bp+12] ;get remainder + mov [si],ax + mov [si+2],dx ;store remainder + mov ax,[bp+6] + mov dx,[bp+8] ;get quotient in dx:ax + + pop bp ;standard C return + pop si + ret + +_muldiv endP + +_TEXT ENDS +END + + + +************************************************************************** + + +; +; Intel-80386 pseudo-32 bit version - for Microsoft C V5.0+ +; Written for MS macro-assembler V5.0+ by Andrej Sauer +; with 'mr_utype' defined as 'long' (32 bit). See mirdef.hpc +; Same comments apply as above (except for 8087 requirement) +; Note that this version will also work with the latest Zortech and +; Borland 16-bit compilers, specifically Borland C++ V3.1+ +; +; For large code models (e.g. medium) +; +; change _TEXT to mrmuldv_TEXT (in three places) +; change NEAR to FAR +; change [bp+4] to [bp+6] +; change [bp+8] to [bp+10] +; change [bp+12] to [bp+14] +; change [bp+16] to [bp+18] +; change [bp+20] to [bp+22] +; etc +; + .386 + ASSUME CS:_TEXT +_TEXT SEGMENT USE16 PUBLIC 'CODE' + + PUBLIC _muldiv +_muldiv PROC NEAR + push bp ;standard C linkage + mov bp,sp + + mov eax,[bp+4] ;get a + mul DWORD PTR [bp+8] ;multiply by b + add eax,DWORD PTR [bp+12] ;add c to low word + adc edx,0h ;add carry to high word + div DWORD PTR [bp+16] ;divide by m + mov bx,WORD PTR [bp+20] ;get address for remainder + mov [bx],edx ;store remainder + shld edx,eax,16 ;shift higher half of quotient + ;into lower half of edx + + pop bp ;standard C return + ret ;quotient: high bits in dx, lows in ax + +_muldiv endP + + PUBLIC _muldvm +_muldvm PROC NEAR + push bp ;standard C linkage + mov bp,sp + + mov edx,[bp+4] ;get a + mov eax,[bp+8] ;add in c + div DWORD PTR [bp+12] ;divide by m + mov bx,WORD PTR [bp+16] ;get address for remainder + mov [bx],edx ;store remainder + shld edx,eax,16 ;shift higher half of quotient + ;into lower half of edx + pop bp ;standard C return + ret ;quotient: high bits in dx, lows in ax + +_muldvm endP + + + PUBLIC _muldvd +_muldvd PROC NEAR + push bp ;standard C linkage + mov bp,sp + + mov eax,[bp+4] ;get a + mul DWORD PTR [bp+8] ;multiply by b + add eax,DWORD PTR [bp+12] ;add c to low word + adc edx,0h ;add carry to high word + mov bx,WORD PTR [bp+16] ;get address for remainder + mov [bx],eax ;store remainder + mov eax,edx + shld edx,eax,16 ;shift higher half of quotient + ;into lower half of edx + + pop bp ;standard C return + ret ;quotient: high bits in dx, lows in ax + +_muldvd endP + + + PUBLIC _muldvd2 +_muldvd2 PROC NEAR + push bp ;standard C linkage + mov bp,sp + push si + + mov eax,[bp+4] ;get a + mul DWORD PTR [bp+8] ;multiply by b + les bx,DWORD PTR [bp+12] + add eax,DWORD PTR es:[bx] + adc edx,0h ;add carry to high word + les si,DWORD PTR [bp+16] + add eax,DWORD PTR es:[si] + adc edx,0h ;add carry to high word + + mov DWORD PTR es:[si],eax ;store remainder + les bx,DWORD PTR [bp+12] + mov DWORD PTR es:[bx],edx + pop si + pop bp ;standard C return + ret + +_muldvd2 endP + +_TEXT ENDS +END + + +*********************************************************************** + + +; +; Large Memory model version of the above. Useful +; for creating 16-bit DLL on 386+. Microsoft/Borland compatible +; + .386 + ASSUME CS:mrmuldv_TEXT +mrmuldv_TEXT SEGMENT USE16 PUBLIC 'CODE' + + PUBLIC _muldiv +_muldiv PROC FAR + push bp ;standard C linkage + mov bp,sp + + mov eax,[bp+6] ;get a + mul DWORD PTR [bp+10] ;multiply by b + add eax,DWORD PTR [bp+14] ;add c to low word + adc edx,0h ;add carry to high word + div DWORD PTR [bp+18] ;divide by m + les bx,DWORD PTR [bp+22] + mov DWORD PTR es:[bx],edx + shld edx,eax,16 ;shift higher half of quotient + ;into lower half of edx + pop bp ;standard C return + ret ;quotient: high bits in dx, lows in ax + +_muldiv endP + + PUBLIC _muldvm +_muldvm PROC FAR + push bp ;standard C linkage + mov bp,sp + + mov edx,[bp+6] ;get a + mov eax,[bp+10] ;add in c + div DWORD PTR [bp+14] ;divide by m + les bx,DWORD PTR [bp+18] + mov DWORD PTR es:[bx],edx + shld edx,eax,16 ;shift higher half of quotient + ;into lower half of edx + pop bp ;standard C return + ret ;quotient: high bits in dx, lows in ax + +_muldvm endP + + + PUBLIC _muldvd +_muldvd PROC FAR + push bp ;standard C linkage + mov bp,sp + + mov eax,[bp+6] ;get a + mul DWORD PTR [bp+10] ;multiply by b + add eax,DWORD PTR [bp+14] ;add c to low word + adc edx,0h ;add carry to high word + les bx,DWORD PTR [bp+18] + mov DWORD PTR es:[bx],eax + mov eax,edx + shld edx,eax,16 ;shift higher half of quotient + ;into lower half of edx + + pop bp ;standard C return + ret ;quotient: high bits in dx, lows in ax + +_muldvd endP + + PUBLIC _muldvd2 +_muldvd2 PROC FAR + push bp ;standard C linkage + mov bp,sp + push si + + mov eax,[bp+6] ;get a + mul DWORD PTR [bp+10] ;multiply by b + les bx,DWORD PTR [bp+14] + add eax,DWORD PTR es:[bx] + adc edx,0h ;add carry to high word + + les si,DWORD PTR [bp+18] + add eax,DWORD PTR es:[si] + adc edx,0h ;add carry to high word + + mov DWORD PTR es:[si],eax + les bx,DWORD PTR [bp+14] + mov DWORD PTR es:[bx],edx + pop si + pop bp ;standard C return + ret + +_muldvd2 endP + +mrmuldv_TEXT ENDS +END + + +**************************************************************************** + + +/* + Borland in-line pseudo-32 bit version of the above + Large memory model version. + Use with mirdef.hpc + + Unfortunately this cannot be used with Microsoft C, + as its 16 bit compiler will not allow inline 386 opcodes +*/ + +#define ASM _asm + +long muldiv(a,b,c,m,rp) +long a,b,c,m,*rp; +{ + ASM mov eax,DWORD PTR a + ASM mul DWORD PTR b + ASM add eax,DWORD PTR c + ASM adc edx,0h + ASM div DWORD PTR m + ASM les bx,DWORD PTR rp + ASM mov DWORD PTR es:[bx],edx + ASM shld edx,eax,16 +} + +long muldvm(a,c,m,rp) +long a,c,m,*rp; +{ + ASM mov edx,DWORD PTR a + ASM mov eax,DWORD PTR c + ASM div DWORD PTR m + ASM les bx,DWORD PTR rp + ASM mov DWORD PTR es:[bx],edx + ASM shld edx,eax,16 +} + +long muldvd(a,b,c,rp) +long a,b,c,*rp; +{ + ASM mov eax,DWORD PTR a + ASM mul DWORD PTR b + ASM add eax,DWORD PTR c + ASM adc edx,0h + ASM les bx,DWORD PTR rp + ASM mov DWORD PTR es:[bx],eax + ASM mov eax,edx + ASM shld edx,eax,16 +} + +void muldvd2(a,b,c,rp) +long a,b,*c,*rp; +{ + ASM mov eax,DWORD PTR a + ASM mul DWORD PTR b + ASM les bx,DWORD PTR c + ASM add eax,DWORD PTR es:[bx] + ASM adc edx,0h + ASM les si,DWORD PTR rp + ASM add eax,DWORD PTR es:[si] + ASM adc edx,0h + ASM mov DWORD PTR es:[si],eax + ASM les bx,DWORD PTR c + ASM mov DWORD PTR es:[bx],edx +} + + + +*********************************************************************** + + +/* + * Borland C++ 32-bit compiler (BCC32). Use with mirdef.h32 + * Uses inline assembly feature. Suitable for Win32 Apps + * Also compatible with Microsoft Visual C++ 32-bit compiler +*/ + +#define ASM _asm + +int muldiv(a,b,c,m,rp) +int a,b,c,m,*rp; +{ + ASM mov eax,DWORD PTR a + ASM mul DWORD PTR b + ASM add eax,DWORD PTR c + ASM adc edx,0h + ASM div DWORD PTR m + ASM mov ebx,DWORD PTR rp + ASM mov [ebx],edx +} + +int muldvm(a,c,m,rp) +int a,c,m,*rp; +{ + ASM mov edx,DWORD PTR a + ASM mov eax,DWORD PTR c + ASM div DWORD PTR m + ASM mov ebx,DWORD PTR rp + ASM mov [ebx],edx +} + +int muldvd(a,b,c,rp) +int a,b,c,*rp; +{ + ASM mov eax,DWORD PTR a + ASM mul DWORD PTR b + ASM add eax,DWORD PTR c + ASM adc edx,0h + ASM mov ebx,DWORD PTR rp + ASM mov [ebx],eax + ASM mov eax,edx +} + + +void muldvd2(a,b,c,rp) +int a,b,*c,*rp; +{ + ASM mov eax,DWORD PTR a + ASM mul DWORD PTR b + ASM mov ebx,DWORD PTR c + ASM add eax,[ebx] + ASM adc edx,0h + ASM mov esi,DWORD PTR rp + ASM add eax,[esi] + ASM adc edx,0h + ASM mov [esi],eax + ASM mov [ebx],edx +} + + +************************************************************************* + + + +/ +/ Version for 32-bit Sun 386i Workstation +/ + .file "mrmuldv.c" + .version "sun386-1.0" + .text + .globl muldiv +muldiv: + pushl %ebp + movl %esp,%ebp + + movl 8(%ebp),%eax /get a + mull 12(%ebp) /multiply by b + addl 16(%ebp),%eax /add c to low word + adcl $0,%edx /add carry to high word + + divl 20(%ebp) /divide by m + movl 24(%ebp),%ebx /get address for remainder + movl %edx,(%ebx) /store remainder + + popl %ebp + ret + + .text + .globl muldvm +muldvm: + pushl %ebp + movl %esp,%ebp + + movl 8(%ebp),%edx /get a + movl 12(%ebp),%eax /add in c + divl 16(%ebp) /divide by m + + movl 20(%ebp),%ebx /get address for remainder + movl %edx,(%ebx) /store remainder + + popl %ebp + ret + + .text + .globl muldvd +muldvd: + pushl %ebp + movl %esp,%ebp + + movl 8(%ebp),%eax /get a + mull 12(%ebp) /multiply by b + addl 16(%ebp),%eax /add c to low word + adcl $0,%edx /add carry to high word + movl 20(%ebp),%ebx /get address for remainder + movl %eax,(%ebx) /store remainder + movl %edx,%eax /get quotient + + popl %ebp + ret + + +************************************************************************** + + +/ +/ DJGPP GNU C version for DOS +/ M. Scott 22/3/98 +/ + + + .file "mrmuldv.c" +.text +.globl _muldiv +_muldiv: + pushl %ebp + movl %esp,%ebp + pushl %ebx + + + movl 8(%ebp),%eax + mull 12(%ebp) + addl 16(%ebp),%eax + adcl $0,%edx + + divl 20(%ebp) + movl 24(%ebp),%ebx + movl %edx,(%ebx) + + popl %ebx + popl %ebp + ret + + .globl _muldvm +_muldvm: + pushl %ebp + movl %esp,%ebp + pushl %ebx + + movl 8(%ebp),%edx + movl 12(%ebp),%eax + divl 16(%ebp) + + movl 20(%ebp),%ebx + movl %edx,(%ebx) + + popl %ebx + popl %ebp + ret + + .globl _muldvd +_muldvd: + pushl %ebp + movl %esp,%ebp + pushl %ebx + + movl 8(%ebp),%eax + mull 12(%ebp) + addl 16(%ebp),%eax + adcl $0,%edx + movl 20(%ebp),%ebx + movl %eax,(%ebx) + movl %edx,%eax + + popl %ebx + popl %ebp + ret + + .globl _muldvd2 +_muldvd2: + pushl %ebp + movl %esp,%ebp + pushl %ebx + pushl %esi + + movl 8(%ebp),%eax + mull 12(%ebp) + movl 16(%ebp),%ebx + addl (%ebx),%eax + adcl $0,%edx + movl 20(%ebp),%esi + addl (%esi),%eax + adcl $0,%edx + + movl %eax,(%esi) + movl %edx,(%ebx) + + popl %esi + popl %ebx + popl %ebp + ret + + +************************************************************************* + +/ +/ GNU C for Linux (and other 386 based Linux/Unix??) +/ +/ + + .file "mrmuldv.s" +.text +.globl muldiv +muldiv: + pushl %ebp + movl %esp,%ebp + pushl %ebx + + + movl 8(%ebp),%eax + mull 12(%ebp) + addl 16(%ebp),%eax + adcl $0,%edx + + divl 20(%ebp) + movl 24(%ebp),%ebx + movl %edx,(%ebx) + + popl %ebx + popl %ebp + ret + + .globl muldvm +muldvm: + pushl %ebp + movl %esp,%ebp + pushl %ebx + + movl 8(%ebp),%edx + movl 12(%ebp),%eax + divl 16(%ebp) + + movl 20(%ebp),%ebx + movl %edx,(%ebx) + + popl %ebx + popl %ebp + ret + + .globl muldvd +muldvd: + pushl %ebp + movl %esp,%ebp + pushl %ebx + + movl 8(%ebp),%eax + mull 12(%ebp) + addl 16(%ebp),%eax + adcl $0,%edx + movl 20(%ebp),%ebx + movl %eax,(%ebx) + movl %edx,%eax + + popl %ebx + popl %ebp + ret + + .globl muldvd2 +muldvd2: + pushl %ebp + movl %esp,%ebp + pushl %ebx + pushl %esi + + movl 8(%ebp),%eax + mull 12(%ebp) + movl 16(%ebp),%ebx + addl (%ebx),%eax + adcl $0,%edx + movl 20(%ebp),%esi + addl (%esi),%eax + adcl $0,%edx + + movl %eax,(%esi) + movl %edx,(%ebx) + + popl %esi + popl %ebx + popl %ebp + ret + + +************************************************************************* + + +/* GCC inline assembly version for Linux/DJGPP */ + +#include "miracl.h" + + +mr_small muldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_small *rp) +{ + mr_small q; + __asm__ __volatile__ ( + "movl %1,%%eax\n" + "mull %2\n" + "addl %3,%%eax\n" + "adcl $0,%%edx\n" + "divl %4\n" + "movl %5,%%ebx\n" + "movl %%edx,(%%ebx)\n" + "movl %%eax,%0\n" + : "=m"(q) + : "m"(a),"m"(b),"m"(c),"m"(m),"m"(rp) + : "eax","ebx","memory" + ); + return q; +} + +mr_small muldvm(mr_small a,mr_small c,mr_small m,mr_small *rp) +{ + mr_small q; + __asm__ __volatile__ ( + "movl %1,%%edx\n" + "movl %2,%%eax\n" + "divl %3\n" + "movl %4,%%ebx\n" + "movl %%edx,(%%ebx)\n" + "movl %%eax,%0\n" + : "=m"(q) + : "m"(a),"m"(c),"m"(m),"m"(rp) + : "eax","ebx","memory" + ); + return q; +} + +mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) +{ + mr_small q; + __asm__ __volatile__ ( + "movl %1,%%eax\n" + "mull %2\n" + "addl %3,%%eax\n" + "adcl $0,%%edx\n" + "movl %4,%%ebx\n" + "movl %%eax,(%%ebx)\n" + "movl %%edx,%0\n" + : "=m"(q) + : "m"(a),"m"(b),"m"(c),"m"(rp) + : "eax","ebx","memory" + ); + return q; +} + +void muldvd2(mr_small a,mr_small b,mr_small *c,mr_small *rp) +{ + __asm__ __volatile__ ( + "movl %0,%%eax\n" + "mull %1\n" + "movl %2,%%ebx\n" + "addl (%%ebx),%%eax\n" + "adcl $0,%%edx\n" + "movl %3,%%esi\n" + "addl (%%esi),%%eax\n" + "adcl $0,%%edx\n" + "movl %%eax,(%%esi)\n" + "movl %%edx,(%%ebx)\n" + : + : "m"(a),"m"(b),"m"(c),"m"(rp) + : "eax","ebx","esi","memory" + ); + +} + +*********************************************************** + +; +; Watcom C/386 32-bit compiler V7.0. Use with mirdef.h32 +; Most parameters passed in registers +; Written for Phar Lap 386ASM macro-assembler +; +; V4.0 NOTE! Inline assembly versions of these routines, +; are also available. See miracl.h for details +; + + .386 + ASSUME CS:_TEXT +_TEXT SEGMENT BYTE PUBLIC 'CODE' + + PUBLIC muldiv_ +muldiv_ PROC NEAR + + mul edx ;multiply a*b + add eax,ebx ;add in c + adc edx,0 ;carry + div ecx ;divide by m + mov ebx,[esp+4] + mov [ebx],edx ;remainder + ret 4 ;quotient in eax + +muldiv_ endP + + PUBLIC muldvm_ +muldvm_ PROC NEAR + + xchg eax,edx ;a*base+c + div ebx ;divide by m + mov [ecx],edx ;store remainder + ret ;quotient in eax + +muldvm_ endP + + PUBLIC muldvd_ +muldvd_ PROC NEAR + + mul edx ;multiply a*b + add eax,ebx ;add in c + adc edx,0 + mov [ecx],eax ;store remainder + mov eax,edx ;get quotient + ret ;quotient in eax + +muldvd_ endP + +_TEXT ENDS +END + + +******************************************************************* + + +; +; Zortech C/386 32-bit compiler V2.1 +; Use with mirdef.h32 +; Written for Phar lap 386ASM macro-assembler +; + + .386 + ASSUME CS:_TEXT +_TEXT SEGMENT BYTE PUBLIC 'CODE' + + PUBLIC _muldiv +_muldiv PROC NEAR + + mov eax,DWORD PTR [esp+4] + mul DWORD PTR [esp+8] + add eax,DWORD PTR [esp+12] + adc edx,0 + div DWORD PTR [esp+16] + mov ebx,DWORD PTR [esp+20] + mov [ebx],edx + ret + +_muldiv endP + + PUBLIC _muldvm +_muldvm PROC NEAR + + mov edx,DWORD PTR [esp+4] + mov eax,DWORD PTR [esp+8] + div DWORD PTR [esp+12] + mov ebx,DWORD PTR [esp+16] + mov [ebx],edx + ret + +_muldvm endP + + PUBLIC _muldvd +_muldvd PROC NEAR + + mov eax,DWORD PTR [esp+4] + mul DWORD PTR [esp+8] + add eax,DWORD PTR [esp+12] + adc edx,0 + mov ebx,DWORD PTR [esp+16] + mov [ebx],eax + mov eax,edx + ret + +_muldvd endP + +_TEXT ENDS +END + + + +************************************************************************ + + +unsigned int muldiv(a,b,c,m,rp) +unsigned int a,b,c,m,*rp; +{ + asm + { + ; + ; MACintosh version for Megamax or Lightspeed Think C compiler + ; with 16-bit int, 68000 processor + ; For a 32 bit version for the 68020, see below + ; + move a(A6),D1 ;get a + mulu b(A6),D1 ;multiply by b + clr.l D0 + move c(A6),D0 ;get c + add.l D0,D1 ;D1 contains a*b+c + divu m(A6),D1 ;divide by m + move D1,D0 ;return with quotient in D0 + swap D1 ;get remainder + move.l rp(A6),A0 ;get address for remainder + move D1,(A0) ;store remainder + } +} + +unsigned int muldvm(a,c,m,rp) +unsigned int a,c,m,*rp; +{ + asm + { + ; + ; Version of muldvm for Apple MAC + ; + clr.l D1 + move a(A6),D1 ;get a + swap D1 ;move a to high word + move c(A6),D1 ;add in c + divu m(A6),D1 ;divide by m + move D1,D0 ;return quotient in D0 + swap D1 ;get remainder + move.l rp(A6),A0 ;get address for remainder + move D1,(A0) ;store remainder + } +} + +unsigned int muldvd(a,b,c,rp) +unsigned int a,b,c,*rp; +{ + asm + { + ; + ; Version of muldvd for Apple MAC + ; + move a(A6),D1 ;get a + mulu b(a6),D1 ;multiply by b + clr.l D0 + move c(A6),D0 ;get c + add.l D0,D1 ;add in c + move.l D1,D0 + swap D0 ;return quotient in D0 + move.l rp(A6),A0 ;get address for remainder + move D1,(A0) ;store remainder + } +} + + +********************************************************************** + + +# +# 68020+ versions for Next, and for new 32-bit Macs +# Parameters come off the stack +# + +.globl _muldiv,_muldvm,_muldvd + +_muldiv: + movel sp@(4),d0 + mulul sp@(8),d1:d0 + addl sp@(12),d0 + negxl d1 # tricky stuff! + negl d1 + divul sp@(16),d1:d0 + movel sp@(20),a0 + movel d1,a0@ + rts + +_muldvm: + movel sp@(4),d1 + movel sp@(8),d0 + divul sp@(12),d1:d0 + movel sp@(16),a0 + movel d1,a0@ + rts + +_muldvd: + movel sp@(4),d1 + mulul sp@(8),d0:d1 + addl sp@(12),d1 + negxl d0 + negl d0 + movel sp@(16),a0 + movel d1,a0@ + rts + + + +************************************************************************* + + +unsigned int muldiv(a,b,c,m,rp) +unsigned int a,b,c,m,*rp; +{ + asm + { + ; + ; 32016 processor version for BBC Master Scientific + ; with 32-bit int, by Dudley Long, Rutherford-Appleton Labs. + ; No muldvm() or muldvd() + ; + movd a,0 ;move a to R0 + meid b,0 ;multiply by b, result extended + addd c,0 ;add c to extended number in R0 & R1 + addcd #0,1 + deid m,0 ;divide by m + movd 0,0(rp) ;remainder to *rp + movd 1,0 ;quotient returned in R0 + } +} + + +******************************************************************* + + +; +; MOTE! This code is obsolete. Newer ARMs support a 32x32 UMULL instruction +; The ARM compiler supports a long long type, so a C only version may be +; faster +; +; Acorn ARM Risc version (32-bit) for Archimedes micro +; Wingpass Macro Assembler +; Use with mirdef.h32 +; +.INCLUDE "A.REGNAMES" + +.AREA C$$code, .CODE, .READONLY + +muldiv:: + MOV ip, sp ;standard linkage + STMFD sp!, {v1-v4} + + CMPS a2,#0x80000000 ;check for b=MAXBASE + MOVEQ v3,a1,LSL #31 ;this idea is quicker because + MOVEQ v4,a1,LSR #1 ;of ARM barrel shifting capability + BEQ addin + MOV v1,a1,LSR #16 ;do it the hard way + MOV v2,a2,LSR #16 + BIC a1,a1,v1,LSL #16 + BIC a2,a2,v2,LSL #16 + MUL v3,a1,a2 ;form partial products of a*b + MUL v4,v1,v2 + SUB v1,v1,a1 + SUB v2,a2,v2 + MLA v1,v2,v1,v3 ;look - only 3 MULs! + ADD v1,v1,v4 + ADDS v3,v3,v1,LSL #16 + ADC v4,v4,v1,LSR #16 +addin: + ADDS v3,v3,a3 ;now add in c + ADCCS v4,v4,#0 + + CMPS a4,#0x80000000 ;check for m=MAXBASE + MOVEQ a1,v3,LSR #31 + ADDEQ a1,a1,v4,LSL #1 + BICEQ v4,v3,#0x80000000 + BEQ leave + MOV a1,#0 ;do long division by m + +divlp: + +.REPEAT 32 ;2xfaster than a loop! + MOVS v3,v3,ASL #1 ;get next bit into carry + ADC v4,v4,v4 ;accumulate remainder + CMPS v4,a4 + SUBCS v4,v4,a4 + ADC a1,a1,a1 ;accumulate quotient +.ENDREPEAT + +leave: + LDR v3,[ip] + STR v4,[v3] ;store remainder + LDMFD sp!, {v1-v4} + MOVS pc,lr + +muldvm:: + STMFD sp!, {v1-v2} + + MOV v2,a1 ;'multiply' by 2^32 + MOV v1,a2 ;add in c + + MOV a1,#0 ;do long division by m + +.REPEAT 32 ;2xfaster than a loop! + MOVS v1,v1,ASL #1 ;get next bit into carry + ADCS v2,v2,v2 ;accumulate remainder + CMPCCS v2,a3 + SUBCS v2,v2,a3 + ADC a1,a1,a1 ;accumulate quotient +.ENDREPEAT + + STR v2,[a4] ;store remainder + LDMFD sp!, {v1-v2} + MOVS pc,lr + + +muldvd:: + STMFD sp!, {v1-v2} + + MOV ip,a1,LSR #16 ;do it the hard way + MOV v2,a2,LSR #16 + BIC a1,a1,ip,LSL #16 + BIC a2,a2,v2,LSL #16 + MUL v1,a1,a2 ;form partial products of a*b + MUL a2,ip,a2 + MUL a1,v2,a1 + MUL v2,ip,v2 + ADDS a1,a2,a1 + ADDCS v2,v2,#0x10000 + ADDS v1,v1,a1,LSL #16 + ADC v2,v2,a1,LSR #16 + + ADDS v1,v1,a3 ;now add in c + ADCCS v2,v2,#0 + MOV a1,v2 ;get quotient + + STR v1,[a4] ;store remainder + LDMFD sp!, {v1-v2} + MOVS pc,lr + + + +******************************************************************** + + +; +; Version for Pyramid 90x and 98x computers +; from Rod Worley, Monash University, Victoria, Australia +; +; No muldvm() or muldvd() +; + .text 0 + .globl _muldiv +_muldiv: + movw pr0,pr8 ;save a in reg 8 + movw $0x0,pr0 ;zero reg0 so long reg 0,1 is b + emul pr8,pr0 ;extended multiply by a + addw pr2,pr1 ;add c to extended result + addwc $0x0,pr0 + ediv pr3,pr0 ;extended div by m + movw pr1,(pr4) ;store remainder + ret ;return qotient in pr0 + + +************************************************************************ + + +/* This is the transputer version, by A.H. Pepperdine */ +/* Assumes that the result will fit into a 32-bit word */ +/* The error flag will be set if */ +/* (a*b+c)/m >= 2**32 */ +/* ie. equivalently, if */ +/* ( (a*b+c) >> 32) >= m */ + +unsigned int muldiv(unsigned int a, unsigned int b, unsigned int c, + unsigned int m, unsigned int * rp) +{ + unsigned int q; + __asm + { + ldabc a, b, c; + lmul ; + ld m; + ldiv ; + stab q, *rp; + } + return q; +} + +/* The base is 2**32, ie a full 32-bit unsigned integer */ +/* The error flag will be set if the result will not fit*/ +/* into a word, ie. */ +/* for muldvm that is if (a >= m) */ +/* and for muldvd it cannot happen */ + +unsigned int muldvm(unsigned int a, unsigned int c, + unsigned int m, unsigned int * rp) +{ + unsigned int q; + __asm + { + ldabc m, c, a; + ldiv ; + stab q, *rp; + } + return q; +} + +unsigned int muldvd(unsigned int a, unsigned int b, unsigned int c, + unsigned int * rp) +{ + unsigned int q; + __asm + { + ldabc a, b, c; + lmul ; + stab *rp, q; + } + return q; +} + + +********************************************************************* + + +/* Now ... just to confuse you even more .... + + Blakeley/Sloan 'portable' method for Modular multiplication IEEE Trans + Computers C-34 March 1985 pp 290-292 eliminates need for double length + product - but will be slow. Might suit some RISC computers with no + multiply/divide instructions. To speed up try completely unravelling for() + loops. + + This method should only be used if the mr_utype data type is twice the size + of a "mr_hltype" data-type. This must be defined below. + + Note: DON't define MR_NOASM in mirdef.h if using this method. + + */ + +#include +#include "miracl.h" + +mr_small muldiv(a,b,c,m,rp) +mr_small a,b,c,m; +mr_small *rp; +{ + int i; + mr_small d,q=0,r=0; + d=m-a; + for (i=MIRACL/4;i>0;i--) + { /* do it bit by bit */ + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + } + *rp=r; + return q; +} + +mr_small muldvm(a,c,m,rp) +mr_small a,c,m; +mr_small *rp; +{ /* modified Blakely-Sloan */ + register int i,carry; + register mr_small q=0,r=0; + r=a; + for (i=MIRACL/4;i>0;i--) + { /* do it bit by bit */ + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + } + *rp=r; + return q; +} + +/* define mr_hltype as that C type that is half the size in bits of the + underlying type (mr_utype in mirdef.h). Perhaps short if mr_utype is long? + Possible int if mr_utype is 64-bit long long ?? */ + +#define mr_hltype short + +mr_small muldvd(a,b,c,rp) +mr_small a,b,c; +mr_small *rp; +{ /* multiply by parts */ + mr_small middle,middle2; + mr_small q,r; + unsigned mr_hltype am,al,bm,bl; + int hshift=(MIRACL>>1); + am=(unsigned mr_hltype)(a>>hshift); + al=(unsigned mr_hltype)a; + bm=(unsigned mr_hltype)(b>>hshift); + bl=(unsigned mr_hltype)b; +/* form partial products */ + r= (mr_small)al*bl; + q= (mr_small)am*bm; + middle=(mr_small)al*bm; + middle2=(mr_small)bl*am; + middle+=middle2; /* combine them - carefully */ + if (middle>hshift)<(unsigned mr_hltype)middle) q++; + q+=(middle>>hshift); + r+=c; + if (r>1); + am=(unsigned mr_hltype)(a>>hshift); + al=(unsigned mr_hltype)a; + bm=(unsigned mr_hltype)(b>>hshift); + bl=(unsigned mr_hltype)b; +/* form partial products */ + r= (mr_small)al*bl; + q= (mr_small)am*bm; + middle=(mr_small)al*bm; + middle2=(mr_small)bl*am; + middle+=middle2; /* combine them - carefully */ + if (middle>hshift)<(unsigned mr_hltype)middle) q++; + q+=(middle>>hshift); + r+=*c; + if (r<*c) q++; + r+=*rp; + if (r<*rp) q++; + *rp=r; + *c=q; +} + +************************************************************************* + + +/* SPARC assembler version of above. Note that when Full-width base + working is used, then muldvd() is the most time-critical of these + three routines. Use with above Blakely-Sloan C versions of muldvm + and muldiv (Assumes mr_utype is 32 bit int) */ + .global _muldvd +_muldvd: + mov %o1,%y + andcc %g0,%g0,%o4 + nop + nop + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%o0,%o4 + mulscc %o4,%g0,%o4 + tst %o0 + bge 1f + nop + add %o4,%o1,%o4 +1: + rd %y,%o1 + addcc %o1,%o2,%o1 + st %o1,[%o3] + retl + addxcc %o4,%g0,%o0 + + +************************************************************************** + + +/* If you have a "decent" SPARC which supports UMUL and UDIV instructions + then the following will be much faster. Cut and paste what follows + into mrmuldv.s. See miracl.mak make file + + Aside: God, I hate the Sparc, with its slippery ill-defined Instruction + set. Not all implementations support UMUL and UDIV, so its safer + to use the method above. + + Note: Sometimes the routine name needs a preceding underscore, + so it may be necessary to change for example muldvd to _muldvd + through-out. Depends on the Unix version +*/ + + .global muldvd +muldvd: + umul %o0,%o1,%o0 + rd %y,%o1 + addcc %o0,%o2,%o0 + st %o0,[%o3] + retl + addx %o1,%g0,%o0 + + .global muldvd2 +muldvd2: + umul %o0,%o1,%o0 + rd %y,%o1 + ld [%o2],%o5 + addcc %o0,%o5,%o0 + ld [%o3],%o5 + addx %o1,%g0,%o1 + addcc %o0,%o5,%o0 + st %o0,[%o3] + addx %o1,%g0,%o1 + retl + st %o1,[%o2] + + .global muldvm +muldvm: + mov %o0,%y + nop + nop + nop + udiv %o1,%o2,%o0 + umul %o0,%o2,%o2 + sub %o1,%o2,%o1 + retl + st %o1,[%o3] + + .global muldiv +muldiv: + umul %o0,%o1,%o1 + rd %y,%o0 + addcc %o1,%o2,%o1 + addx %o0,%g0,%o0 + mov %o0,%y + nop + nop + nop + udiv %o1,%o3,%o0 + umul %o0,%o3,%o2 + sub %o1,%o2,%o1 + retl + st %o1,[%o4] + + +/* In-line assembly for SPARC using double type */ + +#include +#include "miracl.h" + +mr_small muldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_small *rp) +{ + mr_small q; + mr_large ldres,dble; + static mr_small magic=MR_MAGIC; + __asm__ __volatile__ ( + "fdmulq %1,%2,%%f0\n" + "fdtoq %3,%%f4\n" + "faddq %%f0,%%f4,%%f0\n" + "fdtoq %4,%%f4\n" + "fdivq %%f0,%%f4,%%f4\n" + "fdtoq %5,%%f8\n" + "faddq %%f4,%%f8,%%f4\n" + "fsubq %%f4,%%f8,%%f4\n" + "fqtod %%f4,%0\n" + "fdmulq %0,%4,%%f8\n" + "fsubq %%f0,%%f8,%%f0\n" + "fqtod %%f0,%%f10\n" + "std %%f10,[%6]\n" + : "=f"(q) + : "f"(a),"f"(b),"f"(c),"f"(m),"f"(magic),"r"(rp) + : "f0","f1","f2","f3","f4","f5","f6","f7","f8","f9","f10","f11","memory" + ); + return q; +} + +#ifdef MR_FP_ROUNDING + +mr_small imuldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_large im,mr_small *rp) +{ + mr_small q; + mr_large ldres,dble; + static mr_small magic=MR_MAGIC; + __asm__ __volatile__ ( + "fdmulq %1,%2,%%f0\n" + "fdtoq %3,%%f4\n" + "faddq %%f0,%%f4,%%f0\n" + + "fmulq %4,%%f0,%%f4\n" + "fdtoq %6,%%f8\n" + "faddq %%f4,%%f8,%%f4\n" + "fsubq %%f4,%%f8,%%f4\n" + "fqtod %%f4,%0\n" + + "fdmulq %0,%5,%%f8\n" + "fsubq %%f0,%%f8,%%f0\n" + "fqtod %%f0,%%f10\n" + "std %%f10,[%7]\n" + : "=f"(q) + : "f"(a),"f"(b),"f"(c),"f"(im),"f"(m),"f"(magic),"r"(rp) + : "f0","f1","f2","f3","f4","f5","f6","f7","f8","f9","f10","f11","memory" + ); + return q; +} + +#endif + + + +/* before leaving the SPARC, here is an interesting idea + Specify the underlying type as the 64-bit long long, as supported by the + GCC compiler. Use the Blakely-Sloan Portable Code above, with mr_hltype + defined as a long. This has been tried and works, getting 64-bit + behaviour from a 32-bit processor! Its slower than the 32-bit code above, + but if the 64-bit mrmuldvd() were rewritten in fast assembler.....? */ + + +************************************************************************ + +######################################################################################### +# +# mrmuldv.s +# author: G. Garth Feb 1996 +# +# implementation of modular multiplication for smalls +# using Blakely-Sloan division algorithm +# for Motorola 601 and 604 RISC PowerPC 32-bit processors +# see IEEE trans. Computers C-34, No. 3, March 1985 pp. 290-292 +# +# see also PowerPC Microprocessor Developer's guide +# by Bunda, Potter & Shadowen, SAMS 1995, Appendix A p. 177 +# +# intended for use in MIRACL library as assembly language implementation +# of routines muldiv, muldvm and muldvd +# written for Apple MPW PPC Assembler for Macintosh PPC computers +# +# Division Algorithm Pseudo Code +# given: integers A,B,C,D and M where D = A * B + C +# this algorithm computes Q and R such that +# D = M * Q + R +# Constraints: +# A,B,C,M < 2^H where H is word length in bits +# 0 <= Q,R < M; 0 < D < 2^(2*H) +# +# let K = # of bits in D +# +# R = Q = 0; +# for(T = K - 1; T >= 0; T--) +# { +# R <<= 1; +# Q <<= 1; +# if(D[T] == 1) +# { +# R += 1; +# } +# while(R >= M) +# { +# R -= M; +# Q += 1; +# } +# } +# +######################################################################################### + + export muldiv[DS] + export .muldiv[PR] + export muldvm[DS] + export .muldvm[PR] + export muldvd[DS] + export .muldvd[PR] + + toc + tc muldiv[TC],muldiv[DS] + tc muldvm[TC],muldvm[DS] + tc muldvd[TC],muldvd[DS] + + csect muldiv[DS] + dc.l .muldiv[PR] + dc.l TOC[tc0] + csect muldvm[DS] + dc.l .muldvm[PR] + dc.l TOC[tc0] + csect muldvd[DS] + dc.l .muldvd[PR] + dc.l TOC[tc0] + +# +# unsigned int muldiv(a,b,c,m,rp) +# unsigned int a,b,c,m,*rp; +# returns q = int[(a*b+c)/m] and *rp = (a*b+c) mod m +# when called a -> (r3), b -> (r4), c -> (r5), m -> (r6), rp -> (r7) +# upon return q -> (r3), *rp -> [(r12)] +# registers used: r3 thru r12 +# + + csect .muldiv[PR] + function .muldiv[PR] + + or r12,r7,r7 ;(r12) <- remainder address + mulhwu r8,r3,r4 ;(r8) <- a * b high word + mullw r9,r3,r4 ;(r9 ) <- a * b low word + addc r4,r5,r9 ;(r4) <- a * b + c dividend.lo + addze r3,r8 ;(r3) <- (r8) + XERca dividend.hi + subic. r5,r3,0 ;test for zero dividend.hi + bne divlong ; + ;here if dividend is single word + divwu r3,r4,r6 ;(r3) <- quotient + mullw r7,r6,r3; ;(r7) <- r6 * int (r4 / r6) + subf r5,r7,r4 ;(r5) <- remainder.lo + stw r5,0x0000(r12) ;[(r12)] <- remainder + blr ;that's all for single word division + +divlong: + xor r7,r7,r7 ;zero divisor.hi + nor r7,r7,r7 ;calc ~divisor.hi + subfic r8,r6,0 ;(r8) <- -divisor.lo, set CA + addze r7,r7 ;(r7) <- ~divisor.hi + CA + or r11,r4,r4 ;(r11) <- dividend.lo + or r4,r3,r3 ;(r4) <- dividend.hi + ;try to shift ahead, skipping unnecessary + ;shifting loops + cntlzw r10,r4 ;find order of dividend.hi + subfic r9,r10,32 ;calc shift = 32 - order + slw r4,r4,r10 ;shift ahead dividend.hi + srw r3,r11,r9 ;get shifted part of dividend.lo + or r4,r4,r3 ;combine with dividend.hi + slw r11,r11,r10 ;shift ahead dividend.lo + addi r9,r9,33 ;setup for looping + mtctr r9 ; + xor r3,r3,r3 ;clear quotient.lo + xor r5,r5,r5 ;clear shift.hi + xor r6,r6,r6 ;clear shift.lo + b ldiff ;skip first round of shifting + align 6 ;align loop to 64-byte boundary +lshift: + rlwinm r5,r5,1,0,30 ;shift.hi <<= 1 + rlwimi r5,r6,1,31,31 ;shift.hi[31] = shift.lo[0] + rlwinm r6,r6,1,0,30 ;shift.lo <<= 1 + rlwimi r6,r4,1,31,31 ;shift.lo[31] = dividend.hi[0] + rlwinm r4,r4,1,0,30 ;dividend.hi <<= 1 + rlwimi r4,r11,1,31,31 ;dividend.hi[31] = dividend.lo[0] + rlwinm r11,r11,1,0,30 ;dividend.lo <<= 1 + rlwinm r3,r3,1,0,30 ;quotient.lo <<=1 +ldiff: + addc r10,r6,r8 ;diff.lo = shift.lo - divisor.lo, set CA + adde. r9,r5,r7 ;diff.hi = shift.hi - divisor.hi + CA + blt lloop ;loop if diff < 0 + or r6,r10,r10 ;shift.lo = diff.lo + or r5,r9,r9 ;shift.hi = diff.hi + ori r3,r3,1 ;set bit in quotient +lloop: + bdnz lshift ;loop until done + stw r6,0x0000(r12) ;store remainder in rp address + blr ;return + +# +# unsigned int muldvm(a,c,m,rp) +# unsigned int a,c,m,*rp; +# returns q = int[(a*base+c)/m] and *rp = (a*base+c) mod m +# when called a -> (r3), c -> (r4), m -> (r5), rp -> (r6) +# upon return q -> (r3), *rp -> [(r12)] +# registers used: r3 thru r12 +# + + csect .muldvm[PR] + function .muldvm[PR] + + or r12,r6,r6 ;(r12) <- remainder address + or r6,r5,r5 ;(r6) <- m + xor r7,r7,r7 ;zero divisor.hi + nor r7,r7,r7 ;calc ~divisor.hi + subfic r8,r6,0 ;(r8) <- calc -divisor.lo, set CA + addze r7,r7 ;(r7) <- ~divisor.hi += CA + or r11,r4,r4 ;(r11) <- dividend.lo + or r4,r3,r3 ;(r4) <- dividend.hi + ;try to shift ahead, skipping unnecessary + ;shifting loops + cntlzw r10,r4 ;find order of dividend.hi + subfic r9,r10,32 ;calc shift = 32 - order + slw r4,r4,r10 ;shift ahead dividend.hi + srw r3,r11,r9 ;get shifted part of dividend.lo + or r4,r4,r3 ;combine with dividend.hi + slw r11,r11,r10 ;shift ahead dividend.lo + addi r9,r9,33 ;setup for looping + mtctr r9 ; + xor r3,r3,r3 ;clear quotient.lo + xor r5,r5,r5 ;clear shift.hi + xor r6,r6,r6 ;clear shift.lo + b sdiff ;skip first round of shifting + align 6 ;align loop to 64-byte boundary +sshift: + rlwinm r5,r5,1,0,30 ;shift.hi <<= 1 + rlwimi r5,r6,1,31,31 ;shift.hi[31] = shift.lo[0] + rlwinm r6,r6,1,0,30 ;shift.lo <<= 1 + rlwimi r6,r4,1,31,31 ;shift.lo[31] = dividend.hi[0] + rlwinm r4,r4,1,0,30 ;dividend.hi <<= 1 + rlwimi r4,r11,1,31,31 ;dividend.hi[31] = dividend.lo[0] + rlwinm r11,r11,1,0,30 ;dividend.lo <<= 1 + rlwinm r3,r3,1,0,30 ;quotient.lo <<=1 +sdiff: + addc r10,r6,r8 ;diff.lo = shift.lo - divisor.lo, set CA + adde. r9,r5,r7 ;diff.hi = shift.hi - divisor.hi + CA + blt sloop ;loop if diff < 0 + or r6,r10,r10 ;shift.lo = diff.lo + or r5,r9,r9 ;shift.hi = diff.hi + ori r3,r3,1 ;set bit in quotient +sloop: + bdnz sshift + stw r6,0x0000(r12) ;store remainder in rp address + blr ;return + +# +# unsigned int muldvd(a,b,c,rp) +# unsigned int a,b,c,*rp; +# returns q = int[(a*b+c)/base] and *rp = (a*b+c) mod base +# when called a -> (r3), b -> (r4), c -> (r5), rp -> (r6) +# upon return q -> (r3), *rp -> [(r6)] +# registers used: r3 thru r8 +# + + csect .muldvd[PR] + function .muldvd[PR] + + mulhwu r7,r3,r4 ;(r7) <- a * b high word + mullw r8,r3,r4 ;(r8) <- a * b low word + addc r4,r8,r5 ;(r4) <- a * b + c + addze r3,r7 ;(r3) <- (r7) + XERca + stw r4,0x0000(r6) ;store remainder -> (r6) + blr ;return + + + +*****************************************************************************/ + + +/* Itanium code for Intel compiler, with mr_small a 64-bit long */ + +#include "miracl.h" + +mr_small muldiv(a,b,c,m,rp) +mr_small a,b,c,m; +mr_small *rp; +{ /* Blakely-Sloan */ + int i; + mr_small d,q=0,r=0; + d=m-a; + for (i=MIRACL/4;i>0;i--) + { /* do it bit by bit */ + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + } + *rp=r; + return q; +} + +mr_small muldvm(a,c,m,rp) +mr_small a,c,m; +mr_small *rp; +{ /* modified Blakely-Sloan */ + register int i,carry; + register mr_small q=0,r=0; + r=a; + for (i=MIRACL/4;i>0;i--) + { /* do it bit by bit */ + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + } + *rp=r; + return q; +} + +/* use intrinsics for speed */ + +/* These are now in-lined - see miracl.h */ + +/* + +#include + +mr_small muldvd(a,b,c,rp) +mr_small a,b,c; +mr_small *rp; +{ + *rp=_m64_xmalu(a,b,c); + return _m64_xmahu(a,b,c); +} + +void muldvd2(a,b,c,rp) +mr_small a,b; +mr_small *c,*rp; +{ + mr_small bot; + bot=_m64_xmalu(a,b,*c); + *c=_m64_xmahu(a,b,*c); + bot+=*rp; + if (bot<*rp) (*c)++; + *rp=bot; +} + +*/ + + +/ +/ GNU C for Linux (AMD64) +/ Parameters are passed in rdi,rsi,rdx,rcx,r8.... +/ + + .file "mrmuldv.s" +.text + .globl muldiv +muldiv: + + pushq %rbx + movq %rdi,%rax + movq %rdx,%rbx + mulq %rsi + addq %rbx,%rax + adcq $0,%rdx + + divq %rcx + movq %r8,%rbx + movq %rdx,(%rbx) + popq %rbx + + ret + + .globl muldvm +muldvm: + + pushq %rbx + movq %rdx,%rbx + movq %rdi,%rdx + movq %rsi,%rax + divq %rbx + + movq %rcx,%rbx + movq %rdx,(%rbx) + popq %rbx + + ret + + .globl muldvd +muldvd: + + pushq %rbx + movq %rdi,%rax + movq %rdx,%rbx + mulq %rsi + addq %rbx,%rax + adcq $0,%rdx + + movq %rcx,%rbx + movq %rax,(%rbx) + movq %rdx,%rax + popq %rbx + + ret + + .globl muldvd2 +muldvd2: + + pushq %rbx + movq %rdi,%rax + movq %rdx,%rbx + mulq %rsi + addq (%rbx),%rax + adcq $0,%rdx + addq (%rcx),%rax + adcq $0,%rdx + + movq %rax,(%rcx) + movq %rdx,(%rbx) + popq %rbx + + ret + +; Written by Ed Runnion with full rights granted to Shamus Software. +; +; An implementation of mrmuldv routines for miracl +; for ml64 assembler used by Microsoft Visual Studio (VC8) and X64 processor (AMD 64) +; X64 arguments are passed in RCX, RDX, R8, R9, Stack... + +;/* +; * MIRACL compiler/hardware definitions - mirdef.h +; * Copyright (c) 1988-2006 Shamus Software Ltd. +; */ +;#define MR_LITTLE_ENDIAN +;#define MIRACL 64 +;#define mr_utype __int64 +;#define mr_unsign64 unsigned __int64 +;#define MR_IBITS 32 +;#define MR_LBITS 32 +;#define mr_unsign32 unsigned int +;#define MR_FLASH 52 +;#define MAXBASE ((mr_small)1<<(MIRACL-1)) +;#define MR_BITSINCHAR 8 + +.code + +ALIGN 16 +PUBLIC muldiv +muldiv PROC + + mov rax,rcx + mul rdx + add rax,r8 + adc rdx,0 + div r9 + mov r10, QWORD PTR [rsp+28h] + mov QWORD PTR[r10],rdx + + ret +muldiv ENDP + +ALIGN 16 +PUBLIC muldvm +muldvm PROC + + mov rax,rdx + mov rdx,rcx + div r8 + mov QWORD PTR[r9],rdx + + ret +muldvm ENDP + + +ALIGN 16 +PUBLIC muldvd +muldvd PROC + + mov rax,rcx + mul rdx + add rax,r8 + adc rdx,0 + mov QWORD PTR[r9],rax + mov rax,rdx + + ret +muldvd ENDP + +ALIGN 16 +PUBLIC muldvd2 +muldvd2 PROC + + mov rax,rcx + mul rdx + add rax,QWORD PTR[r8] + adc rdx,0 + add rax,QWORD PTR[r9] + adc rdx,0 + mov QWORD PTR[r9],rax + mov QWORD PTR[r8],rdx + + ret +muldvd2 ENDP + + end + + +/* Win64 C version of mrmuldv.c, for 64-bit Visual Studio apps */ + +#include "miracl.h" + +mr_small muldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_small *rp) +{ + int i; + mr_small d,q=0,r=0; + d=m-a; + for (i=MIRACL/4;i>0;i--) + { /* do it bit by bit */ + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + } + *rp=r; + return q; +} + +mr_small muldvm(mr_small a,mr_small c,mr_small m,mr_small *rp) +{ /* modified Blakely-Sloan */ + register int i,carry; + register mr_small q=0,r=0; + r=a; + for (i=MIRACL/4;i>0;i--) + { /* do it bit by bit */ + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + } + *rp=r; + return q; +} + +#ifndef MR_NOFULLWIDTH + +/* These are now in-lined - see miracl.h */ + +/* + +mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) +{ + mr_small q,r; + r=_umul128(a,b,&q); + r+=c; + q+=(r +#include "miracl.h" + +mr_small muldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_small *rp) +{ + mr_small q; + mr_large dble=(mr_large)a*b+c; + q=(mr_small)MR_LROUND(dble/m); + *rp=(mr_small)(dble-(mr_large)q*m); + return q; +} + +#ifdef MR_FP_ROUNDING + +mr_small imuldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_large im,mr_small *rp) +{ + mr_small q; + mr_large dble=(mr_large)a*b+c; + q=(mr_small)MR_LROUND(dble*im); + *rp=(mr_small)(dble-(mr_large)q*m); + return q; +} + +#endif + + +#ifndef MR_NOFULLWIDTH + +mr_small muldvm(mr_small a,mr_small c,mr_small m,mr_small *rp) +{ + mr_small q; + union doubleword dble; + dble.h[MR_BOT]=c; + dble.h[MR_TOP]=a; + q=(mr_small)(dble.d/m); + *rp=(mr_small)(dble.d-(mr_large)q*m); + return q; +} + +mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) +{ + union doubleword dble; + dble.d=(mr_large)a*b+c; + *rp=dble.h[MR_BOT]; + return dble.h[MR_TOP]; +} + +void muldvd2(mr_small a,mr_small b,mr_small *c,mr_small *rp) +{ + union doubleword dble; + dble.d=(mr_large)a*b+*c+*rp; + *rp=dble.h[MR_BOT]; + *c=dble.h[MR_TOP]; +} + +#endif + diff --git a/miracl/source/mrmuldv.g64 b/miracl/source/mrmuldv.g64 new file mode 100644 index 0000000..257ad63 --- /dev/null +++ b/miracl/source/mrmuldv.g64 @@ -0,0 +1,80 @@ + +/* GCC inline assembly version for Linux64 */ + +#include "miracl.h" + + +mr_small muldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_small *rp) +{ + mr_small q; + __asm__ __volatile__ ( + "movq %1,%%rax\n" + "mulq %2\n" + "addq %3,%%rax\n" + "adcq $0,%%rdx\n" + "divq %4\n" + "movq %5,%%rbx\n" + "movq %%rdx,(%%rbx)\n" + "movq %%rax,%0\n" + : "=m"(q) + : "m"(a),"m"(b),"m"(c),"m"(m),"m"(rp) + : "rax","rbx","memory" + ); + return q; +} + +mr_small muldvm(mr_small a,mr_small c,mr_small m,mr_small *rp) +{ + mr_small q; + __asm__ __volatile__ ( + "movq %1,%%rdx\n" + "movq %2,%%rax\n" + "divq %3\n" + "movq %4,%%rbx\n" + "movq %%rdx,(%%rbx)\n" + "movq %%rax,%0\n" + : "=m"(q) + : "m"(a),"m"(c),"m"(m),"m"(rp) + : "rax","rbx","memory" + ); + return q; +} + +mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) +{ + mr_small q; + __asm__ __volatile__ ( + "movq %1,%%rax\n" + "mulq %2\n" + "addq %3,%%rax\n" + "adcq $0,%%rdx\n" + "movq %4,%%rbx\n" + "movq %%rax,(%%rbx)\n" + "movq %%rdx,%0\n" + : "=m"(q) + : "m"(a),"m"(b),"m"(c),"m"(rp) + : "rax","rbx","memory" + ); + return q; +} + +void muldvd2(mr_small a,mr_small b,mr_small *c,mr_small *rp) +{ + __asm__ __volatile__ ( + "movq %0,%%rax\n" + "mulq %1\n" + "movq %2,%%rbx\n" + "addq (%%rbx),%%rax\n" + "adcq $0,%%rdx\n" + "movq %3,%%rsi\n" + "addq (%%rsi),%%rax\n" + "adcq $0,%%rdx\n" + "movq %%rax,(%%rsi)\n" + "movq %%rdx,(%%rbx)\n" + : + : "m"(a),"m"(b),"m"(c),"m"(rp) + : "rax","rbx","rsi","memory" + ); + +} + diff --git a/miracl/source/mrmuldv.gcc b/miracl/source/mrmuldv.gcc new file mode 100644 index 0000000..dfab752 --- /dev/null +++ b/miracl/source/mrmuldv.gcc @@ -0,0 +1,80 @@ + +/* GCC inline assembly version for Linux */ + +#include "miracl.h" + + +mr_small muldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_small *rp) +{ + mr_small q; + __asm__ __volatile__ ( + "movl %1,%%eax\n" + "mull %2\n" + "addl %3,%%eax\n" + "adcl $0,%%edx\n" + "divl %4\n" + "movl %5,%%ebx\n" + "movl %%edx,(%%ebx)\n" + "movl %%eax,%0\n" + : "=m"(q) + : "m"(a),"m"(b),"m"(c),"m"(m),"m"(rp) + : "eax","ebx","memory" + ); + return q; +} + +mr_small muldvm(mr_small a,mr_small c,mr_small m,mr_small *rp) +{ + mr_small q; + __asm__ __volatile__ ( + "movl %1,%%edx\n" + "movl %2,%%eax\n" + "divl %3\n" + "movl %4,%%ebx\n" + "movl %%edx,(%%ebx)\n" + "movl %%eax,%0\n" + : "=m"(q) + : "m"(a),"m"(c),"m"(m),"m"(rp) + : "eax","ebx","memory" + ); + return q; +} + +mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) +{ + mr_small q; + __asm__ __volatile__ ( + "movl %1,%%eax\n" + "mull %2\n" + "addl %3,%%eax\n" + "adcl $0,%%edx\n" + "movl %4,%%ebx\n" + "movl %%eax,(%%ebx)\n" + "movl %%edx,%0\n" + : "=m"(q) + : "m"(a),"m"(b),"m"(c),"m"(rp) + : "eax","ebx","memory" + ); + return q; +} + +void muldvd2(mr_small a,mr_small b,mr_small *c,mr_small *rp) +{ + __asm__ __volatile__ ( + "movl %0,%%eax\n" + "mull %1\n" + "movl %2,%%ebx\n" + "addl (%%ebx),%%eax\n" + "adcl $0,%%edx\n" + "movl %3,%%esi\n" + "addl (%%esi),%%eax\n" + "adcl $0,%%edx\n" + "movl %%eax,(%%esi)\n" + "movl %%edx,(%%ebx)\n" + : + : "m"(a),"m"(b),"m"(c),"m"(rp) + : "eax","ebx","esi","memory" + ); + +} + diff --git a/miracl/source/mrmuldv.gpp b/miracl/source/mrmuldv.gpp new file mode 100644 index 0000000..2dff20c --- /dev/null +++ b/miracl/source/mrmuldv.gpp @@ -0,0 +1,87 @@ +/ +/ DJGPP GNU C version for DOS +/ M. Scott 22/3/98 +/ + + + .file "mrmuldv.c" +.text +.globl _muldiv +_muldiv: + pushl %ebp + movl %esp,%ebp + pushl %ebx + + + movl 8(%ebp),%eax + mull 12(%ebp) + addl 16(%ebp),%eax + adcl $0,%edx + + divl 20(%ebp) + movl 24(%ebp),%ebx + movl %edx,(%ebx) + + popl %ebx + popl %ebp + ret + + .globl _muldvm +_muldvm: + pushl %ebp + movl %esp,%ebp + pushl %ebx + + movl 8(%ebp),%edx + movl 12(%ebp),%eax + divl 16(%ebp) + + movl 20(%ebp),%ebx + movl %edx,(%ebx) + + popl %ebx + popl %ebp + ret + + .globl _muldvd +_muldvd: + pushl %ebp + movl %esp,%ebp + pushl %ebx + + movl 8(%ebp),%eax + mull 12(%ebp) + addl 16(%ebp),%eax + adcl $0,%edx + movl 20(%ebp),%ebx + movl %eax,(%ebx) + movl %edx,%eax + + popl %ebx + popl %ebp + ret + + .globl _muldvd2 +_muldvd2: + pushl %ebp + movl %esp,%ebp + pushl %ebx + pushl %esi + + movl 8(%ebp),%eax + mull 12(%ebp) + movl 16(%ebp),%ebx + addl (%ebx),%eax + adcl $0,%edx + movl 20(%ebp),%esi + addl (%esi),%eax + adcl $0,%edx + + movl %eax,(%esi) + movl %edx,(%ebx) + + popl %esi + popl %ebx + popl %ebp + ret + diff --git a/miracl/source/mrmuldv.ppc b/miracl/source/mrmuldv.ppc new file mode 100644 index 0000000..e2f6f3a --- /dev/null +++ b/miracl/source/mrmuldv.ppc @@ -0,0 +1,168 @@ + +/* GCC inline assembly version for Linux */ + +#include "miracl.h" + +mr_small muldiv(a,b,c,m,rp) +mr_small a,b,c,m; +mr_small *rp; +{ + int i; + mr_small d,q=0,r=0; + d=m-a; + for (i=MIRACL/4;i>0;i--) + { /* do it bit by bit */ + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + } + *rp=r; + return q; +} + +mr_small muldvm(a,c,m,rp) +mr_small a,c,m; +mr_small *rp; +{ /* modified Blakely-Sloan */ + register int i,carry; + register mr_small q=0,r=0; + r=a; + for (i=MIRACL/4;i>0;i--) + { /* do it bit by bit */ + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + } + *rp=r; + return q; +} + +void muldvd2(mr_small a,mr_small b,mr_small *c,mr_small *rp) +{ + __asm__ __volatile__ ( + "mulld %%r16,%0,%1\n" + "mulhdu %%r17,%0,%1\n" + "ld %%r18,0(%2)\n" + "addc %%r16,%%r18,%%r16\n" + "addze %%r17,%%r17\n" + "ld %%r19,0(%3)\n" + "addc %%r16,%%r19,%%r16\n" + "addze %%r17,%%r17\n" + "std %%r16,0(%3)\n" + "std %%r17,0(%2)\n" + : + : "r"(a),"r"(b),"r"(c),"r"(rp) + : "r16","r17","r18","r19","memory" + ); + +} + +mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) +{ + mr_small q; + __asm__ __volatile__ ( + "mulld %%r16,%1,%2\n" + "mulhdu %%r17,%1,%2\n" + "addc %%r16,%3,%%r16\n" + "addze %%r17,%%r17\n" + "std %%r16,0(%4)\n" + "or %0,%%r17,%%r17\n" + : "=r"(q) + : "r"(a),"r"(b),"r"(c),"r"(rp) + : "r16","r17","memory" + ); + return q; +} + +/* +mr_small test(mr_small a,mr_small b,mr_small c,mr_small *rp) +{ + mr_small q; + q=a*b+c+*rp; + *rp=q; + return q; +} + +int main() +{ + mr_small a,b,c,q,r; + + + printf("sizeof(mr_small)= %d\n",sizeof(mr_small)); + a=(mr_small)-1; + b=(mr_small)-1; + c=0; + q=0; + r=0; + q=muldvd(a,b,c,&r); + muldvd2(a,b,&c,&r); + printf("c= %lx r= %lx\n",c,r); +} + +*/ diff --git a/miracl/source/mrmuldv.s b/miracl/source/mrmuldv.s new file mode 100644 index 0000000..9a775b1 --- /dev/null +++ b/miracl/source/mrmuldv.s @@ -0,0 +1,82 @@ + + .file "mrmuldv.s" + .text + .globl muldiv +muldiv: + pushl %ebp + movl %esp,%ebp + pushl %ebx + + + movl 8(%ebp),%eax + mull 12(%ebp) + addl 16(%ebp),%eax + adcl $0,%edx + + divl 20(%ebp) + movl 24(%ebp),%ebx + movl %edx,(%ebx) + + popl %ebx + popl %ebp + ret + + .globl muldvm +muldvm: + pushl %ebp + movl %esp,%ebp + pushl %ebx + + movl 8(%ebp),%edx + movl 12(%ebp),%eax + divl 16(%ebp) + + movl 20(%ebp),%ebx + movl %edx,(%ebx) + + popl %ebx + popl %ebp + ret + + .globl muldvd +muldvd: + pushl %ebp + movl %esp,%ebp + pushl %ebx + + movl 8(%ebp),%eax + mull 12(%ebp) + addl 16(%ebp),%eax + adcl $0,%edx + movl 20(%ebp),%ebx + movl %eax,(%ebx) + movl %edx,%eax + + popl %ebx + popl %ebp + ret + + .globl muldvd2 +muldvd2: + pushl %ebp + movl %esp,%ebp + pushl %ebx + pushl %esi + + movl 8(%ebp),%eax + mull 12(%ebp) + movl 16(%ebp),%ebx + addl (%ebx),%eax + adcl $0,%edx + movl 20(%ebp),%esi + addl (%esi),%eax + adcl $0,%edx + + movl %eax,(%esi) + movl %edx,(%ebx) + + popl %esi + popl %ebx + popl %ebp + ret + diff --git a/miracl/source/mrmuldv.s64 b/miracl/source/mrmuldv.s64 new file mode 100644 index 0000000..e4288e3 --- /dev/null +++ b/miracl/source/mrmuldv.s64 @@ -0,0 +1,70 @@ + + .file "mrmuldv.s" +.text + .globl muldiv +muldiv: + + pushq %rbx + movq %rdi,%rax + movq %rdx,%rbx + mulq %rsi + addq %rbx,%rax + adcq $0,%rdx + + divq %rcx + movq %r8,%rbx + movq %rdx,(%rbx) + popq %rbx + + ret + + .globl muldvm +muldvm: + + pushq %rbx + movq %rdx,%rbx + movq %rdi,%rdx + movq %rsi,%rax + divq %rbx + + movq %rcx,%rbx + movq %rdx,(%rbx) + popq %rbx + + ret + + .globl muldvd +muldvd: + + pushq %rbx + movq %rdi,%rax + movq %rdx,%rbx + mulq %rsi + addq %rbx,%rax + adcq $0,%rdx + + movq %rcx,%rbx + movq %rax,(%rbx) + movq %rdx,%rax + popq %rbx + + ret + + .globl muldvd2 +muldvd2: + + pushq %rbx + movq %rdi,%rax + movq %rdx,%rbx + mulq %rsi + addq (%rbx),%rax + adcq $0,%rdx + addq (%rcx),%rax + adcq $0,%rdx + + movq %rax,(%rcx) + movq %rdx,(%rbx) + popq %rbx + + ret + diff --git a/miracl/source/mrmuldv.tcc b/miracl/source/mrmuldv.tcc new file mode 100644 index 0000000..a2eb534 --- /dev/null +++ b/miracl/source/mrmuldv.tcc @@ -0,0 +1,82 @@ +/* + * Turbo C compiler V1.5+, Turbo/Borland C++. Microsoft C/C++ + * Uses inline assembly feature + * Generates code identical to above version, and + * can be used instead. + */ + +#define ASM asm + +/* or perhaps #define ASM _asm */ + +unsigned int muldiv(a,b,c,m,rp) +unsigned int a,b,c,m,*rp; +{ + ASM mov ax,a ;/* get a */ + ASM mul WORD PTR b ;/* multiply by b */ + ASM add ax,c ;/* add c to low word */ + ASM adc dx,0h ;/* add carry to high word */ + ASM div WORD PTR m ;/* divide by m */ + ASM mov bx,rp ;/* get address for remainder */ + ASM mov [bx],dx ;/* store remainder */ +} +/* Replace last two ASM lines when using large data memory models */ +/* ASM les bx, DWORD PTR rp ; get address for remainder */ +/* ASM mov WORD PTR es:[bx],dx ; store remainder */ + +unsigned int muldvm(a,c,m,rp) +unsigned int a,c,m,*rp; +{ + ASM mov dx,a ;/* get a */ + ASM mov ax,c ;/* add in c to low word */ + ASM div WORD PTR m ;/* divide by m */ + ASM mov bx,rp ;/* get address for remainder */ + ASM mov [bx],dx ;/* store remainder */ +} +/* Replace last two ASM lines when using large data memory models */ +/* ASM les bx, DWORD PTR rp ; get address for remainder */ +/* ASM mov WORD PTR es:[bx],dx ; store remainder */ + +unsigned int muldvd(a,b,c,rp) +unsigned int a,b,c,*rp; +{ + ASM mov ax,a ;/* get a */ + ASM mul WORD PTR b ;/* multiply by b */ + ASM add ax,c ;/* add c to low word */ + ASM adc dx,0h ;/* add carry to high word */ + ASM mov bx,rp ;/* get address for remainder */ + ASM mov [bx],ax ;/* store remainder */ + ASM mov ax,dx +} +/* Replace second and third last lines if using large data memory models */ +/* ASM les bx, DWORD PTR rp ; get address for remainder */ +/* ASM mov WORD PTR es:[bx],ax ; store remainder */ + +void muldvd2(a,b,c,rp) +unsigned int a,b,*c,*rp; +{ + ASM mov ax,a ;/* get a */ + ASM mul WORD PTR b ;/* multiply by b */ + ASM mov bx,c + ASM add ax,[bx] + ASM adc dx,0h ;/* add carry to high word */ + ASM mov si,rp + ASM add ax,[si] + ASM adc dx,0h + ASM mov [si],ax + ASM mov [bx],dx +} + +/* for large memory model .... + ASM mov ax,a + ASM mul WORD PTR b + ASM les bx, DWORD PTR c + ASM add ax, WORD PTR es:[bx] + ASM adc dx,0h + ASM les si,DWORD PTR rp + ASM add ax,WORD PTR es:[si] + ASM adc dx,0h + ASM mov WORD PTR es:[si],ax + ASM les bx,DWORD PTR c + ASM mov WORD PTR es:[bx],dx +*/ diff --git a/miracl/source/mrmuldv.w64 b/miracl/source/mrmuldv.w64 new file mode 100644 index 0000000..d549d0b --- /dev/null +++ b/miracl/source/mrmuldv.w64 @@ -0,0 +1,194 @@ +/* Win64 C version of mrmuldv.c */ + +#include "miracl.h" + +mr_small muldiv(mr_small a,mr_small b,mr_small c,mr_small m,mr_small *rp) +{ + int i; + mr_small d,q=0,r=0; + d=m-a; + for (i=MIRACL/4;i>0;i--) + { /* do it bit by bit */ + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if ((mr_utype)b<0) + { + if (r>=m) { r-=d; q++; } + else r+=a; + } + if (r>=m) { r-=m; q++; } + b<<=1; + } + *rp=r; + return q; +} + +mr_small muldvm(mr_small a,mr_small c,mr_small m,mr_small *rp) +{ /* modified Blakely-Sloan */ + register int i,carry; + register mr_small q=0,r=0; + r=a; + for (i=MIRACL/4;i>0;i--) + { /* do it bit by bit */ + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + carry=0; + if ((mr_utype)r<0) carry=1; + r<<=1; + if ((mr_utype)c<0) r++; + c<<=1; + q<<=1; + if (carry || r>=m) { r-=m; q++; } + } + *rp=r; + return q; +} + +#ifndef MR_NOFULLWIDTH + +#ifdef MR_NO_INTRINSICS + +/* define mr_hltype as that C type that is half the size in bits of the + underlying type (mr_utype in mirdef.h). Perhaps short if mr_utype is long? + Possible int if mr_utype is 64-bit long long ?? */ + +#define mr_hltype int + +mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) +{ /* multiply by parts */ + mr_small middle,middle2; + mr_small q,r; + unsigned mr_hltype am,al,bm,bl; + int hshift=(MIRACL>>1); + am=(unsigned mr_hltype)(a>>hshift); + al=(unsigned mr_hltype)a; + bm=(unsigned mr_hltype)(b>>hshift); + bl=(unsigned mr_hltype)b; +/* form partial products */ + r= (mr_small)al*bl; + q= (mr_small)am*bm; + middle=(mr_small)al*bm; + middle2=(mr_small)bl*am; + middle+=middle2; /* combine them - carefully */ + if (middle>hshift)<(unsigned mr_hltype)middle) q++; + q+=(middle>>hshift); + r+=c; + if (r>1); + am=(unsigned mr_hltype)(a>>hshift); + al=(unsigned mr_hltype)a; + bm=(unsigned mr_hltype)(b>>hshift); + bl=(unsigned mr_hltype)b; +/* form partial products */ + r= (mr_small)al*bl; + q= (mr_small)am*bm; + middle=(mr_small)al*bm; + middle2=(mr_small)bl*am; + middle+=middle2; /* combine them - carefully */ + if (middle>hshift)<(unsigned mr_hltype)middle) q++; + q+=(middle>>hshift); + r+=*c; + if (r<*c) q++; + r+=*rp; + if (r<*rp) q++; + *rp=r; + *c=q; +} + + +#endif + +/* These are now in-lined - see miracl.h */ + +/* +mr_small muldvd(mr_small a,mr_small b,mr_small c,mr_small *rp) +{ + mr_small q,r; + r=_umul128(a,b,&q); + r+=c; + q+=(r. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL calculate pi - by Gauss-Legendre method + * mrpi.c + */ + +#include +#include "miracl.h" + +#ifdef MR_FLASH + +void fpi(_MIPD_ flash pi) +{ /* Calculate pi using Guass-Legendre method */ + int x,nits,op[5]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(53) + + if (size(mr_mip->pi)!=0) + { + copy(mr_mip->pi,pi); + mr_mip->EXACT=FALSE; + MR_OUT + return; + } + + fconv(_MIPP_ 1,2,mr_mip->pi); + froot(_MIPP_ mr_mip->pi,2,mr_mip->pi); + fconv(_MIPP_ 1,1,mr_mip->w11); + fconv(_MIPP_ 1,4,mr_mip->w12); + x=1; + op[0]=0x6C; + op[1]=1; + op[4]=0; + nits=mr_mip->lg2b*mr_mip->nib/4; + while (xw11,mr_mip->w13); + op[2]=1; + op[3]=2; + flop(_MIPP_ mr_mip->w11,mr_mip->pi,op,mr_mip->w11); + fmul(_MIPP_ mr_mip->pi,mr_mip->w13,mr_mip->pi); + froot(_MIPP_ mr_mip->pi,2,mr_mip->pi); + fsub(_MIPP_ mr_mip->w11,mr_mip->w13,mr_mip->w13); + fmul(_MIPP_ mr_mip->w13,mr_mip->w13,mr_mip->w13); + op[3]=1; + op[2]=(-x); + flop(_MIPP_ mr_mip->w12,mr_mip->w13,op,mr_mip->w12); /* w12 = w12 - x.w13 */ + x*=2; + } + fadd(_MIPP_ mr_mip->w11,mr_mip->pi,mr_mip->pi); + fmul(_MIPP_ mr_mip->pi,mr_mip->pi,mr_mip->pi); + op[0]=0x48; + op[2]=0; + op[3]=4; + flop(_MIPP_ mr_mip->pi,mr_mip->w12,op,mr_mip->pi); /* pi = pi/(4.w12) */ + if (pi!=NULL) copy(mr_mip->pi,pi); + MR_OUT +} + +#endif + diff --git a/miracl/source/mrpower.c b/miracl/source/mrpower.c new file mode 100644 index 0000000..d760f03 --- /dev/null +++ b/miracl/source/mrpower.c @@ -0,0 +1,624 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL methods for modular exponentiation + * mrpower.c + */ + +#include +#include "miracl.h" + +void nres_powltr(_MIPD_ int x,big y,big w) +{ /* calculates w=x^y mod z using Left to Right Method */ + /* uses only n^2 modular squarings, because x is small */ + /* Note: x is NOT an nresidue */ + int i,nb; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return; + copy(y,mr_mip->w1); + + MR_IN(86) + + zero(w); + if (x==0) + { + if (size(mr_mip->w1)==0) + { /* 0^0 = 1 */ + copy(mr_mip->one,w); + } + MR_OUT + return; + } + + copy(mr_mip->one,w); + if (size(mr_mip->w1)==0) + { + MR_OUT + return; + } + if (size(mr_mip->w1)<0) mr_berror(_MIPP_ MR_ERR_NEG_POWER); + if (mr_mip->ERNUM) + { + MR_OUT + return; + } + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { +#endif + nb=logb2(_MIPP_ mr_mip->w1); + convert(_MIPP_ x,w); + nres(_MIPP_ w,w); + if (nb>1) for (i=nb-2;i>=0;i--) + { /* Left to Right binary method */ + + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + nres_modmult(_MIPP_ w,w,w); + if (mr_testbit(_MIPP_ mr_mip->w1,i)) + { /* this is quick */ + premult(_MIPP_ w,x,w); + divide(_MIPP_ w,mr_mip->modulus,mr_mip->modulus); + } + } +#ifndef MR_ALWAYS_BINARY + } + else + { + expb2(_MIPP_ logb2(_MIPP_ mr_mip->w1)-1,mr_mip->w2); + while (size(mr_mip->w2)!=0) + { /* Left to Right binary method */ + + if (mr_mip->user!=NULL) (*mr_mip->user)(); + if (mr_mip->ERNUM) break; + nres_modmult(_MIPP_ w,w,w); + if (mr_compare(mr_mip->w1,mr_mip->w2)>=0) + { + premult(_MIPP_ w,x,w); + divide(_MIPP_ w,mr_mip->modulus,mr_mip->modulus); + subtract(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); + } + subdiv(_MIPP_ mr_mip->w2,2,mr_mip->w2); + } + } +#endif + if (size(w)<0) add(_MIPP_ w,mr_mip->modulus,w); + MR_OUT + return; +} + +#ifndef MR_STATIC + +void nres_powmodn(_MIPD_ int n,big *x,big *y,big w) +{ + int i,j,k,m,nb,ea; + big *G; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(112) + + m=1<nb) nb=k; + + copy(mr_mip->one,w); + +#ifndef MR_ALWAYS_BINARY + + if (mr_mip->base==mr_mip->base2) + { +#endif + for (i=nb-1;i>=0;i--) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + ea=0; + k=1; + for (j=0;jERNUM) return; + + MR_IN(113) + + prepare_monty(_MIPP_ p); + for (j=0;jERNUM) return; + copy(y,mr_mip->w1); + copy(x,mr_mip->w2); + copy(b,mr_mip->w3); + copy(a,mr_mip->w4); + zero(w); + if (size(mr_mip->w2)==0 || size(mr_mip->w4)==0) return; + + MR_IN(99) + + copy(mr_mip->one,w); + if (size(mr_mip->w1)==0 && size(mr_mip->w3)==0) + { + MR_OUT + return; + } + if (size(mr_mip->w1)<0 || size(mr_mip->w3)<0) mr_berror(_MIPP_ MR_ERR_NEG_POWER); + if (mr_mip->ERNUM) + { + MR_OUT + return; + } + +#ifndef MR_ALWAYS_BINARY + + if (mr_mip->base==mr_mip->base2) + { /* uses 2-bit sliding window. This is 25% faster! */ +#endif + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w4,mr_mip->w5); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w12); + nres_modmult(_MIPP_ mr_mip->w4,mr_mip->w4,mr_mip->w13); + nres_modmult(_MIPP_ mr_mip->w4,mr_mip->w13,mr_mip->w14); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w13,mr_mip->w6); + nres_modmult(_MIPP_ mr_mip->w6,mr_mip->w4,mr_mip->w15); + nres_modmult(_MIPP_ mr_mip->w4,mr_mip->w12,mr_mip->w8); + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w12,mr_mip->w9); + nres_modmult(_MIPP_ mr_mip->w4,mr_mip->w9,mr_mip->w10); + nres_modmult(_MIPP_ mr_mip->w14,mr_mip->w12,mr_mip->w11); + nres_modmult(_MIPP_ mr_mip->w9,mr_mip->w13,mr_mip->w12); + nres_modmult(_MIPP_ mr_mip->w10,mr_mip->w13,mr_mip->w13); + + table[0]=NULL; table[1]=mr_mip->w4; table[2]=mr_mip->w2; table[3]=mr_mip->w5; + table[4]=NULL; table[5]=mr_mip->w14; table[6]=mr_mip->w6; table[7]=mr_mip->w15; + table[8]=NULL; table[9]=mr_mip->w8; table[10]=mr_mip->w9; table[11]=mr_mip->w10; + table[12]=NULL;table[13]=mr_mip->w11;table[14]=mr_mip->w12; table[15]=mr_mip->w13; + nb=logb2(_MIPP_ mr_mip->w1); + if ((nb2=logb2(_MIPP_ mr_mip->w3))>nb) nb=nb2; + + for (i=nb-1;i>=0;) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + n=mr_window2(_MIPP_ mr_mip->w1,mr_mip->w3,i,&nbw,&nzs); + for (j=0;j0) nres_modmult(_MIPP_ w,table[n],w); + i-=nbw; + if (nzs) + { + nres_modmult(_MIPP_ w,w,w); + i--; + } + } +#ifndef MR_ALWAYS_BINARY + } + else + { + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w4,mr_mip->w5); + + if (mr_compare(mr_mip->w1,mr_mip->w3)>=0) + expb2(_MIPP_ logb2(_MIPP_ mr_mip->w1)-1,mr_mip->w6); + else expb2(_MIPP_ logb2(_MIPP_ mr_mip->w3)-1,mr_mip->w6); + while (size(mr_mip->w6)!=0) + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + if (mr_mip->ERNUM) break; + nres_modmult(_MIPP_ w,w,w); + if (mr_compare(mr_mip->w1,mr_mip->w6)>=0) + { + if (mr_compare(mr_mip->w3,mr_mip->w6)>=0) + { + nres_modmult(_MIPP_ w,mr_mip->w5,w); + subtract(_MIPP_ mr_mip->w3,mr_mip->w6,mr_mip->w3); + } + + else nres_modmult(_MIPP_ w,mr_mip->w2,w); + subtract(_MIPP_ mr_mip->w1,mr_mip->w6,mr_mip->w1); + } + else + { + if (mr_compare(mr_mip->w3,mr_mip->w6)>=0) + { + nres_modmult(_MIPP_ w,mr_mip->w4,w); + subtract(_MIPP_ mr_mip->w3,mr_mip->w6,mr_mip->w3); + } + } + subdiv(_MIPP_ mr_mip->w6,2,mr_mip->w6); + } + } +#endif + MR_OUT +} + +void powmod2(_MIPD_ big x,big y,big a,big b,big n,big w) +{/* w=x^y.a^b mod n */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(79) + + prepare_monty(_MIPP_ n); + nres(_MIPP_ x,mr_mip->w2); + nres(_MIPP_ a,mr_mip->w4); + nres_powmod2(_MIPP_ mr_mip->w2,y,mr_mip->w4,b,w); + redc(_MIPP_ w,w); + + MR_OUT +} + + +void powmod(_MIPD_ big x,big y,big n,big w) +{ /* fast powmod, using Montgomery's method internally */ + + mr_small norm; + BOOL mty; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(18) + + mty=TRUE; + + if (mr_mip->base!=mr_mip->base2) + { + if (size(n)<2 || sgcd(n->w[0],mr_mip->base)!=1) mty=FALSE; + } + else + if (subdivisible(_MIPP_ n,2)) mty=FALSE; + + if (!mty) + { /* can't use Montgomery */ + copy(y,mr_mip->w1); + copy(x,mr_mip->w3); + zero(w); + if (size(mr_mip->w3)==0) + { + MR_OUT + return; + } + convert(_MIPP_ 1,w); + if (size(mr_mip->w1)==0) + { + MR_OUT + return; + } + if (size(mr_mip->w1)<0) mr_berror(_MIPP_ MR_ERR_NEG_POWER); + if (w==n) mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS) ; + if (mr_mip->ERNUM) + { + MR_OUT + return; + } + + norm=normalise(_MIPP_ n,n); + divide(_MIPP_ mr_mip->w3,n,n); + forever + { + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + if (subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1)!=0) + mad(_MIPP_ w,mr_mip->w3,mr_mip->w3,n,n,w); + if (mr_mip->ERNUM || size(mr_mip->w1)==0) break; + mad(_MIPP_ mr_mip->w3,mr_mip->w3,mr_mip->w3,n,n,mr_mip->w3); + } + if (norm!=1) + { +#ifdef MR_FP_ROUNDING + mr_sdiv(_MIPP_ n,norm,mr_invert(norm),n); +#else + mr_sdiv(_MIPP_ n,norm,n); +#endif + divide(_MIPP_ w,n,n); + } + } + else + { /* optimized code for odd moduli */ + prepare_monty(_MIPP_ n); + nres(_MIPP_ x,mr_mip->w3); + nres_powmod(_MIPP_ mr_mip->w3,y,w); + redc(_MIPP_ w,w); + } + + MR_OUT +} + +int powltr(_MIPD_ int x, big y, big n, big w) +{ + mr_small norm; + BOOL clean_up,mty; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + + MR_IN(71) + mty=TRUE; + + if (mr_mip->base!=mr_mip->base2) + { + if (size(n)<2 || sgcd(n->w[0],mr_mip->base)!=1) mty=FALSE; + } + else + { + if (subdivisible(_MIPP_ n,2)) mty=FALSE; + } + +/* Is Montgomery modulus in use... */ + + clean_up=FALSE; + if (mty) + { /* still a chance to use monty... */ + if (size(mr_mip->modulus)!=0) + { /* somebody else is using it */ + if (mr_compare(n,mr_mip->modulus)!=0) mty=FALSE; + } + else + { /* its unused, so use it, but clean up after */ + clean_up=TRUE; + } + } + if (!mty) + { /* can't use Montgomery! */ + copy(y,mr_mip->w1); + zero(w); + if (x==0) + { + MR_OUT + return 0; + } + convert(_MIPP_ 1,w); + if (size(mr_mip->w1)==0) + { + MR_OUT + return 1; + } + + if (size(mr_mip->w1)<0) mr_berror(_MIPP_ MR_ERR_NEG_POWER); + if (w==n) mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS) ; + if (mr_mip->ERNUM) + { + MR_OUT + return 0; + } + + norm=normalise(_MIPP_ n,n); + + expb2(_MIPP_ logb2(_MIPP_ mr_mip->w1)-1,mr_mip->w2); + while (size(mr_mip->w2)!=0) + { /* Left to Right binary method */ + + if (mr_mip->user!=NULL) (*mr_mip->user)(); + if (mr_mip->ERNUM) break; + mad(_MIPP_ w,w,w,n,n,w); + if (mr_compare(mr_mip->w1,mr_mip->w2)>=0) + { + premult(_MIPP_ w,x,w); + divide(_MIPP_ w,n,n); + subtract(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); + } + subdiv(_MIPP_ mr_mip->w2,2,mr_mip->w2); + } + if (norm!=1) + { +#ifdef MR_FP_ROUNDING + mr_sdiv(_MIPP_ n,norm,mr_invert(norm),n); +#else + mr_sdiv(_MIPP_ n,norm,n); +#endif + divide(_MIPP_ w,n,n); + } + } + else + { /* optimized code for odd moduli */ + prepare_monty(_MIPP_ n); + nres_powltr(_MIPP_ x,y,w); + redc(_MIPP_ w,w); + if (clean_up) kill_monty(_MIPPO_ ); + } + MR_OUT + return (size(w)); +} + +void nres_powmod(_MIPD_ big x,big y,big w) +{ /* calculates w=x^y mod z, using m-residues * + * See "Analysis of Sliding Window Techniques for * + * Exponentiation, C.K. Koc, Computers. Math. & * + * Applic. Vol. 30 pp17-24 1995. Uses work-space * + * variables for pre-computed table. */ + int i,j,k,t,nb,nbw,nzs,n; + big table[16]; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + copy(y,mr_mip->w1); + copy(x,mr_mip->w3); + + MR_IN(84) + zero(w); + if (size(x)==0) + { + if (size(mr_mip->w1)==0) + { /* 0^0 = 1 */ + copy(mr_mip->one,w); + } + MR_OUT + return; + } + + copy(mr_mip->one,w); + if (size(mr_mip->w1)==0) + { + MR_OUT + return; + } + + if (size(mr_mip->w1)<0) mr_berror(_MIPP_ MR_ERR_NEG_POWER); + + if (mr_mip->ERNUM) + { + MR_OUT + return; + } + +#ifndef MR_ALWAYS_BINARY + if (mr_mip->base==mr_mip->base2) + { /* build a table. Up to 5-bit sliding windows. Windows with + * two adjacent 0 bits simply won't happen */ +#endif + table[0]=mr_mip->w3; table[1]=mr_mip->w4; table[2]=mr_mip->w5; table[3]=mr_mip->w14; + table[4]=NULL; table[5]=mr_mip->w6; table[6]=mr_mip->w15; table[7]=mr_mip->w8; + table[8]=NULL; table[9]=NULL; table[10]=mr_mip->w9; table[11]=mr_mip->w10; + table[12]=NULL; table[13]=mr_mip->w11; table[14]=mr_mip->w12; table[15]=mr_mip->w13; + + nres_modmult(_MIPP_ mr_mip->w3,mr_mip->w3,mr_mip->w2); /* x^2 */ + n=15; + j=0; + do + { /* pre-computations */ + t=1; k=j+1; + while (table[k]==NULL) {k++; t++;} + copy(table[j],table[k]); + for (i=0;iw2,table[k]); + j=k; + } while (jw1); + copy(mr_mip->w3,w); + if (nb>1) for (i=nb-2;i>=0;) + { /* Left to Right method */ + + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + n=mr_window(_MIPP_ mr_mip->w1,i,&nbw,&nzs,5); + + for (j=0;j0) + nres_modmult(_MIPP_ w,table[n/2],w); + + i-=nbw; + if (nzs) + { + for (j=0;jw3,mr_mip->w2); + forever + { /* "Russian peasant" Right-to-Left exponentiation */ + + if (mr_mip->user!=NULL) (*mr_mip->user)(); + + if (subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1)!=0) + nres_modmult(_MIPP_ w,mr_mip->w2,w); + if (mr_mip->ERNUM || size(mr_mip->w1)==0) break; + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w2); + } + } +#endif + MR_OUT +} + diff --git a/miracl/source/mrprime.c b/miracl/source/mrprime.c new file mode 100644 index 0000000..7ff2969 --- /dev/null +++ b/miracl/source/mrprime.c @@ -0,0 +1,378 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL prime number routines - test for and generate prime numbers + * mrprime.c + */ + +#include +#include "miracl.h" + +#ifndef MR_STATIC + +#if MIRACL==8 +#define MR_MAXPRIME 100 +#else +#define MR_MAXPRIME 1000 +#endif + + +void gprime(_MIPD_ int maxp) +{ /* generate all primes less than maxp into global PRIMES */ + char *sv; + int pix,i,k,prime; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + if (maxp<=0) + { + if (mr_mip->PRIMES!=NULL) mr_free(mr_mip->PRIMES); + mr_mip->PRIMES=NULL; + return; + } + + MR_IN(70) + + if (maxp>=MR_TOOBIG) + { + mr_berror(_MIPP_ MR_ERR_TOO_BIG); + MR_OUT + return; + } + if (maxpPRIMES!=NULL) mr_free(mr_mip->PRIMES); + mr_mip->PRIMES=(int *)mr_alloc(_MIPP_ pix+2,sizeof(int)); + if (mr_mip->PRIMES==NULL) + { + mr_free(sv); + mr_berror(_MIPP_ MR_ERR_OUT_OF_MEMORY); + MR_OUT + return; + } + mr_mip->PRIMES[0]=2; + pix=1; + for (i=0;iPRIMES[pix++]=i+i+3; + mr_mip->PRIMES[pix]=0; + mr_free(sv); + MR_OUT + return; +} + +#else + +void gprime(_MIPD_ int maxp) +{ /* dummy - does nothing */ +} + + +#endif + +int trial_division(_MIPD_ big x,big y) +{ + /* general purpose trial-division function, works in two modes */ + /* if (x==y) quick test for candidate prime, using trial * + * division by the small primes in the instance array PRIMES[] */ + /* returns 0 if definitely not a prime * + * returns 1 if definitely is a prime * + * returns 2 if possibly a prime */ + /* if x!=y it continues to extract small factors, and returns * + * the largest factor of x in y, * + * i.e. completely factors over the small primes in PRIMES * + * In this case the returned value refers to the status of y */ + /* returns 1 if y is definitely a prime (and x was smooth) * + * returns 2 if y is possibly a prime */ + int i; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return 0; + if (size(x)<=1) return 0; + + MR_IN(105) + + copy(x,y); + +#ifndef MR_STATIC + if (mr_mip->PRIMES==NULL) gprime(_MIPP_ MR_MAXPRIME); +#endif + for (i=0;mr_mip->PRIMES[i]!=0;i++) + { /* test for divisible by first few primes */ + while (subdiv(_MIPP_ y,mr_mip->PRIMES[i],mr_mip->w1)==0) + { + if (x==y) + { + MR_OUT + if (size(mr_mip->w1)==1) return 1; + else return 0; + } + else + { + if (size(mr_mip->w1)==1) + { /* y is largest prime factor */ + MR_OUT + return 1; + } + copy(mr_mip->w1,y); + continue; + } + } + if (size(mr_mip->w1)<=mr_mip->PRIMES[i]) + { + MR_OUT + return 1; + } + } + MR_OUT + return 2; +} + +BOOL isprime(_MIPD_ big x) +{ /* test for primality (probably); TRUE if x is prime. test done NTRY * + * times; chance of wrong identification << (1/4)^NTRY. Note however * + * that this is an extreme upper bound. For example for a 100 digit * + * "prime" the chances of false witness are actually < (.00000003)^NTRY * + * See Kim & Pomerance "The probability that a random probable prime * + * is Composite", Math. Comp. October 1989 pp.721-741 * + * The value of NTRY is now adjusted internally to account for this. */ + int j,k,n,r,times,d; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return TRUE; + if (size(x)<=1) return FALSE; + + MR_IN(22) + + k=trial_division(_MIPP_ x,x); + if (k==0) + { + MR_OUT + return FALSE; + } + if (k==1) + { + MR_OUT + return TRUE; + } + +/* Miller-Rabin */ + + decr(_MIPP_ x,1,mr_mip->w1); /* calculate k and mr_w8 ... */ + k=0; + while (subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1)==0) + { + k++; + copy(mr_mip->w1,mr_mip->w8); + } /* ... such that x=1+mr_w8*2**k */ + times=mr_mip->NTRY; + if (times>100) times=100; + d=logb2(_MIPP_ x); /* for larger primes, reduce NTRYs */ + if (d>220) times=2+((10*times)/(d-210)); + + for (n=1;n<=times;n++) + { /* perform test times times */ + j=0; +#ifndef MR_NO_RAND + do + { + r=(int)brand(_MIPPO_ )%MR_TOOBIG; + if (size(x)PRIMES[n]; /* possibly unsafe.. */ + if (r==0) break; +#endif + powltr(_MIPP_ r,mr_mip->w8,x,mr_mip->w9); +/* use small random numbers... */ + decr(_MIPP_ x,1,mr_mip->w2); + + while ((j>0 || size(mr_mip->w9)!=1) + && mr_compare(mr_mip->w9,mr_mip->w2)!=0) + { + j++; + if ((j>1 && size(mr_mip->w9)==1) || j==k) + { /* definitely not prime */ + MR_OUT + return FALSE; + } + mad(_MIPP_ mr_mip->w9,mr_mip->w9,mr_mip->w9,x,x,mr_mip->w9); + } + + if (mr_mip->user!=NULL) if (!(*mr_mip->user)()) + { + MR_OUT + return FALSE; + } + } + + MR_OUT + return TRUE; /* probably prime */ +} + +BOOL nxprime(_MIPD_ big w,big x) +{ /* find next highest prime from w using * + * probabilistic primality test */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(21) + + copy(w,x); + if (size(x)<2) + { + convert(_MIPP_ 2,x); + MR_OUT + return TRUE; + } + if (subdiv(_MIPP_ x,2,mr_mip->w1)==0) incr(_MIPP_ x,1,x); + else incr(_MIPP_ x,2,x); + while (!isprime(_MIPP_ x)) + { + incr(_MIPP_ x,2,x); + if (mr_mip->user!=NULL) if (!(*mr_mip->user)()) + { + MR_OUT + return FALSE; + } + } + MR_OUT + return TRUE; +} + + +BOOL nxsafeprime(_MIPD_ int type,int subset,big w,big p) +{ /* If type=0 finds next highest "safe" prime p >= w * + * A safe prime is one for which q=(p-1)/2 is also * + * prime, and will be congruent to 3 mod 4 * + * However if type=1 finds a prime p for which * + * q=(p+1)/2 is prime, congruent to 1 mod 4 * + * Set subset=1 for q=1 mod 4, subset=3 for * + * q=3 mod 4, subset=0 if you don't care which */ + + int rem,increment; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(106) + + copy(w,p); + + rem=remain(_MIPP_ p,8); + if (subset==0) + { + rem=rem%4; + if (type==0) incr(_MIPP_ p,3-rem,p); + else + { + if (rem>1) incr(_MIPP_ p,5-rem,p); + else incr(_MIPP_ p,1-rem,p); + } + increment=4; + } + else + { + if (subset==1) + { + if (type==0) + { + if (rem>3) incr(_MIPP_ p,11-rem,p); + else incr(_MIPP_ p,3-rem,p); + } + else + { + if (rem>1) incr(_MIPP_ p,9-rem,p); + else incr(_MIPP_ p,1-rem,p); + } + } + else + { + if (type==0) incr(_MIPP_ p,7-rem,p); + else + { + if (rem>5) incr(_MIPP_ p,13-rem,p); + else incr(_MIPP_ p,5-rem,p); + } + } + increment=8; + } + if (type==0) decr(_MIPP_ p,1,mr_mip->w10); + else incr(_MIPP_ p,1,mr_mip->w10); + subdiv(_MIPP_ mr_mip->w10,2,mr_mip->w10); + + forever + { + do { + if (mr_mip->user!=NULL) if (!(*mr_mip->user)()) + { + MR_OUT + return FALSE; + } + incr(_MIPP_ p,increment,p); + incr(_MIPP_ mr_mip->w10,increment/2,mr_mip->w10); + } while (!trial_division(_MIPP_ p,p) || !trial_division(_MIPP_ mr_mip->w10,mr_mip->w10)); + if (!isprime(_MIPP_ mr_mip->w10)) continue; + if (isprime(_MIPP_ p)) break; + } + + MR_OUT + return TRUE; +} + diff --git a/miracl/source/mrrand.c b/miracl/source/mrrand.c new file mode 100644 index 0000000..78e03e7 --- /dev/null +++ b/miracl/source/mrrand.c @@ -0,0 +1,110 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL random number routines + * mrrand.c + */ + +#include "miracl.h" + +#ifdef MR_FP +#include +#endif + +#ifndef MR_NO_RAND + +void bigrand(_MIPD_ big w,big x) +{ /* generate a big random number 0<=xERNUM) return; + + MR_IN(20) + + /* decr(_MIPP_ w,2,w); */ + m=0; + zero(mr_mip->w0); + + do + { /* create big rand piece by piece */ + m++; + mr_mip->w0->len=m; + r=brand(_MIPPO_ ); + if (mr_mip->base==0) mr_mip->w0->w[m-1]=r; + else mr_mip->w0->w[m-1]=MR_REMAIN(r,mr_mip->base); + } while (mr_compare(mr_mip->w0,w)<0); + mr_lzero(mr_mip->w0); + divide(_MIPP_ mr_mip->w0,w,w); + + copy(mr_mip->w0,x); + /* incr(_MIPP_ x,2,x); + if (w!=x) incr(_MIPP_ w,2,w); */ + MR_OUT +} + +void bigdig(_MIPD_ int n,int b,big x) +{ /* generate random number n digits long * + * to "printable" base b */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(19) + + if (b<2 || b>256) + { + mr_berror(_MIPP_ MR_ERR_BASE_TOO_BIG); + MR_OUT + return; + } + + do + { /* repeat if x too small */ + expint(_MIPP_ b,n,mr_mip->w1); + bigrand(_MIPP_ mr_mip->w1,x); + subdiv(_MIPP_ mr_mip->w1,b,mr_mip->w1); + } while (!mr_mip->ERNUM && mr_compare(x,mr_mip->w1)<0); + + MR_OUT +} + +#endif diff --git a/miracl/source/mrround.c b/miracl/source/mrround.c new file mode 100644 index 0000000..d6b59fd --- /dev/null +++ b/miracl/source/mrround.c @@ -0,0 +1,218 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL euclidean mediant rounding routine + * mrround.c + */ + +#include "miracl.h" + +#ifdef MR_FP +#include +#endif + +#ifdef MR_FLASH + +static int euclid(_MIPD_ big x,int num) +{ /* outputs next c.f. quotient from gcd(w5,w6) */ + mr_small sr,m; +#ifdef MR_FP + mr_small dres; +#endif + mr_small lr,lq; + big t; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (num==0) + { + mr_mip->oldn=(-1); + mr_mip->carryon=FALSE; + mr_mip->last=FALSE; + if (mr_compare(mr_mip->w6,mr_mip->w5)>0) + { /* ensure w5>w6 */ + t=mr_mip->w5,mr_mip->w5=mr_mip->w6,mr_mip->w6=t; + return (mr_mip->q=0); + } + } + else if (num==mr_mip->oldn || mr_mip->q<0) return mr_mip->q; + mr_mip->oldn=num; + if (mr_mip->carryon) goto middle; +start: + if (size(mr_mip->w6)==0) return (mr_mip->q=(-1)); + mr_mip->ndig=(int)mr_mip->w5->len; + mr_mip->carryon=TRUE; + mr_mip->a=1; + mr_mip->b=0; + mr_mip->c=0; + mr_mip->d=1; + if (mr_mip->ndig==1) + { + mr_mip->last=TRUE; + mr_mip->u=mr_mip->w5->w[0]; + mr_mip->v=mr_mip->w6->w[0]; + } + else + { + m=mr_mip->w5->w[mr_mip->ndig-1]+1; + if (mr_mip->base==0) + { +#ifndef MR_NOFULLWIDTH + if (m==0) + { + mr_mip->u=mr_mip->w5->w[mr_mip->ndig-1]; + mr_mip->v=mr_mip->w6->w[mr_mip->ndig-1]; + } + else + { + mr_mip->u=muldvm(mr_mip->w5->w[mr_mip->ndig-1],mr_mip->w5->w[mr_mip->ndig-2],m,&sr); + mr_mip->v=muldvm(mr_mip->w6->w[mr_mip->ndig-1],mr_mip->w6->w[mr_mip->ndig-2],m,&sr); + } +#endif + } + else + { + mr_mip->u=muldiv(mr_mip->w5->w[mr_mip->ndig-1],mr_mip->base,mr_mip->w5->w[mr_mip->ndig-2],m,&sr); + mr_mip->v=muldiv(mr_mip->w6->w[mr_mip->ndig-1],mr_mip->base,mr_mip->w6->w[mr_mip->ndig-2],m,&sr); + } + } + mr_mip->ku=mr_mip->u; + mr_mip->kv=mr_mip->v; +middle: + forever + { /* work only with most significant piece */ + if (mr_mip->last) + { + if (mr_mip->v==0) return (mr_mip->q=(-1)); + lq=MR_DIV(mr_mip->u,mr_mip->v); + } + else + { + if (((mr_mip->v+mr_mip->c)==0) || ((mr_mip->v+mr_mip->d)==0)) break; + lq=MR_DIV((mr_mip->u+mr_mip->a),(mr_mip->v+mr_mip->c)); + if (lq!=MR_DIV((mr_mip->u+mr_mip->b),(mr_mip->v+mr_mip->d))) break; + } + if (lq>=(mr_small)(MR_TOOBIG/mr_abs(mr_mip->d))) break; + + mr_mip->q=(int)lq; + mr_mip->r=mr_mip->a-mr_mip->q*mr_mip->c; + mr_mip->a=mr_mip->c; + mr_mip->c=mr_mip->r; + mr_mip->r=mr_mip->b-mr_mip->q*mr_mip->d; + mr_mip->b=mr_mip->d; + mr_mip->d=mr_mip->r; + lr=mr_mip->u-lq*mr_mip->v; + mr_mip->u=mr_mip->v; + mr_mip->v=lr; + return mr_mip->q; + } + mr_mip->carryon=FALSE; + if (mr_mip->b==0) + { /* update w5 and w6 */ + mr_mip->check=OFF; + divide(_MIPP_ mr_mip->w5,mr_mip->w6,mr_mip->w7); + mr_mip->check=ON; + if (mr_lent(mr_mip->w7)>mr_mip->nib) return (mr_mip->q=(-2)); + t=mr_mip->w5,mr_mip->w5=mr_mip->w6,mr_mip->w6=t; /* swap(w5,w6) */ + copy(mr_mip->w7,x); + return (mr_mip->q=size(x)); + } + else + { + mr_mip->check=OFF; + premult(_MIPP_ mr_mip->w5,mr_mip->c,mr_mip->w7); + premult(_MIPP_ mr_mip->w5,mr_mip->a,mr_mip->w5); + premult(_MIPP_ mr_mip->w6,mr_mip->b,mr_mip->w0); + premult(_MIPP_ mr_mip->w6,mr_mip->d,mr_mip->w6); + add(_MIPP_ mr_mip->w5,mr_mip->w0,mr_mip->w5); + add(_MIPP_ mr_mip->w6,mr_mip->w7,mr_mip->w6); + mr_mip->check=ON; + } + goto start; +} + + +void mround(_MIPD_ big num,big den,flash z) +{ /* reduces and rounds the fraction num/den into z */ + int s; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + if (size(num)==0) + { + zero(z); + return; + } + + MR_IN(34) + + if (size(den)==0) + { + mr_berror(_MIPP_ MR_ERR_FLASH_OVERFLOW); + MR_OUT + return; + } + copy(num,mr_mip->w5); + copy(den,mr_mip->w6); + s=exsign(mr_mip->w5)*exsign(mr_mip->w6); + insign(PLUS,mr_mip->w5); + insign(PLUS,mr_mip->w6); + if (mr_compare(mr_mip->w5,mr_mip->w6)==0) + { + convert(_MIPP_ s,z); + MR_OUT + return; + } + if (size(mr_mip->w6)==1) + { + if ((int)mr_mip->w5->len>mr_mip->nib) + { + mr_berror(_MIPP_ MR_ERR_FLASH_OVERFLOW); + MR_OUT + return; + } + copy(mr_mip->w5,z); + insign(s,z); + MR_OUT + return; + } + build(_MIPP_ z,euclid); + insign(s,z); + MR_OUT +} + +#endif + diff --git a/miracl/source/mrscrt.c b/miracl/source/mrscrt.c new file mode 100644 index 0000000..9accd8e --- /dev/null +++ b/miracl/source/mrscrt.c @@ -0,0 +1,261 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL Chinese Remainder Thereom routines (for use with small moduli) + * mrscrt.c + */ + + +#include +#include "miracl.h" + +#ifdef MR_FP +#include +#endif + +static mr_utype in_range(mr_utype x,mr_utype y) +{ /* x=x%y, and positive */ + mr_utype r; +#ifdef MR_FP + mr_small dres; +#endif + r=MR_REMAIN(x,y); + if (r<0) r+=y; + return r; +} + +#ifndef MR_STATIC + +BOOL scrt_init(_MIPD_ small_chinese *c,int r,mr_utype *moduli) +{ /* calculate CRT constants - returns FALSE if there is a problem */ + int i,j,k; + if (r<1) return FALSE; + if (r==1) + { + c->NP=1; + c->M=(mr_utype *)mr_alloc(_MIPP_ r,sizeof(mr_utype)); + if (c->M==NULL) return FALSE; + c->M[0]=moduli[0]; + return TRUE; + } + for (i=0;iM=(mr_utype *)mr_alloc(_MIPP_ r,sizeof(mr_utype)); + if (c->M==NULL) return FALSE; + c->C=(mr_utype *)mr_alloc(_MIPP_ r*(r-1)/2,sizeof(mr_utype)); + if (c->C==NULL) + { /* no room */ + mr_free(c->M); + return FALSE; + } + c->V=(mr_utype *)mr_alloc(_MIPP_ r,sizeof(mr_utype)); + if (c->V==NULL) + { /* no room */ + mr_free(c->M); + mr_free(c->C); + return FALSE; + } + for (k=0,i=0;iM[i]=moduli[i]; + for (j=0;jC[k]=invers(c->M[j],c->M[i]); + } + c->NP=r; + return TRUE; +} + +void scrt_end(small_chinese *c) +{ /* clean up after CRT */ + if (c->NP<1) + { + c->NP=0; + return; + } + if (c->NP==1) + { + mr_free(c->M); + c->NP=0; + return; + } + mr_free(c->M); + mr_free(c->V); + mr_free(c->C); + c->NP=0; +} + +#endif + +void scrt(_MIPD_ small_chinese *c,mr_utype *u,big x) +{ /* Chinese Remainder Thereom * + * Calculate x given remainders u[i] mod M[i] */ + int i,j,k,len; + mr_utype *V,*C,*M; + mr_small t; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif +#ifdef MR_FP_ROUNDING + mr_large im; +#endif + V=c->V; + C=c->C; + M=c->M; + len=c->NP; + if (len<1) return; + if (len==1) + { + t=smul(1,in_range(u[0],M[0]),M[0]); + convert(_MIPP_ 1,mr_mip->w5); + mr_pmul(_MIPP_ mr_mip->w5,t,x); + return; + } + V[0]=u[0]; + k=0; + for (i=1;iw5); + for (j=1;jw5,(mr_small)(M[j-1]),mr_mip->w5); + mr_pmul(_MIPP_ mr_mip->w5,(mr_small)(V[j]),mr_mip->w0); + mr_padd(_MIPP_ x,mr_mip->w0,x); + } +} + diff --git a/miracl/source/mrsha3.c b/miracl/source/mrsha3.c new file mode 100644 index 0000000..159090c --- /dev/null +++ b/miracl/source/mrsha3.c @@ -0,0 +1,223 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * Implementation of the Secure Hashing Algorithm SHA3 - Keccak + * M. Scott 19/06/2013 + * + * For use with byte-oriented messages only. + * + * NOTE: This requires a 64-bit integer type to be defined + */ + +#include "miracl.h" + +#ifdef mr_unsign64 + +/* round constants */ + +static const mr_unsign64 RC[24]={ +0x0000000000000001LL,0x0000000000008082LL,0x800000000000808ALL,0x8000000080008000LL, +0x000000000000808BLL,0x0000000080000001LL,0x8000000080008081LL,0x8000000000008009LL, +0x000000000000008ALL,0x0000000000000088LL,0x0000000080008009LL,0x000000008000000ALL, +0x000000008000808BLL,0x800000000000008BLL,0x8000000000008089LL,0x8000000000008003LL, +0x8000000000008002LL,0x8000000000000080LL,0x000000000000800ALL,0x800000008000000ALL, +0x8000000080008081LL,0x8000000000008080LL,0x0000000080000001LL,0x8000000080008008LL}; + +/* functions */ + +#define SHA3_ROUNDS 24 +#define rotl(x,n) (((x)<>(64-n))) + +/* permutation */ + +static void shs_transform(sha3 *sh) +{ + int i,j,k; + mr_unsign64 C[5],D[5],B[5][5]; + + for (k=0;kS[0][0]^sh->S[0][1]^sh->S[0][2]^sh->S[0][3]^sh->S[0][4]; + C[1]=sh->S[1][0]^sh->S[1][1]^sh->S[1][2]^sh->S[1][3]^sh->S[1][4]; + C[2]=sh->S[2][0]^sh->S[2][1]^sh->S[2][2]^sh->S[2][3]^sh->S[2][4]; + C[3]=sh->S[3][0]^sh->S[3][1]^sh->S[3][2]^sh->S[3][3]^sh->S[3][4]; + C[4]=sh->S[4][0]^sh->S[4][1]^sh->S[4][2]^sh->S[4][3]^sh->S[4][4]; + + D[0]=C[4]^rotl(C[1],1); + D[1]=C[0]^rotl(C[2],1); + D[2]=C[1]^rotl(C[3],1); + D[3]=C[2]^rotl(C[4],1); + D[4]=C[3]^rotl(C[0],1); + + for (i=0;i<5;i++) + for (j=0;j<5;j++) + sh->S[i][j]^=D[i]; /* let the compiler unroll it! */ + + B[0][0]=sh->S[0][0]; + B[1][3]=rotl(sh->S[0][1],36); + B[2][1]=rotl(sh->S[0][2],3); + B[3][4]=rotl(sh->S[0][3],41); + B[4][2]=rotl(sh->S[0][4],18); + + B[0][2]=rotl(sh->S[1][0],1); + B[1][0]=rotl(sh->S[1][1],44); + B[2][3]=rotl(sh->S[1][2],10); + B[3][1]=rotl(sh->S[1][3],45); + B[4][4]=rotl(sh->S[1][4],2); + + B[0][4]=rotl(sh->S[2][0],62); + B[1][2]=rotl(sh->S[2][1],6); + B[2][0]=rotl(sh->S[2][2],43); + B[3][3]=rotl(sh->S[2][3],15); + B[4][1]=rotl(sh->S[2][4],61); + + B[0][1]=rotl(sh->S[3][0],28); + B[1][4]=rotl(sh->S[3][1],55); + B[2][2]=rotl(sh->S[3][2],25); + B[3][0]=rotl(sh->S[3][3],21); + B[4][3]=rotl(sh->S[3][4],56); + + B[0][3]=rotl(sh->S[4][0],27); + B[1][1]=rotl(sh->S[4][1],20); + B[2][4]=rotl(sh->S[4][2],39); + B[3][2]=rotl(sh->S[4][3],8); + B[4][0]=rotl(sh->S[4][4],14); + + for (i=0;i<5;i++) + for (j=0;j<5;j++) + sh->S[i][j]=B[i][j]^(~B[(i+1)%5][j]&B[(i+2)%5][j]); + + sh->S[0][0]^=RC[k]; + } +} + +/* Re-Initialize. olen is output length in bytes - + should be 28, 32, 48 or 64 (224, 256, 384, 512 bits resp.) */ + +void sha3_init(sha3 *sh,int olen) +{ + int i,j; + for (i=0;i<5;i++) + for (j=0;j<5;j++) + sh->S[i][j]=0; /* 5x5x8 bytes = 200 bytes of state */ + sh->length=0; + sh->len=olen; + sh->rate=200-2*olen; /* number of bytes consumed in one gulp. Note that some bytes in the + state ("capacity") are not touched. Gulps are smaller for larger digests. + Important that olenlength%sh->rate); + int i,j,b=cnt%8; + cnt/=8; + i=cnt%5; j=cnt/5; /* process by columns! */ + sh->S[i][j]^=((mr_unsign64)byte<<(8*b)); + sh->length++; + if (sh->length%sh->rate==0) shs_transform(sh); +} + +void sha3_hash(sha3 *sh,char *hash) +{ /* pad message and finish - supply digest */ + int i,j,k,m=0; + mr_unsign64 el; + int q=sh->rate-(sh->length%sh->rate); + if (q==1) sha3_process(sh,0x86); + else + { + sha3_process(sh,0x06); + while (sh->length%sh->rate!=sh->rate-1) sha3_process(sh,0x00); + sha3_process(sh,0x80); /* this will force a final transform */ + } + +/* extract by columns - assuming here digest size < rate */ + for (j=0;j<5;j++) + for (i=0;i<5;i++) + { + el=sh->S[i][j]; + for (k=0;k<8;k++) + { + hash[m++]=(el&0xff); + if (m>=sh->len) return; + el>>=8; + } + } +} + +#endif + +/* test program - see http://www.di-mgt.com.au/sha_testvectors.html + +//char *s="abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + +//char *s="abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; + +char *s="abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmno"; + +int main() +{ + mr_unsign64 ii; + int i,j,k,olen; + char hash[64]; + sha3 sh; + + for (j=0;j<4;j++) + { + + if (j==0) olen=28; + if (j==1) olen=32; + if (j==2) olen=48; + if (j==3) olen=64; + sha3_init(&sh,olen); + +// for (ii=0;ii<16777216;ii++) +// { +// for (k=0;k. * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * Implementation of the Secure Hashing Standard (SHS) + * specified for use with the NIST Digital Signature Standard (DSS) + * + * Generates a 160 bit message digest. It should be impossible to come + * come up with two messages that hash to the same value ("collision free"). + * + * For use with byte-oriented messages only. Could/Should be speeded + * up by unwinding loops in shs_transform(), and assembly patches. + */ + +#include "miracl.h" + /* for definition of mr_unsign32 & prototypes */ +#define FIX + +/* Include this #define in order to implement the + rather mysterious 'fix' to SHS + + With this definition in, SHA-1 is implemented + Without this definition, SHA-0 is implemented +*/ + + +#define H0 0x67452301L +#define H1 0xefcdab89L +#define H2 0x98badcfeL +#define H3 0x10325476L +#define H4 0xc3d2e1f0L + +#define K0 0x5a827999L +#define K1 0x6ed9eba1L +#define K2 0x8f1bbcdcL +#define K3 0xca62c1d6L + +#define PAD 0x80 +#define ZERO 0 + +/* functions */ + +#define S(n,x) (((x)<>(32-n))) + +#define F0(x,y,z) (z^(x&(y^z))) +#define F1(x,y,z) (x^y^z) +#define F2(x,y,z) ((x&y) | (z&(x|y))) +#define F3(x,y,z) (x^y^z) + +static void shs_transform(sha *sh) +{ /* basic transformation step */ + mr_unsign32 a,b,c,d,e,temp; + int t; +#ifdef FIX + for (t=16;t<80;t++) sh->w[t]=S(1,sh->w[t-3]^sh->w[t-8]^sh->w[t-14]^sh->w[t-16]); +#else + for (t=16;t<80;t++) sh->w[t]=sh->w[t-3]^sh->w[t-8]^sh->w[t-14]^sh->w[t-16]; +#endif + a=sh->h[0]; b=sh->h[1]; c=sh->h[2]; d=sh->h[3]; e=sh->h[4]; + for (t=0;t<20;t++) + { /* 20 times - mush it up */ + temp=K0+F0(b,c,d)+S(5,a)+e+sh->w[t]; + e=d; d=c; + c=S(30,b); + b=a; a=temp; + } + for (t=20;t<40;t++) + { /* 20 more times - mush it up */ + temp=K1+F1(b,c,d)+S(5,a)+e+sh->w[t]; + e=d; d=c; + c=S(30,b); + b=a; a=temp; + } + for (t=40;t<60;t++) + { /* 20 more times - mush it up */ + temp=K2+F2(b,c,d)+S(5,a)+e+sh->w[t]; + e=d; d=c; + c=S(30,b); + b=a; a=temp; + } + for (t=60;t<80;t++) + { /* 20 more times - mush it up */ + temp=K3+F3(b,c,d)+S(5,a)+e+sh->w[t]; + e=d; d=c; + c=S(30,b); + b=a; a=temp; + } + sh->h[0]+=a; sh->h[1]+=b; sh->h[2]+=c; + sh->h[3]+=d; sh->h[4]+=e; +} + +void shs_init(sha *sh) +{ /* re-initialise */ + int i; + for (i=0;i<80;i++) sh->w[i]=0L; + sh->length[0]=sh->length[1]=0L; + sh->h[0]=H0; + sh->h[1]=H1; + sh->h[2]=H2; + sh->h[3]=H3; + sh->h[4]=H4; +} + +void shs_process(sha *sh,int byte) +{ /* process the next message byte */ + int cnt; + + cnt=(int)((sh->length[0]/32)%16); + + sh->w[cnt]<<=8; + sh->w[cnt]|=(mr_unsign32)(byte&0xFF); + + sh->length[0]+=8; + if (sh->length[0]==0L) { sh->length[1]++; sh->length[0]=0L; } + if ((sh->length[0]%512)==0) shs_transform(sh); +} + +void shs_hash(sha *sh,char hash[20]) +{ /* pad message and finish - supply digest */ + int i; + mr_unsign32 len0,len1; + len0=sh->length[0]; + len1=sh->length[1]; + shs_process(sh,PAD); + while ((sh->length[0]%512)!=448) shs_process(sh,ZERO); + sh->w[14]=len1; + sh->w[15]=len0; + shs_transform(sh); + for (i=0;i<20;i++) + { /* convert to bytes */ + hash[i]=(char)((sh->h[i/4]>>(8*(3-i%4))) & 0xffL); + } + shs_init(sh); +} + +/* test program: should produce digest + + 84983e44 1c3bd26e baae4aa1 f95129e5 e54670f1 + +#include +#include "miracl.h" + +char test[]="abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + +int main() +{ + char hash[20]; + int i; + sha sh; + shs_init(&sh); + for (i=0;test[i]!=0;i++) shs_process(&sh,test[i]); + shs_hash(&sh,hash); + for (i=0;i<20;i++) printf("%02x",(unsigned char)hash[i]); + printf("\n"); + return 0; +} + +*/ + diff --git a/miracl/source/mrshs256.c b/miracl/source/mrshs256.c new file mode 100644 index 0000000..f39cf37 --- /dev/null +++ b/miracl/source/mrshs256.c @@ -0,0 +1,177 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * Implementation of the Secure Hashing Algorithm (SHA-256) + * + * Generates a 256 bit message digest. It should be impossible to come + * come up with two messages that hash to the same value ("collision free"). + * + * For use with byte-oriented messages only. Could/Should be speeded + * up by unwinding loops in shs_transform(), and assembly patches. + */ + +#include "miracl.h" + +#define H0 0x6A09E667L +#define H1 0xBB67AE85L +#define H2 0x3C6EF372L +#define H3 0xA54FF53AL +#define H4 0x510E527FL +#define H5 0x9B05688CL +#define H6 0x1F83D9ABL +#define H7 0x5BE0CD19L + +static const mr_unsign32 K[64]={ +0x428a2f98L,0x71374491L,0xb5c0fbcfL,0xe9b5dba5L,0x3956c25bL,0x59f111f1L,0x923f82a4L,0xab1c5ed5L, +0xd807aa98L,0x12835b01L,0x243185beL,0x550c7dc3L,0x72be5d74L,0x80deb1feL,0x9bdc06a7L,0xc19bf174L, +0xe49b69c1L,0xefbe4786L,0x0fc19dc6L,0x240ca1ccL,0x2de92c6fL,0x4a7484aaL,0x5cb0a9dcL,0x76f988daL, +0x983e5152L,0xa831c66dL,0xb00327c8L,0xbf597fc7L,0xc6e00bf3L,0xd5a79147L,0x06ca6351L,0x14292967L, +0x27b70a85L,0x2e1b2138L,0x4d2c6dfcL,0x53380d13L,0x650a7354L,0x766a0abbL,0x81c2c92eL,0x92722c85L, +0xa2bfe8a1L,0xa81a664bL,0xc24b8b70L,0xc76c51a3L,0xd192e819L,0xd6990624L,0xf40e3585L,0x106aa070L, +0x19a4c116L,0x1e376c08L,0x2748774cL,0x34b0bcb5L,0x391c0cb3L,0x4ed8aa4aL,0x5b9cca4fL,0x682e6ff3L, +0x748f82eeL,0x78a5636fL,0x84c87814L,0x8cc70208L,0x90befffaL,0xa4506cebL,0xbef9a3f7L,0xc67178f2L}; + +#define PAD 0x80 +#define ZERO 0 + +/* functions */ + +#define S(n,x) (((x)>>n) | ((x)<<(32-n))) +#define R(n,x) ((x)>>n) + +#define Ch(x,y,z) ((x&y)^(~(x)&z)) +#define Maj(x,y,z) ((x&y)^(x&z)^(y&z)) +#define Sig0(x) (S(2,x)^S(13,x)^S(22,x)) +#define Sig1(x) (S(6,x)^S(11,x)^S(25,x)) +#define theta0(x) (S(7,x)^S(18,x)^R(3,x)) +#define theta1(x) (S(17,x)^S(19,x)^R(10,x)) + +static void shs_transform(sha256 *sh) +{ /* basic transformation step */ + mr_unsign32 a,b,c,d,e,f,g,h,t1,t2; + int j; + for (j=16;j<64;j++) + sh->w[j]=theta1(sh->w[j-2])+sh->w[j-7]+theta0(sh->w[j-15])+sh->w[j-16]; + + a=sh->h[0]; b=sh->h[1]; c=sh->h[2]; d=sh->h[3]; + e=sh->h[4]; f=sh->h[5]; g=sh->h[6]; h=sh->h[7]; + + for (j=0;j<64;j++) + { /* 64 times - mush it up */ + t1=h+Sig1(e)+Ch(e,f,g)+K[j]+sh->w[j]; + t2=Sig0(a)+Maj(a,b,c); + h=g; g=f; f=e; + e=d+t1; + d=c; + c=b; + b=a; + a=t1+t2; + } + sh->h[0]+=a; sh->h[1]+=b; sh->h[2]+=c; sh->h[3]+=d; + sh->h[4]+=e; sh->h[5]+=f; sh->h[6]+=g; sh->h[7]+=h; +} + +void shs256_init(sha256 *sh) +{ /* re-initialise */ + int i; + for (i=0;i<64;i++) sh->w[i]=0L; + sh->length[0]=sh->length[1]=0L; + sh->h[0]=H0; + sh->h[1]=H1; + sh->h[2]=H2; + sh->h[3]=H3; + sh->h[4]=H4; + sh->h[5]=H5; + sh->h[6]=H6; + sh->h[7]=H7; +} + +void shs256_process(sha256 *sh,int byte) +{ /* process the next message byte */ + int cnt; + + cnt=(int)((sh->length[0]/32)%16); + + sh->w[cnt]<<=8; + sh->w[cnt]|=(mr_unsign32)(byte&0xFF); + + sh->length[0]+=8; + if (sh->length[0]==0L) { sh->length[1]++; sh->length[0]=0L; } + if ((sh->length[0]%512)==0) shs_transform(sh); +} + +void shs256_hash(sha256 *sh,char hash[32]) +{ /* pad message and finish - supply digest */ + int i; + mr_unsign32 len0,len1; + len0=sh->length[0]; + len1=sh->length[1]; + shs256_process(sh,PAD); + while ((sh->length[0]%512)!=448) shs256_process(sh,ZERO); + sh->w[14]=len1; + sh->w[15]=len0; + shs_transform(sh); + for (i=0;i<32;i++) + { /* convert to bytes */ + hash[i]=(char)((sh->h[i/4]>>(8*(3-i%4))) & 0xffL); + } + shs256_init(sh); +} + +/* test program: should produce digest + +248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1 + + +#include +#include "miracl.h" + +char test[]="abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + +int main() +{ + char hash[32]; + int i; + sha256 sh; + shs256_init(&sh); + for (i=0;test[i]!=0;i++) shs256_process(&sh,test[i]); + shs256_hash(&sh,hash); + for (i=0;i<32;i++) printf("%02x",(unsigned char)hash[i]); + printf("\n"); + return 0; +} + +*/ + diff --git a/miracl/source/mrshs512.c b/miracl/source/mrshs512.c new file mode 100644 index 0000000..085d258 --- /dev/null +++ b/miracl/source/mrshs512.c @@ -0,0 +1,273 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * Implementation of the Secure Hashing Algorithm (SHA-384 and SHA-512) + * + * Generates a a 384 or 512 bit message digest. It should be impossible to come + * come up with two messages that hash to the same value ("collision free"). + * + * For use with byte-oriented messages only. Could/Should be speeded + * up by unwinding loops in shs_transform(), and assembly patches. + * + * NOTE: This requires a 64-bit integer type to be defined + */ + +#include "miracl.h" + +#ifdef mr_unsign64 + +#define H0 0x6a09e667f3bcc908LL +#define H1 0xbb67ae8584caa73bLL +#define H2 0x3c6ef372fe94f82bLL +#define H3 0xa54ff53a5f1d36f1LL +#define H4 0x510e527fade682d1LL +#define H5 0x9b05688c2b3e6c1fLL +#define H6 0x1f83d9abfb41bd6bLL +#define H7 0x5be0cd19137e2179LL + +#define H8 0xcbbb9d5dc1059ed8LL +#define H9 0x629a292a367cd507LL +#define HA 0x9159015a3070dd17LL +#define HB 0x152fecd8f70e5939LL +#define HC 0x67332667ffc00b31LL +#define HD 0x8eb44a8768581511LL +#define HE 0xdb0c2e0d64f98fa7LL +#define HF 0x47b5481dbefa4fa4LL + +/* */ + +static const mr_unsign64 K[80]= +{0x428a2f98d728ae22LL,0x7137449123ef65cdLL,0xb5c0fbcfec4d3b2fLL,0xe9b5dba58189dbbcLL, +0x3956c25bf348b538LL,0x59f111f1b605d019LL,0x923f82a4af194f9bLL,0xab1c5ed5da6d8118LL, +0xd807aa98a3030242LL,0x12835b0145706fbeLL,0x243185be4ee4b28cLL,0x550c7dc3d5ffb4e2LL, +0x72be5d74f27b896fLL,0x80deb1fe3b1696b1LL,0x9bdc06a725c71235LL,0xc19bf174cf692694LL, +0xe49b69c19ef14ad2LL,0xefbe4786384f25e3LL,0x0fc19dc68b8cd5b5LL,0x240ca1cc77ac9c65LL, +0x2de92c6f592b0275LL,0x4a7484aa6ea6e483LL,0x5cb0a9dcbd41fbd4LL,0x76f988da831153b5LL, +0x983e5152ee66dfabLL,0xa831c66d2db43210LL,0xb00327c898fb213fLL,0xbf597fc7beef0ee4LL, +0xc6e00bf33da88fc2LL,0xd5a79147930aa725LL,0x06ca6351e003826fLL,0x142929670a0e6e70LL, +0x27b70a8546d22ffcLL,0x2e1b21385c26c926LL,0x4d2c6dfc5ac42aedLL,0x53380d139d95b3dfLL, +0x650a73548baf63deLL,0x766a0abb3c77b2a8LL,0x81c2c92e47edaee6LL,0x92722c851482353bLL, +0xa2bfe8a14cf10364LL,0xa81a664bbc423001LL,0xc24b8b70d0f89791LL,0xc76c51a30654be30LL, +0xd192e819d6ef5218LL,0xd69906245565a910LL,0xf40e35855771202aLL,0x106aa07032bbd1b8LL, +0x19a4c116b8d2d0c8LL,0x1e376c085141ab53LL,0x2748774cdf8eeb99LL,0x34b0bcb5e19b48a8LL, +0x391c0cb3c5c95a63LL,0x4ed8aa4ae3418acbLL,0x5b9cca4f7763e373LL,0x682e6ff3d6b2b8a3LL, +0x748f82ee5defb2fcLL,0x78a5636f43172f60LL,0x84c87814a1f0ab72LL,0x8cc702081a6439ecLL, +0x90befffa23631e28LL,0xa4506cebde82bde9LL,0xbef9a3f7b2c67915LL,0xc67178f2e372532bLL, +0xca273eceea26619cLL,0xd186b8c721c0c207LL,0xeada7dd6cde0eb1eLL,0xf57d4f7fee6ed178LL, +0x06f067aa72176fbaLL,0x0a637dc5a2c898a6LL,0x113f9804bef90daeLL,0x1b710b35131c471bLL, +0x28db77f523047d84LL,0x32caab7b40c72493LL,0x3c9ebe0a15c9bebcLL,0x431d67c49c100d4cLL, +0x4cc5d4becb3e42b6LL,0x597f299cfc657e2aLL,0x5fcb6fab3ad6faecLL,0x6c44198c4a475817LL}; + +#define PAD 0x80 +#define ZERO 0 + +/* functions */ + +#define S(n,x) (((x)>>n) | ((x)<<(64-n))) +#define R(n,x) ((x)>>n) + +#define Ch(x,y,z) ((x&y)^(~(x)&z)) +#define Maj(x,y,z) ((x&y)^(x&z)^(y&z)) +#define Sig0(x) (S(28,x)^S(34,x)^S(39,x)) +#define Sig1(x) (S(14,x)^S(18,x)^S(41,x)) +#define theta0(x) (S(1,x)^S(8,x)^R(7,x)) +#define theta1(x) (S(19,x)^S(61,x)^R(6,x)) + +static void shs_transform(sha512 *sh) +{ /* basic transformation step */ + mr_unsign64 a,b,c,d,e,f,g,h,t1,t2; + int j; + for (j=16;j<80;j++) + sh->w[j]=theta1(sh->w[j-2])+sh->w[j-7]+theta0(sh->w[j-15])+sh->w[j-16]; + + a=sh->h[0]; b=sh->h[1]; c=sh->h[2]; d=sh->h[3]; + e=sh->h[4]; f=sh->h[5]; g=sh->h[6]; h=sh->h[7]; + + for (j=0;j<80;j++) + { /* 80 times - mush it up */ + t1=h+Sig1(e)+Ch(e,f,g)+K[j]+sh->w[j]; + t2=Sig0(a)+Maj(a,b,c); + h=g; g=f; f=e; + e=d+t1; + d=c; + c=b; + b=a; + a=t1+t2; + } + sh->h[0]+=a; sh->h[1]+=b; sh->h[2]+=c; sh->h[3]+=d; + sh->h[4]+=e; sh->h[5]+=f; sh->h[6]+=g; sh->h[7]+=h; +} + +void shs512_init(sha512 *sh) +{ /* re-initialise */ + int i; + for (i=0;i<80;i++) sh->w[i]=0; + sh->length[0]=sh->length[1]=0; + sh->h[0]=H0; + sh->h[1]=H1; + sh->h[2]=H2; + sh->h[3]=H3; + sh->h[4]=H4; + sh->h[5]=H5; + sh->h[6]=H6; + sh->h[7]=H7; +} + +void shs384_init(sha384 *sh) +{ /* re-initialise */ + int i; + for (i=0;i<80;i++) sh->w[i]=0; + sh->length[0]=sh->length[1]=0; + sh->h[0]=H8; + sh->h[1]=H9; + sh->h[2]=HA; + sh->h[3]=HB; + sh->h[4]=HC; + sh->h[5]=HD; + sh->h[6]=HE; + sh->h[7]=HF; +} + + +void shs512_process(sha512 *sh,int byte) +{ /* process the next message byte */ + int cnt; + + cnt=(int)((sh->length[0]/64)%16); + + sh->w[cnt]<<=8; + sh->w[cnt]|=(mr_unsign64)(byte&0xFF); + + sh->length[0]+=8; + if (sh->length[0]==0L) { sh->length[1]++; sh->length[0]=0L; } + if ((sh->length[0]%1024)==0) shs_transform(sh); +} + + +void shs384_process(sha384 *sh,int byte) +{ /* process the next message byte */ + int cnt; + + cnt=(int)((sh->length[0]/64)%16); + + sh->w[cnt]<<=8; + sh->w[cnt]|=(mr_unsign64)(byte&0xFF); + + sh->length[0]+=8; + if (sh->length[0]==0L) { sh->length[1]++; sh->length[0]=0L; } + if ((sh->length[0]%1024)==0) shs_transform(sh); +} + + +void shs512_hash(sha512 *sh,char hash[64]) +{ /* pad message and finish - supply digest */ + int i; + mr_unsign64 len0,len1; + len0=sh->length[0]; + len1=sh->length[1]; + shs512_process(sh,PAD); + while ((sh->length[0]%1024)!=896) shs512_process(sh,ZERO); + sh->w[14]=len1; + sh->w[15]=len0; + shs_transform(sh); + for (i=0;i<64;i++) + { /* convert to bytes */ + hash[i]=(char)((sh->h[i/8]>>(8*(7-i%8))) & 0xffL); + } + shs512_init(sh); +} + +void shs384_hash(sha384 *sh,char hash[48]) +{ /* pad message and finish - supply digest */ + int i; + mr_unsign64 len0,len1; + len0=sh->length[0]; + len1=sh->length[1]; + shs384_process(sh,PAD); + while ((sh->length[0]%1024)!=896) shs384_process(sh,ZERO); + sh->w[14]=len1; + sh->w[15]=len0; + shs_transform(sh); + for (i=0;i<48;i++) + { /* convert to bytes */ + hash[i]=(char)((sh->h[i/8]>>(8*(7-i%8))) & 0xffL); + } + shs384_init(sh); +} + + +#endif + +/* test program: should produce digests + +512 bit + +8e959b75dae313da 8cf4f72814fc143f 8f7779c6eb9f7fa1 7299aeadb6889018 +501d289e4900f7e4 331b99dec4b5433a c7d329eeb6dd2654 5e96e55b874be909 + + +384 bit + +09330c33f71147e8 3d192fc782cd1b47 53111b173b3b05d2 2fa08086e3b0f712 +fcc7c71a557e2db9 66c3e9fa91746039 + + +#include +#include "miracl.h" + +char test[]="abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; + +int main() +{ + char hash[64]; + int i; + sha512 sh; + shs512_init(&sh); + for (i=0;test[i]!=0;i++) shs512_process(&sh,test[i]); + shs512_hash(&sh,hash); + for (i=0;i<64;i++) printf("%02x",(unsigned char)hash[i]); + printf("\n"); + + shs384_init(&sh); + for (i=0;test[i]!=0;i++) shs384_process(&sh,test[i]); + shs384_hash(&sh,hash); + for (i=0;i<48;i++) printf("%02x",(unsigned char)hash[i]); + printf("\n"); + + return 0; +} + +*/ + diff --git a/miracl/source/mrsmall.c b/miracl/source/mrsmall.c new file mode 100644 index 0000000..a36da1c --- /dev/null +++ b/miracl/source/mrsmall.c @@ -0,0 +1,238 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL small number theoretic routines + * mrsmall.c + */ + +#include "miracl.h" + +#ifdef MR_FP +#include +#endif + +#ifdef MR_WIN64 +#include +#endif + + +mr_small smul(mr_small x,mr_small y,mr_small n) +{ /* returns x*y mod n */ + mr_small r; + +#ifdef MR_ITANIUM + mr_small tm; +#endif +#ifdef MR_WIN64 + mr_small tm; +#endif +#ifdef MR_FP + mr_small dres; +#endif +#ifndef MR_NOFULLWIDTH + if (n==0) + { /* Assume n=2^MIRACL */ + muldvd(x,y,(mr_small)0,&r); + return r; + } +#endif + x=MR_REMAIN(x,n); + y=MR_REMAIN(y,n); + muldiv(x,y,(mr_small)0,n,&r); + return r; +} + +mr_small invers(mr_small x,mr_small y) +{ /* returns inverse of x mod y */ + mr_small r,s,q,t,p; +#ifdef MR_FP + mr_small dres; +#endif + + BOOL pos; + if (y!=0) x=MR_REMAIN(x,y); + r=1; + s=0; + p=y; + pos=TRUE; +#ifndef MR_NOFULLWIDTH + if (p==0) + { /* if modulus is 0, assume its actually 2^MIRACL */ + if (x==1) return (mr_small)1; + t=r; r=s; s=t; + p=x; + q=muldvm((mr_small)1,(mr_small)0,p,&t); + t=r+s*q; r=s; s=t; + t=0-p*q; x=p; p=t; + } +#endif + while (p!=0) + { /* main euclidean loop */ + q=MR_DIV(x,p); + t=r+s*q; r=s; s=t; + t=x-p*q; x=p; p=t; + pos=!pos; + } + if (!pos) r=y-r; + return r; +} + +int jac(mr_small x,mr_small n) +{ /* finds (x/n) as (-1)^m */ + int m,k,n8,u4; + mr_small t; +#ifdef MR_FP + mr_small dres; +#endif + if (x==0) + { + if (n==1) return 1; + else return 0; + } + if (MR_REMAIN(n,2)==0) return 0; + x=MR_REMAIN(x,n); + m=0; + while(n>1) + { /* main loop */ + if (x==0) return 0; + +/* extract powers of 2 */ + for (k=0;MR_REMAIN(x,2)==0;k++) x=MR_DIV(x,2); + n8=(int)MR_REMAIN(n,8); + if (k%2==1) m+=(n8*n8-1)/8; + +/* quadratic reciprocity */ + u4=(int)MR_REMAIN(x,4); + m+=(n8-1)*(u4-1)/4; + t=n; t=MR_REMAIN(t,x); + n=x; x=t; + m%=2; + } + if (m==0) return 1; + else return (-1); +} + +#ifndef MR_STATIC + +mr_small spmd(mr_small x,mr_small n,mr_small m) +{ /* returns x^n mod m */ + mr_small r,sx; +#ifdef MR_FP + mr_small dres; +#endif + x=MR_REMAIN(x,m); + r=0; + if (x==0) return r; + r=1; + if (n==0) return r; + sx=x; + forever + { + if (MR_REMAIN(n,2)!=0) muldiv(r,sx,(mr_small)0,m,&r); + n=MR_DIV(n,2); + if (n==0) return r; + muldiv(sx,sx,(mr_small)0,m,&sx); + } +} + +mr_small sqrmp(mr_small x,mr_small m) +{ /* square root mod a small prime by Shanks method * + * returns 0 if root does not exist or m not prime */ + mr_small z,y,v,w,t,q; +#ifdef MR_FP + mr_small dres; +#endif + int i,e,n,r; + BOOL pp; + x=MR_REMAIN(x,m); + if (x==0) return 0; + if (x==1) return 1; + if (spmd(x,(mr_small)((m-1)/2),m)!=1) return 0; /* Legendre symbol not 1 */ + if (MR_REMAIN(m,4)==3) return spmd(x,(mr_small)((m+1)/4),m); /* easy case for m=4.k+3 */ + if (MR_REMAIN(m,8)==5) + { /* also relatively easy */ + t=spmd(x,(mr_small)((m-1)/4),m); + if (t==1) return spmd(x,(mr_small)((m+3)/8),m); + if (t==(mr_small)(m-1)) + { + muldiv((mr_small)4,x,(mr_small)0,m,&t); + t=spmd(t,(mr_small)((m+3)/8),m); + muldiv(t,(mr_small)((m+1)/2),(mr_small)0,m,&t); + return t; + } + return 0; + } + q=m-1; + e=0; + while (MR_REMAIN(q,2)==0) + { + q=MR_DIV(q,2); + e++; + } + if (e==0) return 0; /* even m */ + for (r=2;;r++) + { /* find suitable z */ + z=spmd((mr_small)r,q,m); + if (z==1) continue; + t=z; + pp=FALSE; + for (i=1;i=r) return 0; + y=spmd(y,mr_shiftbits(1,r-n-1),m); + muldiv(v,y,(mr_small)0,m,&v); + muldiv(y,y,(mr_small)0,m,&y); + muldiv(w,y,(mr_small)0,m,&w); + r=n; + } + return v; +} + +#endif diff --git a/miracl/source/mrsroot.c b/miracl/source/mrsroot.c new file mode 100644 index 0000000..b6d1ad1 --- /dev/null +++ b/miracl/source/mrsroot.c @@ -0,0 +1,188 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL method for modular square root + * mrsroot.c + * + * Siguna Mueller's O(lg(p)^3) algorithm, Designs Codes and Cryptography, 2004 + * + * This is a little slower for p=1 mod 4 primes, but its not time critical, and + * more importantly it doesn't pull in the large powmod code into elliptic curve programs + * It does require code from mrjack.c and mrlucas.c + * + * If p=3 mod 4, then sqrt(a)=a^[(p+1)/4] mod p. Note that for many elliptic curves + * (p+1)/4 has very low hamming weight. + * + * (was sqrt(a) = V_{(p+1)/4}(a+1/a,1)/(1+1/a)) + * + * Mueller's method is also very simple, uses very little memory, and it works just fine for p=1 mod 8 primes + * (for example the "annoying" NIST modulus 2^224-2^96+1) + * Also doesn't waste time on non-squares, as a jacobi test is done first + * + * If you know that the prime is 3 mod 4, and you know that x is almost certainly a QR + * then the jacobi-dependent code can be deleted with some space savings. + * + * NOTE - IF p IS NOT PRIME, THIS CODE WILL FAIL SILENTLY! + * + */ + +#include +#include "miracl.h" + +BOOL nres_sqroot(_MIPD_ big x,big w) +{ /* w=sqrt(x) mod p. This depends on p being prime! */ + int t,js; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + copy(x,w); + if (size(w)==0) return TRUE; + + MR_IN(100) + + redc(_MIPP_ w,w); /* get it back into normal form */ + + if (size(w)==1) /* square root of 1 is 1 */ + { + nres(_MIPP_ w,w); + MR_OUT + return TRUE; + } + + if (size(w)==4) /* square root of 4 is 2 */ + { + convert(_MIPP_ 2,w); + nres(_MIPP_ w,w); + MR_OUT + return TRUE; + } + + if (jack(_MIPP_ w,mr_mip->modulus)!=1) + { /* Jacobi test */ + zero(w); + MR_OUT + return FALSE; + } + + js=mr_mip->pmod8%4-2; /* 1 mod 4 or 3 mod 4 prime? */ + + incr(_MIPP_ mr_mip->modulus,js,mr_mip->w10); + subdiv(_MIPP_ mr_mip->w10,4,mr_mip->w10); /* (p+/-1)/4 */ + + if (js==1) + { /* 3 mod 4 primes - do a quick and dirty sqrt(x)=x^(p+1)/4 mod p */ + nres(_MIPP_ w,mr_mip->w2); + copy(mr_mip->one,w); + forever + { /* Simple Right-to-Left exponentiation */ + + if (mr_mip->user!=NULL) (*mr_mip->user)(); + if (subdiv(_MIPP_ mr_mip->w10,2,mr_mip->w10)!=0) + nres_modmult(_MIPP_ w,mr_mip->w2,w); + if (mr_mip->ERNUM || size(mr_mip->w10)==0) break; + nres_modmult(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w2); + } + + /* nres_moddiv(_MIPP_ mr_mip->one,w,mr_mip->w11); + nres_modadd(_MIPP_ mr_mip->w11,w,mr_mip->w3); + nres_lucas(_MIPP_ mr_mip->w3,mr_mip->w10,w,w); + nres_modadd(_MIPP_ mr_mip->w11,mr_mip->one,mr_mip->w11); + nres_moddiv(_MIPP_ w,mr_mip->w11,w); */ + } + else + { /* 1 mod 4 primes */ + for (t=1; ;t++) + { /* t=1.5 on average */ + if (t==1) copy(w,mr_mip->w4); + else + { + premult(_MIPP_ w,t,mr_mip->w4); + divide(_MIPP_ mr_mip->w4,mr_mip->modulus,mr_mip->modulus); + premult(_MIPP_ mr_mip->w4,t,mr_mip->w4); + divide(_MIPP_ mr_mip->w4,mr_mip->modulus,mr_mip->modulus); + } + + decr(_MIPP_ mr_mip->w4,4,mr_mip->w1); + if (jack(_MIPP_ mr_mip->w1,mr_mip->modulus)==js) break; + if (mr_mip->ERNUM) break; + } + + decr(_MIPP_ mr_mip->w4,2,mr_mip->w3); + nres(_MIPP_ mr_mip->w3,mr_mip->w3); + nres_lucas(_MIPP_ mr_mip->w3,mr_mip->w10,w,w); /* heavy lifting done here */ + if (t!=1) + { + convert(_MIPP_ t,mr_mip->w11); + nres(_MIPP_ mr_mip->w11,mr_mip->w11); + nres_moddiv(_MIPP_ w,mr_mip->w11,w); + } + } + + MR_OUT + return TRUE; +} + +BOOL sqroot(_MIPD_ big x,big p,big w) +{ /* w = sqrt(x) mod p */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + MR_IN(101) + + if (subdivisible(_MIPP_ p,2)) + { /* p must be odd */ + zero(w); + MR_OUT + return FALSE; + } + + prepare_monty(_MIPP_ p); + nres(_MIPP_ x,w); + if (nres_sqroot(_MIPP_ w,w)) + { + redc(_MIPP_ w,w); + MR_OUT + return TRUE; + } + + zero(w); + MR_OUT + return FALSE; +} diff --git a/miracl/source/mrstrong.c b/miracl/source/mrstrong.c new file mode 100644 index 0000000..7474062 --- /dev/null +++ b/miracl/source/mrstrong.c @@ -0,0 +1,243 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL cryptographic strong random number generator + * mrstrong.c + * + * Unguessable seed -> SHA -> PRNG internal state -> SHA -> random numbers + * Slow - but secure + * + * See ftp://ftp.rsasecurity.com/pub/pdfs/bull-1.pdf for a justification + */ + +#include "miracl.h" + +#ifndef MR_NO_RAND + +static mr_unsign32 sbrand(csprng *rng) +{ /* Marsaglia & Zaman random number generator */ + int i,k; + mr_unsign32 pdiff,t; + rng->rndptr++; + if (rng->rndptrira[rng->rndptr]; + rng->rndptr=0; + for (i=0,k=NK-NJ;iira[k]; + pdiff=t - rng->ira[i] - rng->borrow; + if (pdiffborrow=0; + if (pdiff>t) rng->borrow=1; + rng->ira[i]=pdiff; + } + return rng->ira[0]; +} + +static void sirand(csprng* rng,mr_unsign32 seed) +{ /* initialise random number system */ + /* modified so that a subsequent call "stirs" in another seed value */ + /* in this way as many seed bits as desired may be used */ + int i,in; + mr_unsign32 t,m=1L; + rng->borrow=0L; + rng->rndptr=0; + rng->ira[0]^=seed; + for (i=1;iira[in]^=m; /* note XOR */ + t=m; + m=seed-m; + seed=t; + } + for (i=0;i<10000;i++) sbrand(rng ); /* "warm-up" & stir the generator */ +} + +static void fill_pool(csprng *rng) +{ /* hash down output of RNG to re-fill the pool */ + int i; + sha256 sh; + shs256_init(&sh); + for (i=0;i<128;i++) shs256_process(&sh,sbrand(rng)); + shs256_hash(&sh,rng->pool); + rng->pool_ptr=0; +} + +void strong_init(csprng *rng,int rawlen,char *raw,mr_unsign32 tod) +{ /* initialise from at least 128 byte string of raw * + * random (keyboard?) input, and 32-bit time-of-day */ + int i; + mr_unsign32 hash[MR_HASH_BYTES/4]; + sha256 sh; + rng->pool_ptr=0; + for (i=0;iira[i]=0; + if (rawlen>0) + { + shs256_init(&sh); + for (i=0;ipool_ptr=rng->rndptr=0; + for (i=0;ipool[i]=0; + for (i=0;iira[i]=0; + rng->borrow=0; +} + +/* get random byte */ + +int strong_rng(csprng *rng) +{ + int r; + r=rng->pool[rng->pool_ptr++]; + if (rng->pool_ptr>=MR_HASH_BYTES) fill_pool(rng); + return r; +} + +void strong_bigrand(_MIPD_ csprng *rng,big w,big x) +{ + int i, m; + mr_small r; + unsigned int ran; + unsigned int ch; + +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(20) + + m = 0; + zero(mr_mip->w1); + + do + { + m++; + mr_mip->w1->len=m; + for (r = 0, i = 0; i < sizeof(mr_small); i++) { + ch=(unsigned char)strong_rng(rng); + ran=ch; + r = (r << 8) ^ ran; + } + if (mr_mip->base==0) mr_mip->w1->w[m-1]=r; + else mr_mip->w1->w[m-1]=MR_REMAIN(r,mr_mip->base); + } while (mr_compare(mr_mip->w1,w)<0); + mr_lzero(mr_mip->w1); + divide(_MIPP_ mr_mip->w1,w,w); + + copy(mr_mip->w1,x); + MR_OUT +} + +void strong_bigdig(_MIPD_ csprng *rng,int n,int b,big x) +{ /* generate random number n digits long * + * to "printable" base b */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(19) + + if (b<2 || b>256) + { + mr_berror(_MIPP_ MR_ERR_BASE_TOO_BIG); + MR_OUT + return; + } + + do + { /* repeat if x too small */ + expint(_MIPP_ b,n,mr_mip->w2); + strong_bigrand(_MIPP_ rng,mr_mip->w2,x); + subdiv(_MIPP_ mr_mip->w2,b,mr_mip->w2); + } while (!mr_mip->ERNUM && mr_compare(x,mr_mip->w2)<0); + + MR_OUT +} + +#endif + +/* test main program + +#include +#include "miracl.h" +#include + +void main() +{ + int i; + char raw[256]; + big x,w; + time_t seed; + csprng rng; + miracl *mip=mirsys(200,256); + x=mirvar(0); + w=mirvar(0); + printf("Enter Raw random string= "); + scanf("%s",raw); + getchar(); + time(&seed); + strong_init(&rng,strlen(raw),raw,(long)seed); + mip->IOBASE=16; + expint(2,256,w); + cotnum(w,stdout); + for (i=0;i<20;i++) + { + strong_bigrand(&rng,w,x); + cotnum(x,stdout); + } + printf("\n"); + for (i=0;i<20;i++) + { + strong_bigdig(&rng,128,2,x); + cotnum(x,stdout); + } +} + +*/ + diff --git a/miracl/source/mrxgcd.c b/miracl/source/mrxgcd.c new file mode 100644 index 0000000..7d82a14 --- /dev/null +++ b/miracl/source/mrxgcd.c @@ -0,0 +1,495 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL Extended Greatest Common Divisor module. + * mrxgcd.c + */ + +#include "miracl.h" + +#ifdef MR_FP +#include +#endif + +#ifdef MR_COUNT_OPS +extern int fpx; +#endif + +#ifndef MR_USE_BINARY_XGCD + +#ifdef mr_dltype + +static mr_small qdiv(mr_large u,mr_large v) +{ /* fast division - small quotient expected. */ + mr_large lq,x=u; +#ifdef MR_FP + mr_small dres; +#endif + x-=v; + if (x=MAXBASE) return 0; + return (mr_small)lq; +} + +#else + +static mr_small qdiv(mr_small u,mr_small v) +{ /* fast division - small quotient expected */ + mr_small x=u; + x-=v; + if (xERNUM) return 0; + + MR_IN(30) + +#ifdef MR_COUNT_OPS + fpx++; +#endif + + copy(x,mr_mip->w1); + copy(y,mr_mip->w2); + s=exsign(mr_mip->w1); + insign(PLUS,mr_mip->w1); + insign(PLUS,mr_mip->w2); + convert(_MIPP_ 1,mr_mip->w3); + zero(mr_mip->w4); + last=FALSE; + a=b=c=d=0; + iter=0; + + while (size(mr_mip->w2)!=0) + { + if (b==0) + { /* update mr_mip->w1 and mr_mip->w2 */ + + divide(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w5); + t=mr_mip->w1,mr_mip->w1=mr_mip->w2,mr_mip->w2=t; /* swap(mr_mip->w1,mr_mip->w2) */ + multiply(_MIPP_ mr_mip->w4,mr_mip->w5,mr_mip->w0); + add(_MIPP_ mr_mip->w3,mr_mip->w0,mr_mip->w3); + t=mr_mip->w3,mr_mip->w3=mr_mip->w4,mr_mip->w4=t; /* swap(xd,yd) */ + iter++; + + } + else + { + + /* printf("a= %I64u b= %I64u c= %I64u d= %I64u \n",a,b,c,d); */ + + mr_pmul(_MIPP_ mr_mip->w1,c,mr_mip->w5); /* c*w1 */ + mr_pmul(_MIPP_ mr_mip->w1,a,mr_mip->w1); /* a*w1 */ + mr_pmul(_MIPP_ mr_mip->w2,b,mr_mip->w0); /* b*w2 */ + mr_pmul(_MIPP_ mr_mip->w2,d,mr_mip->w2); /* d*w2 */ + + if (!dplus) + { + mr_psub(_MIPP_ mr_mip->w0,mr_mip->w1,mr_mip->w1); /* b*w2-a*w1 */ + mr_psub(_MIPP_ mr_mip->w5,mr_mip->w2,mr_mip->w2); /* c*w1-d*w2 */ + } + else + { + mr_psub(_MIPP_ mr_mip->w1,mr_mip->w0,mr_mip->w1); /* a*w1-b*w2 */ + mr_psub(_MIPP_ mr_mip->w2,mr_mip->w5,mr_mip->w2); /* d*w2-c*w1 */ + } + mr_pmul(_MIPP_ mr_mip->w3,c,mr_mip->w5); + mr_pmul(_MIPP_ mr_mip->w3,a,mr_mip->w3); + mr_pmul(_MIPP_ mr_mip->w4,b,mr_mip->w0); + mr_pmul(_MIPP_ mr_mip->w4,d,mr_mip->w4); + + if (a==0) copy(mr_mip->w0,mr_mip->w3); + else mr_padd(_MIPP_ mr_mip->w3,mr_mip->w0,mr_mip->w3); + mr_padd(_MIPP_ mr_mip->w4,mr_mip->w5,mr_mip->w4); + } + if (mr_mip->ERNUM || size(mr_mip->w2)==0) break; + + + n=(int)mr_mip->w1->len; + if (n==1) + { + last=TRUE; + u=mr_mip->w1->w[0]; + v=mr_mip->w2->w[0]; + } + else + { + m=mr_mip->w1->w[n-1]+1; +#ifndef MR_SIMPLE_BASE + if (mr_mip->base==0) + { +#endif +#ifndef MR_NOFULLWIDTH +#ifdef mr_dltype + /* use double length type if available */ + if (n>2 && m!=0) + { /* squeeze out as much significance as possible */ + uu.h[MR_TOP]=muldvm(mr_mip->w1->w[n-1],mr_mip->w1->w[n-2],m,&sr); + uu.h[MR_BOT]=muldvm(sr,mr_mip->w1->w[n-3],m,&sr); + vv.h[MR_TOP]=muldvm(mr_mip->w2->w[n-1],mr_mip->w2->w[n-2],m,&sr); + vv.h[MR_BOT]=muldvm(sr,mr_mip->w2->w[n-3],m,&sr); + } + else + { + uu.h[MR_TOP]=mr_mip->w1->w[n-1]; + uu.h[MR_BOT]=mr_mip->w1->w[n-2]; + vv.h[MR_TOP]=mr_mip->w2->w[n-1]; + vv.h[MR_BOT]=mr_mip->w2->w[n-2]; + if (n==2) last=TRUE; + } + + u=uu.d; + v=vv.d; +#else + if (m==0) + { + u=mr_mip->w1->w[n-1]; + v=mr_mip->w2->w[n-1]; + } + else + { + u=muldvm(mr_mip->w1->w[n-1],mr_mip->w1->w[n-2],m,&sr); + v=muldvm(mr_mip->w2->w[n-1],mr_mip->w2->w[n-2],m,&sr); + } +#endif +#endif +#ifndef MR_SIMPLE_BASE + } + else + { +#ifdef mr_dltype + if (n>2) + { /* squeeze out as much significance as possible */ + u=muldiv(mr_mip->w1->w[n-1],mr_mip->base,mr_mip->w1->w[n-2],m,&sr); + u=u*mr_mip->base+muldiv(sr,mr_mip->base,mr_mip->w1->w[n-3],m,&sr); + v=muldiv(mr_mip->w2->w[n-1],mr_mip->base,mr_mip->w2->w[n-2],m,&sr); + v=v*mr_mip->base+muldiv(sr,mr_mip->base,mr_mip->w2->w[n-3],m,&sr); + } + else + { + u=(mr_large)mr_mip->base*mr_mip->w1->w[n-1]+mr_mip->w1->w[n-2]; + v=(mr_large)mr_mip->base*mr_mip->w2->w[n-1]+mr_mip->w2->w[n-2]; + last=TRUE; + } +#else + u=muldiv(mr_mip->w1->w[n-1],mr_mip->base,mr_mip->w1->w[n-2],m,&sr); + v=muldiv(mr_mip->w2->w[n-1],mr_mip->base,mr_mip->w2->w[n-2],m,&sr); +#endif + } +#endif + } + + dplus=TRUE; + a=1; b=0; c=0; d=1; + + forever + { /* work only with most significant piece */ + if (last) + { + if (v==0) break; + q=qdiv(u,v); + if (q==0) break; + } + else + { + if (dplus) + { + if ((mr_small)(v-c)==0 || (mr_small)(v+d)==0) break; + + q=qdiv(u+a,v-c); + + if (q==0) break; + + if (q!=qdiv(u-b,v+d)) break; + } + else + { + if ((mr_small)(v+c)==0 || (mr_small)(v-d)==0) break; + q=qdiv(u-a,v+c); + if (q==0) break; + if (q!=qdiv(u+b,v-d)) break; + } + } + + if (q==1) + { + if ((mr_small)(b+d) >= MAXBASE) break; + r=a+c; a=c; c=r; + r=b+d; b=d; d=r; + lr=u-v; u=v; v=lr; + } + else + { + if (q>=MR_DIV(MAXBASE-b,d)) break; + r=a+q*c; a=c; c=r; + r=b+q*d; b=d; d=r; + lr=u-q*v; u=v; v=lr; + } + iter++; + dplus=!dplus; + } + iter%=2; + + } + + if (s==MINUS) iter++; + if (iter%2==1) subtract(_MIPP_ y,mr_mip->w3,mr_mip->w3); + + if (xd!=yd) + { + negify(x,mr_mip->w2); + mad(_MIPP_ mr_mip->w2,mr_mip->w3,mr_mip->w1,y,mr_mip->w4,mr_mip->w4); + copy(mr_mip->w4,yd); + } + copy(mr_mip->w3,xd); + if (z!=xd && z!=yd) copy(mr_mip->w1,z); + + MR_OUT + return (size(mr_mip->w1)); +} + +int invmodp(_MIPD_ big x,big y,big z) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + int gcd; + + MR_IN(213); + gcd=xgcd(_MIPP_ x,y,z,z,z); + MR_OUT + return gcd; +} + +#else + +/* much smaller, much slower binary inversion algorithm */ +/* fails silently if a is not co-prime to p */ + +/* experimental! At least 3 times slower than standard method.. */ + +int invmodp(_MIPD_ big a,big p,big z) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + big u,v,x1,x2; + + MR_IN(213); + + u=mr_mip->w1; v=mr_mip->w2; x1=mr_mip->w3; x2=mr_mip->w4; + copy(a,u); + copy(p,v); + convert(_MIPP_ 1,x1); + zero(x2); + + while (size(u)!=1 && size(v)!=1) + { + while (remain(_MIPP_ u,2)==0) + { + subdiv(_MIPP_ u,2,u); + if (remain(_MIPP_ x1,2)!=0) add(_MIPP_ x1,p,x1); + subdiv(_MIPP_ x1,2,x1); + } + while (remain(_MIPP_ v,2)==0) + { + subdiv(_MIPP_ v,2,v); + if (remain(_MIPP_ x2,2)!=0) add(_MIPP_ x2,p,x2); + subdiv(_MIPP_ x2,2,x2); + } + if (mr_compare(u,v)>=0) + { + mr_psub(_MIPP_ u,v,u); + subtract(_MIPP_ x1,x2,x1); + } + else + { + mr_psub(_MIPP_ v,u,v); + subtract(_MIPP_ x2,x1,x2); + } + } + if (size(u)==1) copy(x1,z); + else copy(x2,z); + + if (size(z)<0) add(_MIPP_ z,p,z); + + MR_OUT + return 1; /* note - no checking that gcd=1 */ +} + +#endif + +#ifndef MR_STATIC + +/* Montgomery's method for multiple + simultaneous modular inversions */ + +BOOL double_inverse(_MIPD_ big n,big x,big y,big w,big z) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + MR_IN(146) + + mad(_MIPP_ x,w,w,n,n,mr_mip->w6); + if (size(mr_mip->w6)==0) + { + mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); + MR_OUT + return FALSE; + } + invmodp(_MIPP_ mr_mip->w6,n,mr_mip->w6); + + mad(_MIPP_ w,mr_mip->w6,w,n,n,y); + mad(_MIPP_ x,mr_mip->w6,x,n,n,z); + + MR_OUT + return TRUE; +} + +BOOL multi_inverse(_MIPD_ int m,big *x,big n,big *w) +{ /* find w[i]=1/x[i] mod n, for i=0 to m-1 * + * x and w MUST be distinct */ + int i; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (m==0) return TRUE; + if (m<0) return FALSE; + + MR_IN(25) + + if (x==w) + { + mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + MR_OUT + return FALSE; + } + if (m==1) + { + invmodp(_MIPP_ x[0],n,w[0]); + MR_OUT + return TRUE; + } + + convert(_MIPP_ 1,w[0]); + copy(x[0],w[1]); + for (i=2;iw6); /* y=x[0]*x[1]*x[2]....x[m-1] */ + if (size(mr_mip->w6)==0) + { + mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); + MR_OUT + return FALSE; + } + + invmodp(_MIPP_ mr_mip->w6,n,mr_mip->w6); + +/* Now y=1/y */ + + copy(x[m-1],mr_mip->w5); + mad(_MIPP_ w[m-1],mr_mip->w6,mr_mip->w6,n,n,w[m-1]); + + for (i=m-2;;i--) + { + if (i==0) + { + mad(_MIPP_ mr_mip->w5,mr_mip->w6,mr_mip->w6,n,n,w[0]); + break; + } + mad(_MIPP_ w[i],mr_mip->w5,w[i],n,n,w[i]); + mad(_MIPP_ w[i],mr_mip->w6,w[i],n,n,w[i]); + mad(_MIPP_ mr_mip->w5,x[i],x[i],n,n,mr_mip->w5); + } + + MR_OUT + return TRUE; +} + +#endif diff --git a/miracl/source/mrzzn2.c b/miracl/source/mrzzn2.c new file mode 100644 index 0000000..e3498c9 --- /dev/null +++ b/miracl/source/mrzzn2.c @@ -0,0 +1,721 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL F_p^2 support functions + * mrzzn2.c + */ + +#include +#include "miracl.h" + +#ifdef MR_COUNT_OPS +extern int fpmq,fpsq,fpaq; +#endif + +BOOL zzn2_iszero(zzn2 *x) +{ + if (size(x->a)==0 && size(x->b)==0) return TRUE; + return FALSE; +} + +BOOL zzn2_isunity(_MIPD_ zzn2 *x) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM || size(x->b)!=0) return FALSE; + + if (mr_compare(x->a,mr_mip->one)==0) return TRUE; + return FALSE; + +} + +BOOL zzn2_compare(zzn2 *x,zzn2 *y) +{ + if (mr_compare(x->a,y->a)==0 && mr_compare(x->b,y->b)==0) return TRUE; + return FALSE; +} + +void zzn2_from_int(_MIPD_ int i,zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(156) + if (i==1) + { + copy(mr_mip->one,w->a); + } + else + { + convert(_MIPP_ i,mr_mip->w1); + nres(_MIPP_ mr_mip->w1,w->a); + } + zero(w->b); + MR_OUT +} + +void zzn2_from_ints(_MIPD_ int i,int j,zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(168) + convert(_MIPP_ i,mr_mip->w1); + nres(_MIPP_ mr_mip->w1,w->a); + convert(_MIPP_ j,mr_mip->w1); + nres(_MIPP_ mr_mip->w1,w->b); + + MR_OUT +} + +void zzn2_from_zzns(big x,big y,zzn2 *w) +{ + copy(x,w->a); + copy(y,w->b); +} + +void zzn2_from_bigs(_MIPD_ big x,big y, zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(166) + nres(_MIPP_ x,w->a); + nres(_MIPP_ y,w->b); + MR_OUT +} + +void zzn2_from_zzn(big x,zzn2 *w) +{ + copy(x,w->a); + zero(w->b); +} + +void zzn2_from_big(_MIPD_ big x, zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(167) + nres(_MIPP_ x,w->a); + zero(w->b); + MR_OUT +} + +void zzn2_copy(zzn2 *x,zzn2 *w) +{ + if (x==w) return; + copy(x->a,w->a); + copy(x->b,w->b); +} + +void zzn2_zero(zzn2 *w) +{ + zero(w->a); + zero(w->b); +} + +void zzn2_negate(_MIPD_ zzn2 *x,zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(157) + zzn2_copy(x,w); + nres_negate(_MIPP_ w->a,w->a); + nres_negate(_MIPP_ w->b,w->b); + MR_OUT +} + +void zzn2_conj(_MIPD_ zzn2 *x,zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + MR_IN(158) + if (mr_mip->ERNUM) return; + zzn2_copy(x,w); + nres_negate(_MIPP_ w->b,w->b); + MR_OUT +} + +void zzn2_add(_MIPD_ zzn2 *x,zzn2 *y,zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; +#ifdef MR_COUNT_OPS +fpaq++; +#endif + MR_IN(159) + nres_modadd(_MIPP_ x->a,y->a,w->a); + nres_modadd(_MIPP_ x->b,y->b,w->b); + MR_OUT +} + +void zzn2_sadd(_MIPD_ zzn2 *x,big y,zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(169) + nres_modadd(_MIPP_ x->a,y,w->a); + MR_OUT +} + +void zzn2_sub(_MIPD_ zzn2 *x,zzn2 *y,zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; +#ifdef MR_COUNT_OPS +fpaq++; +#endif + MR_IN(160) + nres_modsub(_MIPP_ x->a,y->a,w->a); + nres_modsub(_MIPP_ x->b,y->b,w->b); + MR_OUT +} + +void zzn2_ssub(_MIPD_ zzn2 *x,big y,zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(170) + nres_modsub(_MIPP_ x->a,y,w->a); + MR_OUT +} + +void zzn2_smul(_MIPD_ zzn2 *x,big y,zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(161) + if (size(x->a)!=0) nres_modmult(_MIPP_ x->a,y,w->a); + else zero(w->a); + if (size(x->b)!=0) nres_modmult(_MIPP_ x->b,y,w->b); + else zero(w->b); + MR_OUT +} + +void zzn2_imul(_MIPD_ zzn2 *x,int y,zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(152) + if (size(x->a)!=0) nres_premult(_MIPP_ x->a,y,w->a); + else zero(w->a); + if (size(x->b)!=0) nres_premult(_MIPP_ x->b,y,w->b); + else zero(w->b); + MR_OUT +} + +void zzn2_sqr(_MIPD_ zzn2 *x,zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return; +#ifdef MR_COUNT_OPS +fpsq++; +#endif + MR_IN(210) + + nres_complex(_MIPP_ x->a,x->b,w->a,w->b); + + MR_OUT +} + +void zzn2_mul(_MIPD_ zzn2 *x,zzn2 *y,zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return; + if (x==y) {zzn2_sqr(_MIPP_ x,w); return; } + MR_IN(162) + /* Uses w1, w2, and w5 */ + + if (zzn2_iszero(x) || zzn2_iszero(y)) zzn2_zero(w); + else + { +#ifdef MR_COUNT_OPS +fpmq++; +#endif +#ifndef MR_NO_LAZY_REDUCTION + if (x->a->len!=0 && x->b->len!=0 && y->a->len!=0 && y->b->len!=0) + nres_lazy(_MIPP_ x->a,x->b,y->a,y->b,w->a,w->b); + else + { +#endif + nres_modmult(_MIPP_ x->a,y->a,mr_mip->w1); + nres_modmult(_MIPP_ x->b,y->b,mr_mip->w2); + nres_modadd(_MIPP_ x->a,x->b,mr_mip->w5); + nres_modadd(_MIPP_ y->a,y->b,w->b); + nres_modmult(_MIPP_ w->b,mr_mip->w5,w->b); + nres_modsub(_MIPP_ w->b,mr_mip->w1,w->b); + nres_modsub(_MIPP_ w->b,mr_mip->w2,w->b); + nres_modsub(_MIPP_ mr_mip->w1,mr_mip->w2,w->a); + if (mr_mip->qnr==-2) + nres_modsub(_MIPP_ w->a,mr_mip->w2,w->a); +#ifndef MR_NO_LAZY_REDUCTION + } +#endif + } + MR_OUT +} + + +/* +void zzn2_print(_MIPD_ char *label, zzn2 *x) +{ + char s1[1024], s2[1024]; + big a, b; + +#ifdef MR_STATIC + char mem_big[MR_BIG_RESERVE(2)]; + memset(mem_big, 0, MR_BIG_RESERVE(2)); + a=mirvar_mem(_MIPP_ mem_big,0); + b=mirvar_mem(_MIPP_ mem_big,1); +#else + a = mirvar(_MIPP_ 0); + b = mirvar(_MIPP_ 0); +#endif + redc(_MIPP_ x->a, a); otstr(_MIPP_ a, s1); + redc(_MIPP_ x->b, b); otstr(_MIPP_ b, s2); + + printf("%s: [%s,%s]\n", label, s1, s2); +#ifndef MR_STATIC + mr_free(a); mr_free(b); +#endif +} + +static void nres_print(_MIPD_ char *label, big x) +{ + char s[1024]; + big a; +#ifdef MR_STATIC + char mem_big[MR_BIG_RESERVE(1)]; + memset(mem_big, 0, MR_BIG_RESERVE(1)); + a=mirvar_mem(_MIPP_ mem_big,0); +#else + a = mirvar(_MIPP_ 0); +#endif + + redc(_MIPP_ x, a); + otstr(_MIPP_ a, s); + + printf("%s: %s\n", label, s); +#ifndef MR_STATIC + mr_free(a); +#endif +} + +*/ +void zzn2_inv(_MIPD_ zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(163) + nres_modmult(_MIPP_ w->a,w->a,mr_mip->w1); + nres_modmult(_MIPP_ w->b,w->b,mr_mip->w2); + nres_modadd(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); + + if (mr_mip->qnr==-2) + nres_modadd(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); + redc(_MIPP_ mr_mip->w1,mr_mip->w6); + + invmodp(_MIPP_ mr_mip->w6,mr_mip->modulus,mr_mip->w6); + + nres(_MIPP_ mr_mip->w6,mr_mip->w6); + + nres_modmult(_MIPP_ w->a,mr_mip->w6,w->a); + nres_negate(_MIPP_ mr_mip->w6,mr_mip->w6); + nres_modmult(_MIPP_ w->b,mr_mip->w6,w->b); + MR_OUT +} + +/* divide zzn2 by 2 */ + +void zzn2_div2(_MIPD_ zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(173) + + nres_div2(_MIPP_ w->a,w->a); + nres_div2(_MIPP_ w->b,w->b); + + MR_OUT +} + +/* divide zzn2 by 3 */ + +void zzn2_div3(_MIPD_ zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(200) + + nres_div3(_MIPP_ w->a,w->a); + nres_div3(_MIPP_ w->b,w->b); + + MR_OUT +} + +/* divide zzn2 by 5 */ + +void zzn2_div5(_MIPD_ zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(209) + + nres_div5(_MIPP_ w->a,w->a); + nres_div5(_MIPP_ w->b,w->b); + + MR_OUT +} + +/* multiply zzn2 by i */ + +void zzn2_timesi(_MIPD_ zzn2 *u) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(164) + copy(u->a,mr_mip->w1); + nres_negate(_MIPP_ u->b,u->a); + if (mr_mip->qnr==-2) + nres_modadd(_MIPP_ u->a,u->a,u->a); + + copy(mr_mip->w1,u->b); + MR_OUT +} + +void zzn2_txx(_MIPD_ zzn2 *u) +{ + /* multiply w by t^2 where x^2-t is irreducible polynomial for ZZn4 + + for p=5 mod 8 t=sqrt(sqrt(-2)), qnr=-2 + for p=3 mod 8 t=sqrt(1+sqrt(-1)), qnr=-1 + for p=7 mod 8 and p=2,3 mod 5 t=sqrt(2+sqrt(-1)), qnr=-1 */ + zzn2 t; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(196) + + switch (mr_mip->pmod8) + { + case 5: + zzn2_timesi(_MIPP_ u); + break; + case 3: + t.a=mr_mip->w3; + t.b=mr_mip->w4; + zzn2_copy(u,&t); + zzn2_timesi(_MIPP_ u); + zzn2_add(_MIPP_ u,&t,u); + break; + case 7: + t.a=mr_mip->w3; + t.b=mr_mip->w4; + zzn2_copy(u,&t); + zzn2_timesi(_MIPP_ u); + zzn2_add(_MIPP_ u,&t,u); + zzn2_add(_MIPP_ u,&t,u); + break; + default: break; + } + MR_OUT +} + +void zzn2_txd(_MIPD_ zzn2 *u) +{ /* divide w by t^2 where x^2-t is irreducible polynomial for ZZn4 + + for p=5 mod 8 t=sqrt(sqrt(-2)), qnr=-2 + for p=3 mod 8 t=sqrt(1+sqrt(-1)), qnr=-1 + for p=7 mod 8 and p=2,3 mod 5 t=sqrt(2+sqrt(-1)), qnr=-1 */ + zzn2 t; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(197) + t.a=mr_mip->w3; + t.b=mr_mip->w4; + switch (mr_mip->pmod8) + { + case 5: + copy(u->b,t.a); + nres_div2(_MIPP_ u->a,t.b); + nres_negate(_MIPP_ t.b,t.b); + zzn2_copy(&t,u); + break; + case 3: + nres_modadd(_MIPP_ u->a,u->b,t.a); + nres_modsub(_MIPP_ u->b,u->a,t.b); + zzn2_div2(_MIPP_ &t); + zzn2_copy(&t,u); + break; + case 7: + nres_modadd(_MIPP_ u->a,u->a,t.a); + nres_modadd(_MIPP_ t.a,u->b,t.a); + nres_modadd(_MIPP_ u->b,u->b,t.b); + nres_modsub(_MIPP_ t.b,u->a,t.b); + zzn2_div5(_MIPP_ &t); + zzn2_copy(&t,u); +/* + nres_modadd(_MIPP_ u->a,u->b,t.a); + nres_modadd(_MIPP_ t.a,u->b,t.a); + nres_modsub(_MIPP_ u->b,u->a,t.b); + zzn2_div3(_MIPP_ &t); + zzn2_copy(&t,u); +*/ + break; + default: break; + } + + MR_OUT +} + +/* find w[i]=1/x[i] mod n, for i=0 to m-1 * + * x and w MUST be distinct */ + +BOOL zzn2_multi_inverse(_MIPD_ int m,zzn2 *x,zzn2 *w) +{ + int i; + zzn2 t1,t2; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (m==0) return TRUE; + if (m<0) return FALSE; + MR_IN(214) + + if (x==w) + { + mr_berror(_MIPP_ MR_ERR_BAD_PARAMETERS); + MR_OUT + return FALSE; + } + + if (m==1) + { + zzn2_copy(&x[0],&w[0]); + zzn2_inv(_MIPP_ &w[0]); + + MR_OUT + return TRUE; + } + + zzn2_from_int(_MIPP_ 1,&w[0]); + zzn2_copy(&x[0],&w[1]); + + for (i=2;iw8; + t1.b=mr_mip->w9; + t2.a=mr_mip->w10; + t2.b=mr_mip->w11; + + zzn2_mul(_MIPP_ &w[m-1],&x[m-1],&t1); + if (zzn2_iszero(&t1)) + { + mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); + MR_OUT + return FALSE; + } + + zzn2_inv(_MIPP_ &t1); + + zzn2_copy(&x[m-1],&t2); + zzn2_mul(_MIPP_ &w[m-1],&t1,&w[m-1]); + + for (i=m-2;;i--) + { + if (i==0) + { + zzn2_mul(_MIPP_ &t2,&t1,&w[0]); + break; + } + zzn2_mul(_MIPP_ &w[i],&t2,&w[i]); + zzn2_mul(_MIPP_ &w[i],&t1,&w[i]); + if (!zzn2_isunity(_MIPP_ &x[i])) zzn2_mul(_MIPP_ &t2,&x[i],&t2); + } + + MR_OUT + return TRUE; +} + + +/* +static void zzn2_print(_MIPD_ char *label, zzn2 *x) +{ + char s1[1024], s2[1024]; + big a, b; + + + a = mirvar(_MIPP_ 0); + b = mirvar(_MIPP_ 0); + + redc(_MIPP_ x->a, a); otstr(_MIPP_ a, s1); + redc(_MIPP_ x->b, b); otstr(_MIPP_ b, s2); + + printf("%s: [%s,%s]\n", label, s1, s2); + + mr_free(a); mr_free(b); + +} + +static void nres_print(_MIPD_ char *label, big x) +{ + char s[1024]; + big a; + + a = mirvar(_MIPP_ 0); + + redc(_MIPP_ x, a); + otstr(_MIPP_ a, s); + + printf("%s: %s\n", label, s); + + mr_free(a); +} + +*/ + +/* Lucas-style ladder exponentiation - for ZZn4 exponentiation + +void zzn2_powl(_MIPD_ zzn2 *x,big e,zzn2 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + int i,s; + zzn2 t1,t3,t4; + if (mr_mip->ERNUM) return; + MR_IN(165) + t1.a=mr_mip->w3; + t1.b=mr_mip->w4; + t3.a=mr_mip->w8; + t3.b=mr_mip->w9; + t4.a=mr_mip->w10; + t4.b=mr_mip->w11; + + zzn2_from_int(_MIPP_ 1,&t1); + + s=size(e); + if (s==0) + { + zzn2_copy(&t1,w); + return; + } + zzn2_copy(x,w); + if (s==1 || s==(-1)) return; + + i=logb2(_MIPP_ e)-1; + + zzn2_copy(w,&t3); + zzn2_sqr(_MIPP_ w,&t4); + zzn2_add(_MIPP_ &t4,&t4,&t4); + zzn2_sub(_MIPP_ &t4,&t1,&t4); + + while (i-- && !mr_mip->ERNUM) + { + if (mr_testbit(_MIPP_ e,i)) + { + zzn2_mul(_MIPP_ &t3,&t4,&t3); + zzn2_add(_MIPP_ &t3,&t3,&t3); + zzn2_sub(_MIPP_ &t3,w,&t3); + zzn2_sqr(_MIPP_ &t4,&t4); + zzn2_add(_MIPP_ &t4,&t4,&t4); + zzn2_sub(_MIPP_ &t4,&t1,&t4); + } + else + { + zzn2_mul(_MIPP_ &t4,&t3,&t4); + zzn2_add(_MIPP_ &t4,&t4,&t4); + zzn2_sub(_MIPP_ &t4,w,&t4); + zzn2_sqr(_MIPP_ &t3,&t3); + zzn2_add(_MIPP_ &t3,&t3,&t3); + zzn2_sub(_MIPP_ &t3,&t1,&t3); + } + + } + zzn2_copy(&t4,w); + MR_OUT +} +*/ diff --git a/miracl/source/mrzzn2b.c b/miracl/source/mrzzn2b.c new file mode 100644 index 0000000..8404c92 --- /dev/null +++ b/miracl/source/mrzzn2b.c @@ -0,0 +1,188 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL F_p^2 support functions + * mrzzn2b.c + */ + +#include +#include "miracl.h" + +BOOL zzn2_qr(_MIPD_ zzn2 *u) +{ + int j; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return FALSE; + if (zzn2_iszero(u)) return TRUE; + if (size(u->b)==0) return TRUE; + + if (mr_mip->qnr==-1 && size(u->a)==0) return TRUE; + + + MR_IN(203) + + nres_modmult(_MIPP_ u->b,u->b,mr_mip->w1); + if (mr_mip->qnr==-2) nres_modadd(_MIPP_ mr_mip->w1,mr_mip->w1,mr_mip->w1); + nres_modmult(_MIPP_ u->a,u->a,mr_mip->w2); + nres_modadd(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); + redc(_MIPP_ mr_mip->w1,mr_mip->w1); + j=jack(_MIPP_ mr_mip->w1,mr_mip->modulus); + + MR_OUT + if (j==1) return TRUE; + return FALSE; +} + +BOOL zzn2_sqrt(_MIPD_ zzn2 *u,zzn2 *w) +{ /* sqrt(a+ib) = sqrt(a+sqrt(a*a-n*b*b)/2)+ib/(2*sqrt(a+sqrt(a*a-n*b*b)/2)) + where i*i=n */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return FALSE; + + zzn2_copy(u,w); + if (zzn2_iszero(w)) return TRUE; + + MR_IN(204) + + if (size(w->b)==0) + { + if (!nres_sqroot(_MIPP_ w->a,mr_mip->w15)) + { + nres_negate(_MIPP_ w->a,w->b); + zero(w->a); + if (mr_mip->qnr==-2) nres_div2(_MIPP_ w->b,w->b); + nres_sqroot(_MIPP_ w->b,w->b); + } + else + copy(mr_mip->w15,w->a); + + MR_OUT + return TRUE; + } + + if (mr_mip->qnr==-1 && size(w->a)==0) + { + nres_div2(_MIPP_ w->b,w->b); + if (nres_sqroot(_MIPP_ w->b,mr_mip->w15)) + { + copy(mr_mip->w15,w->b); + copy(w->b,w->a); + } + else + { + nres_negate(_MIPP_ w->b,w->b); + nres_sqroot(_MIPP_ w->b,w->b); + nres_negate(_MIPP_ w->b,w->a); + } + + MR_OUT + return TRUE; + } + + nres_modmult(_MIPP_ w->b,w->b,mr_mip->w7); + if (mr_mip->qnr==-2) nres_modadd(_MIPP_ mr_mip->w7,mr_mip->w7,mr_mip->w7); + nres_modmult(_MIPP_ w->a,w->a,mr_mip->w1); + nres_modadd(_MIPP_ mr_mip->w7,mr_mip->w1,mr_mip->w7); + + if (!nres_sqroot(_MIPP_ mr_mip->w7,mr_mip->w7)) /* s=w7 */ + { + zzn2_zero(w); + MR_OUT + return FALSE; + } + + nres_modadd(_MIPP_ w->a,mr_mip->w7,mr_mip->w15); + nres_div2(_MIPP_ mr_mip->w15,mr_mip->w15); + + if (!nres_sqroot(_MIPP_ mr_mip->w15,mr_mip->w15)) + { + + nres_modsub(_MIPP_ w->a,mr_mip->w7,mr_mip->w15); + nres_div2(_MIPP_ mr_mip->w15,mr_mip->w15); + if (!nres_sqroot(_MIPP_ mr_mip->w15,mr_mip->w15)) + { + zzn2_zero(w); + MR_OUT + return FALSE; + } + } + + copy(mr_mip->w15,w->a); + nres_modadd(_MIPP_ mr_mip->w15,mr_mip->w15,mr_mip->w15); + nres_moddiv(_MIPP_ w->b,mr_mip->w15,w->b); + + MR_OUT + return TRUE; +} + +/* y=1/x, z=1/w + +BOOL zzn2_double_inverse(_MIPD_ zzn2 *x,zzn2 *y,zzn2 *w,zzn2 *z) +{ + zzn2 t1,t2; +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + MR_IN(214) + + t1.a=mr_mip->w8; + t1.b=mr_mip->w9; + t2.a=mr_mip->w10; + t2.b=mr_mip->w11; + + zzn2_mul(_MIPP_ x,w,&t1); + if (zzn2_iszero(_MIPP_ &t1)) + { + mr_berror(_MIPP_ MR_ERR_DIV_BY_ZERO); + MR_OUT + return FALSE; + } + zzn2_inv(_MIPP_ &t1); + + zzn2_mul(_MIPP_ &w,&t1,&t2); + zzn2_mul(_MIPP_ &x,&t1,&z); + zzn2_copy(&t2,&y); + + MR_OUT + return TRUE; + +} +*/ + diff --git a/miracl/source/mrzzn3.c b/miracl/source/mrzzn3.c new file mode 100644 index 0000000..08e33d7 --- /dev/null +++ b/miracl/source/mrzzn3.c @@ -0,0 +1,471 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL F_p^3 support functions + * mrzzn3.c + * + * This code assumes p=1 mod 3 + * Irreducible polynomial is x^3+cnr + * + * Did you know that 2 is a cnr iff p cannot be written as x^2+27.y^2 ? + */ + +#include +#include "miracl.h" + +BOOL zzn3_iszero(zzn3 *x) +{ + if (size(x->a)==0 && size(x->b)==0 && size(x->c)==0) return TRUE; + return FALSE; +} + +BOOL zzn3_isunity(_MIPD_ zzn3 *x) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM || size(x->b)!=0 || size(x->c)!=0) return FALSE; + + if (mr_compare(x->a,mr_mip->one)==0) return TRUE; + return FALSE; +} + +BOOL zzn3_compare(zzn3 *x,zzn3 *y) +{ + if (mr_compare(x->a,y->a)==0 && mr_compare(x->b,y->b)==0 && mr_compare(x->c,y->c)==0) return TRUE; + return FALSE; +} + +void zzn3_from_int(_MIPD_ int i,zzn3 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(174) + convert(_MIPP_ i,mr_mip->w1); + nres(_MIPP_ mr_mip->w1,w->a); + zero(w->b); zero(w->c); + MR_OUT +} + +void zzn3_from_ints(_MIPD_ int i,int j,int k,zzn3 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(175) + convert(_MIPP_ i,mr_mip->w1); + nres(_MIPP_ mr_mip->w1,w->a); + convert(_MIPP_ j,mr_mip->w1); + nres(_MIPP_ mr_mip->w1,w->b); + convert(_MIPP_ k,mr_mip->w1); + nres(_MIPP_ mr_mip->w1,w->c); + + MR_OUT +} + +void zzn3_from_zzns(big x,big y,big z,zzn3 *w) +{ + copy(x,w->a); + copy(y,w->b); + copy(z,w->c); +} + +void zzn3_from_bigs(_MIPD_ big x,big y,big z,zzn3 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(176) + nres(_MIPP_ x,w->a); + nres(_MIPP_ y,w->b); + nres(_MIPP_ z,w->c); + MR_OUT +} + +void zzn3_from_zzn(big x,zzn3 *w) +{ + copy(x,w->a); + zero(w->b); zero(w->c); +} + +void zzn3_from_zzn_1(big x,zzn3 *w) +{ + copy(x,w->b); + zero(w->a); zero(w->c); +} + +void zzn3_from_zzn_2(big x,zzn3 *w) +{ + copy(x,w->c); + zero(w->a); zero(w->b); +} + +void zzn3_from_big(_MIPD_ big x, zzn3 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(177) + nres(_MIPP_ x,w->a); + zero(w->b); zero(w->c); + MR_OUT +} + +void zzn3_copy(zzn3 *x,zzn3 *w) +{ + if (x==w) return; + copy(x->a,w->a); + copy(x->b,w->b); + copy(x->c,w->c); +} + +void zzn3_zero(zzn3 *w) +{ + zero(w->a); + zero(w->b); + zero(w->c); +} + +void zzn3_negate(_MIPD_ zzn3 *x,zzn3 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(177) + zzn3_copy(x,w); + nres_negate(_MIPP_ w->a,w->a); + nres_negate(_MIPP_ w->b,w->b); + nres_negate(_MIPP_ w->c,w->c); + MR_OUT +} + +void zzn3_powq(_MIPD_ zzn3 *x,zzn3 *w) +{ /* sru - precalculated sixth root of unity */ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + MR_IN(178) + zzn3_copy(x,w); + nres_modmult(_MIPP_ mr_mip->sru,mr_mip->sru,mr_mip->w1); /* cube root of unity */ + nres_modmult(_MIPP_ w->b,mr_mip->w1,w->b); + nres_modmult(_MIPP_ w->c,mr_mip->w1,w->c); + nres_modmult(_MIPP_ w->c,mr_mip->w1,w->c); + + MR_OUT +} + +void zzn3_set(_MIPD_ int cnr,big sru) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + mr_mip->cnr=cnr; + nres(_MIPP_ sru,mr_mip->sru); +} + +void zzn3_add(_MIPD_ zzn3 *x,zzn3 *y,zzn3 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(180) + nres_modadd(_MIPP_ x->a,y->a,w->a); + nres_modadd(_MIPP_ x->b,y->b,w->b); + + nres_modadd(_MIPP_ x->c,y->c,w->c); + + MR_OUT +} + +void zzn3_sadd(_MIPD_ zzn3 *x,big y,zzn3 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(181) + nres_modadd(_MIPP_ x->a,y,w->a); + MR_OUT +} + +void zzn3_sub(_MIPD_ zzn3 *x,zzn3 *y,zzn3 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(182) + nres_modsub(_MIPP_ x->a,y->a,w->a); + nres_modsub(_MIPP_ x->b,y->b,w->b); + nres_modsub(_MIPP_ x->c,y->c,w->c); + MR_OUT +} + +void zzn3_ssub(_MIPD_ zzn3 *x,big y,zzn3 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(183) + nres_modsub(_MIPP_ x->a,y,w->a); + MR_OUT +} + +void zzn3_smul(_MIPD_ zzn3 *x,big y,zzn3 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(184) + if (size(x->a)!=0) nres_modmult(_MIPP_ x->a,y,w->a); + else zero(w->a); + if (size(x->b)!=0) nres_modmult(_MIPP_ x->b,y,w->b); + else zero(w->b); + if (size(x->c)!=0) nres_modmult(_MIPP_ x->c,y,w->c); + else zero(w->c); + + MR_OUT +} + +void zzn3_imul(_MIPD_ zzn3 *x,int y,zzn3 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(185) + if (size(x->a)!=0) nres_premult(_MIPP_ x->a,y,w->a); + else zero(w->a); + if (size(x->b)!=0) nres_premult(_MIPP_ x->b,y,w->b); + else zero(w->b); + if (size(x->c)!=0) nres_premult(_MIPP_ x->c,y,w->c); + else zero(w->c); + + MR_OUT +} + +void zzn3_mul(_MIPD_ zzn3 *x,zzn3 *y,zzn3 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + + if (mr_mip->ERNUM) return; + MR_IN(186) + + if (x==y) + { /* Chung-Hasan SQR2 */ + nres_modmult(_MIPP_ x->a,x->a,mr_mip->w1); + nres_modmult(_MIPP_ x->b,x->c,mr_mip->w2); + nres_modadd(_MIPP_ mr_mip->w2,mr_mip->w2,mr_mip->w2); + nres_modmult(_MIPP_ x->c,x->c,mr_mip->w3); + nres_modmult(_MIPP_ x->a,x->b,mr_mip->w4); + nres_modadd(_MIPP_ mr_mip->w4,mr_mip->w4,mr_mip->w4); + + nres_modadd(_MIPP_ x->a,x->b,mr_mip->w5); + nres_modadd(_MIPP_ mr_mip->w5,x->c,w->c); + nres_modmult(_MIPP_ w->c,w->c,w->c); + + nres_premult(_MIPP_ mr_mip->w2,mr_mip->cnr,w->a); + nres_modadd(_MIPP_ mr_mip->w1,w->a,w->a); + nres_premult(_MIPP_ mr_mip->w3,mr_mip->cnr,w->b); + nres_modadd(_MIPP_ mr_mip->w4,w->b,w->b); + + nres_modsub(_MIPP_ w->c,mr_mip->w1,w->c); + nres_modsub(_MIPP_ w->c,mr_mip->w2,w->c); + nres_modsub(_MIPP_ w->c,mr_mip->w3,w->c); + nres_modsub(_MIPP_ w->c,mr_mip->w4,w->c); + } + else + { + nres_modmult(_MIPP_ x->a,y->a,mr_mip->w1); /* Z0 */ + nres_modmult(_MIPP_ x->b,y->b,mr_mip->w2); /* Z2 */ + nres_modmult(_MIPP_ x->c,y->c,mr_mip->w3); /* Z4 */ + + nres_modadd(_MIPP_ x->a,x->b,mr_mip->w4); + nres_modadd(_MIPP_ y->a,y->b,mr_mip->w5); + nres_modmult(_MIPP_ mr_mip->w4,mr_mip->w5,mr_mip->w6); /* Z1 */ + nres_modsub(_MIPP_ mr_mip->w6,mr_mip->w1,mr_mip->w6); + nres_modsub(_MIPP_ mr_mip->w6,mr_mip->w2,mr_mip->w6); + + nres_modadd(_MIPP_ x->b,x->c,mr_mip->w4); + nres_modadd(_MIPP_ y->b,y->c,mr_mip->w5); + nres_modmult(_MIPP_ mr_mip->w4,mr_mip->w5,w->b); /* Z3 */ + + nres_modadd(_MIPP_ x->a,x->c,mr_mip->w4); + nres_modadd(_MIPP_ y->a,y->c,mr_mip->w5); + + nres_modsub(_MIPP_ w->b,mr_mip->w2,w->b); + nres_modsub(_MIPP_ w->b,mr_mip->w3,w->b); + nres_premult(_MIPP_ w->b,mr_mip->cnr,w->a); + + nres_modmult(_MIPP_ mr_mip->w4,mr_mip->w5,mr_mip->w4); + nres_modadd(_MIPP_ mr_mip->w2,mr_mip->w4,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w2,mr_mip->w1,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w2,mr_mip->w3,w->c); + + nres_modadd(_MIPP_ w->a,mr_mip->w1,w->a); + nres_premult(_MIPP_ mr_mip->w3,mr_mip->cnr,w->b); + nres_modadd(_MIPP_ w->b,mr_mip->w6,w->b); + } + + MR_OUT +} + +void zzn3_inv(_MIPD_ zzn3 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(187) + + nres_modmult(_MIPP_ w->a,w->a,mr_mip->w1); + nres_modmult(_MIPP_ w->b,w->c,mr_mip->w2); + + nres_premult(_MIPP_ mr_mip->w2,mr_mip->cnr,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w3); + + nres_modmult(_MIPP_ w->c,w->c,mr_mip->w1); + nres_modmult(_MIPP_ w->a,w->b,mr_mip->w2); + + nres_premult(_MIPP_ mr_mip->w1,mr_mip->cnr,mr_mip->w1); + nres_modsub(_MIPP_ mr_mip->w2,mr_mip->w1,mr_mip->w4); + nres_negate(_MIPP_ mr_mip->w4,mr_mip->w4); + + nres_modmult(_MIPP_ w->b,w->b,mr_mip->w1); + nres_modmult(_MIPP_ w->a,w->c,mr_mip->w2); + nres_modsub(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w5); + + nres_modmult(_MIPP_ w->b,mr_mip->w5,mr_mip->w1); + nres_modmult(_MIPP_ w->c,mr_mip->w4,mr_mip->w2); + nres_modadd(_MIPP_ mr_mip->w2,mr_mip->w1,mr_mip->w2); + nres_premult(_MIPP_ mr_mip->w2,mr_mip->cnr,mr_mip->w2); + nres_modmult(_MIPP_ w->a,mr_mip->w3,mr_mip->w1); + nres_modadd(_MIPP_ mr_mip->w1,mr_mip->w2,mr_mip->w1); + + copy(mr_mip->w3,w->a); + copy(mr_mip->w4,w->b); + copy(mr_mip->w5,w->c); + + redc(_MIPP_ mr_mip->w1,mr_mip->w6); + invmodp(_MIPP_ mr_mip->w6,mr_mip->modulus,mr_mip->w6); + nres(_MIPP_ mr_mip->w6,mr_mip->w6); + + nres_modmult(_MIPP_ w->a,mr_mip->w6,w->a); + nres_modmult(_MIPP_ w->b,mr_mip->w6,w->b); + nres_modmult(_MIPP_ w->c,mr_mip->w6,w->c); + + MR_OUT +} + +/* divide zzn3 by 2 */ + +void zzn3_div2(_MIPD_ zzn3 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(188) + copy(w->a,mr_mip->w1); + if (remain(_MIPP_ mr_mip->w1,2)!=0) + add(_MIPP_ mr_mip->w1,mr_mip->modulus,mr_mip->w1); + subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1); + copy(mr_mip->w1,w->a); + + copy(w->b,mr_mip->w1); + if (remain(_MIPP_ mr_mip->w1,2)!=0) + add(_MIPP_ mr_mip->w1,mr_mip->modulus,mr_mip->w1); + subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1); + copy(mr_mip->w1,w->b); + + copy(w->c,mr_mip->w1); + if (remain(_MIPP_ mr_mip->w1,2)!=0) + add(_MIPP_ mr_mip->w1,mr_mip->modulus,mr_mip->w1); + subdiv(_MIPP_ mr_mip->w1,2,mr_mip->w1); + copy(mr_mip->w1,w->c); + + MR_OUT +} + +/* multiply zzn3 by i */ + +void zzn3_timesi(_MIPD_ zzn3 *u) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(189) + + copy(u->a,mr_mip->w1); + nres_premult(_MIPP_ u->c,mr_mip->cnr,u->a); + copy(u->b,u->c); + copy(mr_mip->w1,u->b); + + MR_OUT +} + +/* multiply zzn3 by i^2 */ + +void zzn3_timesi2(_MIPD_ zzn3 *u) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(224) + + copy(u->a,mr_mip->w1); + nres_premult(_MIPP_ u->b,mr_mip->cnr,u->a); + nres_premult(_MIPP_ u->c,mr_mip->cnr,u->b); + copy(mr_mip->w1,u->c); + + MR_OUT +} diff --git a/miracl/source/mrzzn4.c b/miracl/source/mrzzn4.c new file mode 100644 index 0000000..15d7b15 --- /dev/null +++ b/miracl/source/mrzzn4.c @@ -0,0 +1,439 @@ + +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* + * MIRACL F_p^4 support functions + * mrzzn4.c + */ + +#include +#include "miracl.h" + +#define FUNC_BASE 226 + +BOOL zzn4_iszero(zzn4 *x) +{ + if (zzn2_iszero(&(x->a)) && zzn2_iszero(&(x->b))) return TRUE; + return FALSE; +} + +BOOL zzn4_isunity(_MIPD_ zzn4 *x) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM || !zzn2_iszero(&(x->b))) return FALSE; + + if (zzn2_isunity(_MIPP_ &x->a)) return TRUE; + return FALSE; +} + +BOOL zzn4_compare(zzn4 *x,zzn4 *y) +{ + if (zzn2_compare(&(x->a),&(y->a)) && zzn2_compare(&(x->b),&(y->b))) return TRUE; + return FALSE; +} + +void zzn4_from_int(_MIPD_ int i,zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(FUNC_BASE+0) + if (i==1) + { + copy(mr_mip->one,w->a.a); + w->unitary=TRUE; + } + else + { + convert(_MIPP_ i,mr_mip->w1); + nres(_MIPP_ mr_mip->w1,(w->a).a); + w->unitary=FALSE; + } + zero((w->a).b); + zero((w->b).a); + zero((w->b).b); + + MR_OUT +} + +void zzn4_copy(zzn4 *x,zzn4 *w) +{ + if (x==w) return; + zzn2_copy(&(x->a),&(w->a)); + zzn2_copy(&(x->b),&(w->b)); + w->unitary=x->unitary; +} + +void zzn4_zero(zzn4 *w) +{ + zzn2_zero(&(w->a)); + zzn2_zero(&(w->b)); + w->unitary=FALSE; +} + +void zzn4_from_zzn2s(zzn2 *x,zzn2 *y,zzn4 *w) +{ + zzn2_copy(x,&(w->a)); + zzn2_copy(y,&(w->b)); + w->unitary=FALSE; +} + +void zzn4_from_zzn2(zzn2 *x,zzn4 *w) +{ + zzn2_copy(x,&(w->a)); + zzn2_zero(&(w->b)); + w->unitary=FALSE; +} + +void zzn4_from_zzn2h(zzn2 *x,zzn4 *w) +{ + zzn2_copy(x,&(w->b)); + zzn2_zero(&(w->a)); + w->unitary=FALSE; +} + +void zzn4_from_zzn(big x,zzn4 *w) +{ + zzn2_from_zzn(x,&(w->a)); + zzn2_zero(&(w->b)); + w->unitary=FALSE; +} + +void zzn4_from_big(_MIPD_ big x, zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(FUNC_BASE+16) + zzn2_from_big(_MIPP_ x,&(w->a)); + zzn2_zero(&(w->b)); + MR_OUT +} + +void zzn4_negate(_MIPD_ zzn4 *x,zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(FUNC_BASE+1) + zzn4_copy(x,w); + zzn2_negate(_MIPP_ &(w->a),&(w->a)); + zzn2_negate(_MIPP_ &(w->b),&(w->b)); + MR_OUT +} + +void zzn4_conj(_MIPD_ zzn4 *x,zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + MR_IN(FUNC_BASE+2) + if (mr_mip->ERNUM) return; + zzn4_copy(x,w); + zzn2_negate(_MIPP_ &(w->b),&(w->b)); + MR_OUT +} + +void zzn4_add(_MIPD_ zzn4 *x,zzn4 *y,zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(FUNC_BASE+3) + zzn2_add(_MIPP_ &(x->a),&(y->a),&(w->a)); + zzn2_add(_MIPP_ &(x->b),&(y->b),&(w->b)); + w->unitary=FALSE; + MR_OUT +} + +void zzn4_sadd(_MIPD_ zzn4 *x,zzn2 *y,zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(FUNC_BASE+4) + zzn2_add(_MIPP_ &(x->a),y,&(w->a)); + w->unitary=FALSE; + MR_OUT +} + +void zzn4_sub(_MIPD_ zzn4 *x,zzn4 *y,zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(FUNC_BASE+5) + zzn2_sub(_MIPP_ &(x->a),&(y->a),&(w->a)); + zzn2_sub(_MIPP_ &(x->b),&(y->b),&(w->b)); + w->unitary=FALSE; + + MR_OUT +} + +void zzn4_ssub(_MIPD_ zzn4 *x,zzn2 *y,zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + + MR_IN(FUNC_BASE+6) + zzn2_sub(_MIPP_ &(x->a),y,&(w->a)); + w->unitary=FALSE; + + MR_OUT +} + +void zzn4_smul(_MIPD_ zzn4 *x,zzn2 *y,zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(FUNC_BASE+7) + if (!zzn2_iszero(&(x->a))) zzn2_mul(_MIPP_ &(x->a),y,&(w->a)); + else zzn2_zero(&(w->a)); + if (!zzn2_iszero(&(x->b))) zzn2_mul(_MIPP_ &(x->b),y,&(w->b)); + else zzn2_zero(&(w->b)); + w->unitary=FALSE; + + MR_OUT +} + +void zzn4_lmul(_MIPD_ zzn4 *x,big y,zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(FUNC_BASE+15) + + if (!zzn2_iszero(&(x->a))) zzn2_smul(_MIPP_ &(x->a),y,&(w->a)); + else zzn2_zero(&(w->a)); + if (!zzn2_iszero(&(x->b))) zzn2_smul(_MIPP_ &(x->b),y,&(w->b)); + else zzn2_zero(&(w->b)); + w->unitary=FALSE; + + MR_OUT +} + + +void zzn4_imul(_MIPD_ zzn4 *x,int y,zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(FUNC_BASE+14) + zzn2_imul(_MIPP_ &(x->a),y,&(w->a)); + zzn2_imul(_MIPP_ &(x->b),y,&(w->b)); + + MR_OUT +} + +void zzn4_sqr(_MIPD_ zzn4 *x,zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zzn2 t1,t2; + if (mr_mip->ERNUM) return; + + MR_IN(FUNC_BASE+8) + + t1.a=mr_mip->w10; + t1.b=mr_mip->w11; + t2.a=mr_mip->w8; + t2.b=mr_mip->w9; + + zzn4_copy(x,w); + if (x->unitary) + { /* this is a lot faster.. - see Lenstra & Stam */ + zzn2_mul(_MIPP_ &(w->b),&(w->b),&t1); + zzn2_add(_MIPP_ &(w->b),&(w->a),&(w->b)); + zzn2_mul(_MIPP_ &(w->b),&(w->b),&(w->b)); + zzn2_sub(_MIPP_ &(w->b),&t1,&(w->b)); + zzn2_txx(_MIPP_ &t1); + zzn2_copy(&t1,&(w->a)); + zzn2_sub(_MIPP_ &(w->b),&(w->a),&(w->b)); + zzn2_add(_MIPP_ &(w->a),&(w->a),&(w->a)); + zzn2_sadd(_MIPP_ &(w->a),mr_mip->one,&(w->a)); + zzn2_ssub(_MIPP_ &(w->b),mr_mip->one,&(w->b)); + } + else + { + zzn2_copy(&(w->b),&t2); // t2=b; + zzn2_add(_MIPP_ &(w->a),&t2,&t1); // t1=a+b + + zzn2_txx(_MIPP_ &t2); + zzn2_add(_MIPP_ &t2,&(w->a),&t2); // t2=a+txx(b) + + zzn2_mul(_MIPP_ &(w->b),&(w->a),&(w->b)); // b*=a + zzn2_mul(_MIPP_ &t1,&t2,&(w->a)); // a=t1*t2 + + zzn2_copy(&(w->b),&t2); //t2=b + zzn2_sub(_MIPP_ &(w->a),&t2,&(w->a)); //a-=b + zzn2_txx(_MIPP_ &t2); // t2=txx(b) + zzn2_sub(_MIPP_ &(w->a),&t2,&(w->a)); // a-=txx(b); + zzn2_add(_MIPP_ &(w->b),&(w->b),&(w->b)); // b+=b; + + } + + MR_OUT +} + +void zzn4_mul(_MIPD_ zzn4 *x,zzn4 *y,zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zzn2 t1,t2,t3; + if (mr_mip->ERNUM) return; + if (x==y) {zzn4_sqr(_MIPP_ x,w); return; } + MR_IN(FUNC_BASE+9) + + t1.a=mr_mip->w12; + t1.b=mr_mip->w13; + t2.a=mr_mip->w8; + t2.b=mr_mip->w9; + t3.a=mr_mip->w10; + t3.b=mr_mip->w11; + zzn2_copy(&(x->a),&t1); + zzn2_copy(&(x->b),&t2); + zzn2_mul(_MIPP_ &t1,&(y->a),&t1); /* t1= x->a * y->a */ + zzn2_mul(_MIPP_ &t2,&(y->b),&t2); /* t2 = x->b * y->b */ + zzn2_copy(&(y->a),&t3); + zzn2_add(_MIPP_ &t3,&(y->b),&t3); /* y->a + y->b */ + + zzn2_add(_MIPP_ &(x->b),&(x->a),&(w->b)); /* x->a + x->b */ + zzn2_mul(_MIPP_ &(w->b),&t3,&(w->b)); /* t3= (x->a + x->b)*(y->a + y->b) */ + zzn2_sub(_MIPP_ &(w->b),&t1,&(w->b)); + zzn2_sub(_MIPP_ &(w->b),&t2,&(w->b)); /* w->b = t3-(t1+t2) */ + zzn2_copy(&t1,&(w->a)); + zzn2_txx(_MIPP_ &t2); + zzn2_add(_MIPP_ &(w->a),&t2,&(w->a)); /* w->a = t1+tx(t2) */ + if (x->unitary && y->unitary) w->unitary=TRUE; + else w->unitary=FALSE; + + MR_OUT +} + +void zzn4_inv(_MIPD_ zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zzn2 t1,t2; + if (mr_mip->ERNUM) return; + if (w->unitary) + { + zzn4_conj(_MIPP_ w,w); + return; + } + MR_IN(FUNC_BASE+10) + + t1.a=mr_mip->w8; + t1.b=mr_mip->w9; + t2.a=mr_mip->w10; + t2.b=mr_mip->w11; + zzn2_mul(_MIPP_ &(w->a),&(w->a),&t1); + zzn2_mul(_MIPP_ &(w->b),&(w->b),&t2); + zzn2_txx(_MIPP_ &t2); + zzn2_sub(_MIPP_ &t1,&t2,&t1); + zzn2_inv(_MIPP_ &t1); + zzn2_mul(_MIPP_ &(w->a),&t1,&(w->a)); + zzn2_negate(_MIPP_ &t1,&t1); + zzn2_mul(_MIPP_ &(w->b),&t1,&(w->b)); + + MR_OUT +} + +/* divide zzn4 by 2 */ + +void zzn4_div2(_MIPD_ zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + if (mr_mip->ERNUM) return; + MR_IN(FUNC_BASE+11) + + zzn2_div2(_MIPP_ &(w->a)); + zzn2_div2(_MIPP_ &(w->b)); + w->unitary=FALSE; + + MR_OUT +} + +void zzn4_powq(_MIPD_ zzn2 *fr,zzn4 *w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + MR_IN(FUNC_BASE+12) + zzn2_conj(_MIPP_ &(w->a),&(w->a)); + zzn2_conj(_MIPP_ &(w->b),&(w->b)); + zzn2_mul(_MIPP_ &(w->b),fr,&(w->b)); + MR_OUT +} + +void zzn4_tx(_MIPD_ zzn4* w) +{ +#ifdef MR_OS_THREADS + miracl *mr_mip=get_mip(); +#endif + zzn2 t; + MR_IN(FUNC_BASE+13) + + t.a=mr_mip->w8; + t.b=mr_mip->w9; + zzn2_copy(&(w->b),&t); + zzn2_txx(_MIPP_ &t); + zzn2_copy(&(w->a),&(w->b)); + zzn2_copy(&t,&(w->a)); + + MR_OUT +} diff --git a/miracl/source/ms86.mcs b/miracl/source/ms86.mcs new file mode 100644 index 0000000..85c1f32 --- /dev/null +++ b/miracl/source/ms86.mcs @@ -0,0 +1,457 @@ +; MCS macro file for Microsoft/Borland compilers +; +; Triple register is cl|DDI|DBP +; MUL_START. Initialise registers. Make PBX and PSI point to multipliers a +; and b. PDI points at result c. Note PDI is shared. +; Initialise Triple register to 0 +; See makemcs.txt for more information about this file. +; + +MACRO PMUL_START + ASM { + push PBP + push DDI + push DSI + mov PBX,a + mov DSI,b + mov PDI,c + xor DCX,DCX + mov DBP,sn +ENDM + +MACRO PMUL + mov DAX,DBP + mul POINTER [PBX+N*%d] + add DAX,DCX + adc DDX,0 + mov DCX,DDX + mov POINTER [PSI+N*%d],0 + mov [PDI+N*%d],DAX +ENDM + +MACRO PMUL_END + mov DAX,DBP + mul DCX + mov [PSI],DAX + mov [PSI+N],DDX + pop DSI + pop DDI + pop PBP + } +ENDM + +MACRO MUL_START + ASM { + push PBP + push DDI + push DSI + mov PBX,a + mov PSI,b + mov PDI,c + push PDI + xor DCX,DCX + xor DDI,DDI + xor DBP,DBP +ENDM +; +; STEP macro. Calculates a double-register partial product +; and adds it to the triple register total +; Parameters 1 & 2: Indices i and j for partial product multipliers a[i] +; and b[j] +MACRO STEP + mov DAX,[PBX+N*%d] + mul POINTER [PSI+N*%d] + add DBP,DAX + adc DDI,DDX + adc cl,ch +ENDM +; +; MFIN macro. Finish column calculation. Store Sum for this column +; and get Carry for next +; Parameter 1: Index k for Column Sum c[k] +MACRO MFIN + mov DDX,DDI + pop PDI + mov [PDI+N*%d],DBP + push PDI + mov DBP,DDX + mov DDI,DCX + xor cl,cl +ENDM +; +; MUL_END +; Parameter 1: Index for final carry c[.] +MACRO MUL_END + pop PDI + mov [PDI+N*%d],DBP + pop DSI + pop DDI + pop PBP + } +ENDM +; +; LAST +; +MACRO LAST + mov DAX,[PBX+N*%d] + mul POINTER [PSI+N*%d] + add DBP,DAX +ENDM +; +; SQR_START +; +MACRO SQR_START + ASM { + push PBP + push DDI + push DSI + mov PBX,a + mov PSI,c + xor DCX,DCX + xor DDI,DDI + xor DBP,DBP +ENDM +; +; DSTEP macro. Calculates a double-register partial product +; and add it twice to a triple register total +; Parameters 1 & 2 : Indices of partial product multipliers +MACRO DSTEP + mov DAX,[PBX+N*%d] + mul POINTER [PBX+N*%d] + add DBP,DAX + adc DDI,DDX + adc cl,ch + add DBP,DAX + adc DDI,DDX + adc cl,ch +ENDM +; +; SELF macro. Calculate the double-register square and +; add it to a triple register total +; Parameter 1 : Index of diagonal element +MACRO SELF + mov DAX,[PBX+N*%d] + mul DAX + add DBP,DAX + adc DDI,DDX + adc cl,ch +ENDM +; +; SFIN macro. Finish column calculation for squaring. Store Sum +; and get Carry for next column. +; Parameter 1: Index of Column Sum +MACRO SFIN + mov [PSI+N*%d],DBP + mov DBP,DDI + mov DDI,DCX + xor cl,cl +ENDM +; +; SQR_END +; Parameter 1: Index for final carry +MACRO SQR_END + mov [PSI+N*%d],DBP + pop DSI + pop DDI + pop PBP + } +ENDM +; +; REDC_START macro +; +MACRO REDC_START + ASM { + push PBP + push DDI + push DSI + mov PBX,a + mov PSI,b + mov DDX,ndash + push DDX + xor DDI,DDI + xor DCX,DCX + mov DBP,[PBX] +ENDM +; +; RFINU macro +; +MACRO RFINU + mov DAX,DBP + pop DDX + push DDX + mul DDX + mov [PBX+N*%d],DAX + mul POINTER [PSI] + add DBP,DAX + adc DDI,DDX + adc cl,ch + mov DBP,DDI + mov DDI,DCX + xor DCX,DCX + add DBP,[PBX+N*(%d+1)] + adc DDI,DCX +ENDM +; +; RFIND macro +; +MACRO RFIND + mov [PBX+N*%d],DBP + mov DBP,DDI + mov DDI,DCX + xor DCX,DCX + add DBP,[PBX+N*(%d+1)] + adc DDI,DCX +ENDM +; +; REDC_END +; +MACRO REDC_END + mov [PBX+N*%d],DBP + mov [PBX+N*(%d+1)],DDI + pop DDX + pop DSI + pop DDI + pop PBP + } +ENDM +; +; ADD_START macro - initialise for add/subtract. Do the first one. +; +MACRO ADD_START + ASM { + push PSI + push PDI + mov PSI,a + mov PBX,b + mov PDI,c + mov DAX,[PSI] + add DAX,[PBX] + mov [PDI],DAX +ENDM +; +; ADD macro. Add two numbers from memory and store result in memory. +; Don't forget carry bit +; +MACRO ADD + mov DAX,[PSI+N*%d] + adc DAX,[PBX+N*%d] + mov [PDI+N*%d],DAX +ENDM +; +; ADD_END macro. Catch Carry +; +MACRO ADD_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + pop PDI + pop PSI + } +ENDM +; +; DOUBLE_START macro +; +MACRO DOUBLE_START + ASM { + mov PBX,a + mov DAX,[PBX] + add [PBX],DAX +ENDM +; +; DOUBLE macro +; +MACRO DOUBLE + mov DAX,[PBX+N*%d] + adc [PBX+N*%d],DAX +ENDM +; +; DOUBLE_END +; +MACRO DOUBLE_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + } +ENDM +; +; INC_START macro - initialise for increment/decrement. Do first one. +; add b[0] to a[0] +MACRO INC_START + ASM { + push PDI + mov PBX,b + mov PDI,a + mov DAX,[PBX] + add [PDI],DAX +ENDM +; +; INC macro. Increment number in memory. Don't forget carry +; +MACRO INC + mov DAX,[PBX+N*%d] + adc [PDI+N*%d],DAX +ENDM +; +; INC_END macro. Catch Carry +; +MACRO INC_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + pop PDI + } +ENDM +; +; SUB_START macro. Do first one +; +MACRO SUB_START + ASM { + push PSI + push PDI + mov PSI,a + mov PBX,b + mov PDI,c + mov DAX,[PSI] + sub DAX,[PBX] + mov [PDI],DAX +ENDM +; +; SUB macro. Subtract two numbers in memory and store result in memory. +; +MACRO SUB + mov DAX,[PSI+N*%d] + sbb DAX,[PBX+N*%d] + mov [PDI+N*%d],DAX +ENDM +; +; SUB_END macro +; +MACRO SUB_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + pop PDI + pop PSI + } +ENDM +; +; DEC_START macro +; +MACRO DEC_START + ASM { + push PDI + mov PBX,b + mov PDI,a + mov DAX,[PBX] + sub [PDI],DAX +ENDM +; +; DEC macro. Decrement from number in memory. Don't forget borrow. +; +MACRO DEC + mov DAX,[PBX+N*%d] + sbb [PDI+N*%d],DAX +ENDM +; +; DEC_END macro. Catch carry +; +MACRO DEC_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + pop PDI + } +ENDM +; +; KADD_START macro. Zero carry flag. +; +MACRO KADD_START + ASM { + push PSI + push PDI + mov PSI,a + mov PBX,b + mov PDI,c + mov PCX,n + xor DAX,DAX + k%d: +ENDM +; +; KASL macro. Important that carry flag is undisturbed +; +MACRO KASL + dec PCX + je k%d + lea PSI,[PSI+N*%d] + lea PBX,[PBX+N*%d] + lea PDI,[PDI+N*%d] + jmp k%d + k%d: +ENDM +; +; KADD_END macro +; +MACRO KADD_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + pop PDI + pop PSI + } +ENDM +; +; KINC_START macro. Zero Carry Flag +; +MACRO KINC_START + ASM { + push PDI + mov PDI,a + mov PBX,b + mov PCX,n + xor DAX,DAX + k%d: +ENDM +; +; KIDL macro. Important that carry flag is undisturbed! +; +MACRO KIDL + dec PCX + je k%d + lea PBX,[PBX+N*%d] + lea PDI,[PDI+N*%d] + jmp k%d + k%d: +ENDM +; +; KINC_END macro +; +MACRO KINC_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + pop PDI + } +ENDM +; +; KDEC_START macro. Zero Carry flag +; +MACRO KDEC_START + ASM { + push PDI + mov PDI,a + mov PBX,b + mov PCX,n + xor DAX,DAX + k%d: +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + mov DAX,0 + adc DAX,DAX + mov carry,DAX + pop PDI + } +ENDM + diff --git a/miracl/source/msp430.mcs b/miracl/source/msp430.mcs new file mode 100644 index 0000000..3b3a7be --- /dev/null +++ b/miracl/source/msp430.mcs @@ -0,0 +1,471 @@ +; Comba/KCM Macros for TI msp430 +; +; The latest version of the IAR Workbench C compiler seems to have forgotten how to +; handle local variables in inline assembly language, so you might have to go and +; change a, b, c and carry in mrcomba.c to the actual registers assigned by the +; compiler. Look at the assembler .s output file to figure this. +; +; Alternatively replace a, b, c and carry with globals g_a, g_b, g_c and g_carry, as +; the compiler inline assembly does seem to recognise global variables. So at file +; scope of mrcomba.c place +; +; static mr_small *g_a,*g_b,*g_c,g_carry; +; +; and modify all references to a, b, c and carry in mrcomba.c to g_a,g_b,g_c and g_carry +; +; See ecdhp16.c for an example that uses this file +; +; Triple register is r8|r7|r6 +; +; See makemcs.txt for more information about this file +; +; Contributed by Piotr Szczechowiak +; (uses hardware multiplier) +; +MACRO MUL_START + __asm ( + "PUSH r10\n" + "PUSH r11\n" + "PUSH r12\n" + "MOV &a,r10\n" + "MOV &b,r11\n" + "MOV &c,r12\n" + "PUSH r8\n" + "PUSH r7\n" + "PUSH r6\n" + "PUSH r5\n" + + "CLR r8\n" + "CLR r7\n" + "CLR r6\n" + "CLR r5\n" +ENDM +; +; STEP macros +; +MACRO STEP + "MOV (2*%d)(r10),r15\n" + "MOV r15,&0130h\n" + "MOV (2*%d)(r11),r15\n" + "MOV r15,&0138h\n" + "ADD &013Ah,r6\n" + "ADDC &013Ch,r7\n" + "ADDC r5,r8\n" +ENDM +; +; MFIN macro +; +MACRO MFIN + "MOV r6,(2*%d)(r12)\n" + "MOV r7,r6\n" + "MOV r8,r7\n" + "CLR r8\n" +ENDM +; +; LAST +; +MACRO LAST + "MOV (2*%d)(r10),r15\n" + "MOV r15,&0130h\n" + "MOV (2*%d)(r11),r15\n" + "MOV r15,&0138h\n" + "ADD &013Ah,r6\n" +ENDM +; +; MULE +; +MACRO MUL_END + "MOV r6,(2*%d)(r12)\n" + "POP r5\n" + "POP r6\n" + "POP r7\n" + "POP r8\n" + "POP r12\n" + "POP r11\n" + "POP r10\n" + ); +ENDM +; +; SQR_START +; +MACRO SQR_START + __asm ( + "PUSH r10\n" + "PUSH r12\n" + "MOV &a,r10\n" + "MOV &c,r12\n" + "PUSH r8\n" + "PUSH r7\n" + "PUSH r6\n" + "PUSH r5\n" + "CLR r8\n" + "CLR r7\n" + "CLR r6\n" + "CLR r5\n" +ENDM +; +; DSTEP +; +MACRO DSTEP + "MOV (2*%d)(r10),r15\n" + "MOV r15,&0130h\n" + "MOV (2*%d)(r10),r15\n" + "MOV r15,&0138h\n" + "ADD &013Ah,r6\n" + "ADDC &013Ch,r7\n" + "ADDC r5,r8\n" + "ADD &013Ah,r6\n" + "ADDC &013Ch,r7\n" + "ADDC r5,r8\n" +ENDM +; +; SELF +; +MACRO SELF + "MOV (2*%d)(r10),r15\n" + "MOV r15,&0130h\n" + "MOV r15,&0138h\n" + "ADD &013Ah,r6\n" + "ADDC &013Ch,r7\n" + "ADDC r5,r8\n" +ENDM +; +; SFIN +; +MACRO SFIN + "MOV r6,(2*%d)(r12)\n" + "MOV r7,r6\n" + "MOV r8,r7\n" + "CLR r8\n" +ENDM +; +; SQR_END +; +MACRO SQR_END + "MOV r6,(2*%d)(r12)\n" + "POP r5\n" + "POP r6\n" + "POP r7\n" + "POP r8\n" + "POP r12\n" + "POP r10\n" + ); +ENDM +; +; REDC_START +; +MACRO REDC_START + __asm ( + "PUSH r10\n" + "PUSH r11\n" + "PUSH r12\n" + "MOV &a,r10\n" + "MOV &b,r11\n" + "MOV &ndash,r12\n" + "PUSH r8\n" + "PUSH r7\n" + "PUSH r6\n" + "PUSH r5\n" + "CLR r8\n" + "CLR r7\n" + "MOV r10,r6\n" + "CLR r5\n" +ENDM +; +; RFINU macro +; +MACRO RFINU + "MOV r6,&0130h\n" + "MOV r12,&0138h\n" + "MOV &013Ah,(2*%d)(r10)\n" + "MOV r11,&0130h\n" + "MOV &013Ah,&0138h\n" + "ADD &013Ah,r6\n" + "ADDC &013Ch,r7\n" + "ADDC r5,r8\n" + "MOV r7,r6\n" + "MOV r8,r7\n" + "CLR r8\n" + "MOV (2*(%d+1))(r10),r15\n" + "ADD r15,r6\n" + "ADDC r5,r7\n" + "CLR r8\n" +ENDM +; +; RFIND macro +; +MACRO RFIND + "MOV r6,(2*%d)(r10)\n" + "MOV r7,r6\n" + "MOV r8,r7\n" + "CLR r8\n" + "MOV (2*(%d+1))(r10),r15\n" + "ADD r15,r6\n" + "ADDC r5,r7\n" + "CLR r8\n" +ENDM +; +; REDC_END macro +; +MACRO REDC_END + "MOV r6,(2*%d)(r10)\n" + "MOV r7,(2*(%d+1))(r10)\n" + "POP r5\n" + "POP r6\n" + "POP r7\n" + "POP r8\n" + "POP r12\n" + "POP r11\n" + "POP r10\n" + ); +ENDM +; +; ADD_START macro +; +MACRO ADD_START + __asm ( + "PUSH r10\n" + "PUSH r11\n" + "PUSH r12\n" + "PUSH r13\n" + "MOV &a,r10\n" + "MOV &b,r11\n" + "MOV &c,r12\n" + "MOV (2*0)(r10),r15\n" + "MOV (2*0)(r11),r13\n" + "ADD r13,r15\n" + "MOV r15,(2*0)(r12)\n" +ENDM +; +; ADD macro - c[.]=a[.]+b[.] +; +MACRO ADD + "MOV (2*%d)(r10),r15\n" + "MOV (2*%d)(r11),r13\n" + "ADDC r13,r15\n" + "MOV r15,(2*%d)(r12)\n" +ENDM +; +; ADD_END macro. +; +MACRO ADD_END + "CLR r15\n" + "ADC r15\n" + "MOV r15,&carry\n" + "POP r13\n" + "POP r12\n" + "POP r11\n" + "POP r10\n" + ); +ENDM +; +; INC_START macro. Do first one. +; +MACRO INC_START + __asm ( + "PUSH r10\n" + "PUSH r11\n" + "PUSH r13\n" + "MOV &a,r10\n" + "MOV &b,r11\n" + "MOV (2*0)(r10),r15\n" + "MOV (2*0)(r11),r13\n" + "ADD r13,r15\n" + "MOV r15,(2*0)(r10)\n" +ENDM +; +; INC macro a[.]+=b[.] +; +MACRO INC + "MOV (2*%d)(r10),r15\n" + "MOV (2*%d)(r11),r13\n" + "ADDC r13,r15\n" + "MOV r15,(2*%d)(r10)\n" +ENDM +MACRO INC_END + "CLR r15\n" + "ADC r15\n" + "MOV r15,&carry\n" + "POP r13\n" + "POP r11\n" + "POP r10\n" + ); +ENDM +MACRO SUB_START + __asm ( + "PUSH r10\n" + "PUSH r11\n" + "PUSH r12\n" + "PUSH r13\n" + "MOV &a,r10\n" + "MOV &b,r11\n" + "MOV &c,r12\n" + "MOV (2*0)(r10),r15\n" + "MOV (2*0)(r11),r13\n" + "SUB r13,r15\n" + "MOV r15,(2*0)(r12)\n" +ENDM +; +; SUB macro - c[.]=a[.]-b[.] +; +MACRO SUB + "MOV (2*%d)(r10),r15\n" + "MOV (2*%d)(r11),r13\n" + "SUBC r13,r15\n" + "MOV r15,(2*%d)(r12)\n" +ENDM +MACRO SUB_END + "CLR r15\n" + "ADC r15\n" + "XOR.B #1,r15\n" + "MOV r15,&carry\n" + "POP r13\n" + "POP r12\n" + "POP r11\n" + "POP r10\n" + ); +ENDM +; +; DEC_START macro +; +MACRO DEC_START + __asm ( + "PUSH r10\n" + "PUSH r11\n" + "PUSH r13\n" + "MOV &a,r10\n" + "MOV &b,r11\n" + "MOV (2*0)(r10),r15\n" + "MOV (2*0)(r11),r13\n" + "SUB r13,r15\n" + "MOV r15,(2*0)(r10)\n" +ENDM +; +; DEC macro a[.]-=b[.] +; +MACRO DEC + "MOV (2*%d)(r10),r15\n" + "MOV (2*%d)(r11),r13\n" + "SUBC r13,r15\n" + "MOV r15,(2*%d)(r10)\n" +ENDM +; +; DEC_END macro +; +MACRO DEC_END + "CLR r15\n" + "ADC r15\n" + "XOR.B #1,r15\n" + "MOV r15,&carry\n" + "POP r13\n" + "POP r11\n" + "POP r10\n" + ); +ENDM +; +; KADD_START macro. Zero Carry +; +MACRO KADD_START + "PUSH r10\n" + "PUSH r11\n" + "PUSH r12\n" + "PUSH r13\n" + "MOV &a,r10\n" + "MOV &b,r11\n" + "MOV &c,r12\n" + "MOV &n,r13\n" + "CLRC\n" + "k%d:\n" +ENDM +; +; KASL macro +; +MACRO KASL + "DEC r13\n" + "JZ k%d\n" + "CLR r15\n" + "ADC r15\n" + "ADD #(2*%d),r10\n" + "ADD #(2*%d),r11\n" + "ADD #(2*%d),r12\n" + "RRC r15\n" + "JMP k%d\n" + "k%d:\n" +ENDM +; +; KADD_END macro +; +MACRO KADD_END + "CLR r15\n" + "ADC r15\n" + "MOV r15,&carry\n" + "POP r13\n" + "POP r12\n" + "POP r11\n" + "POP r10\n" + ); +ENDM +; +; KINC_START macro +; +MACRO KINC_START + "PUSH r10\n" + "PUSH r11\n" + "PUSH r13\n" + "MOV &a,r10\n" + "MOV &b,r11\n" + "MOV &n,r13\n" + "CLRC\n" + "k%d:\n" +ENDM +; +; KIDL macro +; +MACRO KIDL + "DEC r13\n" + "JZ k%d\n" + "CLR r15\n" + "ADC r15\n" + "ADD #(2*%d),r10\n" + "ADD #(2*%d),r11\n" + "RRC r15\n" + "JMP k%d\n" + "k%d:\n" +ENDM +; +; KINC_END macro +; +MACRO KINC_END + "CLR r15\n" + "ADC r15\n" + "MOV r15,&carry\n" + "POP r13\n" + "POP r11\n" + "POP r10\n" + ); +ENDM +; +; KDEC_START macro. Zero carry +; +MACRO KDEC_START + "PUSH r10\n" + "PUSH r11\n" + "PUSH r13\n" + "MOV &a,r10\n" + "MOV &b,r11\n" + "MOV &n,r13\n" + "CLRC\n" + "k%d:\n" +ENDM +; +; KDEC_END macro +; +MACRO KDEC_END + "CLR r15\n" + "ADC r15\n" + "MOV r15,&carry\n" + "POP r13\n" + "POP r11\n" + "POP r10\n" + ); +ENDM diff --git a/miracl/source/my160.ecs b/miracl/source/my160.ecs new file mode 100644 index 0000000..4e40acd --- /dev/null +++ b/miracl/source/my160.ecs @@ -0,0 +1,7 @@ +160 +FFFFFFFFFFFF0000000000010000000000000001 +-3 +9D +FFFFFFFFFFFEFFFFFFFE593A36C9A36FC73935C3 +E1160583EF68E14CAC6787AD373E6AAD4E35A11E +570775746D02E48A761E5E8B63F0CE44F29E8460 diff --git a/miracl/source/newbasis.cpp b/miracl/source/newbasis.cpp new file mode 100644 index 0000000..b7d0153 --- /dev/null +++ b/miracl/source/newbasis.cpp @@ -0,0 +1,113 @@ +// +// cl /O2 /GX newbasis.cpp poly2.cpp gf2m.cpp big.cpp miracl.lib +// +// Program to convert a GF(2^m) value from one irreducible polynomial +// representation to another +// +// + +#include +#include "poly2.h" + +using namespace std; + +Miracl precision(50,0); + +int main(int argc,char **argv) +{ + miracl *mip=&precision; + Poly2 g,c,h,ut; + GF2m u,f,w[600],r; + Big t[600],a,d; + Variable x; + int i,ii,m,b,n,a1,b1,c1,a2,b2,c2,Base,ip; + + argv++; argc--; + if (argc!=8 && argc!=9) + { + cout << "Incorrect Usage" << endl; + cout << "Program converts a value from one polynomial basis to another" << endl; + cout << "newbasis " << endl; + cout << "for decimal , OR" << endl; + cout << "newbasis -h " << endl; + cout << "for in hex" << endl; + cout << "converts from basis x^m+x^a1+x^b1+x^c1+1 to basis x^m+x^a2+x^b2+x^c2+1" << endl; + return 0; + } + ip=0; + m=a1=b1=c1=a2=b2=c2=0; + mip->IOBASE=10; + if (strcmp(argv[0],"-h")==0) {mip->IOBASE=16; ip=1;} + + a=argv[ip]; + mip->IOBASE=10; + + m=atoi(argv[ip+1]); + a1=atoi(argv[ip+2]); + b1=atoi(argv[ip+3]); + c1=atoi(argv[ip+4]); + a2=atoi(argv[ip+5]); + b2=atoi(argv[ip+6]); + c2=atoi(argv[ip+7]); + + prepare_basis(m,a2,b2,c2,TRUE); // convert to this basis.. + g=pow2(x,m)+pow2(x,a1)+pow2(x,b1)+pow2(x,c1)+1; // from this basis + +// IEEE-1363 Algorithm A5.6, find a Root in GF (2m) of the Irreducible Binary Polynomial + + irand(6L); + + cout << "Finding root of irreducible polynomial...." << endl; + while (degree(g)>1) + { + u=random2(); + ut.addterm(u,1); + c=ut; + for (i=1;idegree(g)) g=g/h; + else g=h; + } + + r=g.coeff(0); + +// Now compute change-of-basis matrix - A7.3 +// This matrix t[.] can be precomputed and stored + + cout << "Now computing change of basis matrix..." << endl; + + w[0]=1; + for (i=1;i=0;n--) + { + t[n]=0; + for (i=m-1;i>=0;i--) + { + b=bit((Big)w[i],n); + t[n]=(t[n]<<1)+b; + } + } + +// Do the conversion + + cout << "Finally convert the value to new representation" << endl; + + d=0; + for (i=m-1;i>=0;i--) + { + b=ham(land(a,t[i]))%2; + d=(d<<1)+b; + } + + f=d; + + cout << (Big)f << " decimal" << endl; + mip->IOBASE=16; + cout << (Big)f << " hex" << endl; + + return 0; +} diff --git a/miracl/source/nist163.ecs b/miracl/source/nist163.ecs new file mode 100644 index 0000000..050ddb5 --- /dev/null +++ b/miracl/source/nist163.ecs @@ -0,0 +1,9 @@ +163 +1 +20A601907B8C953CA1481EB10512F78744A3205FD +40000000000000000000292FE77E70C12A4234C33 +3F0EBA16286A2D57EA0991168D4994637E8343E36 +D51FBC6C71A0094FA2CDD545B11C5C0C797324F1 +7 +6 +3 diff --git a/miracl/source/nist233.ecs b/miracl/source/nist233.ecs new file mode 100644 index 0000000..0c50b44 --- /dev/null +++ b/miracl/source/nist233.ecs @@ -0,0 +1,9 @@ +233 +1 +66647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD +1000000000000000000000000000013E974E72F8A6922031D2603CFE0D7 +FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B +1006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052 +74 +0 +0 diff --git a/miracl/source/nist283.ecs b/miracl/source/nist283.ecs new file mode 100644 index 0000000..3cca5c4 --- /dev/null +++ b/miracl/source/nist283.ecs @@ -0,0 +1,9 @@ +283 +1 +27B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5 +3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307 +5F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053 +3676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4 +12 +7 +5 diff --git a/miracl/source/nist571.ecs b/miracl/source/nist571.ecs new file mode 100644 index 0000000..26f594f --- /dev/null +++ b/miracl/source/nist571.ecs @@ -0,0 +1,9 @@ +571 +1 +2F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A +3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47 +303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19 +37BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B +10 +5 +2 diff --git a/miracl/source/p1363/ecdh.c b/miracl/source/p1363/ecdh.c new file mode 100644 index 0000000..d9b43c9 --- /dev/null +++ b/miracl/source/p1363/ecdh.c @@ -0,0 +1,1013 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ + +/* ECDH/ECIES/ECDSA Functions - see main program below */ + +/* Note that in production code miracl COMBA mechanism should be invoked for 2-3 times speed up */ +/* Use this mirdef.h for 32-bit processor - note no assembly required + +#define MR_LITTLE_ENDIAN +#define MIRACL 32 +#define mr_utype int +#define mr_dltype long long +#define mr_unsign64 unsigned long long +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define MR_ALWAYS_BINARY +#define MR_STATIC 8 +#define MR_GENERIC_MT +#define MR_STRIPPED_DOWN +#define MR_NOSUPPORT_COMPRESSION +#define MR_SIMPLE_BASE +#define MR_SIMPLE_IO +#define MR_NOASM +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 +*/ + +/* Use this mirdef.h for 64-bit processor + +#define MR_LITTLE_ENDIAN +#define MIRACL 64 +#define mr_utype long long +#define mr_unsign64 unsigned long long +#define MR_IBITS 32 +#define MR_LBITS 32 +#define mr_unsign32 unsigned int +#define MR_ALWAYS_BINARY +#define MR_STATIC 4 +#define MR_GENERIC_MT +#define MR_STRIPPED_DOWN +#define MR_NOSUPPORT_COMPRESSION +#define MR_SIMPLE_BASE +#define MR_SIMPLE_IO +#define MAXBASE ((mr_small)1<<(MIRACL-1)) +#define MR_BITSINCHAR 8 + +*/ + +/* Link to these files + +mrcore.c +mrarth0.c +mrarth1.c +mrarth2.c +mrio1.c +mrgcd.c +mrxgcd.c +mrarth3.c +mrbits.c +mrmonty.c +mrcurve.c +mraes.c +mrshs256.c +mrstrong.c + +For 64-bit build using Microsoft compiler mrmuldv.w64 must be included as well +For 64-bit build using Linux and Intel chips, mrmuldv.g64 must be included as well + + +To use COMBA speed-up, for 32-bit build add + +#define MR_COMBA 8 +#define MR_GENERALISED_MERSENNE +#define MR_SPECIAL + +For 64-bit build add + +#define MR_COMBA 4 +#define MR_GENERALISED_MERSENNE +#define MR_SPECIAL + + +to mirdef.h + +Also create mrcomba.c using MEX utility, and add mrcomba.c in build + +*/ + +#include +#include +#include +#include + +#include "ecdh.h" + +/* Elliptic Curve parameters - NIST P256 Curve */ + +#if MIRACL==64 + +const mr_small ecrom[]={ +0xffffffffffffffff,0xffffffff,0x0,0xffffffff00000001, +0x3bce3c3e27d2604b,0x651d06b0cc53b0f6,0xb3ebbd55769886bc,0x5ac635d8aa3a93e7, +0xf3b9cac2fc632551,0xbce6faada7179e84,0xffffffffffffffff,0xffffffff00000000, +0xf4a13945d898c296,0x77037d812deb33a0,0xf8bce6e563a440f2,0x6b17d1f2e12c4247, +0xcbb6406837bf51f5,0x2bce33576b315ece,0x8ee7eb4a7c0f9e16,0x4fe342e2fe1a7f9b}; + +#endif + +#if MIRACL==32 + +const mr_small ecrom[]={ +0xffffffff,0xffffffff,0xffffffff,0x0,0x0,0x0,0x1,0xffffffff, +0x27d2604b,0x3bce3c3e,0xcc53b0f6,0x651d06b0,0x769886bc,0xb3ebbd55,0xaa3a93e7,0x5ac635d8, +0xfc632551,0xf3b9cac2,0xa7179e84,0xbce6faad,0xffffffff,0xffffffff,0x0,0xffffffff, +0xd898c296,0xf4a13945,0x2deb33a0,0x77037d81,0x63a440f2,0xf8bce6e5,0xe12c4247,0x6b17d1f2, +0x37bf51f5,0xcbb64068,0x6b315ece,0x2bce3357,0x7c0f9e16,0x8ee7eb4a,0xfe1a7f9b,0x4fe342e2}; + +#endif + + +static void hash(octet *p,int n,octet *x,octet *y,octet *w) +{ + int i,hlen,c[4]; + HASHFUNC sha; + char hh[HASH_BYTES]; + + hlen=HASH_BYTES; + + SHS_INIT(&sha); + if (p!=NULL) + for (i=0;ilen;i++) SHS_PROCESS(&sha,p->val[i]); + if (n>0) + { + c[0]=(n>>24)&0xff; + c[1]=(n>>16)&0xff; + c[2]=(n>>8)&0xff; + c[3]=(n)&0xff; + for (i=0;i<4;i++) SHS_PROCESS(&sha,c[i]); + } + if (x!=NULL) + for (i=0;ilen;i++) SHS_PROCESS(&sha,x->val[i]); + if (y!=NULL) + for (i=0;ilen;i++) SHS_PROCESS(&sha,y->val[i]); + + + SHS_HASH(&sha,hh); + + OCTET_EMPTY(w); + OCTET_JOIN_BYTES(hh,hlen,w); + for (i=0;ilen,RAW->val,0L); +} + +void KILL_CSPRNG(csprng *RNG) +{ + strong_kill(RNG); +} + +BOOL HMAC(octet *m,octet *k,int olen,octet *tag) +{ +/* Input is from an octet m * + * olen is requested output length in bytes. k is the key * + * The output is the calculated tag */ + int i,hlen,b; + char h[HASH_BYTES],k0[HASH_BLOCK]; + octet H={0,sizeof(h),h}; + octet K0={0,sizeof(k0),k0}; + + hlen=HASH_BYTES; b=HASH_BLOCK; + if (olen<4 || olen>hlen) return FALSE; + + if (k->len > b) hash(k,-1,NULL,NULL,&K0); + else OCTET_COPY(k,&K0); + + OCTET_JOIN_BYTE(0,b-K0.len,&K0); + + OCTET_XOR_BYTE(0x36,&K0); + + hash(&K0,-1,m,NULL,&H); + + OCTET_XOR_BYTE(0x6a,&K0); /* 0x6a = 0x36 ^ 0x5c */ + hash(&K0,-1,&H,NULL,&H); + + OCTET_EMPTY(tag); + OCTET_JOIN_BYTES(H.val,olen,tag); + + return TRUE; +} + +/* Key Derivation Functions */ +/* Input octet z */ +/* Output key of length olen */ + +void KDF1(octet *z,int olen,octet *key) +{ + char h[HASH_BYTES]; + octet H={0,sizeof(h),h}; + int counter,cthreshold; + int hlen=HASH_BYTES; + + OCTET_EMPTY(key); + + cthreshold=MR_ROUNDUP(olen,hlen); + + for (counter=0;counterlen+hlen>olen) OCTET_JOIN_BYTES(H.val,olen%hlen,key); + else OCTET_JOIN_OCTET(&H,key); + } +} + +void KDF2(octet *z,octet *p,int olen,octet *key) +{ +/* NOTE: the parameter olen is the length of the output k in bytes */ + char h[HASH_BYTES]; + octet H={0,sizeof(h),h}; + int counter,cthreshold; + int hlen=HASH_BYTES; + + OCTET_EMPTY(key); + + cthreshold=MR_ROUNDUP(olen,hlen); + + for (counter=1;counter<=cthreshold;counter++) + { + hash(z,counter,p,NULL,&H); + if (key->len+hlen>olen) OCTET_JOIN_BYTES(H.val,olen%hlen,key); + else OCTET_JOIN_OCTET(&H,key); + } +} + +/* Password based Key Derivation Function */ +/* Input password p, salt s, and repeat count */ +/* Output key of length olen */ + +void PBKDF2(octet *p,octet *s,int rep,int olen,octet *key) +{ + int i,j,len,d=MR_ROUNDUP(olen,HASH_BYTES); + char f[EFS],u[EFS]; + octet F={0,sizeof(f),f}; + octet U={0,sizeof(u),u}; + OCTET_EMPTY(key); + + for (i=1;i<=d;i++) + { + len=s->len; + OCTET_JOIN_LONG(i,4,s); + HMAC(s,p,EFS,&F); + s->len=len; + OCTET_COPY(&F,&U); + for (j=2;j<=rep;j++) + { + HMAC(&U,p,EFS,&U); + OCTET_XOR(&U,&F); + } + + OCTET_JOIN_OCTET(&F,key); + } + OCTET_CHOP(key,olen,NULL); +} + +/* AES encryption/decryption */ + +void AES_CBC_IV0_ENCRYPT(octet *k,octet *m,octet *c) +{ /* AES CBC encryption, with Null IV and key k */ + /* Input is from an octet string m, output is to an octet string c */ + /* Input is padded as necessary to make up a full final block */ + aes a; + BOOL fin; + int i,j,ipt,opt,ch; + char buff[16]; + int padlen; + + OCTET_CLEAR(c); + if (m->len==0) return; + if (!aes_init(&a,MR_CBC,k->len,k->val,NULL)) return; + + ipt=opt=0; + fin=FALSE; + forever + { + for (i=0;i<16;i++) + { + if (iptlen) buff[i]=m->val[ipt++]; + else {fin=TRUE; break;} + } + if (fin) break; + aes_encrypt(&a,buff); + for (i=0;i<16;i++) + if (optmax) c->val[opt++]=buff[i]; + } + +/* last block, filled up to i-th index */ + + padlen=16-i; + for (j=i;j<16;j++) buff[j]=padlen; + aes_encrypt(&a,buff); + for (i=0;i<16;i++) + if (optmax) c->val[opt++]=buff[i]; + aes_end(&a); + c->len=opt; +} + +/* returns TRUE if all consistent, else returns FALSE */ + +BOOL AES_CBC_IV0_DECRYPT(octet *k,octet *c,octet *m) +{ /* padding is removed */ + aes a; + int i,ipt,opt,ch; + char buff[16]; + BOOL fin,bad; + int padlen; + ipt=opt=0; + + OCTET_CLEAR(m); + if (c->len==0) return TRUE; + ch=c->val[ipt++]; + + if (!aes_init(&a,MR_CBC,k->len,k->val,NULL)) return FALSE; + fin=FALSE; + + forever + { + for (i=0;i<16;i++) + { + buff[i]=ch; + if (ipt>=c->len) {fin=TRUE; break;} + else ch=c->val[ipt++]; + } + aes_decrypt(&a,buff); + if (fin) break; + for (i=0;i<16;i++) + if (optmax) m->val[opt++]=buff[i]; + } + aes_end(&a); + bad=FALSE; + padlen=buff[15]; + if (i!=15 || padlen<1 || padlen>16) bad=TRUE; + if (padlen>=2 && padlen<=16) + for (i=16-padlen;i<16;i++) if (buff[i]!=padlen) bad=TRUE; + + if (!bad) for (i=0;i<16-padlen;i++) + if (optmax) m->val[opt++]=buff[i]; + + m->len=opt; + if (bad) return FALSE; + return TRUE; +} + + +/*** EC GF(p) primitives - support functions ***/ +/* destroy the EC GF(p) domain structure */ + +void ECP_DOMAIN_KILL(ecp_domain *DOM) +{ + int i; + for (i=0;iQ[i]=0; + DOM->A[i]=0; + DOM->B[i]=0; + DOM->Gx[i]=0; + DOM->Gy[i]=0; + } + for (i=0;iR[i]=0; +} + +/* Initialise the EC GF(p) domain structure + * It is assumed that the EC domain details are obtained from ROM + */ + +int ECP_DOMAIN_INIT(ecp_domain *DOM,const void *rom) +{ /* get domain details from ROM */ + + FILE *fp; +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,2*EFS,16); +#else + miracl *mr_mip=mirsys(2*EFS,16); +#endif + BOOL fileinput=TRUE; + big q,r,gx,gy,a,b; + int words,promptr,err,res=0; +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 6); +#else + char mem[MR_BIG_RESERVE(6)]; + memset(mem,0,MR_BIG_RESERVE(6)); +#endif + + DOM->nibbles=2*EFS; + words=MR_ROUNDUP(EFS*8,MIRACL); + + if (mr_mip==NULL || mem==NULL) res= ECDH_OUT_OF_MEMORY; + + mr_mip->ERCON=TRUE; + + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + r=mirvar_mem(_MIPP_ mem, 3); + gx=mirvar_mem(_MIPP_ mem, 4); + gy=mirvar_mem(_MIPP_ mem, 5); + + promptr=0; + init_big_from_rom(q,words,(const mr_small *)rom,words*5,&promptr); /* Read in prime modulus q from ROM */ + init_big_from_rom(b,words,(const mr_small *)rom,words*5,&promptr); /* Read in curve parameter b from ROM */ + init_big_from_rom(r,words,(const mr_small *)rom,words*5,&promptr); /* Read in curve parameter r from ROM */ + init_big_from_rom(gx,words,(const mr_small *)rom,words*5,&promptr); /* Read in curve parameter gx from ROM */ + init_big_from_rom(gy,words,(const mr_small *)rom,words*5,&promptr); /* Read in curve parameter gy from ROM */ + convert(_MIPP_ -3,a); + add(_MIPP_ q,a,a); + + big_to_bytes(_MIPP_ EFS,q,DOM->Q,TRUE); + big_to_bytes(_MIPP_ EFS,a,DOM->A,TRUE); + big_to_bytes(_MIPP_ EFS,b,DOM->B,TRUE); + big_to_bytes(_MIPP_ EGS,r,DOM->R,TRUE); + big_to_bytes(_MIPP_ EFS,gx,DOM->Gx,TRUE); + big_to_bytes(_MIPP_ EFS,gy,DOM->Gy,TRUE); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,6); +#else + memset(mem,0,MR_BIG_RESERVE(6)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return ECDH_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return ECDH_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/* Calculate a public/private EC GF(p) key pair. W=S.g mod EC(p), + * where S is the secret key and W is the public key + * If RNG is NULL then the private key is provided externally in S + * otherwise it is generated randomly internally */ + +int ECP_KEY_PAIR_GENERATE(ecp_domain *DOM,csprng *RNG,octet* S,octet *W) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->nibbles,16); +#else + miracl *mr_mip=mirsys(DOM->nibbles,16); +#endif + big q,a,b,r,gx,gy,s,wx,wy; + epoint *G,*WP; + int err,res=0; +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 9); + char *mem1=(char *)ecp_memalloc(_MIPP_ 2); +#else + char mem[MR_BIG_RESERVE(9)]; + char mem1[MR_ECP_RESERVE(2)]; + memset(mem,0,MR_BIG_RESERVE(9)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + + if (mr_mip==NULL || mem==NULL || mem1==NULL) res= ECDH_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + + + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + r=mirvar_mem(_MIPP_ mem, 3); + gx=mirvar_mem(_MIPP_ mem, 4); + gy=mirvar_mem(_MIPP_ mem, 5); + s=mirvar_mem(_MIPP_ mem, 6); + wx=mirvar_mem(_MIPP_ mem, 7); + wy=mirvar_mem(_MIPP_ mem, 8); + + bytes_to_big(_MIPP_ EFS,DOM->Q,q); + bytes_to_big(_MIPP_ EFS,DOM->A,a); + bytes_to_big(_MIPP_ EFS,DOM->B,b); + bytes_to_big(_MIPP_ EGS,DOM->R,r); + bytes_to_big(_MIPP_ EFS,DOM->Gx,gx); + bytes_to_big(_MIPP_ EFS,DOM->Gy,gy); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + WP=epoint_init_mem(_MIPP_ mem1,1); + epoint_set(_MIPP_ gx,gy,0,G); + + if (RNG!=NULL) + strong_bigrand(_MIPP_ RNG,r,s); + else + { + bytes_to_big(_MIPP_ S->len,S->val,s); + divide(_MIPP_ s,r,r); + } + + ecurve_mult(_MIPP_ s,G,WP); + epoint_get(_MIPP_ WP,wx,wy); + + if (RNG!=NULL) S->len=big_to_bytes(_MIPP_ 0,s,S->val,FALSE); + + W->len=2*EFS+1; W->val[0]=4; + big_to_bytes(_MIPP_ EFS,wx,&(W->val[1]),TRUE); + big_to_bytes(_MIPP_ EFS,wy,&(W->val[EFS+1]),TRUE); + } + +#ifndef MR_STATIC + memkill(_MIPP_ mem,9); + ecp_memkill(_MIPP_ mem1,2); +#else + memset(mem,0,MR_BIG_RESERVE(9)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return ECDH_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return ECDH_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/* validate an EC GF(p) public key. Set full=TRUE for fuller, + * but more time-consuming test */ + +int ECP_PUBLIC_KEY_VALIDATE(ecp_domain *DOM,BOOL full,octet *W) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->nibbles,16); +#else + miracl *mr_mip=mirsys(DOM->nibbles,16); +#endif + big q,a,b,r,wx,wy; + epoint *WP; + BOOL valid; + int err,res=0; +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 6); + char *mem1=(char *)ecp_memalloc(_MIPP_ 1); +#else + char mem[MR_BIG_RESERVE(6)]; + char mem1[MR_ECP_RESERVE(1)]; + memset(mem,0,MR_BIG_RESERVE(6)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + + if (mr_mip==NULL || mem==NULL || mem1==NULL) res= ECDH_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + r=mirvar_mem(_MIPP_ mem, 3); + wx=mirvar_mem(_MIPP_ mem, 4); + wy=mirvar_mem(_MIPP_ mem, 5); + + + bytes_to_big(_MIPP_ EFS,DOM->Q,q); + bytes_to_big(_MIPP_ EFS,DOM->A,a); + bytes_to_big(_MIPP_ EFS,DOM->B,b); + bytes_to_big(_MIPP_ EGS,DOM->R,r); + + bytes_to_big(_MIPP_ EFS,&(W->val[1]),wx); + bytes_to_big(_MIPP_ EFS,&(W->val[EFS+1]),wy); + + if (mr_compare(wx,q)>=0 || mr_compare (wy,q)>=0) res=ECDH_INVALID_PUBLIC_KEY; + } + if (res==0) + { + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + WP=epoint_init_mem(_MIPP_ mem1,0); + + valid=epoint_set(_MIPP_ wx,wy,0,WP); + + if (!valid || WP->marker==MR_EPOINT_INFINITY) res=ECDH_INVALID_PUBLIC_KEY; + if (res==0 && full) + { + ecurve_mult(_MIPP_ r,WP,WP); + if (WP->marker!=MR_EPOINT_INFINITY) res=ECDH_INVALID_PUBLIC_KEY; + } + + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,6); + ecp_memkill(_MIPP_ mem1,1); +#else + memset(mem,0,MR_BIG_RESERVE(6)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return ECDH_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return ECDH_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/*** P1363 EC GF(p) primitives ***/ +/* See P1363 documentation for specification */ + +int ECPSVDP_DH(ecp_domain *DOM,octet *S,octet *WD,octet *Z) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->nibbles,16); +#else + miracl *mr_mip=mirsys(DOM->nibbles,16); +#endif + big q,a,b,s,wx,wy,z; + BOOL valid; + epoint *W; + int err,res=0; +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 7); + char *mem1=(char *)ecp_memalloc(_MIPP_ 1); +#else + char mem[MR_BIG_RESERVE(7)]; + char mem1[MR_ECP_RESERVE(1)]; + memset(mem,0,MR_BIG_RESERVE(7)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + + if (mr_mip==NULL || mem==NULL || mem1==NULL) res= ECDH_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + s=mirvar_mem(_MIPP_ mem, 3); + wx=mirvar_mem(_MIPP_ mem, 4); + wy=mirvar_mem(_MIPP_ mem, 5); + z=mirvar_mem(_MIPP_ mem, 6); + + bytes_to_big(_MIPP_ EFS,DOM->Q,q); + bytes_to_big(_MIPP_ EFS,DOM->A,a); + bytes_to_big(_MIPP_ EFS,DOM->B,b); + + bytes_to_big(_MIPP_ S->len,S->val,s); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + W=epoint_init_mem(_MIPP_ mem1,0); + + bytes_to_big(_MIPP_ EFS,&(WD->val[1]),wx); + bytes_to_big(_MIPP_ EFS,&(WD->val[EFS+1]),wy); + + valid=epoint_set(_MIPP_ wx,wy,0,W); + + if (!valid) res=ECDH_ERROR; + } + if (res==0) + { + ecurve_mult(_MIPP_ s,W,W); + if (W->marker==MR_EPOINT_INFINITY) res=ECDH_ERROR; + else + { + epoint_get(_MIPP_ W,z,z); + Z->len=big_to_bytes(_MIPP_ EFS,z,Z->val,TRUE); + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,7); + ecp_memkill(_MIPP_ mem1,1); +#else + memset(mem,0,MR_BIG_RESERVE(7)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return ECDH_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return ECDH_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/* Sign octet F using private key S. Signature in C and D. Must supply RNG */ + +int ECPSP_DSA(ecp_domain *DOM,csprng *RNG,octet *S,octet *F,octet *C,octet *D) +{ + char h[HASH_BYTES]; + octet H={0,sizeof(h),h}; +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->nibbles,16); +#else + miracl *mr_mip=mirsys(DOM->nibbles,16); +#endif + big q,a,b,gx,gy,r,s,f,c,d,u,vx; + epoint *G,*V; + int err,res=0; +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 12); + char *mem1=(char *)ecp_memalloc(_MIPP_ 2); +#else + char mem[MR_BIG_RESERVE(12)]; + char mem1[MR_ECP_RESERVE(2)]; + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + if (mr_mip==NULL || mem==NULL || mem1==NULL) res= ECDH_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + + hash(F,-1,NULL,NULL,&H); /* hash message */ + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + gx=mirvar_mem(_MIPP_ mem, 3); + gy=mirvar_mem(_MIPP_ mem, 4); + r=mirvar_mem(_MIPP_ mem, 5); + s=mirvar_mem(_MIPP_ mem, 6); + f=mirvar_mem(_MIPP_ mem, 7); + c=mirvar_mem(_MIPP_ mem, 8); + d=mirvar_mem(_MIPP_ mem, 9); + u=mirvar_mem(_MIPP_ mem, 10); + vx=mirvar_mem(_MIPP_ mem,11); + + bytes_to_big(_MIPP_ EFS,DOM->Q,q); + bytes_to_big(_MIPP_ EGS,DOM->R,r); + bytes_to_big(_MIPP_ EFS,DOM->Gx,gx); + bytes_to_big(_MIPP_ EFS,DOM->Gy,gy); + bytes_to_big(_MIPP_ EFS,DOM->A,a); + bytes_to_big(_MIPP_ EFS,DOM->B,b); + bytes_to_big(_MIPP_ S->len,S->val,s); + bytes_to_big(_MIPP_ H.len,H.val,f); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + V=epoint_init_mem(_MIPP_ mem1,1); + epoint_set(_MIPP_ gx,gy,0,G); + + do { + if (mr_mip->ERNUM) break; + strong_bigrand(_MIPP_ RNG,r,u); + + ecurve_mult(_MIPP_ u,G,V); + epoint_get(_MIPP_ V,vx,vx); + + copy(vx,c); + divide(_MIPP_ c,r,r); + if (size(c)==0) continue; + xgcd(_MIPP_ u,r,u,u,u); + mad(_MIPP_ s,c,f,r,r,d); + mad(_MIPP_ u,d,u,r,r,d); + + } while (size(d)==0); + + if (res==0) + { + C->len=big_to_bytes(_MIPP_ EGS,c,C->val,TRUE); + D->len=big_to_bytes(_MIPP_ EGS,d,D->val,TRUE); + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,12); + ecp_memkill(_MIPP_ mem1,2); +#else + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return ECDH_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return ECDH_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/* Verify Signature (C, D) on F using public key W */ + +int ECPVP_DSA(ecp_domain *DOM,octet *W,octet *F, octet *C,octet *D) +{ + char h[HASH_BYTES]; + octet H={0,sizeof(h),h}; +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->nibbles,16); +#else + miracl *mr_mip=mirsys(DOM->nibbles,16); +#endif + big q,r,a,b,gx,gy,wx,wy,f,c,d,h2; + int bit,err,res=0; + epoint *G,*WP,*P; + BOOL compressed,valid; +#ifndef MR_STATIC + char *mem=(char *)memalloc(_MIPP_ 12); + char *mem1=(char *)ecp_memalloc(_MIPP_ 3); +#else + char mem[MR_BIG_RESERVE(12)]; + char mem1[MR_ECP_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + if (mr_mip==NULL || mem==NULL || mem1==NULL) res= ECDH_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + + hash(F,-1,NULL,NULL,&H); /* hash message */ + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + gx=mirvar_mem(_MIPP_ mem, 3); + gy=mirvar_mem(_MIPP_ mem, 4); + r=mirvar_mem(_MIPP_ mem, 5); + wx=mirvar_mem(_MIPP_ mem, 6); + wy=mirvar_mem(_MIPP_ mem, 7); + f=mirvar_mem(_MIPP_ mem, 8); + c=mirvar_mem(_MIPP_ mem, 9); + d=mirvar_mem(_MIPP_ mem, 10); + h2=mirvar_mem(_MIPP_ mem,11); + + bytes_to_big(_MIPP_ EFS,DOM->Q,q); + bytes_to_big(_MIPP_ EGS,DOM->R,r); + bytes_to_big(_MIPP_ EFS,DOM->Gx,gx); + bytes_to_big(_MIPP_ EFS,DOM->Gy,gy); + bytes_to_big(_MIPP_ EFS,DOM->A,a); + bytes_to_big(_MIPP_ EFS,DOM->B,b); + bytes_to_big(_MIPP_ C->len,C->val,c); + bytes_to_big(_MIPP_ D->len,D->val,d); + bytes_to_big(_MIPP_ H.len,H.val,f); + + if (size(c)<1 || mr_compare(c,r)>=0 || size(d)<1 || mr_compare(d,r)>=0) + res=ECDH_INVALID; + } + + if (res==0) + { + xgcd(_MIPP_ d,r,d,d,d); + mad(_MIPP_ f,d,f,r,r,f); + mad(_MIPP_ c,d,c,r,r,h2); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + WP=epoint_init_mem(_MIPP_ mem1,1); + P=epoint_init_mem(_MIPP_ mem1,2); + epoint_set(_MIPP_ gx,gy,0,G); + + bytes_to_big(_MIPP_ EFS,&(W->val[1]),wx); + bytes_to_big(_MIPP_ EFS,&(W->val[EFS+1]),wy); + + valid=epoint_set(_MIPP_ wx,wy,0,WP); + + if (!valid) res=ECDH_ERROR; + else + { + ecurve_mult2(_MIPP_ f,G,h2,WP,P); + if (P->marker==MR_EPOINT_INFINITY) res=ECDH_INVALID; + else + { + epoint_get(_MIPP_ P,d,d); + divide(_MIPP_ d,r,r); + if (mr_compare(d,c)!=0) res=ECDH_INVALID; + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,12); + ecp_memkill(_MIPP_ mem1,3); +#else + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return ECDH_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return ECDH_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + + +void ECP_ECIES_ENCRYPT(ecp_domain *DOM,octet *P1,octet *P2,csprng *RNG,octet *W,octet *M,int tlen,octet *V,octet *C,octet *T) +{ /* Inputs: Input params, random number generator, his public key, the message to be encrypted and the MAC length */ + /* Outputs: my one-time public key, the ciphertext and the MAC tag */ + + int i,len; + char z[EFS],vz[3*EFS+2],k[32],k1[16],k2[16],l2[8],u[EFS]; + octet Z={0,sizeof(z),z}; + octet VZ={0,sizeof(vz),vz}; + octet K={0,sizeof(k),k}; + octet K1={0,sizeof(k1),k1}; + octet K2={0,sizeof(k2),k2}; + octet L2={0,sizeof(l2),l2}; + octet U={0,sizeof(u),u}; + + if (ECP_KEY_PAIR_GENERATE(DOM,RNG,&U,V)!=0) return; /* one time key pair */ + if (ECPSVDP_DH(DOM,&U,W,&Z)!=0) return; + + OCTET_COPY(V,&VZ); + OCTET_JOIN_OCTET(&Z,&VZ); + + KDF2(&VZ,P1,EFS,&K); + +/* split key into AES encryption key and MAC key */ + + K1.len=K2.len=16; + for (i=0;i<16;i++) {K1.val[i]=K.val[i]; K2.val[i]=K.val[16+i];} + + AES_CBC_IV0_ENCRYPT(&K1,M,C); + + OCTET_JOIN_LONG((long)P2->len,8,&L2); + + len=C->len; + OCTET_JOIN_OCTET(P2,C); + OCTET_JOIN_OCTET(&L2,C); + HMAC(C,&K2,tlen,T); + C->len=len; +} + +/* ECIES Decryption */ + +BOOL ECP_ECIES_DECRYPT(ecp_domain *DOM,octet *P1,octet *P2,octet *V,octet *C,octet *T,octet *U,octet *M) +{ /* Inputs: Input params, ciphertext triple V,C,T and recipients private key */ + /* Output: recovered plaintext M */ + + int i,len; + char z[EFS],vz[3*EFS+2],k[32],k1[16],k2[16],l2[8],tag[32]; + octet Z={0,sizeof(z),z}; + octet VZ={0,sizeof(vz),vz}; + octet K={0,sizeof(k),k}; + octet K1={0,sizeof(k1),k1}; + octet K2={0,sizeof(k2),k2}; + octet L2={0,sizeof(l2),l2}; + octet TAG={0,sizeof(tag),tag}; + + if (ECPSVDP_DH(DOM,U,V,&Z)!=0) return FALSE; + + OCTET_COPY(V,&VZ); + OCTET_JOIN_OCTET(&Z,&VZ); + + KDF2(&VZ,P1,EFS,&K); + +/* split key into AES decryption key and MAC key */ + + K1.len=K2.len=16; + for (i=0;i<16;i++) {K1.val[i]=K.val[i]; K2.val[i]=K.val[16+i];} + + if (!AES_CBC_IV0_DECRYPT(&K1,C,M)) return FALSE; + + OCTET_JOIN_LONG((long)P2->len,8,&L2); + + len=C->len; + OCTET_JOIN_OCTET(P2,C); + OCTET_JOIN_OCTET(&L2,C); + HMAC(C,&K2,T->len,&TAG); + C->len=len; + + if (!OCTET_COMPARE(T,&TAG)) return FALSE; + + return TRUE; + +} + diff --git a/miracl/source/p1363/ecdh.h b/miracl/source/p1363/ecdh.h new file mode 100644 index 0000000..b6ef911 --- /dev/null +++ b/miracl/source/p1363/ecdh.h @@ -0,0 +1,141 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ + +/* + * MIRACL ECDH header file + * Author: M. Scott 2013 + */ + +#ifndef ECDH_H +#define ECDH_H + +#include "miracl.h" +#include "octet.h" + +#define EAS 16 /* Symmetric Key size - 128 bits */ +#define EGS 32 /* ECCSI Group Size - 256 bits */ +#define EFS 32 /* ECCSI Field Size - 256 bits */ + +#define ECDH_OK 0 +#define ECDH_DOMAIN_ERROR -1 +#define ECDH_INVALID_PUBLIC_KEY -2 +#define ECDH_ERROR -3 +#define ECDH_INVALID -4 +#define ECDH_DOMAIN_NOT_FOUND -5 +#define ECDH_OUT_OF_MEMORY -6 +#define ECDH_DIV_BY_ZERO -7 +#define ECDH_BAD_ASSUMPTION -8 + +extern const mr_small ecrom[]; + +/* ECp domain parameters */ + +typedef struct +{ + int nibbles; + char Q[EFS]; + char A[EFS]; + char B[EFS]; + char R[EGS]; + char Gx[EFS]; + char Gy[EFS]; +} ecp_domain; + +#define HASH_BYTES 32 + +#if HASH_BYTES==20 + #define HASHFUNC sha + #define SHS_INIT shs_init + #define SHS_PROCESS shs_process + #define SHS_HASH shs_hash + #define HASH_BLOCK 64 +#endif + +#if HASH_BYTES==32 + #define HASHFUNC sha256 + #define SHS_INIT shs256_init + #define SHS_PROCESS shs256_process + #define SHS_HASH shs256_hash + #define HASH_BLOCK 64 +#endif + +#if HASH_BYTES==48 + #define HASHFUNC sha384 + #define SHS_INIT shs384_init + #define SHS_PROCESS shs384_process + #define SHS_HASH shs384_hash + #define HASH_BLOCK 128 +#endif + +#if HASH_BYTES==64 + #define HASHFUNC sha512 + #define SHS_INIT shs512_init + #define SHS_PROCESS shs512_process + #define SHS_HASH shs512_hash + #define HASH_BLOCK 128 +#endif + +/* ECDH Auxiliary Functions */ + +extern void CREATE_CSPRNG(csprng *,octet *); +extern void KILL_CSPRNG(csprng *); +extern void HASH(octet *,octet *); +extern BOOL HMAC(octet *,octet *,int,octet *); +extern void KDF1(octet *,int,octet *); +extern void KDF2(octet *,octet *,int,octet *); +extern void PBKDF2(octet *,octet *,int,int,octet *); +extern void AES_CBC_IV0_ENCRYPT(octet *,octet *,octet *); +extern BOOL AES_CBC_IV0_DECRYPT(octet *,octet *,octet *); + +/* ECDH primitives - support functions */ + +extern void ECP_DOMAIN_KILL(ecp_domain *); +extern int ECP_DOMAIN_INIT(ecp_domain *,const void *); +extern int ECP_KEY_PAIR_GENERATE(ecp_domain *,csprng *,octet *,octet *); +extern int ECP_PUBLIC_KEY_VALIDATE(ecp_domain *,BOOL,octet *); + +/* ECDH primitives */ + +extern int ECPSVDP_DH(ecp_domain *,octet *,octet *,octet *); +extern int ECPSVDP_DHC(ecp_domain *,octet *,octet *,BOOL,octet *); + +/* ECIES functions */ +extern void ECP_ECIES_ENCRYPT(ecp_domain *,octet *,octet *,csprng *,octet *,octet *,int,octet *,octet *,octet *); +extern BOOL ECP_ECIES_DECRYPT(ecp_domain *,octet *,octet *,octet *,octet *,octet *,octet *,octet *); + +/* ECDSA functions */ +extern int ECPSP_DSA(ecp_domain *,csprng *,octet *,octet *,octet *,octet *); +extern int ECPVP_DSA(ecp_domain *,octet *,octet *,octet *,octet *); +#endif + diff --git a/miracl/source/p1363/octet.c b/miracl/source/p1363/octet.c new file mode 100644 index 0000000..e805b11 --- /dev/null +++ b/miracl/source/p1363/octet.c @@ -0,0 +1,313 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ + + +/*** Basic Octet string maintainance routines ***/ + +#include "octet.h" + +/* Output an octet string (Debug Only) */ + +void OCTET_OUTPUT(octet *w) +{ + int i; + unsigned char ch; + for (i=0;ilen;i++) + { + ch=w->val[i]; + printf("%02x",ch); + } + printf("\n"); +} + +void OCTET_OUTPUT_STRING(octet *w) +{ + int i; + unsigned char ch; + for (i=0;ilen;i++) + { + ch=w->val[i]; + printf("%c",ch); + } + /* printf("\n"); */ +} + +/* Convert C string to octet format - truncates if no room */ + +void OCTET_JOIN_STRING(char *s,octet *y) +{ + int i,j; + i=y->len; + j=0; + while (s[j]!=0 && imax) + { + y->val[i]=s[j]; + y->len++; + i++; j++; + } +} + +/* compare 2 octet strings. + * If x==y return TRUE, else return FALSE */ + +int OCTET_COMPARE(octet *x,octet *y) +{ + int i; + if (x->len>y->len) return 0; + if (x->lenlen) return 0; + for (i=0;ilen;i++) + { + if (x->val[i]!=y->val[i]) return 0; + } + return 1; +} + +/* Append binary string to octet - truncates if no room */ + +void OCTET_JOIN_BYTES(char *b,int len,octet *y) +{ + int i,j; + i=y->len; + for (j=0;jmax;j++) + { + y->val[i]=b[j]; + y->len++; + i++; + } +} + +/* Concatenates two octet strings */ + +void OCTET_JOIN_OCTET(octet *x,octet *y) +{ /* y=y || x */ + int i,j; + if (x==NULL) return; + + for (i=0;ilen;i++) + { + j=y->len+i; + if (j>=y->max) + { + y->len=y->max; + return; + } + y->val[j]=x->val[i]; + } + y->len+=x->len; +} + +/* Append byte to octet rep times */ + +void OCTET_JOIN_BYTE(int ch,int rep,octet *y) +{ + int i,j; + i=y->len; + for (j=0;jmax;j++) + { + y->val[i]=ch; + y->len++; + i++; + } +} + +/* XOR common bytes of x with y */ + +void OCTET_XOR(octet *x,octet *y) +{ /* xor first x->len bytes of y */ + + int i; + for (i=0;ilen && ilen;i++) + { + y->val[i]^=x->val[i]; + } +} + +/* clear an octet */ + +void OCTET_EMPTY(octet *w) +{ + w->len=0; +} + +/* Kill an octet string - Zeroise it for security */ + +void OCTET_CLEAR(octet *w) +{ + int i; + for (i=0;imax;i++) w->val[i]=0; + w->len=0; +} + +/* OCTET_JOIN_LONG primitive */ +/* appends long x of length len bytes to OCTET string */ + +void OCTET_JOIN_LONG(long x,int len,octet *y) +{ + int i,j,n; + n=y->len+len; + if (n>y->max || len<=0) return; + for (i=y->len;ival[i]=0; + y->len=n; + + i=y->len; + while (x>0 && i>0) + { + i--; + y->val[i]=x%256; + x/=256; + } +} + +/* Pad an octet to a given length */ + +void OCTET_PAD(int n,octet *w) +{ + int i,d; + if (w->len>=n || n>w->max) return; + d=n-w->len; + for (i=n-1;i>=d;i--) + w->val[i]=w->val[i-d]; + for (i=d-1;i>=0;i--) + w->val[i]=0; + w->len=n; +} + +/* Convert an octet string to base64 string */ + +void OCTET_TO_BASE64(octet *w,char *b) +{ + int i,j,k,rem,last; + int c,ch[4]; + unsigned char ptr[3]; + rem=w->len%3; j=k=0; last=4; + while (jlen) + { + for (i=0;i<3;i++) + { + if (jlen) ptr[i]=w->val[j++]; + else {ptr[i]=0; last--;} + } + ch[0]=(ptr[0]>>2)&0x3f; + ch[1]=((ptr[0]<<4)|(ptr[1]>>4))&0x3f; + ch[2]=((ptr[1]<<2)|(ptr[2]>>6))&0x3f; + ch[3]=ptr[2]&0x3f; + for (i=0;i=26 && c<52) c+=71; + if (c>=52 && c<62) c-=4; + if (c==62) c='+'; + if (c==63) c='/'; + b[k++]=c; + } + } + if (rem>0) for (i=rem;i<3;i++) b[k++]='='; + b[k]='\0'; // dangerous! +} + +void OCTET_FROM_BASE64(char *b,octet *w) +{ + int i,j,k,pads,len=strlen(b); + int c,ch[4],ptr[3]; + int lead=1; + j=k=0; + while (jmax) + { + pads=0; + for (i=0;i<4;i++) + { + c=80+b[j++]; + if (c<=112) continue; /* ignore white space */ + if (c>144 && c<171) c-=145; + if (c>176 && c<203) c-=151; + if (c>127 && c<138) c-=76; + if (c==123) c=62; + if (c==127) c=63; + if (c==141) {pads++; continue;} /* ignore pads '=' */ + ch[i]=c; + } + ptr[0]=(ch[0]<<2)|(ch[1]>>4); + ptr[1]=(ch[1]<<4)|(ch[2]>>2); + ptr[2]=(ch[2]<<6)|ch[3]; + for (i=0;i<3-pads && kmax;i++) + { /* don't put in leading zeros */ + /* if (lead && ptr[i]==0) continue; */ + w->val[k++]=ptr[i]; + lead=0; + } + + } + w->len=k; +} + +/* copy an octet string - truncates if no room */ + +void OCTET_COPY(octet *x,octet *y) +{ + int i; + OCTET_CLEAR(y); + y->len=x->len; + if (y->len>y->max) y->len=y->max; + + for (i=0;ilen;i++) + y->val[i]=x->val[i]; +} + +/* XOR m with all of x */ + +void OCTET_XOR_BYTE(int m,octet *x) +{ + int i; + for (i=0;ilen;i++) x->val[i]^=m; +} + +/* truncates x to n bytes and places the rest in y (if y is not NULL) */ + +void OCTET_CHOP(octet *x,int n,octet *y) +{ + int i; + if (n>=x->len) + { + if (y!=NULL) y->len=0; + return; + } + if (y!=NULL) y->len=x->len-n; + x->len=n; + + if (y!=NULL) + { + for (i=0;ilen && imax;i++) y->val[i]=x->val[i+n]; + } +} diff --git a/miracl/source/p1363/octet.h b/miracl/source/p1363/octet.h new file mode 100644 index 0000000..edb85d9 --- /dev/null +++ b/miracl/source/p1363/octet.h @@ -0,0 +1,72 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ + + +#ifndef OCTET_H +#define OCTET_H + +#include +#include +#include + +/* portable representation of a big positive number */ + +typedef struct +{ + int len; + int max; + char *val; +} octet; + +/* Octet string handlers */ + +extern void OCTET_OUTPUT(octet *); +extern void OCTET_OUTPUT_STRING(octet *); +extern void OCTET_CLEAR(octet *); +extern int OCTET_COMPARE(octet *,octet *); +extern void OCTET_JOIN_STRING(char *,octet *); +extern void OCTET_JOIN_BYTES(char *,int,octet *); +extern void OCTET_JOIN_BYTE(int,int,octet *); +extern void OCTET_JOIN_OCTET(octet *,octet *); +extern void OCTET_XOR(octet *,octet *); +extern void OCTET_EMPTY(octet *); +extern void OCTET_PAD(int,octet *); +extern void OCTET_TO_BASE64(octet *,char *); +extern void OCTET_FROM_BASE64(char *,octet *); +extern void OCTET_COPY(octet *,octet *); +extern void OCTET_XOR_BYTE(int,octet *); +extern void OCTET_CHOP(octet *,int,octet *); +extern void OCTET_JOIN_LONG(long,int,octet *); + +#endif diff --git a/miracl/source/p1363/p1363.c b/miracl/source/p1363/p1363.c new file mode 100644 index 0000000..604bfe7 --- /dev/null +++ b/miracl/source/p1363/p1363.c @@ -0,0 +1,6939 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ + +/* + * MIRACL-based implementation of the IEEE 1363 standard + * Version 1.6 July 2010 + * + * NEW 1.1 - Elliptic curve points now stored in a single OCTET as recommended + * in P1363a. Such octets will be 2*fs+1 in length, where fs is + * the field size. If compression is used they may be fs+1 + * + * NEW 1.2 - Auxiliary functions completely re-written + * More primitives and functions implemented + * New mirvar_mem function used for extra speed + * + * NEW 1.3 - Cryptographically strong RNG interface improved + * + * NEW 1.6 - Support for .NET applications. See below + * + * Implements most of the cryptographic primitives, message encoding methods, + * key derivation functions and auxiliary functions necessary for realising the + * recommended methods. Note that GF(p) and GF(2^m) Elliptic curves are + * treated seperately. + * + * See the IEEE 1363 documentation for details + * http://grouper.ieee.org/groups/1363/index.html + * This IS the documentation for this implementation. Each P1363 function + * has the same name, and same inputs/outputs as those described in the + * official 1363 documentation. + * + * The user is responsible for the initialisation and maintainance of + * "Octet strings" which store Cryptographic keys and application info. + * These octet strings store big numbers in binary, from MSB down to LSB + * NOTE:- Leading zeros can be suppressed! Use OCTET_PAD() to insert leading + * zeros to make an octet a particular length, e.g. 20 bytes, 160 bits. + * + * An instance of a Cryptographically Strong Random Number Generator + * must be created and initialised by the user with + * raw random data. This doesn't have to be high quality (e.g. mouse movement + * coordinates), but there must be enough of it for it to be unguessable. + * It is subsequently maintained internally by the system + * The secure random number generation method used is based on that described + * in ftp://ftp.rsasecurity.com/pub/pdfs/bull-1.pdf + * + * The above is the recommended approach. + * Alternatvely when generating a key pair a random number can be specified + * directly as a private key, and this internal system by-passed. + * + * Domain and Public/Private key data is stored in structures defined in + * p1363.h. The first parameter in each function is a pointer to a function + * which will be called during time-consuming calculations - e.g. a Windows + * message pump. Negative return values indicate an error - see p1363.h for + * definitions. Most common MIRACL errors are mapped to these values. + * Unlikely MIRACL errors are returned as -(1000+MEC), where MEC + * is the MIRACL Error Code (see miracl.h) + * + * quick start:- + * cl /O2 test1363.c p1363.c miracl.lib + * + * Recommended for use with a (32-bit) MIRACL library built + * from a mirdef.h file that looks something like this:- + * + * #define MIRACL 32 + * #define MR_LITTLE_ENDIAN + * #define mr_utype int + * #define MR_IBITS 32 + * #define MR_LBITS 32 + * #define mr_unsign32 unsigned int + * #define MR_STRIPPED_DOWN + * #define MR_GENERIC_MT + * #define mr_dltype __int64 + * #define mr_unsign64 unsigned __int64 + * #define MAXBASE ((mr_small)1<<(MIRACL-1)) + * + * Note that this is a multi-threaded build, ideal for a Cryptographic DLL + * The compiler may need a multithreaded flag set (/MT ??) + * + * The miracl instance variable ERCON is set to TRUE in each routine, so + * MIRACL does not attempt to report an error. Instead the variable ERNUM + * latches the last error, and if set causes each subsequent routine to + * "fall through". + * + * Octet strings are not tested for overflow. In fact overflow will not + * happen as octets will be truncated - so buffer overflow attacks against + * this code will not succeed. To avoid unintentional overflow its best to + * initialise the length of most octets to that recommended and returned by + * the XXX_DOMAIN_INIT() routines. Note however that elliptic curve point + * octets should be initialised to "twice this length plus 1" (or only "this + * length plus 1" if compression is used) + * + * A test driver main() function is provided in test1363.c to test all the + * functions, and to implement many of the recommended methods, ECDSA, IFSSA, + * IFSSR, DLSSR, DLSSR-PV and ECIES + * + * In Win32 MS C:- + * cl /O2 /MT test1363.c p1363.c miracl.lib /link /NODEFAULTLIB:libc.lib + * and run the executable + * + * test1363 ; + * test1363 -c ; uses EC point compression + * test1363 -p ; uses precomputation (window size = 8) for signature + * test1363 -c -p ; uses both precomputation and EC point compression + * + * To create a Windows P1363 DLL, compile as + * cl /O2 /W3 /MT /DMR_P1363_DLL /LD p1363.c miracl.lib /link /NODEFAULTLIB:libc.lib + * To run the test program to use the DLL, compile as + * cl /O2 /MT /DMR_P1363_DLL test1363.c p1363.lib + * + * In .NET MS C:- + * Build miracl library as described in managed.txt - but perhaps include + * #define MR_GENERIC_MT + * #define MR_STRIPPED_DOWN + * + * To create a DLL compile as + * cl /clr /O2 /DMR_P1363_DLL /LD /Tp p1363.c miracl.lib + * To run the test program to use the DLL, compile as + * cl /clr /O2 /DMR_P1363_DLL /Tp test1363.c p1363.lib + * + * Discrete Logarithm/GF(p) Elliptic Curve/GF(2^m) Elliptic Curve Domain + * details are read from the files common.dss, common.ecs and common2.ecs + * respectively. Suitable files are included in the standard MIRACL + * distribution. You can generate your own using for example the utilities + * dssetup.cpp, schoof.cpp and schoof2.cpp. But make sure that the group order + * in each case is at least 160-bits, or the demo may fail. + * + * Note that for a full 1363 implementation various simple message-encoding + * regimes must be also implemented, as described in the P1363 and P1363a + * documentation. Many of these are now implemented here. Also suitable hashing + * functions must be available. The SHA1/SHA256/SHA384 and SHA512 algorithms + * are recommended, and implemented in MIRACL + * + * Note that some of the message encoding functions can take input from a file + * rather than from a string. This is convenient for example if "signing" a + * large document. In these cases the parameters are typically "octet *x,FILE + * *fp", in which case either an OCTET string x can be specified OR a + * filename, but not both. + * + * Version 1.5 + * Miracl STATIC (no-heap version) supported. However octets (which are often + * variable length) are still allocated from the heap by default. To allocate + * fixed size octets from the stack edit p1363.h and define OCTET_FROM_STACK_SIZE + * NOTE: Precomputation not directly supported in this mode + * + * NOTE: It would be typical to break this file up and just use the parts that are needed + * (For example if using Elliptic curve methods only, then the size of structures could be much smaller) + * + * NOTE: Certain methods employed in the IEEE-1363 may be subject to US patent protection. + * Check http://grouper.ieee.org/groups/1363/index.html for more details + * + */ + +/* define this next to create Windows DLL */ + +/* #define MR_1363_DLL */ + +#ifdef MR_P1363_DLL +#define P1363_DLL +#endif + +#include +#include +#include "p1363.h" + +/* Hash IDs for supported EMSA3 hash functions. , */ + +static unsigned char SHA160ID[]={15,0x30,0x21,0x30,0x09,0x06,0x05,0x2b,0x0e,0x03,0x02,0x1a,0x05,0x00,0x04,0x14}; +static unsigned char SHA256ID[]={19,0x30,0x31,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x01,0x05,0x00,0x04,0x20}; +static unsigned char SHA384ID[]={19,0x30,0x41,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x02,0x05,0x00,0x04,0x30}; +static unsigned char SHA512ID[]={19,0x30,0x51,0x30,0x0d,0x06,0x09,0x60,0x86,0x48,0x01,0x65,0x03,0x04,0x02,0x03,0x05,0x00,0x04,0x40}; + + +/* IDs for SHA1,RIPEMD,SHA256,SHA384 and SHA512 */ +/* NOTE ripemd is not implemented */ + +static unsigned char sha_id[]={0x33,0x31,0x34,0x36,0x35}; + +/* Internal functions */ + +static long filelength(FILE *fp) +{ /* return file length in reasonably portable fashion */ + long len; + fseek(fp,0,SEEK_END); + len=ftell(fp); + fseek(fp,0,SEEK_SET); + return len; +} + +static void OS2FEP(_MIPD_ octet *s,big w) +{ /* internal:- converts from octet to big format */ + bytes_to_big(_MIPP_ s->len,s->val,w); +} + +static void convert_big_octet(_MIPD_ big w,octet *s) +{ /* internal:- converts from big integer to octet format */ + s->len=(oltype)big_to_bytes(_MIPP_ 0,w,s->val,FALSE); +} + +static void FE2OSP(_MIPD_ big w,int fsize,octet *s) +{ /* internal:- converts from big to field element format */ + s->len=(oltype)big_to_bytes(_MIPP_ fsize,w,s->val,TRUE); +} + +static void EC2OSP(_MIPD_ big x,big y,int cbit,BOOL compressed,int fsize,octet *s) +{ /* internal:- converts from (x,y) to octet string */ + s->len=1; + if (compressed) s->val[0]=2+cbit; + else s->val[0]=6+cbit; /* hybrid */ + s->len+=(oltype)big_to_bytes(_MIPP_ fsize,x,&(s->val[1]),TRUE); + if (!compressed) s->len+=(oltype)big_to_bytes(_MIPP_ fsize,y,&(s->val[fsize+1]),TRUE); +} + +static BOOL OS2ECP(_MIPD_ octet *s,big x,big y,int fsize,int *bit) +{ /* converts from octet string to (x,y) point */ + + bytes_to_big(_MIPP_ fsize,&(s->val[1]),x); + if (s->val[0]&4) + { /* uncompressed ..but don't put a y if not required */ + if(y!=NULL) bytes_to_big(_MIPP_ fsize,&(s->val[fsize+1]),y); + return FALSE; + } + else + { /* compressed */ + *bit=s->val[0]&1; + return TRUE; + } +} + +/* return output length of hash function in bytes, also hash function input + block size if desired */ + +static int hash_params(int hash_type,int *block) +{ + switch (hash_type) + { + case SHA1: + if (block!=NULL) *block=64; + return 20; + case SHA256: + if (block!=NULL) *block=64; + return 32; +#ifdef mr_unsign64 + case SHA384: + if (block!=NULL) *block=128; + return 48; + case SHA512: + if (block!=NULL) *block=128; + return 64; +#endif + default: + break; + } + return 0; +} + +/*** Basic Octet string maintainance routines ***/ +/* initialize an octet string */ +/* make it impossible to write beyond max length */ + +P1363_API BOOL OCTET_INIT(octet *w,int bytes) +{ + w->len=0; + w->max=bytes; +#ifndef OCTET_FROM_STACK_SIZE + w->val=(char *)malloc(bytes); + if (w->val!=NULL) return TRUE; + else return FALSE; +#else + return TRUE; +#endif +} + +P1363_API void OCTET_INIT_FROM_ARRAY(octet *w,int bytes,char *array) +{ + w->len=0; + w->max=bytes; + w->val=array; +} + +/* clear an octet string */ + +P1363_API void OCTET_CLEAR(octet *w) +{ + int i; + for (i=0;ilen;i++) w->val[i]=0; + w->len=0; +} + +/* XOR m with all of x */ + +P1363_API void OCTET_XOR_BYTE(octet *x,int m) +{ + int i; + for (i=0;ilen;i++) x->val[i]^=m; +} + +/* XOR common bytes of x with y */ + +P1363_API void OCTET_XOR(octet *x,octet *y) +{ /* xor first x->len bytes of y */ + + int i; + for (i=0;ilen && ilen;i++) + { + y->val[i]^=x->val[i]; + } +} + +/* clear an octet */ + +P1363_API void OCTET_EMPTY(octet *w) +{ + w->len=0; +} + +/* copy an octet string - truncates if no room */ + +P1363_API void OCTET_COPY(octet *x,octet *y) +{ + int i; + OCTET_CLEAR(y); + y->len=x->len; + if (y->len>y->max) y->len=y->max; + + for (i=0;ilen;i++) + y->val[i]=x->val[i]; +} + +/* compare 2 octet strings. + * If x==y return TRUE, else return FALSE */ + +P1363_API BOOL OCTET_COMPARE(octet *x,octet *y) +{ + int i; + if (x->len>y->len) return FALSE; + if (x->lenlen) return FALSE; + for (i=0;ilen;i++) + { + if (x->val[i]!=y->val[i]) return FALSE; + } + return TRUE; +} + +/* check are first n bytes the same */ + +P1363_API BOOL OCTET_NCOMPARE(octet *x,octet *y,int n) +{ + int i; + if (n>y->len || n>x->len) return FALSE; + for (i=0;ival[i]!=y->val[i]) return FALSE; + } + return TRUE; +} + +/* Pads an octet with leading zeros - returns FALSE if not enough room */ + +P1363_API BOOL OCTET_PAD(octet *x,int len) +{ + int i,d; + if (len>x->max || x->len>len) return FALSE; + if (len==x->len) return TRUE; + d=len - x->len; + for (i=len-1;i>=d;i--) + x->val[i]=x->val[i-d]; + + for (i=0;ival[i]=0; + x->len=(oltype)len; + return TRUE; +} + +/* Shift octet to the left by n bytes. Leftmost bytes disappear */ + +P1363_API void OCTET_SHIFT_LEFT(octet *x,int n) +{ + int i; + if (n>=x->len) + { + x->len=0; + return; + } + x->len-=n; + for (i=0;ilen;i++) + x->val[i]=x->val[i+n]; +} + +/* truncates x to n bytes and places the rest in y (if y is not NULL) */ + +P1363_API void OCTET_CHOP(octet *x,int n,octet *y) +{ + int i; + if (n>=x->len) + { + if (y!=NULL) y->len=0; + return; + } + if (y!=NULL) y->len=x->len-n; + x->len=n; + + if (y!=NULL) + { + for (i=0;ilen && imax;i++) y->val[i]=x->val[i+n]; + } +} + +/* Concatenates two octet strings */ + +P1363_API void OCTET_JOIN_OCTET(octet *x,octet *y) +{ /* y=y || x */ + int i,j; + if (x==NULL) return; + + for (i=0;ilen;i++) + { + j=y->len+i; + if (j>=y->max) + { + y->len=y->max; + return; + } + y->val[j]=x->val[i]; + } + y->len+=x->len; +} + +/* OCTET_JOIN_LONG primitive */ +/* appends long x of length len bytes to OCTET string */ + +P1363_API void OCTET_JOIN_LONG(long x, int len,octet *y) { + int i,j,n; + n=y->len+len; + if (n>y->max || len<=0) return; + for (i=y->len;ival[i]=0; + y->len=n; + + i=y->len; + while (x>0 && i>0) + { + i--; + y->val[i]=x%256; + x/=256; + } +} + +/* Convert C string to octet format - truncates if no room */ + +P1363_API void OCTET_JOIN_STRING(char *s,octet *y) +{ + int i,j; + i=y->len; + j=0; + while (s[j]!=0 && imax) + { + y->val[i]=s[j]; + y->len++; + i++; j++; + } +} + +/* Append binary string to octet - truncates if no room */ + +P1363_API void OCTET_JOIN_BYTES(char *b,int len,octet *y) +{ + int i,j; + i=y->len; + for (j=0;jmax;j++) + { + y->val[i]=b[j]; + y->len++; + i++; + } +} + +/* Append byte to octet rep times */ + +P1363_API void OCTET_JOIN_BYTE(int ch,int rep,octet *y) +{ + int i,j; + i=y->len; + for (j=0;jmax;j++) + { + y->val[i]=ch; + y->len++; + i++; + } +} + +/* Copy len random bytes into octet */ + +P1363_API void OCTET_RAND(csprng *RNG,int len,octet *x) +{ + int i; + if (len>x->max) len=x->max; + x->len=len; + + for (i=0;ival[i]=strong_rng(RNG); +} + +/* Output an octet string (Debug Only) */ + +P1363_API void OCTET_OUTPUT(octet *w) +{ + int i; + unsigned char ch; + for (i=0;ilen;i++) + { + ch=w->val[i]; + printf("%02x",ch); + } + printf("\n"); +} + +P1363_API void OCTET_PRINT_STRING(octet *w) +{ + int i; + unsigned char ch; + for (i=0;ilen;i++) + { + ch=w->val[i]; + printf("%c",ch); + } +} + +/* Kill an octet string - Zeroise it for security */ + +P1363_API void OCTET_KILL(octet *w) +{ + int i; + for (i=0;imax;i++) w->val[i]=0; + w->len=0; + w->max=0; +#ifndef OCTET_FROM_STACK_SIZE + free(w->val); +#endif +} + +/*** P1363 Auxiliary Functions ***/ + +/* Internal - All Purpose Hash function */ + +/* Input is taken from + +1. octet p +2. pointer to 32-bit number n +3. octet x +4. file fp - opened by calling program +5. octet e + + in this order. + +Returns TRUE if x and/or fp are empty + +*/ + +static BOOL hash(octet *p,int *n,octet *x,FILE *fp,octet *e,int hash_type,octet *w) +{ + BOOL result=TRUE; + int i,hlen,ch,c[4]; + sha256 sh32; +#ifdef mr_unsign64 + sha512 sh64; +#endif + char hh[MAX_HASH_BYTES]; + + if (n!=NULL) + { + c[0]=(*n>>24)&0xff; + c[1]=(*n>>16)&0xff; + c[2]=(*n>>8)&0xff; + c[3]=(*n)&0xff; + } + + hlen=hash_params(hash_type,NULL); + if (hlen==0) + { + OCTET_EMPTY(w); + return result; + } + + switch (hash_type) + { + case SHA1: + shs_init(&sh32); + if (p!=NULL) + for (i=0;ilen;i++) shs_process(&sh32,p->val[i]); + if (n!=NULL) + for (i=0;i<4;i++) shs_process(&sh32,c[i]); + if (x!=NULL) + for (i=0;ilen;i++) + { shs_process(&sh32,x->val[i]); result=FALSE; } + if (fp!=NULL) + while ((ch=fgetc(fp))!=EOF) + { shs_process(&sh32,ch); result=FALSE;} + if (e!=NULL) + for (i=0;ilen;i++) shs_process(&sh32,e->val[i]); + shs_hash(&sh32,hh); + break; + case SHA256: + shs256_init(&sh32); + if (p!=NULL) + for (i=0;ilen;i++) shs256_process(&sh32,p->val[i]); + if (n!=NULL) + for (i=0;i<4;i++) shs256_process(&sh32,c[i]); + if (x!=NULL) + for (i=0;ilen;i++) + { shs256_process(&sh32,x->val[i]); result=FALSE; } + if (fp!=NULL) + while ((ch=fgetc(fp))!=EOF) + { shs256_process(&sh32,ch); result=FALSE; } + if (e!=NULL) + for (i=0;ilen;i++) shs256_process(&sh32,e->val[i]); + shs256_hash(&sh32,hh); + break; +#ifdef mr_unsign64 + case SHA384: + shs384_init(&sh64); + if (p!=NULL) + for (i=0;ilen;i++) shs384_process(&sh64,p->val[i]); + if (n!=NULL) + for (i=0;i<4;i++) shs384_process(&sh64,c[i]); + if (x!=NULL) + for (i=0;ilen;i++) + { shs384_process(&sh64,x->val[i]); result=FALSE; } + if (fp!=NULL) + while ((ch=fgetc(fp))!=EOF) + { shs384_process(&sh64,ch); result=FALSE; } + if (e!=NULL) + for (i=0;ilen;i++) shs384_process(&sh64,e->val[i]); + shs384_hash(&sh64,hh); + break; + case SHA512: + shs512_init(&sh64); + if (p!=NULL) + for (i=0;ilen;i++) shs512_process(&sh64,p->val[i]); + if (n!=NULL) + for (i=0;i<4;i++) shs512_process(&sh64,c[i]); + if (x!=NULL) + for (i=0;ilen;i++) + { shs512_process(&sh64,x->val[i]); result=FALSE; } + if (fp!=NULL) + while ((ch=fgetc(fp))!=EOF) + { shs512_process(&sh64,ch); result=FALSE; } + if (e!=NULL) + for (i=0;ilen;i++) shs512_process(&sh64,e->val[i]); + shs512_hash(&sh64,hh); + break; +#endif + default: + OCTET_EMPTY(w); + return result; + } + OCTET_EMPTY(w); + OCTET_JOIN_BYTES(hh,hlen,w); + for (i=0;ilen,raw->val,0L); +} + +P1363_API void KILL_CSPRNG(csprng *RNG) +{ + strong_kill(RNG); +} + +/* Mask Generation Function */ + +P1363_API void MGF1(octet *z,int olen,int hash_type,octet *mask) +{ + octet h; + int counter,cthreshold; + int hlen; + + hlen=hash_params(hash_type,NULL); + if (hlen==0) return; + OCTET_INIT(&h,hlen); + OCTET_EMPTY(mask); + + cthreshold=MR_ROUNDUP(olen,hlen); + + for (counter=0;counterlen+hlen>olen) OCTET_JOIN_BYTES(h.val,olen%hlen,mask); + else OCTET_JOIN_OCTET(&h,mask); + } + OCTET_KILL(&h); +} + +/*** P1363 recommended Message Encoding Methods ***/ +/* message encoding methods for signatures with Appendix */ + +P1363_API BOOL EMSA1(octet *x,FILE *fp,int bits,int hash_type,octet *w) +{ /* w is a bits-length representative of the * + * octet string message x (if x!=NULL) * + * or of the file fp (if fp!=NULL) * + * w must be initialised for at least 20 bytes */ + unsigned char c1,c2; + int i,hlen; + + hash(NULL,NULL,x,fp,NULL,hash_type,w); + hlen=hash_params(hash_type,NULL); + if (hlen==0) return FALSE; + + if (bits<8*hlen) + { + for (i=hlen-1;i>bits/8;i--) + { /* remove bytes off the end */ + w->val[i]=0; + w->len--; + } + bits=bits%8; + if (bits!=0) + { + for (i=w->len-1;i>=0;i--) + { + c1=(unsigned char)w->val[i]; + c1>>=(8-bits); + if (i>0) + { + c2=(unsigned char)w->val[i-1]; + c2<<=bits; + c1|=c2; + } + w->val[i]=(char)c1; + } + } + } + return TRUE; +} + +P1363_API BOOL EMSA2(octet *x,FILE *fp,int bits,int hash_type,octet *w) +{ /* w is a bits-length representative of the * + * octet string message x (if x!=NULL) * + * and/or of the file fp (if fp!=NULL) * + * w must be initialised for at least 1+bits/8 * + * bytes */ + int lp,hlen; + char id,p1; + octet h; + BOOL zero; + hlen=hash_params(hash_type,NULL); + if (hlen==0 || ((bits+1)%8)!=0) return FALSE; + if (bits<8*hlen+31 || (x!=NULL && fp!=NULL)) return FALSE; + + id=sha_id[hash_type]; + + OCTET_INIT(&h,hlen); + zero=hash(NULL,NULL,x,fp,NULL,hash_type,&h); + + p1=0x4b; + if (!zero) p1=0x6b; + lp=((bits+1)/8)-hlen-4; + + OCTET_EMPTY(w); + OCTET_JOIN_BYTE(p1,1,w); + OCTET_JOIN_BYTE(0xbb,lp,w); + OCTET_JOIN_BYTE(0xba,1,w); + OCTET_JOIN_OCTET(&h,w); + OCTET_JOIN_BYTE(id,1,w); + OCTET_JOIN_BYTE(0xcc,1,w); + + OCTET_KILL(&h); + return TRUE; +} + +P1363_API BOOL EMSA3(octet *x,FILE *fp,int bits,int hash_type,octet *w) +{ /* w is a bits-length representative of the * + * octet string message x (if x!=NULL) * + * or of the file fp (if fp!=NULL) * + * w must be initialised big enough to take * + * the result > hlen+hashIDlen+10 bytes */ + int olen,hlen,hashIDlen; + unsigned char *idptr; + octet h; + hlen=hash_params(hash_type,NULL); + if (hlen==0) return FALSE; + + switch (hash_type) + { + case SHA1: + hashIDlen=SHA160ID[0]; + idptr=&SHA160ID[1]; + break; + case SHA256: + hashIDlen=SHA256ID[0]; + idptr=&SHA256ID[1]; + break; +#ifdef mr_unsign64 + case SHA384: + hashIDlen=SHA384ID[0]; + idptr=&SHA384ID[1]; + break; + case SHA512: + hashIDlen=SHA512ID[0]; + idptr=&SHA512ID[1]; + break; +#endif + default: + break; + } + olen=bits/8; + if (olenhlen+1 || r2len>hlen+1) return FALSE; + } + else + { + if (r1len>hlen || r2len>hlen) return FALSE; + } + + if (fp==NULL) + { + if (m2!=NULL) m2len=m2->len; + else m2len=0; + } + else + { + if (m2!=NULL) return FALSE; + m2len=filelength(fp); + } + + if (m2len==0) rlen=r1len; + else rlen=r2len; + + if (bits<8*rlen) return FALSE; + + if (m1len > olen-rlen) return FALSE; + + OCTET_INIT(&r,rlen+m1len); + OCTET_COPY(f,&r); + if (!OCTET_PAD(&r,rlen+m1len)) + { + OCTET_KILL(&r); + return FALSE; + } + OCTET_CHOP(&r,rlen,m1); + OCTET_INIT(&hh,16+m1len); + OCTET_INIT(&h,hlen+1); + + OCTET_JOIN_LONG((long)m1len,8,&hh); + OCTET_JOIN_LONG(m2len,8,&hh); + OCTET_JOIN_OCTET(m1,&hh); + + hash(&hh,NULL,m2,fp,v,hash_type,&h); + + if (hash_id) + OCTET_JOIN_BYTE(sha_id[hash_type],1,&h); + OCTET_CHOP(&h,rlen,NULL); + + result=OCTET_COMPARE(&h,&r); + OCTET_KILL(&r); + OCTET_KILL(&h); + OCTET_KILL(&hh); + return result; +} + +P1363_API BOOL EMSR1_ENCODE(BOOL hash_id,int r1len,int r2len,octet *m1,octet *m2,FILE *fp,int bits,int hash_type,octet *v,octet *f) +{ /* m2 can come from an OCTET or from a file.... */ + int m1len,rlen,hlen,olen=bits/8; + long m2len; + octet hh,h; + + hlen=hash_params(hash_type,NULL); + if (hlen==0) return FALSE; + if (hash_id) + { + if (r1len!=hlen+1 || r2len!=hlen+1) return FALSE; + } + else + { + if (r1len>hlen || r2len>hlen) return FALSE; + } + + m1len=m1->len; + if (fp==NULL) + { + if (m2!=NULL) m2len=m2->len; + else m2len=0; + } + else + { + if (m2!=NULL) return FALSE; + m2len=filelength(fp); + } + + if (m2len==0) rlen=r1len; + else rlen=r2len; + if (bits<8*rlen) return FALSE; + + if (m1len > olen-rlen) return FALSE; + + OCTET_INIT(&hh,16+m1len); + OCTET_INIT(&h,hlen+1); + + OCTET_JOIN_LONG((long)m1len,8,&hh); + OCTET_JOIN_LONG(m2len,8,&hh); + OCTET_JOIN_OCTET(m1,&hh); + + hash(&hh,NULL,m2,fp,v,hash_type,&h); + + if (hash_id) + OCTET_JOIN_BYTE(sha_id[hash_type],1,&h); + OCTET_CHOP(&h,rlen,NULL); + + OCTET_EMPTY(f); + OCTET_JOIN_OCTET(&h,f); + OCTET_JOIN_OCTET(m1,f); + + OCTET_KILL(&h); + OCTET_KILL(&hh); + + return TRUE; +} + +/* EMSR2 - p is key derivation parameters - NULL by default * + * sym=TRUE - use symmetric encryption + * sym=FALSE - use stream cipher + * assumes KDF2 and AES. */ + +P1363_API BOOL EMSR2_DECODE(int padlen,BOOL sym,int hash_type,octet *p,octet *c,octet *v,octet *m) +{ + int i,len,clen; + octet t,k; + clen=c->len; + if (clen=t.len) + { + OCTET_KILL(&t); + return FALSE; + } + } + OCTET_CHOP(&t,padlen,m); + OCTET_KILL(&t); + + return TRUE; +} + +P1363_API BOOL EMSR2_ENCODE(int padlen,BOOL sym,int hash_type,octet *p,octet *m,octet *v,octet *c) +{ + int mlen; + octet k,t; + + if (padlen<1 || padlen>255) return FALSE; + mlen=m->len; + OCTET_INIT(&t,padlen+mlen); + OCTET_JOIN_BYTE(padlen,padlen,&t); + OCTET_JOIN_OCTET(m,&t); + + if (sym) + { + OCTET_INIT(&k,16); /* AES Key */ + if (!KDF2(v,p,16,hash_type,&k)) + { + OCTET_KILL(&t); + OCTET_KILL(&k); + return FALSE; + } + if (!AES_CBC_IV0_ENCRYPT(&k,&t,NULL,c,NULL)) + { + OCTET_KILL(&t); + OCTET_KILL(&k); + return FALSE; + } + } + else + { + OCTET_INIT(&k,padlen+mlen); + if (!KDF2(v,p,padlen+mlen,hash_type,&k)) + { + OCTET_KILL(&t); + OCTET_KILL(&k); + return FALSE; + } + OCTET_XOR(&k,&t); + OCTET_COPY(&t,c); + } + OCTET_KILL(&t); + OCTET_KILL(&k); + + return TRUE; +} + + +/* PSS Message Encoding */ + +P1363_API BOOL EMSA4_ENCODE(BOOL hash_id,int hash_type,int slen,csprng *RNG,int bits,octet *m,FILE *fp,octet *f) +{ + return EMSR3_ENCODE(hash_id,hash_type,slen,RNG,bits,NULL,m,fp,f); +} + +P1363_API BOOL EMSA4_DECODE(BOOL hash_id,int hash_type,int slen,int bits,octet *f,octet *m,FILE *fp) +{ + return EMSR3_DECODE(hash_id,hash_type,slen,bits,f,m,fp,NULL); +} + +/* PSS-R Message Encoding for signature with recovery */ + +P1363_API BOOL EMSR3_ENCODE(BOOL hash_id,int hash_type,int slen,csprng *RNG,int bits,octet *m1,octet *m2,FILE *fp,octet *f) +{ + int m1len,hlen,u,olen,t,zbytes,dblen; + unsigned char mask; + octet h,salt,md,db; + u=1; + if (hash_id) u=2; + if (m1!=NULL) m1len=m1->len; + else m1len=0; + + hlen=hash_params(hash_type,NULL); + if (hlen==0) return FALSE; + + olen=MR_ROUNDUP(bits,8); + + t=8*olen-bits; + mask=0xFF; + if (t>0) mask>>=t; + + if (8*m1len>bits-8*slen-8*hlen-8*u-1) return FALSE; + + OCTET_INIT(&h,hlen); + hash(NULL,NULL,m2,fp,NULL,hash_type,&h); + + OCTET_INIT(&salt,slen); + OCTET_RAND(RNG,slen,&salt); + + OCTET_INIT(&md,8+m1len+hlen+slen); + OCTET_JOIN_LONG(8*m1len,8,&md); + OCTET_JOIN_OCTET(m1,&md); + OCTET_JOIN_OCTET(&h,&md); + OCTET_JOIN_OCTET(&salt,&md); + + hash(&md,NULL,NULL,NULL,NULL,hash_type,&h); + + OCTET_KILL(&md); + zbytes=olen-m1len-slen-hlen-u; + OCTET_INIT(&db,zbytes+m1len+slen); + OCTET_JOIN_BYTE(0x00,zbytes-1,&db); + OCTET_JOIN_BYTE(0x01,1,&db); + OCTET_JOIN_OCTET(m1,&db); + OCTET_JOIN_OCTET(&salt,&db); + OCTET_KILL(&salt); + + dblen=olen-hlen-u; + + MGF1(&h,dblen,hash_type,f); + + OCTET_XOR(&db,f); + f->val[0]&=mask; + + OCTET_JOIN_OCTET(&h,f); + OCTET_KILL(&h); + OCTET_KILL(&db); + if (hash_id) + { + OCTET_JOIN_BYTE(sha_id[hash_type],1,f); + OCTET_JOIN_BYTE(0xcc,1,f); + } + else + OCTET_JOIN_BYTE(0xbc,1,f); +/* remove leading zeros + while (f->val[0]==0) OCTET_SHIFT_LEFT(f,1); */ + + return TRUE; +} + +P1363_API BOOL EMSR3_DECODE(BOOL hash_id,int hash_type,int slen,int bits,octet *f,octet *m2,FILE *fp,octet *m1) +{ + int k,t,u,hlen,dblen,m1len,olen; + octet salt,h2,h,db,md,dbmask; + unsigned char mask,ch; + BOOL result; + + u=1; + if (hash_id) u=2; + + hlen=hash_params(hash_type,NULL); + if (hlen==0) return FALSE; + if (bits<8*slen+8*hlen+8*u+1) return FALSE; + + olen=MR_ROUNDUP(bits,8); + + t=8*olen-bits; + mask=0xFF; + if (t>0) mask>>=t; + + if (!OCTET_PAD(f,olen)) return FALSE; + if (hash_id) + { + if (f->val[olen-1]!=(char)0xcc) return FALSE; + if (f->val[olen-2]!=sha_id[hash_type]) return FALSE; + } + else + if (f->val[olen-1]!=(char)0xbc) return FALSE; + + if (f->val[0]&(~mask)) return FALSE; + + OCTET_INIT(&h2,hlen); + hash(NULL,NULL,m2,fp,NULL,hash_type,&h2); + + OCTET_INIT(&db,olen); + OCTET_INIT(&h,hlen+2); + + dblen=olen-hlen-u; + + OCTET_COPY(f,&db); + OCTET_CHOP(&db,dblen,&h); + OCTET_CHOP(&h,hlen,NULL); + + OCTET_INIT(&dbmask,dblen); + MGF1(&h,dblen,hash_type,&dbmask); + + OCTET_XOR(&dbmask,&db); + OCTET_KILL(&dbmask); + db.val[0]&=mask; + OCTET_INIT(&salt,slen); + OCTET_CHOP(&db,dblen-slen,&salt); + k=0; + while (klen; + int hlen,seedlen; + octet dbmask,seed; + + hlen=seedlen=hash_params(hash_type,NULL); + if (hlen==0 || mlen>olen-hlen-seedlen-1) return FALSE; + if (m==f) return FALSE; /* must be distinct octets */ + + hash(p,NULL,NULL,NULL,NULL,hash_type,f); + + slen=olen-mlen-hlen-seedlen-1; + + OCTET_JOIN_BYTE(0,slen,f); + OCTET_JOIN_BYTE(0x1,1,f); + OCTET_JOIN_OCTET(m,f); + + OCTET_INIT(&dbmask,olen-seedlen); + + OCTET_INIT(&seed,seedlen); + OCTET_RAND(RNG,seedlen,&seed); + + MGF1(&seed,olen-seedlen,hash_type,&dbmask); + OCTET_XOR(f,&dbmask); + MGF1(&dbmask,seedlen,hash_type,f); + OCTET_XOR(&seed,f); + OCTET_JOIN_OCTET(&dbmask,f); + OCTET_KILL(&seed); + OCTET_KILL(&dbmask); + + return TRUE; +} + +/* OAEP Message Decoding for Decryption */ + +P1363_API BOOL EME1_DECODE(octet *f,int bits,octet *p,int hash_type,octet *m) +{ + BOOL comp; + int i,k,olen=bits/8; + int hlen,seedlen; + octet dbmask,seed,chash; + int x,t; + + seedlen=hlen=hash_params(hash_type,NULL); + if (hlen==0 || olenval[0]; + for (i=seedlen;ival[i+1]; + dbmask.len=olen-seedlen; + + MGF1(&dbmask,seedlen,hash_type,&seed); + for (i=0;ival[i+1]; + MGF1(&seed,olen-seedlen,hash_type,m); + OCTET_XOR(m,&dbmask); + comp=OCTET_NCOMPARE(&chash,&dbmask,hlen); + OCTET_SHIFT_LEFT(&dbmask,hlen); + + OCTET_KILL(&seed); + OCTET_KILL(&chash); + for (k=0;;k++) + { + if (k>=dbmask.len) + { + OCTET_KILL(&dbmask); + return FALSE; + } + if (dbmask.val[k]!=0) break; + } + t=dbmask.val[k]; + if (!comp || x!=0 || t!=0x01) + { + OCTET_KILL(&dbmask); + return FALSE; + } + OCTET_SHIFT_LEFT(&dbmask,k+1); + + OCTET_COPY(&dbmask,m); + OCTET_KILL(&dbmask); + + return TRUE; +} + +/*** P1363 Key Derivation Functions ***/ + +P1363_API void KDF1(octet *z,octet *p,int hash_type,octet *k) +{ + hash(z,NULL,p,NULL,NULL,hash_type,k); +} + +P1363_API BOOL KDF2(octet *z,octet *p,int olen,int hash_type,octet *k) +{ +/* NOTE: the parameter olen is the length of the output k in bytes */ + + int counter,cthreshold; + int hlen; + octet h; + + hlen=hash_params(hash_type,NULL); + if (hlen==0) return FALSE; + cthreshold=MR_ROUNDUP(olen,hlen); + + OCTET_EMPTY(k); + OCTET_INIT(&h,hlen); + for (counter=1;counter<=cthreshold;counter++) + { + hash(z,&counter,p,NULL,NULL,hash_type,&h); + if (k->len+hlen>olen) OCTET_JOIN_BYTES(h.val,olen%hlen,k); + else OCTET_JOIN_OCTET(&h,k); + } + OCTET_KILL(&h); + return TRUE; +} + +/*** P1363 Message Authentication codes ***/ + +P1363_API BOOL MAC1(octet *m,FILE *fp,octet *k,int olen,int hash_type,octet *tag) +{ +/* Input is either from an octet m, or a file fp. * + * olen is requested output length in bytes. k is the key * + * The output is the calculated tag */ + int hlen,b; + octet h,k0; + + hlen=hash_params(hash_type,&b); + if (hlen==0 || k->lenhlen) return FALSE; + + OCTET_INIT(&k0,b); + OCTET_INIT(&h,hlen); + + if (k->len > b) hash(k,NULL,NULL,NULL,NULL,hash_type,&k0); + else OCTET_COPY(k,&k0); + + OCTET_JOIN_BYTE(0,b-k0.len,&k0); + + OCTET_XOR_BYTE(&k0,0x36); + hash(&k0,NULL,m,fp,NULL,hash_type,&h); + + OCTET_XOR_BYTE(&k0,0x6a); /* 0x6a = 0x36 ^ 0x5c */ + hash(&k0,NULL,&h,NULL,NULL,hash_type,&h); + + OCTET_EMPTY(tag); + OCTET_JOIN_BYTES(h.val,olen,tag); + + OCTET_KILL(&h); + OCTET_KILL(&k0); + + return TRUE; +} + +P1363_API BOOL AES_CBC_IV0_DECRYPT(octet *k,octet *c,FILE *ifp,octet *m,FILE *ofp) +{ + aes a; + int i,ipt,opt,ch; + char buff[16]; + BOOL fin,bad; + int padlen; + ipt=opt=0; + if (m!=NULL) + { + if (ofp!=NULL) return FALSE; + OCTET_CLEAR(m); + } + if (c!=NULL) + { + if (ifp!=NULL) return FALSE; + if (c->len==0) return FALSE; + else ch=c->val[ipt++]; + } + if (!aes_init(&a,MR_CBC,k->len,k->val,NULL)) return FALSE; + if (ifp!=NULL) + { + ch=fgetc(ifp); + if (ch==EOF) return FALSE; + } + fin=FALSE; + + forever + { + for (i=0;i<16;i++) + { + if (c!=NULL) + { + buff[i]=ch; + if (ipt>=c->len) {fin=TRUE; break;} + else ch=c->val[ipt++]; + } + if (ifp!=NULL) + { + buff[i]=ch; + if ((ch=fgetc(ifp))==EOF) {fin=TRUE; break;} + } + } + aes_decrypt(&a,buff); + if (fin) break; + for (i=0;i<16;i++) + { + if (m!=NULL) if (optmax) m->val[opt++]=buff[i]; + if (ofp!=NULL) fputc(buff[i],ofp); + } + } + aes_end(&a); + bad=FALSE; + padlen=buff[15]; + if (i!=15 || padlen<1 || padlen>16) bad=TRUE; + if (padlen>=2 && padlen<=16) + for (i=16-padlen;i<16;i++) if (buff[i]!=padlen) bad=TRUE; + + if (!bad) for (i=0;i<16-padlen;i++) + { + if (m!=NULL) if (optmax) m->val[opt++]=buff[i]; + if (ofp!=NULL) fputc(buff[i],ofp); + } + if (m!=NULL) m->len=opt; + if (bad) return FALSE; + return TRUE; +} + +P1363_API BOOL AES_CBC_IV0_ENCRYPT(octet *k,octet *m,FILE *ifp,octet *c,FILE *ofp) +{ /* AES CBC encryption, with Null IV */ + /* Input is from either an octet string m, or from a file ifp, + output is to an octet string c, or a file ofp */ + aes a; + int i,j,ipt,opt,ch; + char buff[16]; + BOOL fin; + int padlen; + if (m!=NULL && ifp!=NULL) return FALSE; + if (c!=NULL) + { + if (ofp!=NULL) return FALSE; + OCTET_CLEAR(c); + } + if (!aes_init(&a,MR_CBC,k->len,k->val,NULL)) return FALSE; + + ipt=opt=0; + fin=FALSE; + forever + { + for (i=0;i<16;i++) + { + if (m!=NULL) + { + if (iptlen) buff[i]=m->val[ipt++]; + else {fin=TRUE; break;} + } + if (ifp!=NULL) + { + if ((ch=fgetc(ifp))!=EOF) buff[i]=ch; + else {fin=TRUE; break;} + } + } + if (fin) break; + aes_encrypt(&a,buff); + for (i=0;i<16;i++) + { + if (c!=NULL) if (optmax) c->val[opt++]=buff[i]; + if (ofp!=NULL) fputc(buff[i],ofp); + } + } + +/* last block, filled up to i-th index */ + + padlen=16-i; + for (j=i;j<16;j++) buff[j]=padlen; + aes_encrypt(&a,buff); + for (i=0;i<16;i++) + { + if (c!=NULL) if (optmax) c->val[opt++]=buff[i]; + if (ofp!=NULL) fputc(buff[i],ofp); + } + aes_end(&a); + if (c!=NULL) c->len=opt; + return TRUE; +} + +/*** DL primitives - support functions ***/ +/* Destroy the DL Domain structure */ + +P1363_API void DL_DOMAIN_KILL(dl_domain *DOM) +{ + OCTET_KILL(&DOM->Q); + OCTET_KILL(&DOM->R); + OCTET_KILL(&DOM->G); + OCTET_KILL(&DOM->K); + OCTET_KILL(&DOM->IK); +#ifndef MR_STATIC + if (DOM->PC.window!=0) + brick_end(&DOM->PC); +#endif + DOM->words=DOM->fsize=0; DOM->H=DOM->rbits=0; +} + +/* Initialise the DL domain structure + * It is assumed that the DL domain details are obtained from a file + * or from an array of strings + * multi-precision numbers are read in in Hex + * A suitable file can be generated offline by the MIRACL example program + * dssetup.c + * Set precompute=window size if a precomputed table is to be used to + * speed up the calculation g^x mod p + * Returns recommended number of bytes for use with octet strings */ + +P1363_API int DL_DOMAIN_INIT(dl_domain *DOM,char *fname,char **params,int precompute) +{ /* get domain details from specified file, OR from an array of strings * + * If input from a file, params=NULL, if input from strings, fname=NULL * + * returns filed size in bytes * + * precompute is 0 for no precomputation, or else window size for Comb method */ + FILE *fp; + BOOL tt1,fileinput=TRUE; +#ifdef MR_GENERIC_AND_STATIC + miracl instance; +#endif + miracl *mr_mip; + big q,r,g,k; + int bits,rbits,bytes,rbytes,err,res=0; + +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(4)]; + memset(mem,0,MR_BIG_RESERVE(4)); +#endif + + if (fname==NULL && params==NULL) return MR_P1363_DOMAIN_NOT_FOUND; + if (fname==NULL) fileinput=FALSE; + + if (fileinput) + { + fp=fopen(fname,"rt"); + if (fp==NULL) return MR_P1363_DOMAIN_NOT_FOUND; + fscanf(fp,"%d\n",&bits); + } + else + sscanf(params[0],"%d\n",&bits); + + DOM->words=MR_ROUNDUP(bits,MIRACL); +#ifdef MR_GENERIC_AND_STATIC + mr_mip=mirsys(&instance,MR_ROUNDUP(bits,4),16); +#else + mr_mip=mirsys(MR_ROUNDUP(bits,4),16); +#endif + if (mr_mip==NULL) + { + if (fileinput) fclose(fp); + return MR_P1363_OUT_OF_MEMORY; + } + +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 4); + if (mem==NULL) + { + if (fileinput) fclose(fp); + res=MR_P1363_OUT_OF_MEMORY; + } +#endif + + mr_mip->ERCON=TRUE; + + if (res==0) + { + q=mirvar_mem(_MIPP_ mem,0); + r=mirvar_mem(_MIPP_ mem,1); + g=mirvar_mem(_MIPP_ mem,2); + k=mirvar_mem(_MIPP_ mem,3); + + bytes=MR_ROUNDUP(bits,8); + + if (fileinput) + { + innum(_MIPP_ q,fp); + innum(_MIPP_ r,fp); + innum(_MIPP_ g,fp); + fclose(fp); + } + else + { + instr(_MIPP_ q,params[1]); + instr(_MIPP_ r,params[2]); + instr(_MIPP_ g,params[3]); + } + + rbits=logb2(_MIPP_ r); /* r is usually much smaller than q */ + rbytes=MR_ROUNDUP(rbits,8); + + OCTET_INIT(&DOM->Q,bytes); + OCTET_INIT(&DOM->R,rbytes); + OCTET_INIT(&DOM->G,bytes); + OCTET_INIT(&DOM->K,bytes); + OCTET_INIT(&DOM->IK,rbytes); + DOM->H=(1+rbits)/2; + DOM->fsize=bytes; + DOM->rbits=rbits; + decr(_MIPP_ q,1,k); + divide(_MIPP_ k,r,k); /* k=(q-1)/r */ + + convert_big_octet(_MIPP_ q,&DOM->Q); + convert_big_octet(_MIPP_ r,&DOM->R); + convert_big_octet(_MIPP_ g,&DOM->G); + convert_big_octet(_MIPP_ k,&DOM->K); + xgcd(_MIPP_ k,r,k,k,k); + convert_big_octet(_MIPP_ k,&DOM->IK); + DOM->PC.window=0; +#ifndef MR_STATIC + if (precompute) + brick_init(_MIPP_ &DOM->PC,g,q,precompute,logb2(_MIPP_ r)); +#endif + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,4); +#else + memset(mem,0,MR_BIG_RESERVE(4)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + if (res<0) return res; + else return bytes; +} + +/* validate DL domain details - good idea if you got them from + * some-one else! */ + +P1363_API int DL_DOMAIN_VALIDATE(BOOL (*idle)(void),dl_domain *DOM) +{ /* do domain checks - IEEE P1363 A16.2 */ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,g,t; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(4)]; + memset(mem,0,MR_BIG_RESERVE(4)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + + mr_mip->ERCON=TRUE; + mr_mip->NTRY=50; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 4); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + + if (res==0) + { + q=mirvar_mem(_MIPP_ mem,0); + r=mirvar_mem(_MIPP_ mem,1); + g=mirvar_mem(_MIPP_ mem,2); + t=mirvar_mem(_MIPP_ mem,3); + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->G,g); + if (size(g)<2 || size(q)<=2 || size(r)<=2) res=MR_P1363_DOMAIN_ERROR; + if (mr_compare(g,q)>=0) res=MR_P1363_DOMAIN_ERROR; + } + if (res==0) + { + gprime(_MIPP_ 10000); + if (!isprime(_MIPP_ q)) res=MR_P1363_DOMAIN_ERROR; + } + if (res==0) + { + if (!isprime(_MIPP_ r)) res=MR_P1363_DOMAIN_ERROR; + } + if (res==0) + { /* is g of order r? */ + powmod(_MIPP_ g,r,q,t); + if (size(t)!=1) res=MR_P1363_DOMAIN_ERROR; + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,4); +#else + memset(mem,0,MR_BIG_RESERVE(4)); +#endif + err=mr_mip->ERNUM; + + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/* Calculate a public/private DL key pair. W=g^S mod p + * where S is the private key and W the public key + * If RNG is NULL then the private key is provided externally in S + * otherwise it is generated randomly internally + */ + +P1363_API int DL_KEY_PAIR_GENERATE(BOOL (*idle)(void),dl_domain *DOM,csprng *RNG, octet *S,octet *W) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,g,s,w; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(5)]; + memset(mem,0,MR_BIG_RESERVE(5)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 5); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem,0); + r=mirvar_mem(_MIPP_ mem,1); + g=mirvar_mem(_MIPP_ mem,2); + s=mirvar_mem(_MIPP_ mem,3); + w=mirvar_mem(_MIPP_ mem,4); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->G,g); + if (RNG!=NULL) + { + strong_bigrand(_MIPP_ RNG,r,s); + } + else + { + OS2FEP(_MIPP_ S,s); + divide(_MIPP_ s,r,r); + } + if (DOM->PC.window==0) + powmod(_MIPP_ g,s,q,w); + else + pow_brick(_MIPP_ &DOM->PC,s,w); + + if (RNG!=NULL) convert_big_octet(_MIPP_ s,S); + FE2OSP(_MIPP_ w,DOM->fsize,W); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,5); +#else + memset(mem,0,MR_BIG_RESERVE(5)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/* validate a DL public key. Set full=TRUE for fuller, + * but more time-consuming test */ + +P1363_API int DL_PUBLIC_KEY_VALIDATE(BOOL (*idle)(void),dl_domain *DOM,BOOL full,octet *W) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,w,t; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(4)]; + memset(mem,0,MR_BIG_RESERVE(4)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 4); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem,0); + r=mirvar_mem(_MIPP_ mem,1); + w=mirvar_mem(_MIPP_ mem,2); + t=mirvar_mem(_MIPP_ mem,3); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ W,w); + if (size(w)<2 || mr_compare(w,q)>=0) res=MR_P1363_INVALID_PUBLIC_KEY; + } + if (res==0 && full) + { + powmod(_MIPP_ w,r,q,t); + if (size(t)!=1) res=MR_P1363_INVALID_PUBLIC_KEY; + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,4); +#else + memset(mem,0,MR_BIG_RESERVE(4)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/*** P1363 DL primitives ***/ +/* See P1363 documentation for specification */ + +P1363_API int DLSVDP_DH(BOOL (*idle)(void),dl_domain *DOM,octet *S,octet *WD,octet *Z) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,s,wd,z; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(4)]; + memset(mem,0,MR_BIG_RESERVE(4)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 4); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem,0); + s=mirvar_mem(_MIPP_ mem,1); + wd=mirvar_mem(_MIPP_ mem,2); + z=mirvar_mem(_MIPP_ mem,3); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ WD,wd); + + powmod(_MIPP_ wd,s,q,z); + + FE2OSP(_MIPP_ z,DOM->fsize,Z); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,4); +#else + memset(mem,0,MR_BIG_RESERVE(4)); +#endif + err=mr_mip->ERNUM; + + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int DLSVDP_DHC(BOOL (*idle)(void),dl_domain *DOM,octet *S,octet *WD,BOOL compatible,octet *Z) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,k,ik,s,wd,t,z; + int sz; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(8)]; + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 8); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem,0); + r=mirvar_mem(_MIPP_ mem,1); + k=mirvar_mem(_MIPP_ mem,2); + ik=mirvar_mem(_MIPP_ mem,3); + s=mirvar_mem(_MIPP_ mem,4); + wd=mirvar_mem(_MIPP_ mem,5); + z=mirvar_mem(_MIPP_ mem,6); + t=mirvar_mem(_MIPP_ mem,7); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->K,k); + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ WD,wd); + + if (compatible) + { + OS2FEP(_MIPP_ &DOM->IK,ik); + mad(_MIPP_ ik,s,ik,r,r,t); /* t=s/k mod r */ + } + else copy(s,t); + multiply(_MIPP_ t,k,t); /* kt */ + powmod(_MIPP_ wd,t,q,z); + + sz=size(z); + if (sz==0 || sz==1) res=MR_P1363_INVALID_PUBLIC_KEY; + else FE2OSP(_MIPP_ z,DOM->fsize,Z); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,8); +#else + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int DLSVDP_MQV(BOOL (*idle)(void),dl_domain *DOM,octet *S,octet *U,octet *V,octet *WD,octet *VD,octet *Z) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + int h; + int err,res=0; + big q,r,s,u,v,wd,vd,e,t,td,z; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(11)]; + memset(mem,0,MR_BIG_RESERVE(11)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 11); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + s=mirvar_mem(_MIPP_ mem, 2); + u=mirvar_mem(_MIPP_ mem, 3); + v=mirvar_mem(_MIPP_ mem, 4); + wd=mirvar_mem(_MIPP_ mem, 5); + vd=mirvar_mem(_MIPP_ mem, 6); + e=mirvar_mem(_MIPP_ mem, 7); + t=mirvar_mem(_MIPP_ mem, 8); + td=mirvar_mem(_MIPP_ mem, 9); + z=mirvar_mem(_MIPP_ mem, 10); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ U,u); + OS2FEP(_MIPP_ V,v); + OS2FEP(_MIPP_ WD,wd); + OS2FEP(_MIPP_ VD,vd); + + h=DOM->H; + expb2(_MIPP_ h,z); + + copy(v,t); + divide(_MIPP_ t,z,z); + add(_MIPP_ t,z,t); + copy(vd,td); + divide(_MIPP_ td,z,z); + add(_MIPP_ td,z,td); + + mad(_MIPP_ t,s,u,r,r,e); + mad(_MIPP_ e,td,td,r,r,t); + powmod2(_MIPP_ vd,e,wd,t,q,z); + + if (size(z)==1) res= MR_P1363_ERROR; + else FE2OSP(_MIPP_ z,DOM->fsize,Z); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,11); +#else + memset(mem,0,MR_BIG_RESERVE(11)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int DLSVDP_MQVC(BOOL (*idle)(void),dl_domain *DOM,octet *S,octet *U,octet *V,octet *WD,octet *VD,BOOL compatible,octet *Z) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + int sz,h; + big q,r,s,u,v,wd,vd,e,t,td,z,k,ik; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(13)]; + memset(mem,0,MR_BIG_RESERVE(13)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 13); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + ik=mirvar_mem(_MIPP_ mem, 2); + k=mirvar_mem(_MIPP_ mem, 3); + s=mirvar_mem(_MIPP_ mem, 4); + u=mirvar_mem(_MIPP_ mem, 5); + v=mirvar_mem(_MIPP_ mem, 6); + wd=mirvar_mem(_MIPP_ mem, 7); + vd=mirvar_mem(_MIPP_ mem, 8); + e=mirvar_mem(_MIPP_ mem, 9); + t=mirvar_mem(_MIPP_ mem, 10); + td=mirvar_mem(_MIPP_ mem, 11); + z=mirvar_mem(_MIPP_ mem, 12); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->K,k); + + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ U,u); + OS2FEP(_MIPP_ V,v); + OS2FEP(_MIPP_ WD,wd); + OS2FEP(_MIPP_ VD,vd); + + h=DOM->H; + expb2(_MIPP_ h,z); + + copy(v,t); + divide(_MIPP_ t,z,z); + add(_MIPP_ t,z,t); + copy(vd,td); + divide(_MIPP_ td,z,z); + add(_MIPP_ td,z,td); + + mad(_MIPP_ t,s,u,r,r,e); + if (compatible) + { + OS2FEP(_MIPP_ &DOM->IK,ik); + mad(_MIPP_ e,ik,e,r,r,e); + } + mad(_MIPP_ e,k,e,r,r,e); + mad(_MIPP_ e,td,td,r,r,t); + powmod2(_MIPP_ vd,e,wd,t,q,z); + + sz=size(z); + if (sz==0 || sz==1) res=MR_P1363_INVALID_PUBLIC_KEY; + FE2OSP(_MIPP_ z,DOM->fsize,Z); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,13); +#else + memset(mem,0,MR_BIG_RESERVE(13)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int DLVP_NR(BOOL (*idle)(void),dl_domain *DOM,octet *W,octet *C,octet *D,octet *F) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,g,w,f,c,d; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(7)]; + memset(mem,0,MR_BIG_RESERVE(7)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 7); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + g=mirvar_mem(_MIPP_ mem, 2); + w=mirvar_mem(_MIPP_ mem, 3); + f=mirvar_mem(_MIPP_ mem, 4); + c=mirvar_mem(_MIPP_ mem, 5); + d=mirvar_mem(_MIPP_ mem, 6); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->G,g); + OS2FEP(_MIPP_ W,w); + OS2FEP(_MIPP_ C,c); + OS2FEP(_MIPP_ D,d); + if (size(c)<1 || mr_compare(c,r)>=0 || size(d)<0 || mr_compare(d,r)>=0) + res=MR_P1363_INVALID; + } + if (res==0) + { + powmod2(_MIPP_ g,d,w,c,q,f); + divide(_MIPP_ f,r,r); + subtract(_MIPP_ c,f,f); + if (size(f)<0) add(_MIPP_ f,r,f); + convert_big_octet(_MIPP_ f,F); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,7); +#else + memset(mem,0,MR_BIG_RESERVE(7)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int DLSP_NR(BOOL (*idle)(void),dl_domain *DOM,csprng *RNG,octet *S,octet *F,octet *C,octet *D) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,g,s,f,c,d,u,v; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(9)]; + memset(mem,0,MR_BIG_RESERVE(9)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 9); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + g=mirvar_mem(_MIPP_ mem, 2); + s=mirvar_mem(_MIPP_ mem, 3); + f=mirvar_mem(_MIPP_ mem, 4); + c=mirvar_mem(_MIPP_ mem, 5); + d=mirvar_mem(_MIPP_ mem, 6); + u=mirvar_mem(_MIPP_ mem, 7); + v=mirvar_mem(_MIPP_ mem, 8); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->G,g); + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ F,f); + if (mr_compare(f,r)>=0) res=MR_P1363_BAD_ASSUMPTION; + } + if (res==0) + { + do { + if (mr_mip->ERNUM) break; + strong_bigrand(_MIPP_ RNG,r,u); + + if (DOM->PC.window==0) + powmod(_MIPP_ g,u,q,v); + else + pow_brick(_MIPP_ &DOM->PC,u,v); + + add(_MIPP_ v,f,c); + divide(_MIPP_ c,r,r); + } while (size(c)==0); + } + if (res==0) + { + mad(_MIPP_ s,c,s,r,r,d); + subtract(_MIPP_ u,d,d); + if (size(d)<0) add(_MIPP_ d,r,d); + + convert_big_octet(_MIPP_ c,C); + convert_big_octet(_MIPP_ d,D); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,9); +#else + memset(mem,0,MR_BIG_RESERVE(9)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int DLVP_DSA(BOOL (*idle)(void),dl_domain *DOM,octet *W,octet *C,octet *D,octet *F) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,g,w,f,c,d,h2; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(8)]; + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 8); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + g=mirvar_mem(_MIPP_ mem, 2); + w=mirvar_mem(_MIPP_ mem, 3); + f=mirvar_mem(_MIPP_ mem, 4); + c=mirvar_mem(_MIPP_ mem, 5); + d=mirvar_mem(_MIPP_ mem, 6); + h2=mirvar_mem(_MIPP_ mem, 7); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->G,g); + OS2FEP(_MIPP_ W,w); + OS2FEP(_MIPP_ C,c); + OS2FEP(_MIPP_ D,d); + OS2FEP(_MIPP_ F,f); + if (size(c)<1 || size(d)<1 || mr_compare(c,r)>=0 || mr_compare(d,r)>=0) + res=MR_P1363_INVALID; + } + if (res==0) + { + xgcd(_MIPP_ d,r,d,d,d); + mad(_MIPP_ f,d,f,r,r,f); + mad(_MIPP_ c,d,c,r,r,h2); + powmod2(_MIPP_ g,f,w,h2,q,d); + divide(_MIPP_ d,r,r); + if (mr_compare(d,c)!=0) res=MR_P1363_INVALID; + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,8); +#else + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int DLSP_DSA(BOOL (*idle)(void),dl_domain *DOM,csprng *RNG,octet *S,octet *F,octet *C,octet *D) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,g,s,f,c,d,u,v; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(9)]; + memset(mem,0,MR_BIG_RESERVE(9)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=FALSE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 9); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + g=mirvar_mem(_MIPP_ mem, 2); + s=mirvar_mem(_MIPP_ mem, 3); + f=mirvar_mem(_MIPP_ mem, 4); + c=mirvar_mem(_MIPP_ mem, 5); + d=mirvar_mem(_MIPP_ mem, 6); + u=mirvar_mem(_MIPP_ mem, 7); + v=mirvar_mem(_MIPP_ mem, 8); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->G,g); + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ F,f); + + do { + if (mr_mip->ERNUM) break; + strong_bigrand(_MIPP_ RNG,r,u); + + if (DOM->PC.window==0) + powmod(_MIPP_ g,u,q,v); + else + pow_brick(_MIPP_ &DOM->PC,u,v); + + copy(v,c); + divide(_MIPP_ c,r,r); + if (size(c)==0) continue; + xgcd(_MIPP_ u,r,u,u,u); + mad(_MIPP_ s,c,f,r,r,d); + mad(_MIPP_ u,d,u,r,r,d); + } while (size(d)==0); + if (res==0) + { + convert_big_octet(_MIPP_ c,C); + convert_big_octet(_MIPP_ d,D); + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,9); +#else + memset(mem,0,MR_BIG_RESERVE(9)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int DLPSP_NR2PV(BOOL (*idle)(void),dl_domain *DOM,csprng *RNG,octet *U,octet *V) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,g,u,v; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(5)]; + memset(mem,0,MR_BIG_RESERVE(5)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=FALSE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 5); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + g=mirvar_mem(_MIPP_ mem, 2); + u=mirvar_mem(_MIPP_ mem, 3); + v=mirvar_mem(_MIPP_ mem, 4); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->G,g); + strong_bigrand(_MIPP_ RNG,r,u); + + if (DOM->PC.window==0) + powmod(_MIPP_ g,u,q,v); + else + pow_brick(_MIPP_ &DOM->PC,u,v); + + convert_big_octet(_MIPP_ u,U); + FE2OSP(_MIPP_ v,DOM->fsize,V); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,5); +#else + memset(mem,0,MR_BIG_RESERVE(5)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int DLSP_NR2(BOOL (*idle)(void),dl_domain *DOM,octet *S,octet *U,octet *V,octet *F,octet *C,octet *D) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,u,v,c,d,s,f; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(8)]; + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=FALSE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 8); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + s=mirvar_mem(_MIPP_ mem, 2); + f=mirvar_mem(_MIPP_ mem, 3); + u=mirvar_mem(_MIPP_ mem, 4); + v=mirvar_mem(_MIPP_ mem, 5); + c=mirvar_mem(_MIPP_ mem, 6); + d=mirvar_mem(_MIPP_ mem, 7); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ F,f); + OS2FEP(_MIPP_ U,u); + OS2FEP(_MIPP_ V,v); + if (mr_compare(f,r)>=0) res=MR_P1363_BAD_ASSUMPTION; + if (size(u)<1 || mr_compare(u,r)>=0) res=MR_P1363_BAD_ASSUMPTION; + if (size(v)<1 || mr_compare(v,q)>=0) res=MR_P1363_BAD_ASSUMPTION; + } + + if (res==0) + { + add(_MIPP_ v,f,c); + divide(_MIPP_ c,r,r); + if (size(c)==0) res=MR_P1363_ERROR; + } + if (res==0) + { + mad(_MIPP_ s,c,s,r,r,d); + subtract(_MIPP_ u,d,d); + if (size(d)<0) add(_MIPP_ d,r,d); + + convert_big_octet(_MIPP_ c,C); + convert_big_octet(_MIPP_ d,D); + } + + OCTET_CLEAR(U); +#ifndef MR_STATIC + memkill(_MIPP_ mem,8); +#else + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int DLVP_NR2(BOOL (*idle)(void),dl_domain *DOM,octet *W,octet *C,octet *D,octet *F,octet *V) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,g,c,d,w,f,v; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(8)]; + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=FALSE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 8); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + g=mirvar_mem(_MIPP_ mem, 2); + w=mirvar_mem(_MIPP_ mem, 3); + c=mirvar_mem(_MIPP_ mem, 4); + d=mirvar_mem(_MIPP_ mem, 5); + f=mirvar_mem(_MIPP_ mem, 6); + v=mirvar_mem(_MIPP_ mem, 7); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->G,g); + OS2FEP(_MIPP_ W,w); + OS2FEP(_MIPP_ C,c); + OS2FEP(_MIPP_ D,d); + if (size(c)<1 || mr_compare(c,r)>=0 || mr_compare(d,r)>=0) res=MR_P1363_INVALID; + } + + if (res==0) + { + powmod2(_MIPP_ g,d,w,c,q,v); + copy(v,f); + divide(_MIPP_ f,r,r); + subtract(_MIPP_ c,f,f); + if (size(f)<0) add(_MIPP_ f,r,f); + convert_big_octet(_MIPP_ f,F); + FE2OSP(_MIPP_ v,DOM->fsize,V); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,8); +#else + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int DLSP_PV(BOOL (*idle)(void),dl_domain *DOM,octet *S,octet *U,octet *H,octet *D) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,h,u,d,s; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(6)]; + memset(mem,0,MR_BIG_RESERVE(6)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=FALSE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 6); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + s=mirvar_mem(_MIPP_ mem, 2); + u=mirvar_mem(_MIPP_ mem, 3); + h=mirvar_mem(_MIPP_ mem, 4); + d=mirvar_mem(_MIPP_ mem, 5); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ U,u); + OS2FEP(_MIPP_ H,h); + if (mr_compare(u,r)>=0) res=MR_P1363_BAD_ASSUMPTION; + } + + if (res==0) + { + mad(_MIPP_ s,h,s,r,r,d); + subtract(_MIPP_ u,d,d); + if (size(d)<0) add(_MIPP_ d,r,d); + + convert_big_octet(_MIPP_ d,D); + } + + OCTET_CLEAR(U); +#ifndef MR_STATIC + memkill(_MIPP_ mem,6); +#else + memset(mem,0,MR_BIG_RESERVE(6)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int DLVP_PV(BOOL (*idle)(void),dl_domain *DOM,octet *W,octet *H,octet *D,octet *V) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,g,d,w,h,v; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(7)]; + memset(mem,0,MR_BIG_RESERVE(7)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=FALSE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 7); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + g=mirvar_mem(_MIPP_ mem, 2); + w=mirvar_mem(_MIPP_ mem, 3); + h=mirvar_mem(_MIPP_ mem, 4); + d=mirvar_mem(_MIPP_ mem, 5); + v=mirvar_mem(_MIPP_ mem, 6); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->G,g); + OS2FEP(_MIPP_ W,w); + OS2FEP(_MIPP_ D,d); + OS2FEP(_MIPP_ H,h); + if (mr_compare(d,r)>=0) res=MR_P1363_INVALID; + } + + if (res==0) + { + powmod2(_MIPP_ g,d,w,h,q,v); + FE2OSP(_MIPP_ v,DOM->fsize,V); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,7); +#else + memset(mem,0,MR_BIG_RESERVE(7)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/*** EC GF(p) primitives - support functions ***/ +/* destroy the EC GF(p) domain structure */ + +P1363_API void ECP_DOMAIN_KILL(ecp_domain *DOM) +{ + OCTET_KILL(&DOM->Q); + OCTET_KILL(&DOM->A); + OCTET_KILL(&DOM->B); + OCTET_KILL(&DOM->R); + OCTET_KILL(&DOM->Gx); + OCTET_KILL(&DOM->Gy); + OCTET_KILL(&DOM->K); + OCTET_KILL(&DOM->IK); +#ifndef MR_STATIC + if (DOM->PC.window!=0) + ebrick_end(&DOM->PC); +#endif + DOM->words=DOM->fsize=0; DOM->H=DOM->rbits=0; +} + +/* Initialise the EC GF(p) domain structure + * It is assumed that the EC domain details are obtained from a file + * or from an array of strings + * multiprecision numbers are read in in Hex + * A suitable file can be generated offline by the MIRACL example program + * schoof.exe + * Set precompute=window size if a precomputed table is to be used to + * speed up the calculation x.G mod EC(p) + * Returns field size in bytes */ + +P1363_API int ECP_DOMAIN_INIT(ecp_domain *DOM,char *fname,char **params,int precompute) +{ /* get domain details from specified file */ + /* If input from a file, params=NULL, if input from strings, fname=NULL */ + /* return max. size in bytes of octet strings */ + /* precompute is 0 for no precomputation, or else window size for Comb method */ + FILE *fp; +#ifdef MR_GENERIC_AND_STATIC + miracl instance; +#endif + miracl *mr_mip; + BOOL fileinput=TRUE; + big q,r,gx,gy,a,b,k; + int bits,rbits,bytes,err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(7)]; + memset(mem,0,MR_BIG_RESERVE(7)); +#endif + + if (fname==NULL && params==NULL) return MR_P1363_DOMAIN_NOT_FOUND; + if (fname==NULL) fileinput=FALSE; + + if (fileinput) + { + fp=fopen(fname,"rt"); + if (fp==NULL) return MR_P1363_DOMAIN_NOT_FOUND; + fscanf(fp,"%d\n",&bits); + } + else + sscanf(params[0],"%d\n",&bits); + + DOM->words=MR_ROUNDUP(bits,MIRACL); +#ifdef MR_GENERIC_AND_STATIC + mr_mip=mirsys(&instance,MR_ROUNDUP(bits,4),16); +#else + mr_mip=mirsys(MR_ROUNDUP(bits,4),16); +#endif + if (mr_mip==NULL) + { + if (fileinput) fclose(fp); + return MR_P1363_OUT_OF_MEMORY; + } + mr_mip->ERCON=TRUE; +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 7); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + r=mirvar_mem(_MIPP_ mem, 3); + gx=mirvar_mem(_MIPP_ mem, 4); + gy=mirvar_mem(_MIPP_ mem, 5); + k=mirvar_mem(_MIPP_ mem, 6); + + bytes=MR_ROUNDUP(bits,8); + + if (fileinput) + { + innum(_MIPP_ q,fp); + innum(_MIPP_ a,fp); + innum(_MIPP_ b,fp); + innum(_MIPP_ r,fp); + innum(_MIPP_ gx,fp); + innum(_MIPP_ gy,fp); + fclose(fp); + + } + else + { + instr(_MIPP_ q,params[1]); + instr(_MIPP_ a,params[2]); + instr(_MIPP_ b,params[3]); + instr(_MIPP_ r,params[4]); + instr(_MIPP_ gx,params[5]); + instr(_MIPP_ gy,params[6]); + } + + OCTET_INIT(&DOM->Q,bytes); + OCTET_INIT(&DOM->A,bytes); + OCTET_INIT(&DOM->B,bytes); + OCTET_INIT(&DOM->R,bytes); + OCTET_INIT(&DOM->Gx,bytes); + OCTET_INIT(&DOM->Gy,bytes); + OCTET_INIT(&DOM->K,bytes); + OCTET_INIT(&DOM->IK,bytes); + rbits=logb2(_MIPP_ r); + DOM->H=(1+rbits)/2; + DOM->fsize=bytes; + DOM->rbits=rbits; + nroot(_MIPP_ q,2,k); + premult(_MIPP_ k,2,k); + add(_MIPP_ k,q,k); + incr(_MIPP_ k,3,k); + + divide(_MIPP_ k,r,k); /* get co-factor k = (q+2q^0.5+3)/r */ + if (size(a)<0) add(_MIPP_ q,a,a); + if (size(b)<0) add(_MIPP_ q,b,b); + + convert_big_octet(_MIPP_ q,&DOM->Q); + convert_big_octet(_MIPP_ a,&DOM->A); + convert_big_octet(_MIPP_ b,&DOM->B); + convert_big_octet(_MIPP_ r,&DOM->R); + convert_big_octet(_MIPP_ gx,&DOM->Gx); + convert_big_octet(_MIPP_ gy,&DOM->Gy); + + convert_big_octet(_MIPP_ k,&DOM->K); + xgcd(_MIPP_ k,r,k,k,k); + convert_big_octet(_MIPP_ k,&DOM->IK); + DOM->PC.window=0; +#ifndef MR_STATIC + if (precompute) ebrick_init(_MIPP_ &DOM->PC,gx,gy,a,b,q,precompute,logb2(_MIPP_ r)); +#endif + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,7); +#else + memset(mem,0,MR_BIG_RESERVE(7)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + if (res<0) return res; + else return bytes; +} + +/* validate EC GF(p) domain details - good idea if you got them from + * some-one else! */ + +P1363_API int ECP_DOMAIN_VALIDATE(BOOL (*idle)(void),ecp_domain *DOM) +{ /* do domain checks - A16.8 */ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,a,b,r,gx,gy,t,w; + epoint *G; + int i,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(8)]; + char mem1[MR_ECP_RESERVE(1)]; + memset(mem,0,MR_BIG_RESERVE(8)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + + mr_mip->ERCON=TRUE; + mr_mip->NTRY=50; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 8); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 1); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + r=mirvar_mem(_MIPP_ mem, 3); + gx=mirvar_mem(_MIPP_ mem, 4); + gy=mirvar_mem(_MIPP_ mem, 5); + t=mirvar_mem(_MIPP_ mem, 6); + w=mirvar_mem(_MIPP_ mem, 7); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + + nroot(_MIPP_ q,2,t); + premult(_MIPP_ t,4,t); + + if (mr_compare(r,t)<=0) res=MR_P1363_DOMAIN_ERROR; + if (mr_compare(b,q)>=0) res=MR_P1363_DOMAIN_ERROR; + if (mr_compare(r,q)==0) res=MR_P1363_DOMAIN_ERROR; + if (size(r)<3 || size(q)<3) res=MR_P1363_DOMAIN_ERROR; + } + + if (res==0) + { + gprime(_MIPP_ 10000); + if (!isprime(_MIPP_ r)) res=MR_P1363_DOMAIN_ERROR; + } + + if (res==0) + { + if (!isprime(_MIPP_ q)) res=MR_P1363_DOMAIN_ERROR; + } + + if (res==0) + { /* check 4a^3+27b^2 !=0 mod q */ + mad(_MIPP_ b,b,b,q,q,t); + premult(_MIPP_ t,27,t); + mad(_MIPP_ a,a,a,q,q,w); + mad(_MIPP_ w,a,a,q,q,w); + premult(_MIPP_ w,4,w); + + add(_MIPP_ t,w,t); + divide(_MIPP_ t,q,q); + if (size(t)<0) add(_MIPP_ t,q,t); + if (size(t)==0) res=MR_P1363_DOMAIN_ERROR; + } + + if (res==0) + { + ecurve_init(_MIPP_ a,b,q,MR_AFFINE); + G=epoint_init_mem(_MIPP_ mem1,0); + + if (!epoint_set(_MIPP_ gx,gy,0,G)) res=MR_P1363_DOMAIN_ERROR; + + if (G->marker==MR_EPOINT_INFINITY) res=MR_P1363_DOMAIN_ERROR; + else + { + ecurve_mult(_MIPP_ r,G,G); + if (G->marker!=MR_EPOINT_INFINITY) res=MR_P1363_DOMAIN_ERROR; + } + } + + if (res==0) + { /* MOV conditon */ + convert(_MIPP_ 1,t); + for (i=0;i<50;i++) + { + mad(_MIPP_ t,q,q,r,r,t); + if (size(t)==1) + { + res=MR_P1363_DOMAIN_ERROR; + break; + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,8); + ecp_memkill(_MIPP_ mem1,1); +#else + memset(mem,0,MR_BIG_RESERVE(8)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/* Calculate a public/private EC GF(p) key pair. W=S.g mod EC(p), + * where S is the secret key and W is the public key + * Indicate if "point compression" is required for public key + * If RNG is NULL then the private key is provided externally in S + * otherwise it is generated randomly internally */ + +P1363_API int ECP_KEY_PAIR_GENERATE(BOOL (*idle)(void),ecp_domain *DOM,csprng *RNG,octet* S,BOOL compress,octet *W) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,a,b,r,gx,gy,s,wx,wy; + epoint *G,*WP; + int bit,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(9)]; + char mem1[MR_ECP_RESERVE(2)]; + memset(mem,0,MR_BIG_RESERVE(9)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 9); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 2); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + r=mirvar_mem(_MIPP_ mem, 3); + gx=mirvar_mem(_MIPP_ mem, 4); + gy=mirvar_mem(_MIPP_ mem, 5); + s=mirvar_mem(_MIPP_ mem, 6); + wx=mirvar_mem(_MIPP_ mem, 7); + wy=mirvar_mem(_MIPP_ mem, 8); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + WP=epoint_init_mem(_MIPP_ mem1,1); + epoint_set(_MIPP_ gx,gy,0,G); + + if (RNG!=NULL) + strong_bigrand(_MIPP_ RNG,r,s); + else + { + OS2FEP(_MIPP_ S,s); + divide(_MIPP_ s,r,r); + } + if (DOM->PC.window==0) + { + ecurve_mult(_MIPP_ s,G,WP); + bit=epoint_get(_MIPP_ WP,wx,wy); + } + else + bit=mul_brick(_MIPP_ &DOM->PC,s,wx,wy); + if (RNG!=NULL) convert_big_octet(_MIPP_ s,S); + + EC2OSP(_MIPP_ wx,wy,bit,compress,DOM->fsize,W); + + } + +#ifndef MR_STATIC + memkill(_MIPP_ mem,9); + ecp_memkill(_MIPP_ mem1,2); +#else + memset(mem,0,MR_BIG_RESERVE(9)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/* validate an EC GF(p) public key. Set full=TRUE for fuller, + * but more time-consuming test */ + +P1363_API int ECP_PUBLIC_KEY_VALIDATE(BOOL (*idle)(void),ecp_domain *DOM,BOOL full,octet *W) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,a,b,r,wx,wy; + epoint *WP; + BOOL valid,compressed; + int bit,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(6)]; + char mem1[MR_ECP_RESERVE(1)]; + memset(mem,0,MR_BIG_RESERVE(6)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 6); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 1); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + r=mirvar_mem(_MIPP_ mem, 3); + wx=mirvar_mem(_MIPP_ mem, 4); + wy=mirvar_mem(_MIPP_ mem, 5); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->R,r); + + compressed=OS2ECP(_MIPP_ W,wx,wy,DOM->fsize,&bit); + if (W->lenfsize+1 || W->len>2*DOM->fsize+1) res=MR_P1363_INVALID_PUBLIC_KEY; + if (mr_compare(wx,q)>=0 || mr_compare (wy,q)>=0) res=MR_P1363_INVALID_PUBLIC_KEY; + } + if (res==0) + { + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + WP=epoint_init_mem(_MIPP_ mem1,0); + + if (!compressed) + valid=epoint_set(_MIPP_ wx,wy,0,WP); + else valid=epoint_set(_MIPP_ wx,wx,bit,WP); + + if (!valid || WP->marker==MR_EPOINT_INFINITY) res=MR_P1363_INVALID_PUBLIC_KEY; + if (res==0 && full) + { + ecurve_mult(_MIPP_ r,WP,WP); + if (WP->marker!=MR_EPOINT_INFINITY) res=MR_P1363_INVALID_PUBLIC_KEY; + } + + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,6); + ecp_memkill(_MIPP_ mem1,1); +#else + memset(mem,0,MR_BIG_RESERVE(6)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/*** P1363 EC GF(p) primitives ***/ +/* See P1363 documentation for specification */ +/* Note the support for point compression */ + +P1363_API int ECPSVDP_DH(BOOL (*idle)(void),ecp_domain *DOM,octet *S,octet *WD,octet *Z) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,a,b,s,wx,wy,z; + BOOL valid,compressed; + epoint *W; + int bit,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(7)]; + char mem1[MR_ECP_RESERVE(1)]; + memset(mem,0,MR_BIG_RESERVE(7)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 7); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 1); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + s=mirvar_mem(_MIPP_ mem, 3); + wx=mirvar_mem(_MIPP_ mem, 4); + wy=mirvar_mem(_MIPP_ mem, 5); + z=mirvar_mem(_MIPP_ mem, 6); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ S,s); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + W=epoint_init_mem(_MIPP_ mem1,0); + + compressed=OS2ECP(_MIPP_ WD,wx,wy,DOM->fsize,&bit); + + if (!compressed) + valid=epoint_set(_MIPP_ wx,wy,0,W); + else valid=epoint_set(_MIPP_ wx,wx,bit,W); + + if (!valid) res=MR_P1363_ERROR; + + ecurve_mult(_MIPP_ s,W,W); + if (W->marker==MR_EPOINT_INFINITY) res=MR_P1363_ERROR; + else + { + epoint_get(_MIPP_ W,z,z); + FE2OSP(_MIPP_ z,DOM->fsize,Z); + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,7); + ecp_memkill(_MIPP_ mem1,1); +#else + memset(mem,0,MR_BIG_RESERVE(7)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int ECPSVDP_DHC(BOOL (*idle)(void),ecp_domain *DOM,octet *S,octet *WD,BOOL compatible,octet *Z) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,a,b,r,s,wx,wy,z,k,ik,t; + BOOL compressed,valid; + epoint *W; + int bit,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(11)]; + char mem1[MR_ECP_RESERVE(1)]; + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 11); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 1); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + r=mirvar_mem(_MIPP_ mem, 3); + s=mirvar_mem(_MIPP_ mem, 4); + wx=mirvar_mem(_MIPP_ mem, 5); + wy=mirvar_mem(_MIPP_ mem, 6); + k=mirvar_mem(_MIPP_ mem, 7); + ik=mirvar_mem(_MIPP_ mem, 8); + z=mirvar_mem(_MIPP_ mem, 9); + t=mirvar_mem(_MIPP_ mem, 10); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->K,k); + OS2FEP(_MIPP_ S,s); + + if (compatible) + { + OS2FEP(_MIPP_ &DOM->IK,ik); + mad(_MIPP_ ik,s,ik,r,r,t); /* t=s/k mod r */ + } + else copy(s,t); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + W=epoint_init_mem(_MIPP_ mem1,0); + + compressed=OS2ECP(_MIPP_ WD,wx,wy,DOM->fsize,&bit); + + if (!compressed) + valid=epoint_set(_MIPP_ wx,wy,0,W); + else valid=epoint_set(_MIPP_ wx,wx,bit,W); + + if (!valid) res=MR_P1363_ERROR; + else + { + multiply(_MIPP_ t,k,t); + ecurve_mult(_MIPP_ t,W,W); + if (W->marker==MR_EPOINT_INFINITY) res=MR_P1363_ERROR; + else + { + epoint_get(_MIPP_ W,z,z); + FE2OSP(_MIPP_ z,DOM->fsize,Z); + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,11); + ecp_memkill(_MIPP_ mem1,1); +#else + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int ECPSVDP_MQV(BOOL (*idle)(void),ecp_domain *DOM,octet *S,octet *U,octet *V,octet *WD,octet *VD,octet *Z) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,a,b,r,s,u,vx,wdx,wdy,vdx,vdy,z,e,t,td; + epoint *P,*WDP,*VDP; + BOOL compressed,valid; + int bit,h,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(15)]; + char mem1[MR_ECP_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(15)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 15); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 3); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + r=mirvar_mem(_MIPP_ mem, 3); + s=mirvar_mem(_MIPP_ mem, 4); + u=mirvar_mem(_MIPP_ mem, 5); + vx=mirvar_mem(_MIPP_ mem, 6); + wdx=mirvar_mem(_MIPP_ mem, 7); + wdy=mirvar_mem(_MIPP_ mem, 8); + vdx=mirvar_mem(_MIPP_ mem, 9); + vdy=mirvar_mem(_MIPP_ mem, 10); + z=mirvar_mem(_MIPP_ mem, 11); + e=mirvar_mem(_MIPP_ mem, 12); + t=mirvar_mem(_MIPP_ mem, 13); + td=mirvar_mem(_MIPP_ mem, 14); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ &DOM->B,b); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ U,u); + + P=epoint_init_mem(_MIPP_ mem1,0); + OS2ECP(_MIPP_ V,vx,NULL,DOM->fsize,&bit); + + WDP=epoint_init_mem(_MIPP_ mem1,1); + + compressed=OS2ECP(_MIPP_ WD,wdx,wdy,DOM->fsize,&bit); + + if (!compressed) + valid=epoint_set(_MIPP_ wdx,wdy,0,WDP); + else valid=epoint_set(_MIPP_ wdx,wdx,bit,WDP); + + if (!valid) res=MR_P1363_ERROR; + else + { + VDP=epoint_init_mem(_MIPP_ mem1,2); + compressed=OS2ECP(_MIPP_ VD,vdx,vdy,DOM->fsize,&bit); + if (!compressed) + valid=epoint_set(_MIPP_ vdx,vdy,0,VDP); + else valid=epoint_set(_MIPP_ vdx,vdx,bit,VDP); + if (!valid) res=MR_P1363_ERROR; + else + { + h=DOM->H; + expb2(_MIPP_ h,z); + copy(vx,t); + divide(_MIPP_ t,z,z); + add(_MIPP_ t,z,t); + copy (vdx,td); + divide(_MIPP_ td,z,z); + add(_MIPP_ td,z,td); + + mad(_MIPP_ t,s,u,r,r,e); + mad(_MIPP_ e,td,td,r,r,t); + ecurve_mult2(_MIPP_ e,VDP,t,WDP,P); + if (P->marker==MR_EPOINT_INFINITY) res=MR_P1363_ERROR; + else + { + epoint_get(_MIPP_ P,z,z); + FE2OSP(_MIPP_ z,DOM->fsize,Z); + } + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,15); + ecp_memkill(_MIPP_ mem1,3); +#else + memset(mem,0,MR_BIG_RESERVE(15)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int ECPSVDP_MQVC(BOOL (*idle)(void),ecp_domain *DOM,octet *S,octet *U,octet *V,octet *WD,octet *VD,BOOL compatible,octet *Z) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,a,b,r,s,u,vx,wdx,wdy,vdx,vdy,z,e,t,td,k,ik; + epoint *P,*WDP,*VDP; + BOOL compressed,valid; + int bit,h,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(17)]; + char mem1[MR_ECP_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(17)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 17); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 3); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + r=mirvar_mem(_MIPP_ mem, 3); + ik=mirvar_mem(_MIPP_ mem, 4); + k=mirvar_mem(_MIPP_ mem, 5); + s=mirvar_mem(_MIPP_ mem, 6); + u=mirvar_mem(_MIPP_ mem, 7); + vx=mirvar_mem(_MIPP_ mem, 8); + wdx=mirvar_mem(_MIPP_ mem, 9); + wdy=mirvar_mem(_MIPP_ mem, 10); + vdx=mirvar_mem(_MIPP_ mem, 11); + vdy=mirvar_mem(_MIPP_ mem, 12); + z=mirvar_mem(_MIPP_ mem, 13); + e=mirvar_mem(_MIPP_ mem, 14); + t=mirvar_mem(_MIPP_ mem, 15); + td=mirvar_mem(_MIPP_ mem, 16); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->K,k); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ &DOM->B,b); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ U,u); + + P=epoint_init_mem(_MIPP_ mem1,0); + + OS2ECP(_MIPP_ V,vx,NULL,DOM->fsize,&bit); + + WDP=epoint_init_mem(_MIPP_ mem1,1); + + compressed=OS2ECP(_MIPP_ WD,wdx,wdy,DOM->fsize,&bit); + if (!compressed) + valid=epoint_set(_MIPP_ wdx,wdy,0,WDP); + else valid=epoint_set(_MIPP_ wdx,wdx,bit,WDP); + + if (!valid) res=MR_P1363_ERROR; + else + { + VDP=epoint_init_mem(_MIPP_ mem1,2); + compressed=OS2ECP(_MIPP_ VD,vdx,vdy,DOM->fsize,&bit); + if (!compressed) + valid=epoint_set(_MIPP_ vdx,vdy,0,VDP); + else valid=epoint_set(_MIPP_ vdx,vdx,bit,VDP); + if (!valid) res=MR_P1363_ERROR; + else + { + h=DOM->H; + expb2(_MIPP_ h,z); + copy(vx,t); + divide(_MIPP_ t,z,z); + add(_MIPP_ t,z,t); + copy (vdx,td); + divide(_MIPP_ td,z,z); + add(_MIPP_ td,z,td); + mad(_MIPP_ t,s,u,r,r,e); + if (compatible) + { + OS2FEP(_MIPP_ &DOM->IK,ik); + mad(_MIPP_ e,ik,e,r,r,e); + } + mad(_MIPP_ e,k,e,r,r,e); + mad(_MIPP_ e,td,td,r,r,t); + ecurve_mult2(_MIPP_ e,VDP,t,WDP,P); + if (P->marker==MR_EPOINT_INFINITY) res=MR_P1363_INVALID_PUBLIC_KEY; + else + { + epoint_get(_MIPP_ P,z,z); + FE2OSP(_MIPP_ z,DOM->fsize,Z); + } + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,17); + ecp_memkill(_MIPP_ mem1,3); +#else + memset(mem,0,MR_BIG_RESERVE(17)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + + err=mr_mip->ERNUM; + + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int ECPSP_NR(BOOL (*idle)(void),ecp_domain *DOM,csprng *RNG,octet *S,octet *F,octet *C,octet *D) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,a,b,gx,gy,r,s,f,c,d,u,vx; + epoint *G,*V; + int err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(12)]; + char mem1[MR_ECP_RESERVE(2)]; + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 12); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 2); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + gx=mirvar_mem(_MIPP_ mem, 3); + gy=mirvar_mem(_MIPP_ mem, 4); + r=mirvar_mem(_MIPP_ mem, 5); + s=mirvar_mem(_MIPP_ mem, 6); + f=mirvar_mem(_MIPP_ mem, 7); + c=mirvar_mem(_MIPP_ mem, 8); + d=mirvar_mem(_MIPP_ mem, 9); + u=mirvar_mem(_MIPP_ mem, 10); + vx=mirvar_mem(_MIPP_ mem,11); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ F,f); + if (mr_compare(f,r)>=0) res=MR_P1363_BAD_ASSUMPTION; + } + if (res==0) + { + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + V=epoint_init_mem(_MIPP_ mem1,1); + epoint_set(_MIPP_ gx,gy,0,G); + + do { + if (mr_mip->ERNUM) break; + + strong_bigrand(_MIPP_ RNG,r,u); + if (DOM->PC.window==0) + { + ecurve_mult(_MIPP_ u,G,V); + epoint_get(_MIPP_ V,vx,vx); + } + else + mul_brick(_MIPP_ &DOM->PC,u,vx,vx); + + divide(_MIPP_ vx,r,r); + add(_MIPP_ vx,f,c); + divide(_MIPP_ c,r,r); + + } while (size(c)==0); + + if (res==0) + { + mad(_MIPP_ s,c,s,r,r,d); + subtract(_MIPP_ u,d,d); + if (size(d)<0) add(_MIPP_ d,r,d); + convert_big_octet(_MIPP_ c,C); + convert_big_octet(_MIPP_ d,D); + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,12); + ecp_memkill(_MIPP_ mem1,2); +#else + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int ECPVP_NR(BOOL (*idle)(void),ecp_domain *DOM,octet *W,octet *C,octet *D,octet *F) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,a,b,gx,gy,wx,wy,f,c,d; + int bit,err,res=0; + epoint *G,*WP,*P; + BOOL compressed,valid; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(11)]; + char mem1[MR_ECP_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 11); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 3); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + gx=mirvar_mem(_MIPP_ mem, 3); + gy=mirvar_mem(_MIPP_ mem, 4); + r=mirvar_mem(_MIPP_ mem, 5); + wx=mirvar_mem(_MIPP_ mem, 6); + wy=mirvar_mem(_MIPP_ mem, 7); + f=mirvar_mem(_MIPP_ mem, 8); + c=mirvar_mem(_MIPP_ mem, 9); + d=mirvar_mem(_MIPP_ mem, 10); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ C,c); + OS2FEP(_MIPP_ D,d); + if (size(c)<1 || mr_compare(c,r)>=0 || size(d)<0 || mr_compare(d,r)>=0) + res=MR_P1363_INVALID; + } + + if (res==0) + { + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + WP=epoint_init_mem(_MIPP_ mem1,1); + P=epoint_init_mem(_MIPP_ mem1,2); + epoint_set(_MIPP_ gx,gy,0,G); + + compressed=OS2ECP(_MIPP_ W,wx,wy,DOM->fsize,&bit); + if (!compressed) + valid=epoint_set(_MIPP_ wx,wy,0,WP); + else valid=epoint_set(_MIPP_ wx,wx,bit,WP); + if (!valid) res=MR_P1363_ERROR; + else + { + ecurve_mult2(_MIPP_ d,G,c,WP,P); + if (P->marker==MR_EPOINT_INFINITY) res=MR_P1363_INVALID; + else + { + epoint_get(_MIPP_ P,f,f); + divide(_MIPP_ f,r,r); + subtract(_MIPP_ c,f,f); + if (size(f)<0) add(_MIPP_ f,r,f); + convert_big_octet(_MIPP_ f,F); + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,11); + ecp_memkill(_MIPP_ mem1,3); +#else + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int ECPPSP_NR2PV(BOOL (*idle)(void),ecp_domain *DOM,csprng *RNG,octet *U,octet *V) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,a,b,gx,gy,r,u,vx; + epoint *G,*VP; + int err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(8)]; + char mem1[MR_ECP_RESERVE(2)]; + memset(mem,0,MR_BIG_RESERVE(8)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 8); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 2); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + gx=mirvar_mem(_MIPP_ mem, 3); + gy=mirvar_mem(_MIPP_ mem, 4); + r=mirvar_mem(_MIPP_ mem, 5); + u=mirvar_mem(_MIPP_ mem, 6); + vx=mirvar_mem(_MIPP_ mem, 7); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->A,a); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + VP=epoint_init_mem(_MIPP_ mem1,1); + epoint_set(_MIPP_ gx,gy,0,G); + + strong_bigrand(_MIPP_ RNG,r,u); + if (DOM->PC.window==0) + { + ecurve_mult(_MIPP_ u,G,VP); + epoint_get(_MIPP_ VP,vx,vx); + } + else + mul_brick(_MIPP_ &DOM->PC,u,vx,vx); + + convert_big_octet(_MIPP_ u,U); + FE2OSP(_MIPP_ vx,DOM->fsize,V); + + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,8); + ecp_memkill(_MIPP_ mem1,2); +#else + memset(mem,0,MR_BIG_RESERVE(8)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int ECPSP_NR2(BOOL (*idle)(void),ecp_domain *DOM,octet *S,octet *U,octet *V,octet *F,octet *C,octet *D) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,u,v,s,c,d,f; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(8)]; + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 8); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + u=mirvar_mem(_MIPP_ mem, 2); + v=mirvar_mem(_MIPP_ mem, 3); + s=mirvar_mem(_MIPP_ mem, 4); + c=mirvar_mem(_MIPP_ mem, 5); + d=mirvar_mem(_MIPP_ mem, 6); + f=mirvar_mem(_MIPP_ mem, 7); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ F,f); + OS2FEP(_MIPP_ U,u); + OS2FEP(_MIPP_ V,v); + if (size(u)<1 || mr_compare(u,r)>=0) res=MR_P1363_BAD_ASSUMPTION; + if (size(v)<1 || mr_compare(v,q)>=0) res=MR_P1363_BAD_ASSUMPTION; + if (mr_compare(f,r)>=0) res=MR_P1363_BAD_ASSUMPTION; + } + if (res==0) + { + add(_MIPP_ v,f,c); + divide(_MIPP_ c,r,r); + if (size(c)==0) res=MR_P1363_ERROR; + } + if (res==0) + { + mad(_MIPP_ s,c,s,r,r,d); + subtract(_MIPP_ u,d,d); + if (size(d)<0) add(_MIPP_ d,r,d); + + convert_big_octet(_MIPP_ c,C); + convert_big_octet(_MIPP_ d,D); + } + + OCTET_CLEAR(U); +#ifndef MR_STATIC + memkill(_MIPP_ mem,8); +#else + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int ECPVP_NR2(BOOL (*idle)(void),ecp_domain *DOM,octet *W,octet *C,octet *D,octet *F,octet *V) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,a,b,gx,gy,v,wx,wy,c,d,f; + epoint *G,*WP,*P; + BOOL compressed,valid; + int bit,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(12)]; + char mem1[MR_ECP_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 12); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 3); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + a=mirvar_mem(_MIPP_ mem, 2); + b=mirvar_mem(_MIPP_ mem, 3); + gx=mirvar_mem(_MIPP_ mem, 4); + gy=mirvar_mem(_MIPP_ mem, 5); + v=mirvar_mem(_MIPP_ mem, 6); + wx=mirvar_mem(_MIPP_ mem, 7); + wy=mirvar_mem(_MIPP_ mem, 8); + c=mirvar_mem(_MIPP_ mem, 9); + d=mirvar_mem(_MIPP_ mem, 10); + f=mirvar_mem(_MIPP_ mem, 11); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ C,c); + OS2FEP(_MIPP_ D,d); + if (size(c)<1 || mr_compare(c,r)>=0 || mr_compare(d,r)>=0) res=MR_P1363_INVALID; + } + if (res==0) + { + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + WP=epoint_init_mem(_MIPP_ mem1,1); + P=epoint_init_mem(_MIPP_ mem1,2); + epoint_set(_MIPP_ gx,gy,0,G); + + compressed=OS2ECP(_MIPP_ W,wx,wy,DOM->fsize,&bit); + if (!compressed) + valid=epoint_set(_MIPP_ wx,wy,0,WP); + else valid=epoint_set(_MIPP_ wx,wx,bit,WP); + if (!valid) res=MR_P1363_ERROR; + else + { + ecurve_mult2(_MIPP_ d,G,c,WP,P); + if (P->marker==MR_EPOINT_INFINITY) res=MR_P1363_INVALID; + else + { + epoint_get(_MIPP_ P,v,v); + copy(v,f); + divide(_MIPP_ f,r,r); + subtract(_MIPP_ c,f,f); + if (size(f)<0) add(_MIPP_ f,r,f); + convert_big_octet(_MIPP_ f,F); + FE2OSP(_MIPP_ v,DOM->fsize,V); + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,12); + ecp_memkill(_MIPP_ mem1,3); +#else + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int ECPSP_PV(BOOL (*idle)(void),ecp_domain *DOM,octet *S,octet *U,octet *H,octet *D) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,u,s,d,h; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(6)]; + memset(mem,0,MR_BIG_RESERVE(6)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 6); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + u=mirvar_mem(_MIPP_ mem, 2); + s=mirvar_mem(_MIPP_ mem, 3); + d=mirvar_mem(_MIPP_ mem, 4); + h=mirvar_mem(_MIPP_ mem, 5); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ U,u); + OS2FEP(_MIPP_ H,h); + if (size(u)<1 || mr_compare(u,r)>=0) res=MR_P1363_BAD_ASSUMPTION; + } + + if (res==0) + { + mad(_MIPP_ s,h,s,r,r,d); + subtract(_MIPP_ u,d,d); + if (size(d)<0) add(_MIPP_ d,r,d); + + convert_big_octet(_MIPP_ d,D); + } + + OCTET_CLEAR(U); +#ifndef MR_STATIC + memkill(_MIPP_ mem,6); +#else + memset(mem,0,MR_BIG_RESERVE(6)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int ECPVP_PV(BOOL (*idle)(void),ecp_domain *DOM,octet *W,octet *H,octet *D,octet *V) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,a,b,gx,gy,v,wx,wy,d,h; + epoint *G,*WP,*P; + BOOL compressed,valid; + int bit,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(11)]; + char mem1[MR_ECP_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 11); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 3); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + a=mirvar_mem(_MIPP_ mem, 2); + b=mirvar_mem(_MIPP_ mem, 3); + gx=mirvar_mem(_MIPP_ mem, 4); + gy=mirvar_mem(_MIPP_ mem, 5); + v=mirvar_mem(_MIPP_ mem, 6); + wx=mirvar_mem(_MIPP_ mem, 7); + wy=mirvar_mem(_MIPP_ mem, 8); + d=mirvar_mem(_MIPP_ mem, 9); + h=mirvar_mem(_MIPP_ mem, 10); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ H,h); + OS2FEP(_MIPP_ D,d); + if (mr_compare(d,r)>=0) res=MR_P1363_INVALID; + } + if (res==0) + { + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + WP=epoint_init_mem(_MIPP_ mem1,1); + P=epoint_init_mem(_MIPP_ mem1,2); + epoint_set(_MIPP_ gx,gy,0,G); + + compressed=OS2ECP(_MIPP_ W,wx,wy,DOM->fsize,&bit); + if (!compressed) + valid=epoint_set(_MIPP_ wx,wy,0,WP); + else valid=epoint_set(_MIPP_ wx,wx,bit,WP); + if (!valid) res=MR_P1363_ERROR; + else + { + ecurve_mult2(_MIPP_ d,G,h,WP,P); + if (P->marker==MR_EPOINT_INFINITY) res=MR_P1363_INVALID; + else + { + epoint_get(_MIPP_ P,v,v); + FE2OSP(_MIPP_ v,DOM->fsize,V); + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,11); + ecp_memkill(_MIPP_ mem1,3); +#else + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int ECPSP_DSA(BOOL (*idle)(void),ecp_domain *DOM,csprng *RNG,octet *S,octet *F,octet *C,octet *D) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,a,b,gx,gy,r,s,f,c,d,u,vx; + epoint *G,*V; + int err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(12)]; + char mem1[MR_ECP_RESERVE(2)]; + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 12); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 2); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + gx=mirvar_mem(_MIPP_ mem, 3); + gy=mirvar_mem(_MIPP_ mem, 4); + r=mirvar_mem(_MIPP_ mem, 5); + s=mirvar_mem(_MIPP_ mem, 6); + f=mirvar_mem(_MIPP_ mem, 7); + c=mirvar_mem(_MIPP_ mem, 8); + d=mirvar_mem(_MIPP_ mem, 9); + u=mirvar_mem(_MIPP_ mem, 10); + vx=mirvar_mem(_MIPP_ mem,11); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ F,f); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + V=epoint_init_mem(_MIPP_ mem1,1); + epoint_set(_MIPP_ gx,gy,0,G); + + do { + if (mr_mip->ERNUM) break; + strong_bigrand(_MIPP_ RNG,r,u); + if (DOM->PC.window==0) + { + ecurve_mult(_MIPP_ u,G,V); + epoint_get(_MIPP_ V,vx,vx); + } + else + mul_brick(_MIPP_ &DOM->PC,u,vx,vx); + + copy(vx,c); + divide(_MIPP_ c,r,r); + if (size(c)==0) continue; + xgcd(_MIPP_ u,r,u,u,u); + mad(_MIPP_ s,c,f,r,r,d); + mad(_MIPP_ u,d,u,r,r,d); + + } while (size(d)==0); + + if (res==0) + { + convert_big_octet(_MIPP_ c,C); + convert_big_octet(_MIPP_ d,D); + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,12); + ecp_memkill(_MIPP_ mem1,2); +#else + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int ECPVP_DSA(BOOL (*idle)(void),ecp_domain *DOM,octet *W,octet *C,octet *D,octet *F) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,r,a,b,gx,gy,wx,wy,f,c,d,h2; + int bit,err,res=0; + epoint *G,*WP,*P; + BOOL compressed,valid; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(12)]; + char mem1[MR_ECP_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 12); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 3); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + gx=mirvar_mem(_MIPP_ mem, 3); + gy=mirvar_mem(_MIPP_ mem, 4); + r=mirvar_mem(_MIPP_ mem, 5); + wx=mirvar_mem(_MIPP_ mem, 6); + wy=mirvar_mem(_MIPP_ mem, 7); + f=mirvar_mem(_MIPP_ mem, 8); + c=mirvar_mem(_MIPP_ mem, 9); + d=mirvar_mem(_MIPP_ mem, 10); + h2=mirvar_mem(_MIPP_ mem,11); + + OS2FEP(_MIPP_ &DOM->Q,q); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ C,c); + OS2FEP(_MIPP_ D,d); + OS2FEP(_MIPP_ F,f); + if (size(c)<1 || mr_compare(c,r)>=0 || size(d)<1 || mr_compare(d,r)>=0) + res=MR_P1363_INVALID; + } + + if (res==0) + { + xgcd(_MIPP_ d,r,d,d,d); + mad(_MIPP_ f,d,f,r,r,f); + mad(_MIPP_ c,d,c,r,r,h2); + + ecurve_init(_MIPP_ a,b,q,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + WP=epoint_init_mem(_MIPP_ mem1,1); + P=epoint_init_mem(_MIPP_ mem1,2); + epoint_set(_MIPP_ gx,gy,0,G); + + compressed=OS2ECP(_MIPP_ W,wx,wy,DOM->fsize,&bit); + if (!compressed) + valid=epoint_set(_MIPP_ wx,wy,0,WP); + else valid=epoint_set(_MIPP_ wx,wx,bit,WP); + if (!valid) res=MR_P1363_ERROR; + else + { + ecurve_mult2(_MIPP_ f,G,h2,WP,P); + if (P->marker==MR_EPOINT_INFINITY) res=MR_P1363_INVALID; + else + { + epoint_get(_MIPP_ P,d,d); + divide(_MIPP_ d,r,r); + if (mr_compare(d,c)!=0) res=MR_P1363_INVALID; + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,12); + ecp_memkill(_MIPP_ mem1,3); +#else + memset(mem,0,MR_BIG_RESERVE(12)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/*** EC GF(2^m) primitives - support functions ***/ +/* destroy the EC GF(2^m) domain structure */ + +P1363_API void EC2_DOMAIN_KILL(ec2_domain *DOM) +{ + OCTET_KILL(&DOM->A); + OCTET_KILL(&DOM->B); + OCTET_KILL(&DOM->R); + OCTET_KILL(&DOM->Gx); + OCTET_KILL(&DOM->Gy); + OCTET_KILL(&DOM->K); + OCTET_KILL(&DOM->IK); +#ifndef MR_STATIC + if (DOM->PC.window!=0) + ebrick2_end(&DOM->PC); +#endif + + DOM->words=DOM->fsize=0; DOM->H=DOM->rbits=0; + DOM->a=0; DOM->b=0; DOM->c=0; +} + +/* Initialise the EC GF(2^m) domain structure + * It is assumed that the EC domain details are obtained from a file + * or from an array of strings + * multiprecision numbers are read in in Hex + * A suitable file can be generated offline by the MIRACL example program + * schoof2.exe + * Set precompute=window size if a precomputed table is to be used to + * speed up the calculation x.G mod EC(2^m) + * Returns field size in bytes */ + +P1363_API int EC2_DOMAIN_INIT(ec2_domain *DOM,char *fname,char **params,int precompute) +{ /* get domain details from specified file */ + /* If input from a file, params=NULL, if input from strings, fname=NULL */ + /* return max. size in bytes of octet strings */ + FILE *fp; +#ifdef MR_GENERIC_AND_STATIC + miracl instance; +#endif + miracl *mr_mip; + BOOL fileinput=TRUE; + big q,r,gx,gy,a,b,k; + int aa,bb,cc,bits,rbits,bytes,err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(7)]; + memset(mem,0,MR_BIG_RESERVE(7)); +#endif + if (fname==NULL && params==NULL) return MR_P1363_DOMAIN_NOT_FOUND; + if (fname==NULL) fileinput=FALSE; + + if (fileinput) + { + fp=fopen(fname,"rt"); + if (fp==NULL) return MR_P1363_DOMAIN_NOT_FOUND; + fscanf(fp,"%d\n",&bits); + } + else + sscanf(params[0],"%d\n",&bits); + + DOM->words=MR_ROUNDUP(mr_abs(bits),MIRACL); +#ifdef MR_GENERIC_AND_STATIC + mr_mip=mirsys(&instance,MR_ROUNDUP(mr_abs(bits),4),16); +#else + mr_mip=mirsys(MR_ROUNDUP(mr_abs(bits),4),16); +#endif + if (mr_mip==NULL) + { + if (fileinput) fclose(fp); + return MR_P1363_OUT_OF_MEMORY; + } + mr_mip->ERCON=TRUE; +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 7); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + r=mirvar_mem(_MIPP_ mem, 1); + gx=mirvar_mem(_MIPP_ mem, 2); + gy=mirvar_mem(_MIPP_ mem, 3); + a=mirvar_mem(_MIPP_ mem, 4); + b=mirvar_mem(_MIPP_ mem, 5); + k=mirvar_mem(_MIPP_ mem, 6); + + bytes=MR_ROUNDUP(mr_abs(bits),8); + + if (fileinput) + { + innum(_MIPP_ a,fp); + innum(_MIPP_ b,fp); + innum(_MIPP_ r,fp); + innum(_MIPP_ gx,fp); + innum(_MIPP_ gy,fp); + fscanf(fp,"%d\n",&aa); + fscanf(fp,"%d\n",&bb); + fscanf(fp,"%d\n",&cc); + fclose(fp); + } + else + { + instr(_MIPP_ a,params[1]); + instr(_MIPP_ b,params[2]); + instr(_MIPP_ r,params[3]); + instr(_MIPP_ gx,params[4]); + instr(_MIPP_ gy,params[5]); + sscanf(params[6],"%d\n",&aa); + sscanf(params[7],"%d\n",&bb); + sscanf(params[8],"%d\n",&cc); + } + DOM->M=bits; + OCTET_INIT(&DOM->A,bytes); + OCTET_INIT(&DOM->B,bytes); + OCTET_INIT(&DOM->R,bytes); + OCTET_INIT(&DOM->Gx,bytes); + OCTET_INIT(&DOM->Gy,bytes); + OCTET_INIT(&DOM->K,bytes); + OCTET_INIT(&DOM->IK,bytes); + rbits=logb2(_MIPP_ r); + DOM->H=(1+rbits)/2; + DOM->fsize=bytes; + DOM->rbits=rbits; + DOM->a=aa; DOM->b=bb; DOM->c=cc; + expb2(_MIPP_ mr_abs(bits),q); /* q=2^m */ + + nroot(_MIPP_ q,2,k); + premult(_MIPP_ k,2,k); + add(_MIPP_ k,q,k); + incr(_MIPP_ k,3,k); + + divide(_MIPP_ k,r,k); /* gets co-factor k */ + + convert_big_octet(_MIPP_ a,&DOM->A); + convert_big_octet(_MIPP_ b,&DOM->B); + convert_big_octet(_MIPP_ r,&DOM->R); + convert_big_octet(_MIPP_ gx,&DOM->Gx); + convert_big_octet(_MIPP_ gy,&DOM->Gy); + convert_big_octet(_MIPP_ k,&DOM->K); + xgcd(_MIPP_ k,r,k,k,k); + convert_big_octet(_MIPP_ k,&DOM->IK); + + DOM->PC.window=0; +#ifndef MR_STATIC + if (precompute) + ebrick2_init(_MIPP_ &DOM->PC,gx,gy,a,b,bits,aa,bb,cc,precompute,logb2(_MIPP_ r)); +#endif + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,7); +#else + memset(mem,0,MR_BIG_RESERVE(7)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + if (res<0) return res; + else return bytes; +} + +/* validate EC GF(2^m) domain details - good idea if you got them from + * some-one else! */ + +P1363_API int EC2_DOMAIN_VALIDATE(BOOL (*idle)(void),ec2_domain *DOM) +{ /* do domain checks - A16.8 */ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big q,a,b,r,gx,gy,t; + epoint *G; + int i,aa,bb,cc,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(7)]; + char mem1[MR_ECP_RESERVE(1)]; + memset(mem,0,MR_BIG_RESERVE(7)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + + mr_mip->ERCON=TRUE; + mr_mip->NTRY=50; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 7); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 1); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + q=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + r=mirvar_mem(_MIPP_ mem, 3); + gx=mirvar_mem(_MIPP_ mem, 4); + gy=mirvar_mem(_MIPP_ mem, 5); + t=mirvar_mem(_MIPP_ mem, 6); + + expb2(_MIPP_ DOM->M,q); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + aa=DOM->a; + bb=DOM->b; + cc=DOM->c; + + nroot(_MIPP_ q,2,t); + premult(_MIPP_ t,4,t); + + if (mr_compare(r,t)<=0) res=MR_P1363_DOMAIN_ERROR; + if (size(r)<3 || size(b)==0) res=MR_P1363_DOMAIN_ERROR; + } + + if (res==0) + { + gprime(_MIPP_ 10000); + if (!isprime(_MIPP_ r)) res=MR_P1363_DOMAIN_ERROR; + } + if (res==0) + { + if (!ecurve2_init(_MIPP_ DOM->M,aa,bb,cc,a,b,TRUE,MR_AFFINE)) + res=MR_P1363_DOMAIN_ERROR; + } + if (res==0) + { + G=epoint_init_mem(_MIPP_ mem1,0); + if (!epoint2_set(_MIPP_ gx,gy,0,G)) res=MR_P1363_DOMAIN_ERROR; + if (G->marker==MR_EPOINT_INFINITY) res=MR_P1363_DOMAIN_ERROR; + else + { + ecurve2_mult(_MIPP_ r,G,G); + if (G->marker!=MR_EPOINT_INFINITY) res=MR_P1363_DOMAIN_ERROR; + } + } + + if (res==0) + { /* MOV conditon */ + convert(_MIPP_ 1,t); + for (i=0;i<50;i++) + { + mad(_MIPP_ t,q,q,r,r,t); + if (size(t)==1) + { + res=MR_P1363_DOMAIN_ERROR; + break; + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,7); + ecp_memkill(_MIPP_ mem1,1); +#else + memset(mem,0,MR_BIG_RESERVE(7)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/* validate an EC GF(2^m) public key W. Set full=TRUE for fuller, + * but more time-consuming test */ + +P1363_API int EC2_PUBLIC_KEY_VALIDATE(BOOL (*idle)(void),ec2_domain *DOM,BOOL full,octet *W) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big a,b,r,wx,wy; + epoint *WP; + BOOL compressed,valid; + int bit,M,aa,bb,cc,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(5)]; + char mem1[MR_ECP_RESERVE(1)]; + memset(mem,0,MR_BIG_RESERVE(5)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 5); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 1); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + a=mirvar_mem(_MIPP_ mem, 0); + b=mirvar_mem(_MIPP_ mem, 1); + r=mirvar_mem(_MIPP_ mem, 2); + wx=mirvar_mem(_MIPP_ mem, 3); + wy=mirvar_mem(_MIPP_ mem, 4); + + M=DOM->M; + aa=DOM->a; + bb=DOM->b; + cc=DOM->c; + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->R,r); + + compressed=OS2ECP(_MIPP_ W,wx,wy,DOM->fsize,&bit); + if (W->lenfsize+1 || W->len>2*DOM->fsize+1) res=MR_P1363_INVALID_PUBLIC_KEY; + if (logb2(_MIPP_ wx)>M || logb2(_MIPP_ wy)>M) res=MR_P1363_INVALID_PUBLIC_KEY; + } + if (res==0) + { + ecurve2_init(_MIPP_ M,aa,bb,cc,a,b,FALSE,MR_PROJECTIVE); + WP=epoint_init_mem(_MIPP_ mem1,0); + + if (!compressed) + valid=epoint2_set(_MIPP_ wx,wy,0,WP); + else valid=epoint2_set(_MIPP_ wx,wx,bit,WP); + + if (!valid || WP->marker==MR_EPOINT_INFINITY) res=MR_P1363_INVALID_PUBLIC_KEY; + if (res==0 && full) + { + ecurve2_mult(_MIPP_ r,WP,WP); + if (WP->marker!=MR_EPOINT_INFINITY) res=MR_P1363_INVALID_PUBLIC_KEY; + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,5); + ecp_memkill(_MIPP_ mem1,1); +#else + memset(mem,0,MR_BIG_RESERVE(5)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/* Calculate a public/private EC GF(2^m) key pair. W=S.g mod EC(2^m), + * where S is the secret key and W is the public key + * Returns a single bit which can be used for "point compression" + * If RNG is NULL then the private key is provided externally in S + * otherwise it is generated randomly internally + * (Set Wy to NULL if y-coordinate not needed) */ + +P1363_API int EC2_KEY_PAIR_GENERATE(BOOL (*idle)(void),ec2_domain *DOM,csprng *RNG,octet*S,BOOL compress,octet *W) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big a,b,r,gx,gy,s,wx,wy; + epoint *G,*WP; + int M,aa,bb,cc; + int bit,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(8)]; + char mem1[MR_ECP_RESERVE(2)]; + memset(mem,0,MR_BIG_RESERVE(8)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 8); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 2); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + a=mirvar_mem(_MIPP_ mem, 0); + b=mirvar_mem(_MIPP_ mem, 1); + r=mirvar_mem(_MIPP_ mem, 2); + gx=mirvar_mem(_MIPP_ mem, 3); + gy=mirvar_mem(_MIPP_ mem, 4); + s=mirvar_mem(_MIPP_ mem, 5); + wx=mirvar_mem(_MIPP_ mem, 6); + wy=mirvar_mem(_MIPP_ mem, 7); + + M=DOM->M; + aa=DOM->a; + bb=DOM->b; + cc=DOM->c; + + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + + ecurve2_init(_MIPP_ M,aa,bb,cc,a,b,FALSE,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + WP=epoint_init_mem(_MIPP_ mem1,1); + epoint2_set(_MIPP_ gx,gy,0,G); + + if (RNG!=NULL) + { + strong_bigrand(_MIPP_ RNG,r,s); + } + else + { + OS2FEP(_MIPP_ S,s); + divide(_MIPP_ s,r,r); + } + if (DOM->PC.window==0) + { + ecurve2_mult(_MIPP_ s,G,WP); + bit=epoint2_get(_MIPP_ WP,wx,wy); + } + else + bit=mul2_brick(_MIPP_ &DOM->PC,s,wx,wy); + if (RNG!=NULL) + convert_big_octet(_MIPP_ s,S); + + EC2OSP(_MIPP_ wx,wy,bit,compress,DOM->fsize,W); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,8); + ecp_memkill(_MIPP_ mem1,2); +#else + memset(mem,0,MR_BIG_RESERVE(8)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/*** P1363 EC GF(2^m) primitives ***/ +/* See P1363 documentation for specification */ +/* Note the support for point compression */ + +P1363_API int EC2SVDP_DH(BOOL (*idle)(void),ec2_domain *DOM,octet *S,octet *WD,octet *Z) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big a,b,s,wx,wy,z; + BOOL compress,valid; + epoint *WP; + int bit,M,aa,bb,cc,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(6)]; + char mem1[MR_ECP_RESERVE(1)]; + memset(mem,0,MR_BIG_RESERVE(6)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 6); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 1); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + a=mirvar_mem(_MIPP_ mem, 0); + b=mirvar_mem(_MIPP_ mem, 1); + s=mirvar_mem(_MIPP_ mem, 2); + wx=mirvar_mem(_MIPP_ mem, 3); + wy=mirvar_mem(_MIPP_ mem, 4); + z=mirvar_mem(_MIPP_ mem, 5); + + M=DOM->M; + aa=DOM->a; + bb=DOM->b; + cc=DOM->c; + + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ S,s); + + ecurve2_init(_MIPP_ M,aa,bb,cc,a,b,FALSE,MR_PROJECTIVE); + WP=epoint_init_mem(_MIPP_ mem1,0); + + compress=OS2ECP(_MIPP_ WD,wx,wy,DOM->fsize,&bit); + + if (!compress) + valid=epoint2_set(_MIPP_ wx,wy,0,WP); + else valid=epoint2_set(_MIPP_ wx,wx,bit,WP); + + if (!valid) res=MR_P1363_ERROR; + else + { + ecurve2_mult(_MIPP_ s,WP,WP); + if (WP->marker==MR_EPOINT_INFINITY) res=MR_P1363_ERROR; + else + { + epoint2_get(_MIPP_ WP,z,z); + convert_big_octet(_MIPP_ z,Z); + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,6); + ecp_memkill(_MIPP_ mem1,1); +#else + memset(mem,0,MR_BIG_RESERVE(6)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int EC2SVDP_DHC(BOOL (*idle)(void),ec2_domain *DOM,octet *S,octet *WD,BOOL compatible,octet *Z) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big a,b,r,s,wx,wy,z,k,ik,t; + BOOL compress,valid; + epoint *WP; + int bit,M,aa,bb,cc,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(10)]; + char mem1[MR_ECP_RESERVE(1)]; + memset(mem,0,MR_BIG_RESERVE(10)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 10); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 1); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + a=mirvar_mem(_MIPP_ mem, 0); + b=mirvar_mem(_MIPP_ mem, 1); + r=mirvar_mem(_MIPP_ mem, 2); + s=mirvar_mem(_MIPP_ mem, 3); + wx=mirvar_mem(_MIPP_ mem,4); + wy=mirvar_mem(_MIPP_ mem,5); + k=mirvar_mem(_MIPP_ mem, 6); + ik=mirvar_mem(_MIPP_ mem,7); + z=mirvar_mem(_MIPP_ mem, 8); + t=mirvar_mem(_MIPP_ mem, 9); + + M=DOM->M; + aa=DOM->a; bb=DOM->b; cc=DOM->c; + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->K,k); + + OS2FEP(_MIPP_ S,s); + + if (compatible) + { + OS2FEP(_MIPP_ &DOM->IK,ik); + mad(_MIPP_ ik,s,ik,r,r,t); /* t=s/k mod r */ + } + else copy(s,t); + + ecurve2_init(_MIPP_ M,aa,bb,cc,a,b,FALSE,MR_PROJECTIVE); + WP=epoint_init_mem(_MIPP_ mem1,0); + + compress=OS2ECP(_MIPP_ WD,wx,wy,DOM->fsize,&bit); + + if (!compress) + valid=epoint2_set(_MIPP_ wx,wy,0,WP); + else valid=epoint2_set(_MIPP_ wx,wx,bit,WP); + + if (!valid) res=MR_P1363_ERROR; + else + { + multiply(_MIPP_ t,k,t); + ecurve2_mult(_MIPP_ t,WP,WP); + if (WP->marker==MR_EPOINT_INFINITY) res=MR_P1363_ERROR; + else + { + epoint2_get(_MIPP_ WP,z,z); + convert_big_octet(_MIPP_ z,Z); + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,10); + ecp_memkill(_MIPP_ mem1,1); +#else + memset(mem,0,MR_BIG_RESERVE(10)); + memset(mem1,0,MR_ECP_RESERVE(1)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int EC2SVDP_MQV(BOOL (*idle)(void),ec2_domain *DOM,octet *S,octet *U,octet *V,octet *WD,octet *VD,octet *Z) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big a,b,r,s,u,vx,wdx,wdy,vdx,vdy,z,e,t,td; + epoint *P,*WDP,*VDP; + BOOL compress,valid; + int bit,M,aa,bb,cc,h,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(14)]; + char mem1[MR_ECP_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(14)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 14); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 3); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + a=mirvar_mem(_MIPP_ mem, 0); + b=mirvar_mem(_MIPP_ mem, 1); + r=mirvar_mem(_MIPP_ mem, 2); + s=mirvar_mem(_MIPP_ mem, 3); + u=mirvar_mem(_MIPP_ mem, 4); + vx=mirvar_mem(_MIPP_ mem, 5); + wdx=mirvar_mem(_MIPP_ mem, 6); + wdy=mirvar_mem(_MIPP_ mem, 7); + vdx=mirvar_mem(_MIPP_ mem, 8); + vdy=mirvar_mem(_MIPP_ mem, 9); + z=mirvar_mem(_MIPP_ mem, 10); + e=mirvar_mem(_MIPP_ mem, 11); + t=mirvar_mem(_MIPP_ mem, 12); + td=mirvar_mem(_MIPP_ mem, 13); + + M=DOM->M; + aa=DOM->a; bb=DOM->b; cc=DOM->c; + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->A,a); + + ecurve2_init(_MIPP_ M,aa,bb,cc,a,b,FALSE,MR_PROJECTIVE); + + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ U,u); + + P=epoint_init_mem(_MIPP_ mem1,0); + + OS2ECP(_MIPP_ V,vx,NULL,DOM->fsize,&bit); + + WDP=epoint_init_mem(_MIPP_ mem1,1); + + compress=OS2ECP(_MIPP_ WD,wdx,wdy,DOM->fsize,&bit); + + if (!compress) + valid=epoint2_set(_MIPP_ wdx,wdy,0,WDP); + else valid=epoint2_set(_MIPP_ wdx,wdx,bit,WDP); + + if (!valid) res=MR_P1363_ERROR; + else + { + VDP=epoint_init_mem(_MIPP_ mem1,2); + + compress=OS2ECP(_MIPP_ VD,vdx,vdy,DOM->fsize,&bit); + if (!compress) + valid=epoint2_set(_MIPP_ vdx,vdy,0,VDP); + else valid=epoint2_set(_MIPP_ vdx,vdx,bit,VDP); + if (!valid) res=MR_P1363_ERROR; + else + { + h=DOM->H; + expb2(_MIPP_ h,z); + copy(vx,t); + divide(_MIPP_ t,z,z); + add(_MIPP_ t,z,t); + copy (vdx,td); + divide(_MIPP_ td,z,z); + add(_MIPP_ td,z,td); + mad(_MIPP_ t,s,u,r,r,e); + mad(_MIPP_ e,td,td,r,r,t); + ecurve2_mult2(_MIPP_ e,VDP,t,WDP,P); + if (P->marker==MR_EPOINT_INFINITY) res=MR_P1363_ERROR; + else + { + epoint2_get(_MIPP_ P,z,z); + convert_big_octet(_MIPP_ z,Z); + } + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,14); + ecp_memkill(_MIPP_ mem1,3); +#else + memset(mem,0,MR_BIG_RESERVE(14)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int EC2SVDP_MQVC(BOOL (*idle)(void),ec2_domain *DOM,octet *S,octet *U,octet *V,octet *WD,octet *VD,BOOL compatible,octet *Z) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big a,b,r,s,u,vx,wdx,wdy,vdx,vdy,z,e,t,td,k,ik; + epoint *P,*WDP,*VDP; + BOOL compress,valid; + int bit,M,aa,bb,cc,h,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(16)]; + char mem1[MR_ECP_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(16)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 16); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 3); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + a=mirvar_mem(_MIPP_ mem, 0); + b=mirvar_mem(_MIPP_ mem, 1); + r=mirvar_mem(_MIPP_ mem, 2); + ik=mirvar_mem(_MIPP_ mem, 3); + k=mirvar_mem(_MIPP_ mem, 4); + s=mirvar_mem(_MIPP_ mem, 5); + u=mirvar_mem(_MIPP_ mem, 6); + vx=mirvar_mem(_MIPP_ mem, 7); + wdx=mirvar_mem(_MIPP_ mem, 8); + wdy=mirvar_mem(_MIPP_ mem, 9); + vdx=mirvar_mem(_MIPP_ mem, 10); + vdy=mirvar_mem(_MIPP_ mem, 11); + z=mirvar_mem(_MIPP_ mem, 12); + e=mirvar_mem(_MIPP_ mem, 13); + t=mirvar_mem(_MIPP_ mem, 14); + td=mirvar_mem(_MIPP_ mem, 15); + + M=DOM->M; + aa=DOM->a; bb=DOM->b; cc=DOM->c; + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->K,k); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->A,a); + + ecurve2_init(_MIPP_ M,aa,bb,cc,a,b,FALSE,MR_PROJECTIVE); + + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ U,u); + + P=epoint_init_mem(_MIPP_ mem1,0); + OS2ECP(_MIPP_ V,vx,NULL,DOM->fsize,&bit); + + WDP=epoint_init_mem(_MIPP_ mem1,1); + + compress=OS2ECP(_MIPP_ WD,wdx,wdy,DOM->fsize,&bit); + if (!compress) + valid=epoint2_set(_MIPP_ wdx,wdy,0,WDP); + else valid=epoint2_set(_MIPP_ wdx,wdx,bit,WDP); + if (!valid) res=MR_P1363_ERROR; + else + { + VDP=epoint_init_mem(_MIPP_ mem1,2); + compress=OS2ECP(_MIPP_ VD,vdx,vdy,DOM->fsize,&bit); + if (!compress) + valid=epoint2_set(_MIPP_ vdx,vdy,0,VDP); + else valid=epoint2_set(_MIPP_ vdx,vdx,bit,VDP); + if (!valid) res=MR_P1363_ERROR; + else + { + h=DOM->H; + expb2(_MIPP_ h,z); + copy(vx,t); + divide(_MIPP_ t,z,z); + add(_MIPP_ t,z,t); + copy (vdx,td); + divide(_MIPP_ td,z,z); + add(_MIPP_ td,z,td); + mad(_MIPP_ t,s,u,r,r,e); + if (compatible) + { + OS2FEP(_MIPP_ &DOM->IK,ik); + mad(_MIPP_ e,ik,e,r,r,e); + } + mad(_MIPP_ e,k,e,r,r,e); + mad(_MIPP_ e,td,td,r,r,t); + ecurve2_mult2(_MIPP_ e,VDP,t,WDP,P); + if (P->marker==MR_EPOINT_INFINITY) res=MR_P1363_INVALID_PUBLIC_KEY; + else + { + epoint2_get(_MIPP_ P,z,z); + convert_big_octet(_MIPP_ z,Z); + } + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,16); + ecp_memkill(_MIPP_ mem1,3); +#else + memset(mem,0,MR_BIG_RESERVE(16)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int EC2SP_NR(BOOL (*idle)(void),ec2_domain *DOM,csprng *RNG,octet *S,octet *F,octet *C,octet *D) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big a,b,gx,gy,r,s,f,c,d,u,vx; + epoint *G,*V; + int M,aa,bb,cc,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(11)]; + char mem1[MR_ECP_RESERVE(2)]; + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 11); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 2); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + a=mirvar_mem(_MIPP_ mem, 0); + b=mirvar_mem(_MIPP_ mem, 1); + gx=mirvar_mem(_MIPP_ mem, 2); + gy=mirvar_mem(_MIPP_ mem, 3); + r=mirvar_mem(_MIPP_ mem, 4); + s=mirvar_mem(_MIPP_ mem, 5); + f=mirvar_mem(_MIPP_ mem, 6); + c=mirvar_mem(_MIPP_ mem, 7); + d=mirvar_mem(_MIPP_ mem, 8); + u=mirvar_mem(_MIPP_ mem, 9); + vx=mirvar_mem(_MIPP_ mem, 10); + + M=DOM->M; + aa=DOM->a; bb=DOM->b; cc=DOM->c; + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ F,f); + if (mr_compare(f,r)>=0) res=MR_P1363_BAD_ASSUMPTION; + } + if (res==0) + { + ecurve2_init(_MIPP_ M,aa,bb,cc,a,b,FALSE,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + V=epoint_init_mem(_MIPP_ mem1,1); + epoint2_set(_MIPP_ gx,gy,0,G); + + do { + if (mr_mip->ERNUM) break; + strong_bigrand(_MIPP_ RNG,r,u); + if (DOM->PC.window==0) + { + ecurve2_mult(_MIPP_ u,G,V); + epoint2_get(_MIPP_ V,vx,vx); + } + else + mul2_brick(_MIPP_ &DOM->PC,u,vx,vx); + + divide(_MIPP_ vx,r,r); + add(_MIPP_ vx,f,c); + divide(_MIPP_ c,r,r); + + } while (size(c)==0); + if (res==0) + { + mad(_MIPP_ s,c,s,r,r,d); + subtract(_MIPP_ u,d,d); + if (size(d)<0) add(_MIPP_ d,r,d); + convert_big_octet(_MIPP_ c,C); + convert_big_octet(_MIPP_ d,D); + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,11); + ecp_memkill(_MIPP_ mem1,2); +#else + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int EC2VP_NR(BOOL (*idle)(void),ec2_domain *DOM,octet *W,octet *C,octet *D,octet *F) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big r,a,b,gx,gy,wx,wy,f,c,d; + int bit,M,aa,bb,cc,err,res=0; + epoint *G,*WP,*P; + BOOL compress,valid; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(10)]; + char mem1[MR_ECP_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(10)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 10); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 3); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + a=mirvar_mem(_MIPP_ mem, 0); + b=mirvar_mem(_MIPP_ mem, 1); + gx=mirvar_mem(_MIPP_ mem, 2); + gy=mirvar_mem(_MIPP_ mem, 3); + r=mirvar_mem(_MIPP_ mem, 4); + wx=mirvar_mem(_MIPP_ mem, 5); + wy=mirvar_mem(_MIPP_ mem, 6); + f=mirvar_mem(_MIPP_ mem, 7); + c=mirvar_mem(_MIPP_ mem, 8); + d=mirvar_mem(_MIPP_ mem, 9); + + M=DOM->M; + aa=DOM->a; bb=DOM->b; cc=DOM->c; + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ C,c); + OS2FEP(_MIPP_ D,d); + if (size(c)<1 || mr_compare(c,r)>=0 || size(d)<0 || mr_compare(d,r)>=0) + res=MR_P1363_INVALID; + } + + if (res==0) + { + ecurve2_init(_MIPP_ M,aa,bb,cc,a,b,FALSE,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + WP=epoint_init_mem(_MIPP_ mem1,1); + P=epoint_init_mem(_MIPP_ mem1,2); + epoint2_set(_MIPP_ gx,gy,0,G); + + compress=OS2ECP(_MIPP_ W,wx,wy,DOM->fsize,&bit); + if (!compress) + valid=epoint2_set(_MIPP_ wx,wy,0,WP); + else valid=epoint2_set(_MIPP_ wx,wx,bit,WP); + + if (!valid) res=MR_P1363_ERROR; + else + { + ecurve2_mult2(_MIPP_ d,G,c,WP,P); + if (P->marker==MR_EPOINT_INFINITY) res=MR_P1363_INVALID; + else + { + epoint2_get(_MIPP_ P,f,f); + divide(_MIPP_ f,r,r); + subtract(_MIPP_ c,f,f); + if (size(f)<0) add(_MIPP_ f,r,f); + convert_big_octet(_MIPP_ f,F); + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,10); + ecp_memkill(_MIPP_ mem1,3); +#else + memset(mem,0,MR_BIG_RESERVE(10)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int EC2SP_DSA(BOOL (*idle)(void),ec2_domain *DOM,csprng *RNG,octet *S,octet *F,octet *C,octet *D) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big a,b,gx,gy,r,s,f,c,d,u,vx; + epoint *G,*V; + int M,aa,bb,cc,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(11)]; + char mem1[MR_ECP_RESERVE(2)]; + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 11); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 2); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + a=mirvar_mem(_MIPP_ mem, 0); + b=mirvar_mem(_MIPP_ mem, 1); + gx=mirvar_mem(_MIPP_ mem, 2); + gy=mirvar_mem(_MIPP_ mem, 3); + r=mirvar_mem(_MIPP_ mem, 4); + s=mirvar_mem(_MIPP_ mem, 5); + f=mirvar_mem(_MIPP_ mem, 6); + c=mirvar_mem(_MIPP_ mem, 7); + d=mirvar_mem(_MIPP_ mem, 8); + u=mirvar_mem(_MIPP_ mem, 9); + vx=mirvar_mem(_MIPP_ mem, 10); + + M=DOM->M; + aa=DOM->a; bb=DOM->b; cc=DOM->c; + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ F,f); + + ecurve2_init(_MIPP_ M,aa,bb,cc,a,b,FALSE,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + V=epoint_init_mem(_MIPP_ mem1,1); + epoint2_set(_MIPP_ gx,gy,0,G); + + do { + if (mr_mip->ERNUM) break; + + strong_bigrand(_MIPP_ RNG,r,u); + if (DOM->PC.window==0) + { + ecurve2_mult(_MIPP_ u,G,V); + epoint2_get(_MIPP_ V,vx,vx); + } + else + mul2_brick(_MIPP_ &DOM->PC,u,vx,vx); + + copy(vx,c); + divide(_MIPP_ c,r,r); + if (size(c)==0) continue; + + xgcd(_MIPP_ u,r,u,u,u); + mad(_MIPP_ s,c,f,r,r,d); + mad(_MIPP_ u,d,u,r,r,d); + + } while (size(d)==0); + if (res==0) + { + convert_big_octet(_MIPP_ c,C); + convert_big_octet(_MIPP_ d,D); + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,11); + ecp_memkill(_MIPP_ mem1,2); +#else + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int EC2VP_DSA(BOOL (*idle)(void),ec2_domain *DOM,octet *W,octet *C,octet *D,octet *F) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big r,a,b,gx,gy,wx,wy,f,c,d,h2; + int bit,M,aa,bb,cc,err,res=0; + epoint *G,*WP,*P; + BOOL compress,valid; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(11)]; + char mem1[MR_ECP_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 11); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 3); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + a=mirvar_mem(_MIPP_ mem, 0); + b=mirvar_mem(_MIPP_ mem, 1); + gx=mirvar_mem(_MIPP_ mem, 2); + gy=mirvar_mem(_MIPP_ mem, 3); + r=mirvar_mem(_MIPP_ mem, 4); + wx=mirvar_mem(_MIPP_ mem, 5); + wy=mirvar_mem(_MIPP_ mem, 6); + f=mirvar_mem(_MIPP_ mem, 7); + c=mirvar_mem(_MIPP_ mem, 8); + d=mirvar_mem(_MIPP_ mem, 9); + h2=mirvar_mem(_MIPP_ mem, 10); + + M=DOM->M; + aa=DOM->a; bb=DOM->b; cc=DOM->c; + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ C,c); + OS2FEP(_MIPP_ D,d); + OS2FEP(_MIPP_ F,f); + if (size(c)<1 || mr_compare(c,r)>=0 || size(d)<1 || mr_compare(d,r)>=0) + res=MR_P1363_INVALID; + } + + if (res==0) + { + xgcd(_MIPP_ d,r,d,d,d); + mad(_MIPP_ f,d,f,r,r,f); + mad(_MIPP_ c,d,c,r,r,h2); + + ecurve2_init(_MIPP_ M,aa,bb,cc,a,b,FALSE,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + WP=epoint_init_mem(_MIPP_ mem1,1); + P=epoint_init_mem(_MIPP_ mem1,2); + epoint2_set(_MIPP_ gx,gy,0,G); + + compress=OS2ECP(_MIPP_ W,wx,wy,DOM->fsize,&bit); + if (!compress) + valid=epoint2_set(_MIPP_ wx,wy,0,WP); + else valid=epoint2_set(_MIPP_ wx,wx,bit,WP); + if (!valid) res=MR_P1363_ERROR; + else + { + ecurve2_mult2(_MIPP_ f,G,h2,WP,P); + if (P->marker==MR_EPOINT_INFINITY) res=MR_P1363_INVALID; + else + { + epoint2_get(_MIPP_ P,d,d); + divide(_MIPP_ d,r,r); + if (mr_compare(d,c)!=0) res=MR_P1363_INVALID; + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,11); + ecp_memkill(_MIPP_ mem1,3); +#else + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int EC2PSP_NR2PV(BOOL (*idle)(void),ec2_domain *DOM,csprng *RNG,octet *U,octet *V) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big a,b,gx,gy,r,u,vx; + epoint *G,*VP; + int M,aa,bb,cc,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(7)]; + char mem1[MR_ECP_RESERVE(2)]; + memset(mem,0,MR_BIG_RESERVE(7)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 7); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 3); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + a=mirvar_mem(_MIPP_ mem, 0); + b=mirvar_mem(_MIPP_ mem, 1); + gx=mirvar_mem(_MIPP_ mem, 2); + gy=mirvar_mem(_MIPP_ mem, 3); + r=mirvar_mem(_MIPP_ mem, 4); + u=mirvar_mem(_MIPP_ mem, 5); + vx=mirvar_mem(_MIPP_ mem, 6); + + M=DOM->M; + aa=DOM->a; bb=DOM->b; cc=DOM->c; + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->A,a); + + ecurve2_init(_MIPP_ M,aa,bb,cc,a,b,FALSE,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + VP=epoint_init_mem(_MIPP_ mem1,1); + epoint2_set(_MIPP_ gx,gy,0,G); + + strong_bigrand(_MIPP_ RNG,r,u); + if (DOM->PC.window==0) + { + ecurve2_mult(_MIPP_ u,G,VP); + epoint2_get(_MIPP_ VP,vx,vx); + } + else + mul2_brick(_MIPP_ &DOM->PC,u,vx,vx); + + convert_big_octet(_MIPP_ u,U); + FE2OSP(_MIPP_ vx,DOM->fsize,V); + + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,7); + ecp_memkill(_MIPP_ mem1,2); +#else + memset(mem,0,MR_BIG_RESERVE(7)); + memset(mem1,0,MR_ECP_RESERVE(2)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int EC2SP_NR2(BOOL (*idle)(void),ec2_domain *DOM,octet *S,octet *U,octet *V,octet *F,octet *C,octet *D) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big r,u,v,s,c,d,f; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(7)]; + memset(mem,0,MR_BIG_RESERVE(7)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 7); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + r=mirvar_mem(_MIPP_ mem, 0); + u=mirvar_mem(_MIPP_ mem, 1); + v=mirvar_mem(_MIPP_ mem, 2); + s=mirvar_mem(_MIPP_ mem, 3); + c=mirvar_mem(_MIPP_ mem, 4); + d=mirvar_mem(_MIPP_ mem, 5); + f=mirvar_mem(_MIPP_ mem, 6); + + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ F,f); + OS2FEP(_MIPP_ U,u); + OS2FEP(_MIPP_ V,v); + if (size(u)<1 || mr_compare(u,r)>=0) res=MR_P1363_BAD_ASSUMPTION; + if (size(v)<1) res=MR_P1363_BAD_ASSUMPTION; + if (mr_compare(f,r)>=0) res=MR_P1363_BAD_ASSUMPTION; + } + if (res==0) + { + add(_MIPP_ v,f,c); + divide(_MIPP_ c,r,r); + if (size(c)==0) res=MR_P1363_ERROR; + } + if (res==0) + { + mad(_MIPP_ s,c,s,r,r,d); + subtract(_MIPP_ u,d,d); + if (size(d)<0) add(_MIPP_ d,r,d); + + convert_big_octet(_MIPP_ c,C); + convert_big_octet(_MIPP_ d,D); + } + + OCTET_CLEAR(U); +#ifndef MR_STATIC + memkill(_MIPP_ mem,7); +#else + memset(mem,0,MR_BIG_RESERVE(7)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int EC2VP_NR2(BOOL (*idle)(void),ec2_domain *DOM,octet *W,octet *C,octet *D,octet *F,octet *V) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big r,a,b,gx,gy,v,wx,wy,c,d,f; + epoint *G,*WP,*P; + BOOL compressed,valid; + int bit,M,aa,bb,cc,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(11)]; + char mem1[MR_ECP_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 11); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 3); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + r=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + gx=mirvar_mem(_MIPP_ mem, 3); + gy=mirvar_mem(_MIPP_ mem, 4); + v=mirvar_mem(_MIPP_ mem, 5); + wx=mirvar_mem(_MIPP_ mem, 6); + wy=mirvar_mem(_MIPP_ mem, 7); + c=mirvar_mem(_MIPP_ mem, 8); + d=mirvar_mem(_MIPP_ mem, 9); + f=mirvar_mem(_MIPP_ mem, 10); + + M=DOM->M; + aa=DOM->a; bb=DOM->b; cc=DOM->c; + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ C,c); + OS2FEP(_MIPP_ D,d); + if (size(c)<1 || mr_compare(c,r)>=0 || mr_compare(d,r)>=0) res=MR_P1363_INVALID; + } + if (res==0) + { + ecurve2_init(_MIPP_ M,aa,bb,cc,a,b,FALSE,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + WP=epoint_init_mem(_MIPP_ mem1,1); + P=epoint_init_mem(_MIPP_ mem1,2); + epoint2_set(_MIPP_ gx,gy,0,G); + + compressed=OS2ECP(_MIPP_ W,wx,wy,DOM->fsize,&bit); + if (!compressed) + valid=epoint2_set(_MIPP_ wx,wy,0,WP); + else valid=epoint2_set(_MIPP_ wx,wx,bit,WP); + if (!valid) res=MR_P1363_ERROR; + else + { + ecurve2_mult2(_MIPP_ d,G,c,WP,P); + if (P->marker==MR_EPOINT_INFINITY) res=MR_P1363_INVALID; + else + { + epoint2_get(_MIPP_ P,v,v); + copy(v,f); + divide(_MIPP_ f,r,r); + subtract(_MIPP_ c,f,f); + if (size(f)<0) add(_MIPP_ f,r,f); + convert_big_octet(_MIPP_ f,F); + FE2OSP(_MIPP_ v,DOM->fsize,V); + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,11); + ecp_memkill(_MIPP_ mem1,3); +#else + memset(mem,0,MR_BIG_RESERVE(11)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int EC2SP_PV(BOOL (*idle)(void),ec2_domain *DOM,octet *S,octet *U,octet *H,octet *D) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big r,u,s,d,h; + int err,res=0; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(5)]; + memset(mem,0,MR_BIG_RESERVE(5)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 5); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + r=mirvar_mem(_MIPP_ mem, 0); + u=mirvar_mem(_MIPP_ mem, 1); + s=mirvar_mem(_MIPP_ mem, 2); + d=mirvar_mem(_MIPP_ mem, 3); + h=mirvar_mem(_MIPP_ mem, 4); + + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ S,s); + OS2FEP(_MIPP_ U,u); + OS2FEP(_MIPP_ H,h); + if (size(u)<1 || mr_compare(u,r)>=0) res=MR_P1363_BAD_ASSUMPTION; + } + + if (res==0) + { + mad(_MIPP_ s,h,s,r,r,d); + subtract(_MIPP_ u,d,d); + if (size(d)<0) add(_MIPP_ d,r,d); + + convert_big_octet(_MIPP_ d,D); + } + + OCTET_CLEAR(U); +#ifndef MR_STATIC + memkill(_MIPP_ mem,5); +#else + memset(mem,0,MR_BIG_RESERVE(5)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int EC2VP_PV(BOOL (*idle)(void),ec2_domain *DOM,octet *W,octet *H,octet *D,octet *V) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,DOM->words,0); +#else + miracl *mr_mip=mirsys(DOM->words,0); +#endif + big r,a,b,gx,gy,v,wx,wy,d,h; + epoint *G,*WP,*P; + BOOL compressed,valid; + int bit,M,aa,bb,cc,err,res=0; +#ifndef MR_STATIC + char *mem; + char *mem1; +#else + char mem[MR_BIG_RESERVE(10)]; + char mem1[MR_ECP_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(10)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 10); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; + mem1=(char *)ecp_memalloc(_MIPP_ 3); + if (mem1==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + r=mirvar_mem(_MIPP_ mem, 0); + a=mirvar_mem(_MIPP_ mem, 1); + b=mirvar_mem(_MIPP_ mem, 2); + gx=mirvar_mem(_MIPP_ mem, 3); + gy=mirvar_mem(_MIPP_ mem, 4); + v=mirvar_mem(_MIPP_ mem, 5); + wx=mirvar_mem(_MIPP_ mem, 6); + wy=mirvar_mem(_MIPP_ mem, 7); + d=mirvar_mem(_MIPP_ mem, 8); + h=mirvar_mem(_MIPP_ mem, 9); + + M=DOM->M; + aa=DOM->a; bb=DOM->b; cc=DOM->c; + OS2FEP(_MIPP_ &DOM->R,r); + OS2FEP(_MIPP_ &DOM->Gx,gx); + OS2FEP(_MIPP_ &DOM->Gy,gy); + OS2FEP(_MIPP_ &DOM->B,b); + OS2FEP(_MIPP_ &DOM->A,a); + OS2FEP(_MIPP_ H,h); + OS2FEP(_MIPP_ D,d); + if (mr_compare(d,r)>=0) res=MR_P1363_INVALID; + } + if (res==0) + { + ecurve2_init(_MIPP_ M,aa,bb,cc,a,b,FALSE,MR_PROJECTIVE); + G=epoint_init_mem(_MIPP_ mem1,0); + WP=epoint_init_mem(_MIPP_ mem1,1); + P=epoint_init_mem(_MIPP_ mem1,2); + epoint2_set(_MIPP_ gx,gy,0,G); + + compressed=OS2ECP(_MIPP_ W,wx,wy,DOM->fsize,&bit); + if (!compressed) + valid=epoint2_set(_MIPP_ wx,wy,0,WP); + else valid=epoint2_set(_MIPP_ wx,wx,bit,WP); + if (!valid) res=MR_P1363_ERROR; + else + { + ecurve2_mult2(_MIPP_ d,G,h,WP,P); + if (P->marker==MR_EPOINT_INFINITY) res=MR_P1363_INVALID; + else + { + epoint2_get(_MIPP_ P,v,v); + FE2OSP(_MIPP_ v,DOM->fsize,V); + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,10); + ecp_memkill(_MIPP_ mem1,3); +#else + memset(mem,0,MR_BIG_RESERVE(10)); + memset(mem1,0,MR_ECP_RESERVE(3)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +/*** RSA/RW primitives - support functions ***/ +/* destroy the Public Key structure */ + +P1363_API void IF_PUBLIC_KEY_KILL(if_public_key *PUB) +{ + OCTET_KILL(&PUB->N); + PUB->words=PUB->fsize=0; PUB->e=0; +} + +/* destroy the Private Key structure */ + +P1363_API void IF_PRIVATE_KEY_KILL(if_private_key *PRIV) +{ + OCTET_KILL(&PRIV->P); + OCTET_KILL(&PRIV->Q); + OCTET_KILL(&PRIV->DP); + OCTET_KILL(&PRIV->DQ); + OCTET_KILL(&PRIV->C); + PRIV->words=0; +} + +/* generate an RSA/RW key pair. The size of the public key in bits + * is passed as a parameter. If the exponent E is even, then an RW key pair + * is generated, otherwise an RSA key pair */ + +P1363_API int IF_KEY_PAIR(BOOL (*idle)(void),csprng *RNG,int bits,int E,if_private_key *PRIV,if_public_key *PUB) +{ /* A16.11/A16.12 more or less */ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; +#endif + miracl *mr_mip; + int hE,m,r,bytes,hbytes,words,err,res=0; + big p,q,dp,dq,c,n,t,p1,q1; + BOOL RW; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(9)]; + memset(mem,0,MR_BIG_RESERVE(9)); +#endif + words=MR_ROUNDUP(bits,MIRACL); +#ifdef MR_GENERIC_AND_STATIC + mr_mip=mirsys(&instance,words,0); +#else + mr_mip=mirsys(words,0); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + mr_mip->NTRY=50; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 9); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + p=mirvar_mem(_MIPP_ mem, 0); + q=mirvar_mem(_MIPP_ mem, 1); + dp=mirvar_mem(_MIPP_ mem, 2); + dq=mirvar_mem(_MIPP_ mem, 3); + c=mirvar_mem(_MIPP_ mem, 4); + n=mirvar_mem(_MIPP_ mem, 5); + p1=mirvar_mem(_MIPP_ mem, 6); + q1=mirvar_mem(_MIPP_ mem, 7); + t=mirvar_mem(_MIPP_ mem, 8); + RW=FALSE; + if (E%2==0) + { + RW=TRUE; /* Rabin-Williams */ + hE=E/2; + } + + PRIV->words=words; + PUB->words=words; + PUB->e=E; + + bytes=MR_ROUNDUP(bits,8); + + PUB->fsize=bytes; + + OCTET_INIT(&PUB->N,bytes); + hbytes=2+(bytes/2); + OCTET_INIT(&PRIV->P,hbytes); + OCTET_INIT(&PRIV->Q,hbytes); + OCTET_INIT(&PRIV->DP,hbytes); + OCTET_INIT(&PRIV->DQ,hbytes); + OCTET_INIT(&PRIV->C,hbytes); + gprime(_MIPP_ 10000); + forever + { + if (mr_mip->ERNUM) break; + m=(bits+1)/2; + expb2(_MIPP_ m,t); + do + { + if (mr_mip->ERNUM) break; + strong_bigrand(_MIPP_ RNG,t,p); + } while (logb2(_MIPP_ p)ERNUM) break; + if (RW) incr(_MIPP_ p,6,p); + incr(_MIPP_ p,1,p); + if (RW) + { + if (hE==1) r=1; + else r=remain(_MIPP_ p,hE); + } + else r=remain(_MIPP_ p,E); + incr(_MIPP_ p,1,p); + if (r==0) continue; + } while (!isprime(_MIPP_ p)); + + expb2(_MIPP_ bits,t); + divide(_MIPP_ t,p,t); + expb2(_MIPP_ bits-1,c); + divide(_MIPP_ c,p,c); + incr(_MIPP_ c,1,c); + do + { + if (mr_mip->ERNUM) break; + strong_bigrand(_MIPP_ RNG,t,q); + } while (mr_compare(q,c)<0); + if (remain(_MIPP_ q,2)==0) incr(_MIPP_ q,1,q); + + if (RW) + { /* make q=7 mod 8 */ + r=remain(_MIPP_ q,8); + incr(_MIPP_ q,(7-r)%8,q); + } + do + { + if (mr_mip->ERNUM) break; + if (RW) incr(_MIPP_ q,6,q); + incr(_MIPP_ q,1,q); + if (RW) + { + if (hE==1) r=1; + else r=remain(_MIPP_ q,hE); + } + else r=remain(_MIPP_ q,E); + incr(_MIPP_ q,1,q); + if (r==0) continue; + } while (!isprime(_MIPP_ q)); + multiply(_MIPP_ p,q,n); + if (logb2(_MIPP_ n)!=bits) continue; /* very rare! */ + decr(_MIPP_ p,1,p1); + decr(_MIPP_ q,1,q1); + multiply(_MIPP_ p1,q1,c); + egcd(_MIPP_ p1,q1,t); + divide(_MIPP_ c,t,c); /* c=LCM(p-1,q-1) */ + if (RW) subdiv(_MIPP_ c,2,c); + convert(_MIPP_ E,t); + + if (xgcd(_MIPP_ t,c,dp,dp,dp)!=1) continue; + break; + } + copy(dp,dq); + divide(_MIPP_ dp,p1,p1); + divide(_MIPP_ dq,q1,q1); + xgcd(_MIPP_ q,p,c,c,c); /* c=1/q mod p */ + + convert_big_octet(_MIPP_ n,&PUB->N); + convert_big_octet(_MIPP_ p,&PRIV->P); + convert_big_octet(_MIPP_ q,&PRIV->Q); + convert_big_octet(_MIPP_ dp,&PRIV->DP); + convert_big_octet(_MIPP_ dq,&PRIV->DQ); + convert_big_octet(_MIPP_ c,&PRIV->C); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,9); +#else + memset(mem,0,MR_BIG_RESERVE(9)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + if (res<0) return res; + else return bytes; +} + +static void private_key_op(_MIPD_ big p,big q,big dp,big dq,big c,big i,big s) +{ /* internal:- basic RSA/RW decryption operation */ + big jp,jq; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(2)]; + memset(mem,0,MR_BIG_RESERVE(2)); +#endif +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 2); +#endif + jp=mirvar_mem(_MIPP_ mem,0); + jq=mirvar_mem(_MIPP_ mem,1); + powmod(_MIPP_ i,dp,p,jp); + powmod(_MIPP_ i,dq,q,jq); + subtract(_MIPP_ jp,jq,jp); + mad(_MIPP_ c,jp,jp,p,p,s); + if (size(s)<0) add(_MIPP_ s,p,s); + multiply(_MIPP_ s,q,jp); + add(_MIPP_ jq,jp,s); +#ifndef MR_STATIC + memkill(_MIPP_ mem,2); +#else + memset(mem,0,MR_BIG_RESERVE(2)); +#endif +} + +/*** P1363 RSA/RW primitives ***/ +/* See P1363 documentation for more details */ + +P1363_API int IFEP_RSA(BOOL (*idle)(void),if_public_key *PUB,octet *F,octet *G) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,PUB->words,0); +#else + miracl *mr_mip=mirsys(PUB->words,0); +#endif + int e,err,res=0; + big f,g,n; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(3)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 3); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + f=mirvar_mem(_MIPP_ mem, 0); + g=mirvar_mem(_MIPP_ mem, 1); + n=mirvar_mem(_MIPP_ mem, 2); + + OS2FEP(_MIPP_ &PUB->N,n); + OS2FEP(_MIPP_ F,f); + if (mr_compare(f,n)>=0) res=MR_P1363_BAD_ASSUMPTION; + } + if (res==0) + { + e=PUB->e; + power(_MIPP_ f,e,n,g); + convert_big_octet(_MIPP_ g,G); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,3); +#else + memset(mem,0,MR_BIG_RESERVE(3)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int IFDP_RSA(BOOL (*idle)(void),if_private_key *PRIV,octet *G,octet *F) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,PRIV->words,0); +#else + miracl *mr_mip=mirsys(PRIV->words,0); +#endif + int err,res=0; + big f,g,p,q,dp,dq,c,n; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(8)]; + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 8); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + f=mirvar_mem(_MIPP_ mem, 0); + g=mirvar_mem(_MIPP_ mem, 1); + p=mirvar_mem(_MIPP_ mem, 2); + q=mirvar_mem(_MIPP_ mem, 3); + dp=mirvar_mem(_MIPP_ mem, 4); + dq=mirvar_mem(_MIPP_ mem, 5); + c=mirvar_mem(_MIPP_ mem, 6); + n=mirvar_mem(_MIPP_ mem, 7); + + OS2FEP(_MIPP_ &PRIV->P,p); + OS2FEP(_MIPP_ &PRIV->Q,q); + OS2FEP(_MIPP_ &PRIV->DP,dp); + OS2FEP(_MIPP_ &PRIV->DQ,dq); + OS2FEP(_MIPP_ &PRIV->C,c); + OS2FEP(_MIPP_ G,g); + multiply(_MIPP_ p,q,n); + if (mr_compare(g,n)>=0) res=MR_P1363_BAD_ASSUMPTION; + } + if (res==0) + { + private_key_op(_MIPP_ p,q,dp,dq,c,g,f); + convert_big_octet(_MIPP_ f,F); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,8); +#else + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int IFSP_RSA1(BOOL (*idle)(void),if_private_key *PRIV,octet *F,octet *S) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,PRIV->words,0); +#else + miracl *mr_mip=mirsys(PRIV->words,0); +#endif + int err,res=0; + big f,s,p,q,dp,dq,c,n; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(8)]; + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 8); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + s=mirvar_mem(_MIPP_ mem, 0); + f=mirvar_mem(_MIPP_ mem, 1); + p=mirvar_mem(_MIPP_ mem, 2); + q=mirvar_mem(_MIPP_ mem, 3); + dp=mirvar_mem(_MIPP_ mem, 4); + dq=mirvar_mem(_MIPP_ mem, 5); + c=mirvar_mem(_MIPP_ mem, 6); + n=mirvar_mem(_MIPP_ mem, 7); + + OS2FEP(_MIPP_ &PRIV->P,p); + OS2FEP(_MIPP_ &PRIV->Q,q); + OS2FEP(_MIPP_ &PRIV->DP,dp); + OS2FEP(_MIPP_ &PRIV->DQ,dq); + OS2FEP(_MIPP_ &PRIV->C,c); + OS2FEP(_MIPP_ F,f); + multiply(_MIPP_ p,q,n); + if (mr_compare(f,n)>=0) res=MR_P1363_BAD_ASSUMPTION; + } + if (res==0) + { + private_key_op(_MIPP_ p,q,dp,dq,c,f,s); + convert_big_octet(_MIPP_ s,S); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,8); +#else + memset(mem,0,MR_BIG_RESERVE(8)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int IFVP_RSA1(BOOL (*idle)(void),if_public_key *PUB,octet *S,octet *F) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,PUB->words,0); +#else + miracl *mr_mip=mirsys(PUB->words,0); +#endif + int e,err,res=0; + big f,s,n; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(3)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 3); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + s=mirvar_mem(_MIPP_ mem, 0); + f=mirvar_mem(_MIPP_ mem, 1); + n=mirvar_mem(_MIPP_ mem, 2); + + OS2FEP(_MIPP_ &PUB->N,n); + OS2FEP(_MIPP_ S,s); + if (mr_compare(s,n)>=0) res=MR_P1363_INVALID; + } + if (res==0) + { + e=PUB->e; + power(_MIPP_ s,e,n,f); + convert_big_octet(_MIPP_ f,F); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,3); +#else + memset(mem,0,MR_BIG_RESERVE(3)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int IFSP_RSA2(BOOL (*idle)(void),if_private_key *PRIV,octet *F,octet *S) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,PRIV->words,0); +#else + miracl *mr_mip=mirsys(PRIV->words,0); +#endif + int err,res=0; + big f,s,p,q,dp,dq,c,n,t; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(9)]; + memset(mem,0,MR_BIG_RESERVE(9)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 9); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + s=mirvar_mem(_MIPP_ mem, 0); + f=mirvar_mem(_MIPP_ mem, 1); + p=mirvar_mem(_MIPP_ mem, 2); + q=mirvar_mem(_MIPP_ mem, 3); + dp=mirvar_mem(_MIPP_ mem, 4); + dq=mirvar_mem(_MIPP_ mem, 5); + c=mirvar_mem(_MIPP_ mem, 6); + n=mirvar_mem(_MIPP_ mem, 7); + t=mirvar_mem(_MIPP_ mem, 8); + + OS2FEP(_MIPP_ &PRIV->P,p); + OS2FEP(_MIPP_ &PRIV->Q,q); + OS2FEP(_MIPP_ &PRIV->DP,dp); + OS2FEP(_MIPP_ &PRIV->DQ,dq); + OS2FEP(_MIPP_ &PRIV->C,c); + OS2FEP(_MIPP_ F,f); + multiply(_MIPP_ p,q,n); + if (remain(_MIPP_ f,16)!=12) res=MR_P1363_BAD_ASSUMPTION; + if (mr_compare(f,n)>=0) res=MR_P1363_BAD_ASSUMPTION; + } + if (res==0) + { + private_key_op(_MIPP_ p,q,dp,dq,c,f,s); + subtract(_MIPP_ n,s,t); + if (mr_compare(s,t)>0) + convert_big_octet(_MIPP_ t,S); + else + convert_big_octet(_MIPP_ s,S); + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,9); +#else + memset(mem,0,MR_BIG_RESERVE(9)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int IFVP_RSA2(BOOL (*idle)(void),if_public_key *PUB,octet *S,octet *F) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,PUB->words,0); +#else + miracl *mr_mip=mirsys(PUB->words,0); +#endif + int e,err,res=0; + big f,s,n; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(3)]; + memset(mem,0,MR_BIG_RESERVE(3)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 3); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + s=mirvar_mem(_MIPP_ mem, 0); + f=mirvar_mem(_MIPP_ mem, 1); + n=mirvar_mem(_MIPP_ mem, 2); + + OS2FEP(_MIPP_ &PUB->N,n); + OS2FEP(_MIPP_ S,s); + decr(_MIPP_ n,1,f); + subdiv(_MIPP_ f,2,f); + if (mr_compare(s,f)>0) res=MR_P1363_INVALID; + } + if (res==0) + { + e=PUB->e; + power(_MIPP_ s,e,n,f); + if (remain(_MIPP_ f,16)==12) + convert_big_octet(_MIPP_ f,F); + else + { + subtract(_MIPP_ n,f,f); + if (remain(_MIPP_ f,16)==12) + convert_big_octet(_MIPP_ f,F); + else + res=MR_P1363_INVALID; + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,3); +#else + memset(mem,0,MR_BIG_RESERVE(3)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int IFSP_RW(BOOL (*idle)(void),if_private_key *PRIV,octet *F,octet *S) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,PRIV->words,0); +#else + miracl *mr_mip=mirsys(PRIV->words,0); +#endif + int err,res=0; + big f,s,p,q,dp,dq,c,n,t; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(9)]; + memset(mem,0,MR_BIG_RESERVE(9)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 9); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + s=mirvar_mem(_MIPP_ mem, 0); + f=mirvar_mem(_MIPP_ mem, 1); + p=mirvar_mem(_MIPP_ mem, 2); + q=mirvar_mem(_MIPP_ mem, 3); + dp=mirvar_mem(_MIPP_ mem, 4); + dq=mirvar_mem(_MIPP_ mem, 5); + c=mirvar_mem(_MIPP_ mem, 6); + n=mirvar_mem(_MIPP_ mem, 7); + t=mirvar_mem(_MIPP_ mem, 8); + + OS2FEP(_MIPP_ &PRIV->P,p); + OS2FEP(_MIPP_ &PRIV->Q,q); + OS2FEP(_MIPP_ &PRIV->DP,dp); + OS2FEP(_MIPP_ &PRIV->DQ,dq); + OS2FEP(_MIPP_ &PRIV->C,c); + OS2FEP(_MIPP_ F,f); + multiply(_MIPP_ p,q,n); + if (remain(_MIPP_ f,16)!=12) res=MR_P1363_BAD_ASSUMPTION; + if (mr_compare(f,n)>=0) res=MR_P1363_BAD_ASSUMPTION; + } + if (res==0) + { + if (jack(_MIPP_ f,n)!=1) + subdiv(_MIPP_ f,2,f); + private_key_op(_MIPP_ p,q,dp,dq,c,f,s); + subtract(_MIPP_ n,s,t); + if (mr_compare(s,t)>0) + convert_big_octet(_MIPP_ t,S); + else + convert_big_octet(_MIPP_ s,S); + + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,9); +#else + memset(mem,0,MR_BIG_RESERVE(9)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + +P1363_API int IFVP_RW(BOOL (*idle)(void),if_public_key *PUB,octet *S,octet *F) +{ +#ifdef MR_GENERIC_AND_STATIC + miracl instance; + miracl *mr_mip=mirsys(&instance,PUB->words,0); +#else + miracl *mr_mip=mirsys(PUB->words,0); +#endif + int e,err,res=0; + big f,s,n,t1,t2; +#ifndef MR_STATIC + char *mem; +#else + char mem[MR_BIG_RESERVE(5)]; + memset(mem,0,MR_BIG_RESERVE(5)); +#endif + if (mr_mip==NULL) return MR_P1363_OUT_OF_MEMORY; + mr_mip->ERCON=TRUE; + set_user_function(_MIPP_ idle); +#ifndef MR_STATIC + mem=(char *)memalloc(_MIPP_ 5); + if (mem==NULL) res=MR_P1363_OUT_OF_MEMORY; +#endif + if (res==0) + { + s=mirvar_mem(_MIPP_ mem, 0); + f=mirvar_mem(_MIPP_ mem, 1); + n=mirvar_mem(_MIPP_ mem, 2); + t1=mirvar_mem(_MIPP_ mem, 3); + t2=mirvar_mem(_MIPP_ mem, 4); + + OS2FEP(_MIPP_ &PUB->N,n); + OS2FEP(_MIPP_ S,s); + decr(_MIPP_ n,1,f); + subdiv(_MIPP_ f,2,f); + if (mr_compare(s,f)>0) res=MR_P1363_INVALID; + } + if (res==0) + { + e=PUB->e; + power(_MIPP_ s,e,n,t1); + subtract(_MIPP_ n,t1,t2); + + if (remain(_MIPP_ t1,16)==12) + convert_big_octet(_MIPP_ t1,F); + else + { + if (remain(_MIPP_ t1,8)==6) + { + premult(_MIPP_ t1,2,f); + convert_big_octet(_MIPP_ f,F); + } + else + { + if (remain(_MIPP_ t2,16)==12) + convert_big_octet(_MIPP_ t2,F); + else + { + if (remain(_MIPP_ t2,8)==6) + { + premult(_MIPP_ t2,2,f); + convert_big_octet(_MIPP_ f,F); + } + else res=MR_P1363_INVALID; + } + } + } + } +#ifndef MR_STATIC + memkill(_MIPP_ mem,5); +#else + memset(mem,0,MR_BIG_RESERVE(5)); +#endif + err=mr_mip->ERNUM; + mirexit(_MIPPO_ ); + if (err==MR_ERR_OUT_OF_MEMORY) return MR_P1363_OUT_OF_MEMORY; + if (err==MR_ERR_DIV_BY_ZERO) return MR_P1363_DIV_BY_ZERO; + if (err!=0) return -(1000+err); + return res; +} + diff --git a/miracl/source/p1363/p1363.h b/miracl/source/p1363/p1363.h new file mode 100644 index 0000000..379f3df --- /dev/null +++ b/miracl/source/p1363/p1363.h @@ -0,0 +1,324 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ + +/* + * MIRACL P1363 header file + * DL - Discrete Logarithm + * ECp - GF(p) Elliptic Curve + * EC2 - GF(2^m) Elliptic Curve + * IF - Integer factorisation-based methods + */ + +#ifndef P1363_H +#define P1363_H + +#include "miracl.h" + +#ifdef MR_P1363_DLL + +#ifdef P1363_DLL +#define P1363_API __declspec(dllexport) +#else +#define P1363_API __declspec(dllimport) +#endif + +#else +#define P1363_API +#endif + +/****** UNCOMMENT THIS TO ALLOCATE FIXED SIZE OCTET'S FROM THE STACK *******/ + +/* #define OCTET_FROM_STACK_SIZE 200 */ + +/* #define OCTET_FROM_STACK_SIZE 60 */ + +/***************************************************************************/ + +/* define Octet Length Type - normally int but could be short or long */ +typedef int oltype; + +#define MR_P1363_OK 0 +#define MR_P1363_DOMAIN_ERROR -1 +#define MR_P1363_INVALID_PUBLIC_KEY -2 +#define MR_P1363_ERROR -3 +#define MR_P1363_INVALID -4 +#define MR_P1363_DOMAIN_NOT_FOUND -5 +#define MR_P1363_OUT_OF_MEMORY -6 +#define MR_P1363_DIV_BY_ZERO -7 +#define MR_P1363_BAD_ASSUMPTION -8 + +/* Supported hash functions */ + +#define SHA1 0 +#define SHA256 2 +#define SHA384 3 +#define SHA512 4 + +#ifdef mr_unsign64 +#define MAX_HASH_BYTES 64 +#else +#define MAX_HASH_BYTES 32 +#endif + +/* portable representation of a big positive number */ + +typedef struct +{ + oltype len; + oltype max; +#ifdef OCTET_FROM_STACK_SIZE + char val[OCTET_FROM_STACK_SIZE]; +#else + char *val; +#endif +} octet; + +/* Discrete Log. domain parameters */ + +typedef struct +{ + int words; + int fsize; + int rbits; + octet Q; + octet R; + octet G; + octet K; + octet IK; + int H; + brick PC; +} dl_domain; + +/* ECp domain parameters */ + +typedef struct +{ + int words; + int fsize; + int rbits; + octet Q; + octet A; + octet B; + octet R; + octet Gx; + octet Gy; + octet K; + octet IK; + int H; + ebrick PC; +} ecp_domain; + +/* EC2 domain parameters */ + +typedef struct +{ + int words; + int fsize; + int rbits; + int M; + octet A; + octet B; + octet R; + octet Gx; + octet Gy; + octet K; + octet IK; + int H; + int a,b,c; + ebrick2 PC; +} ec2_domain; + +/* IF Public Key */ + +typedef struct +{ + int words; + int fsize; + int e; + octet N; +} if_public_key; + +/* IF Private Key */ + +typedef struct +{ + int words; + octet P; + octet Q; + octet DP; + octet DQ; + octet C; +} if_private_key; + +/* Octet string handlers */ + +extern P1363_API BOOL OCTET_INIT(octet *,int); +extern P1363_API void OCTET_INIT_FROM_ARRAY(octet *,int,char *); +extern P1363_API void OCTET_CLEAR(octet *); +extern P1363_API void OCTET_EMPTY(octet *); +extern P1363_API void OCTET_COPY(octet *,octet *); +extern P1363_API int OCTET_COMPARE(octet *,octet *); +extern P1363_API BOOL OCTET_NCOMPARE(octet *,octet *,int); +extern P1363_API void OCTET_XOR_BYTE(octet *,int); +extern P1363_API void OCTET_XOR(octet *,octet *); +extern P1363_API BOOL OCTET_PAD(octet *,int); +extern P1363_API void OCTET_JOIN_OCTET(octet *,octet *); +extern P1363_API void OCTET_OUTPUT(octet *); +extern P1363_API void OCTET_RAND(csprng *,int,octet *); +extern P1363_API void OCTET_SHIFT_LEFT(octet *,int); +extern P1363_API void OCTET_CHOP(octet *,int n,octet *y); +extern P1363_API void OCTET_KILL(octet *); +extern P1363_API void OCTET_JOIN_LONG(long,int,octet *); +extern P1363_API void OCTET_JOIN_STRING(char *,octet *); +extern P1363_API void OCTET_JOIN_BYTES(char *,int,octet *); +extern P1363_API void OCTET_JOIN_BYTE(int,int,octet *); +extern P1363_API void OCTET_PRINT_STRING(octet *); + +/* P1363 Auxiliary Functions */ + +extern P1363_API void CREATE_CSPRNG(csprng *,octet *); +extern P1363_API void KILL_CSPRNG(csprng *); +extern P1363_API void HASH(int,octet *,octet *); +extern P1363_API void MGF1(octet *,int,int,octet *); +extern P1363_API BOOL EMSA1(octet *,FILE *,int,int,octet *); +extern P1363_API BOOL EMSA2(octet *,FILE *,int,int,octet *); +extern P1363_API BOOL EMSA3(octet *,FILE *,int,int,octet *); +extern P1363_API BOOL EMSA4_ENCODE(BOOL,int,int,csprng *,int,octet *,FILE *,octet *); +extern P1363_API BOOL EMSA4_DECODE(BOOL,int,int,int,octet *,octet *,FILE *); +extern P1363_API BOOL EMSR1_ENCODE(BOOL,int,int,octet *,octet *,FILE *,int,int,octet *,octet *); +extern P1363_API BOOL EMSR1_DECODE(BOOL,int,int,octet *,octet *,FILE *,int,int,octet *,int,octet *); +extern P1363_API BOOL EMSR2_ENCODE(int,BOOL,int,octet *,octet *,octet *,octet *); +extern P1363_API BOOL EMSR2_DECODE(int,BOOL,int,octet *,octet *,octet *,octet *); +extern P1363_API BOOL EMSR3_ENCODE(BOOL,int,int,csprng *,int,octet *,octet *,FILE *,octet *); +extern P1363_API BOOL EMSR3_DECODE(BOOL,int,int,int,octet *,octet *,FILE *,octet *); +extern P1363_API BOOL EME1_ENCODE(octet *,csprng *,int,octet *,int,octet *); +extern P1363_API BOOL EME1_DECODE(octet *,int,octet *,int,octet *); +extern P1363_API void KDF1(octet *,octet *,int,octet *); +extern P1363_API BOOL KDF2(octet *,octet *,int,int,octet *); + +extern P1363_API BOOL MAC1(octet *,FILE *,octet *,int,int,octet *); +extern P1363_API BOOL AES_CBC_IV0_ENCRYPT(octet *,octet *,FILE *,octet *,FILE *); +extern P1363_API BOOL AES_CBC_IV0_DECRYPT(octet *,octet *,FILE *,octet *,FILE *); + +/* DL primitives - support functions */ + +extern P1363_API void DL_DOMAIN_KILL(dl_domain *); +extern P1363_API int DL_DOMAIN_INIT(dl_domain *,char *,char **,int); +extern P1363_API int DL_DOMAIN_VALIDATE(BOOL (*)(void),dl_domain *); +extern P1363_API int DL_KEY_PAIR_GENERATE(BOOL (*)(void),dl_domain *,csprng *,octet *,octet *); +extern P1363_API int DL_PUBLIC_KEY_VALIDATE(BOOL (*)(void),dl_domain *,BOOL,octet *); + +/* P1363 DL Primitives */ + +extern P1363_API int DLSVDP_DH(BOOL (*)(void),dl_domain *,octet *,octet *,octet *); +extern P1363_API int DLSVDP_DHC(BOOL (*)(void),dl_domain *,octet *,octet *,BOOL,octet *); +extern P1363_API int DLSVDP_MQV(BOOL (*)(void),dl_domain *,octet *,octet *,octet *,octet *,octet *,octet *); +extern P1363_API int DLSVDP_MQVC(BOOL (*)(void),dl_domain *,octet *,octet *,octet *,octet *,octet *,BOOL,octet *); +extern P1363_API int DLVP_NR(BOOL (*)(void),dl_domain *,octet *,octet *,octet *,octet *); +extern P1363_API int DLSP_NR(BOOL (*)(void),dl_domain *,csprng *,octet *,octet *,octet *,octet *); +extern P1363_API int DLVP_DSA(BOOL (*)(void),dl_domain *,octet *,octet *,octet *,octet *); +extern P1363_API int DLSP_DSA(BOOL (*)(void),dl_domain *,csprng *,octet *,octet *,octet *,octet *); +extern P1363_API int DLPSP_NR2PV(BOOL (*)(void),dl_domain *,csprng *,octet *,octet *); +extern P1363_API int DLSP_NR2(BOOL (*)(void),dl_domain *,octet *,octet *,octet *,octet *,octet *,octet *); +extern P1363_API int DLVP_NR2(BOOL (*)(void),dl_domain *,octet *,octet *,octet *,octet *,octet *); +extern P1363_API int DLSP_PV(BOOL (*)(void),dl_domain *,octet *,octet *,octet *,octet *); +extern P1363_API int DLVP_PV(BOOL (*)(void),dl_domain *,octet *,octet *,octet *,octet *); + +/* ECP primitives - support functions */ + +extern P1363_API void ECP_DOMAIN_KILL(ecp_domain *); +extern P1363_API int ECP_DOMAIN_INIT(ecp_domain *,char *,char **,int); +extern P1363_API int ECP_DOMAIN_VALIDATE(BOOL (*)(void),ecp_domain *); +extern P1363_API int ECP_KEY_PAIR_GENERATE(BOOL (*)(void),ecp_domain *,csprng *,octet *,int,octet *); +extern P1363_API int ECP_PUBLIC_KEY_VALIDATE(BOOL (*)(void),ecp_domain *,BOOL,octet *); + +/* P1363 ECP primitives */ + +extern P1363_API int ECPSVDP_DH(BOOL (*)(void),ecp_domain *,octet *,octet *,octet *); +extern P1363_API int ECPSVDP_DHC(BOOL (*)(void),ecp_domain *,octet *,octet *,BOOL,octet *); +extern P1363_API int ECPSVDP_MQV(BOOL (*)(void),ecp_domain *,octet *,octet *,octet *,octet *,octet *,octet *); +extern P1363_API int ECPSVDP_MQVC(BOOL (*)(void),ecp_domain *,octet *,octet *,octet *,octet *,octet *,BOOL,octet *); +extern P1363_API int ECPSP_NR(BOOL (*)(void),ecp_domain *,csprng *,octet *,octet *,octet *,octet *); +extern P1363_API int ECPVP_NR(BOOL (*)(void),ecp_domain *,octet *,octet *,octet *,octet *); +extern P1363_API int ECPSP_DSA(BOOL (*)(void),ecp_domain *,csprng *,octet *,octet *,octet *,octet *); +extern P1363_API int ECPVP_DSA(BOOL (*)(void),ecp_domain *,octet *,octet *,octet *,octet *); +extern P1363_API int ECPPSP_NR2PV(BOOL (*)(void),ecp_domain *,csprng *,octet *,octet *); +extern P1363_API int ECPSP_NR2(BOOL (*)(void),ecp_domain *,octet *,octet *,octet *,octet *,octet *,octet *); +extern P1363_API int ECPVP_NR2(BOOL (*)(void),ecp_domain *,octet *,octet *,octet *,octet *,octet *); +extern P1363_API int ECPSP_PV(BOOL (*)(void),ecp_domain *,octet *,octet *,octet *,octet *); +extern P1363_API int ECPVP_PV(BOOL (*)(void),ecp_domain *,octet *,octet *,octet *,octet *); + +/* EC2 primitives - support functions */ + +extern P1363_API void EC2_DOMAIN_KILL(ec2_domain *); +extern P1363_API int EC2_DOMAIN_INIT(ec2_domain *,char *,char **,int); +extern P1363_API int EC2_DOMAIN_VALIDATE(BOOL (*)(void),ec2_domain *); +extern P1363_API int EC2_KEY_PAIR_GENERATE(BOOL (*)(void),ec2_domain *,csprng *,octet *,BOOL,octet *); +extern P1363_API int EC2_PUBLIC_KEY_VALIDATE(BOOL (*)(void),ec2_domain *,BOOL,octet *); + +/* P1363 EC2 primitives */ + +extern P1363_API int EC2SVDP_DH(BOOL (*)(void),ec2_domain *,octet *,octet *,octet *); +extern P1363_API int EC2SVDP_DHC(BOOL (*)(void),ec2_domain *,octet *,octet *,BOOL,octet *); +extern P1363_API int EC2SVDP_MQV(BOOL (*)(void),ec2_domain *,octet *,octet *,octet *,octet *,octet *,octet *); +extern P1363_API int EC2SVDP_MQVC(BOOL (*)(void),ec2_domain *,octet *,octet *,octet *,octet *,octet *,BOOL,octet *); +extern P1363_API int EC2SP_NR(BOOL (*)(void),ec2_domain *,csprng *,octet *,octet *,octet *,octet *); +extern P1363_API int EC2VP_NR(BOOL (*)(void),ec2_domain *,octet *,octet *,octet *,octet *); +extern P1363_API int EC2SP_DSA(BOOL (*)(void),ec2_domain *,csprng *,octet *,octet *,octet *,octet *); +extern P1363_API int EC2VP_DSA(BOOL (*)(void),ec2_domain *,octet *,octet *,octet *,octet *); +extern P1363_API int EC2PSP_NR2PV(BOOL (*)(void),ec2_domain *,csprng *,octet *,octet *); +extern P1363_API int EC2SP_NR2(BOOL (*)(void),ec2_domain *,octet *,octet *,octet *,octet *,octet *,octet *); +extern P1363_API int EC2VP_NR2(BOOL (*)(void),ec2_domain *,octet *,octet *,octet *,octet *,octet *); +extern P1363_API int EC2SP_PV(BOOL (*)(void),ec2_domain *,octet *,octet *,octet *,octet *); +extern P1363_API int EC2VP_PV(BOOL (*)(void),ec2_domain *,octet *,octet *,octet *,octet *); + +/* RSA/RW primitives - support functions */ + +extern P1363_API void IF_PUBLIC_KEY_KILL(if_public_key *); +extern P1363_API void IF_PRIVATE_KEY_KILL(if_private_key *); +extern P1363_API int IF_KEY_PAIR(BOOL (*)(void),csprng *,int,int,if_private_key *,if_public_key *); + +/* P1363 RSA/RW primitives */ + +extern P1363_API int IFEP_RSA(BOOL (*)(void),if_public_key *,octet *,octet *); +extern P1363_API int IFDP_RSA(BOOL (*)(void),if_private_key *,octet *,octet *); +extern P1363_API int IFSP_RSA1(BOOL (*)(void),if_private_key *,octet *,octet *); +extern P1363_API int IFVP_RSA1(BOOL (*)(void),if_public_key *,octet *,octet *); +extern P1363_API int IFSP_RSA2(BOOL (*)(void),if_private_key *,octet *,octet *); +extern P1363_API int IFVP_RSA2(BOOL (*)(void),if_public_key *,octet *,octet *); +extern P1363_API int IFSP_RW(BOOL (*)(void),if_private_key *,octet *,octet *); +extern P1363_API int IFVP_RW(BOOL (*)(void),if_public_key *,octet *,octet *); + +#endif + diff --git a/miracl/source/p1363/rsa.c b/miracl/source/p1363/rsa.c new file mode 100644 index 0000000..8bd513f --- /dev/null +++ b/miracl/source/p1363/rsa.c @@ -0,0 +1,78 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* simplest possible secure rsa implementation */ +/* Uses IEEE-1363 standard methods */ +/* See IEEE-1363 section 11.2 IFES, page 57 */ +/* cl /O2 rsa.c p1363.c miracl.lib */ + +#include +#include "p1363.h" + +int main() +{ + int i,bytes,res; + octet m,m1,c,e,raw; + if_public_key pub; + if_private_key priv; + csprng RNG; + /* some true randomness needed here */ + OCTET_INIT(&raw,100); /* should be filled with 100 random bytes */ + + CREATE_CSPRNG(&RNG,&raw); /* initialise strong RNG */ + + bytes=IF_KEY_PAIR(NULL,&RNG,1024,65537,&priv,&pub); + /* generate random public & private key */ + OCTET_INIT(&m,bytes); /* allocate space for plaintext and ciphertext */ + OCTET_INIT(&m1,bytes); + OCTET_INIT(&c,bytes); OCTET_INIT(&e,bytes); + + OCTET_JOIN_STRING((char *)"Hello World\n",&m); + + EME1_ENCODE(&m,&RNG,1023,NULL,SHA256,&e); /* OAEP encode message m to e */ + /* must be less than 1024 bits */ + + IFEP_RSA(NULL,&pub,&e,&c); /* encrypt encoded message */ + IFDP_RSA(NULL,&priv,&c,&m1); /* ... and then decrypt it */ + + EME1_DECODE(&m1,1023,NULL,SHA256,&m1); /* decode it */ + + OCTET_PRINT_STRING(&m1); /* print out decrypted/decoded message */ + + OCTET_KILL(&m); OCTET_KILL(&m1); /* clean up afterwards */ + OCTET_KILL(&c); OCTET_KILL(&raw); OCTET_KILL(&e); + + IF_PUBLIC_KEY_KILL(&pub); /* kill the keys */ + IF_PRIVATE_KEY_KILL(&priv); +} + diff --git a/miracl/source/p1363/test1363.c b/miracl/source/p1363/test1363.c new file mode 100644 index 0000000..f4ba3ba --- /dev/null +++ b/miracl/source/p1363/test1363.c @@ -0,0 +1,1088 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ +/* test driver and function exerciser for P1363 Functions */ +/* NOTE: its important to initialize OCTETs to the correct size */ +/* see comments in p1363.c */ +/* cl /O2 test1363.c p1363.c miracl.lib */ +/* define this next to use Windows DLL */ +/* #define MR_P1363_DLL */ + +#include +#include +#include +#include +#include "p1363.h" + +int main(int argc,char **argv) +{ + int i,ip,mlen,precompute; + BOOL compress,dhaes,result; + octet h,s,p,f,g,c,d,u,v,w,m,m1,tag,tag1; + octet s0,s1,w0,w1,u0,u1,v0,v1,k1,k2,z,vz; + octet z1,z2,f1,f2,f3,k; + octet p1,p2,L2,C; + octet raw; + unsigned long ran; + dl_domain dom; + ecp_domain epdom; + ec2_domain e2dom; + if_public_key pub; + if_private_key priv; + csprng RNG; /* Crypto Strong RNG */ + + int res,bytes,bits; + + argc--; argv++; + compress=FALSE; + precompute=0; + + ip=0; + while (ip>8; + raw.val[2]=ran>>16; + raw.val[3]=ran>>24; + for (i=4;i<100;i++) raw.val[i]=i+1; + + CREATE_CSPRNG(&RNG,&raw); /* initialise strong RNG */ + + OCTET_KILL(&raw); + +/* + OCTET_INIT(&k,100); + OCTET_JOIN_BYTE(0x0b,20,&k); + OCTET_INIT(&m,100); + OCTET_JOIN_STRING("Hi There",&m); + OCTET_INIT(&d,100); + + if (!MAC1(&m,NULL,&k,20,SHA1,&d)) printf("failed\n"); + + OCTET_OUTPUT(&k); + OCTET_OUTPUT(&m); + OCTET_OUTPUT(&d); + + OCTET_KILL(&k); + OCTET_KILL(&m); + OCTET_KILL(&d); +*/ + + bytes=DL_DOMAIN_INIT(&dom,"common.dss",NULL,precompute); + + res=DL_DOMAIN_VALIDATE(NULL,&dom); + if (res!=0) + { + printf("Domain parameters are invalid\n"); + return 0; + } + OCTET_INIT(&s0,bytes); + OCTET_INIT(&s1,bytes); + OCTET_INIT(&w0,bytes); + OCTET_INIT(&w1,bytes); + + DL_KEY_PAIR_GENERATE(NULL,&dom,&RNG,&s0,&w0); + DL_KEY_PAIR_GENERATE(NULL,&dom,&RNG,&s1,&w1); + + OCTET_INIT(&z,bytes); + OCTET_INIT(&z1,bytes); + OCTET_INIT(&z2,bytes); + DLSVDP_DH(NULL,&dom,&s0,&w1,&z); + DLSVDP_DH(NULL,&dom,&s1,&w0,&z1); + + if (OCTET_COMPARE(&z,&z1)) + printf("DLSVDP-DH - OK\n"); + else + { + printf("*** DLSVDP-DH Failed\n"); + return 0; + } + + res=DLSVDP_DHC(NULL,&dom,&s1,&w0,TRUE,&z2); + + + if (OCTET_COMPARE(&z,&z2)) + printf("DLSVDP-DHC Compatibility Mode - OK\n"); + else + { + printf("*** DLSVDP-DHC Compatibility Mode Failed\n"); + return 0; + } + + DLSVDP_DHC(NULL,&dom,&s0,&w1,FALSE,&z); + DLSVDP_DHC(NULL,&dom,&s1,&w0,FALSE,&z1); + + if (OCTET_COMPARE(&z,&z1)) + printf("DLSVDP-DHC - OK\n"); + else + { + printf("*** DLSVDP-DHC Failed\n"); + return 0; + } + + OCTET_INIT(&u0,bytes); + OCTET_INIT(&u1,bytes); + OCTET_INIT(&v0,bytes); + OCTET_INIT(&v1,bytes); + + DL_KEY_PAIR_GENERATE(NULL,&dom,&RNG,&u0,&v0); + DL_KEY_PAIR_GENERATE(NULL,&dom,&RNG,&u1,&v1); + + DLSVDP_MQV(NULL,&dom,&s0,&u0,&v0,&w1,&v1,&z); + DLSVDP_MQV(NULL,&dom,&s1,&u1,&v1,&w0,&v0,&z1); + + if (OCTET_COMPARE(&z,&z1)) + printf("DLSVDP-MQV - OK\n"); + else + { + printf("*** DLSVDP-MQV Failed\n"); + return 0; + } + + DLSVDP_MQVC(NULL,&dom,&s0,&u0,&v0,&w1,&v1,TRUE,&z2); + + if (OCTET_COMPARE(&z,&z2)) + printf("DLSVDP-MQVC Compatibility Mode - OK\n"); + else + { + printf("*** DLSVDP-MQVC Compatibility Mode Failed\n"); + return 0; + } + + DLSVDP_MQVC(NULL,&dom,&s0,&u0,&v0,&w1,&v1,FALSE,&z); + DLSVDP_MQVC(NULL,&dom,&s0,&u0,&v0,&w1,&v1,FALSE,&z1); + + if (OCTET_COMPARE(&z,&z1)) + printf("DLSVDP-MQVC - OK\n"); + else + { + printf("*** DLSVDP-MQVC Failed\n"); + return 0; + } + + OCTET_INIT(&s,bytes); + OCTET_INIT(&p,bytes); + + DL_KEY_PAIR_GENERATE(NULL,&dom,&RNG,&s,&p); + res=DL_PUBLIC_KEY_VALIDATE(NULL,&dom,TRUE,&p); + if (res!=0) + { + printf("DL Public Key is invalid!\n"); + return 0; + } + + OCTET_INIT(&f,bytes+1); + OCTET_INIT(&c,bytes); + OCTET_INIT(&d,bytes); + OCTET_INIT(&f1,bytes); + OCTET_INIT(&f2,bytes); + + f.len=16; /* fake a message */ + for (i=0;i<16;i++) f.val[i]=i+1; + /* make sure its less than group order */ + /* because we will use the same message */ + /* to test signature with message recovery */ + OCTET_INIT(&k,16); + k.len=16; for (i=0;i<16;i++) k.val[i]=1; /* fake an AES key */ + + res=AES_CBC_IV0_ENCRYPT(&k,&f,NULL,&f1,NULL); + res=AES_CBC_IV0_DECRYPT(&k,&f1,NULL,&f2,NULL); + + if (OCTET_COMPARE(&f,&f2)) + printf("AES Encrypt/Decrypt OK\n"); + else + { + printf("*** AES Encrypt/Decrypt Failed\n"); + return 0; + } + + OCTET_KILL(&k); + +/* Test OAEP/EME1 encoding and decoding */ + + OCTET_INIT(&f3,128); + res=EME1_ENCODE(&f,&RNG,1023,NULL,SHA256,&f3); + res=EME1_DECODE(&f3,1023,NULL,SHA256,&f2); + if (OCTET_COMPARE(&f,&f2)) + printf("OAEP Encoding/Decoding - OK\n"); + else + { + printf("*** OAEP Encoding/Decoding Failed\n"); + return 0; + } + + OCTET_KILL(&f2); + OCTET_KILL(&f3); + + + res=DLSP_DSA(NULL,&dom,&RNG,&s,&f,&c,&d); /* sign it */ + res=DLVP_DSA(NULL,&dom,&p,&c,&d,&f); /* verify it */ + if (res==0) + printf("DL DSA Signature - OK\n"); + else + { + printf("*** DL DSA Signature Failed\n"); + return 0; + } + + res=DLSP_NR(NULL,&dom,&RNG,&s,&f,&c,&d); /* sign it */ + res=DLVP_NR(NULL,&dom,&p,&c,&d,&f1); + + if (OCTET_COMPARE(&f,&f1)) + printf("DL NR Signature - OK\n"); + else + { + printf("*** DL NR Signature Failed\n"); + return 0; + } + + OCTET_INIT(&u,bytes); + OCTET_INIT(&v,bytes); + + res=DLPSP_NR2PV(NULL,&dom,&RNG,&u,&v); + res=DLSP_NR2(NULL,&dom,&s,&u,&v,&f,&c,&d); + res=DLVP_NR2(NULL,&dom,&p,&c,&d,&f1,&v1); + + if (OCTET_COMPARE(&f,&f1) && OCTET_COMPARE(&v,&v1)) + printf("DL NR2 Signature - OK\n"); + else + { + printf("*** DL NR2 Signature Failed\n"); + return 0; + } + + res=DLPSP_NR2PV(NULL,&dom,&RNG,&u,&v); + res=DLSP_PV(NULL,&dom,&s,&u,&f,&d); + res=DLVP_PV(NULL,&dom,&p,&f,&d,&v1); + + if (OCTET_COMPARE(&v,&v1)) + printf("DL PV Signature - OK\n"); + else + { + printf("*** DL PV Signature Failed\n"); + return 0; + } + + OCTET_KILL(&u); OCTET_KILL(&v); + OCTET_KILL(&s0); OCTET_KILL(&s1); + OCTET_KILL(&w0); OCTET_KILL(&w1); + OCTET_KILL(&z); OCTET_KILL(&z1); OCTET_KILL(&z2); + OCTET_KILL(&u0); OCTET_KILL(&u1); + OCTET_KILL(&v0); OCTET_KILL(&v1); + OCTET_KILL(&s); OCTET_KILL(&p); + OCTET_KILL(&f); OCTET_KILL(&f1); + OCTET_KILL(&c); OCTET_KILL(&d); + + DL_DOMAIN_KILL(&dom); + +/* Now test Elliptic Curves mod p */ + + bytes=ECP_DOMAIN_INIT(&epdom,"common.ecs",NULL,precompute); + res=ECP_DOMAIN_VALIDATE(NULL,&epdom); + if (res!=0) + { + printf("Domain parameters are invalid %d\n",res); + return 0; + } + OCTET_INIT(&s0,bytes); + OCTET_INIT(&s1,bytes); + OCTET_INIT(&w0,2*bytes+1); + OCTET_INIT(&w1,2*bytes+1); /* NOTE: these are EC points (x,y) */ + /* hence the size of 2*bytes+1. However */ + /* bytes+1 is OK if compression is used */ + + ECP_KEY_PAIR_GENERATE(NULL,&epdom,&RNG,&s0,compress,&w0); + res=ECP_PUBLIC_KEY_VALIDATE(NULL,&epdom,TRUE,&w0); + if (res!=0) + { + printf("ECP Public Key is invalid!\n"); + return 0; + } + + ECP_KEY_PAIR_GENERATE(NULL,&epdom,&RNG,&s1,compress,&w1); + res=ECP_PUBLIC_KEY_VALIDATE(NULL,&epdom,TRUE,&w1); + if (res!=0) + { + printf("ECP Public Key is invalid!\n"); + return 0; + } + + OCTET_INIT(&z,bytes); + OCTET_INIT(&z1,bytes); + OCTET_INIT(&z2,bytes); + + ECPSVDP_DH(NULL,&epdom,&s0,&w1,&z); + ECPSVDP_DH(NULL,&epdom,&s1,&w0,&z1); + + if (OCTET_COMPARE(&z,&z1)) + printf("ECPSVDP-DH - OK\n"); + else + { + printf("*** ECPSVDP-DH Failed\n"); + return 0; + } + + ECPSVDP_DHC(NULL,&epdom,&s1,&w0,TRUE,&z2); + + if (OCTET_COMPARE(&z,&z2)) + printf("ECPSVDP-DHC Compatibility Mode - OK\n"); + else + { + printf("*** ECPSVDP-DHC Compatibility Mode Failed\n"); + return 0; + } + + ECPSVDP_DHC(NULL,&epdom,&s0,&w1,FALSE,&z); + ECPSVDP_DHC(NULL,&epdom,&s1,&w0,FALSE,&z1); + + if (OCTET_COMPARE(&z,&z1)) + printf("ECPSVDP-DHC - OK\n"); + else + { + printf("*** ECPSVDP-DHC Failed\n"); + return 0; + } + + OCTET_INIT(&u0,bytes); + OCTET_INIT(&u1,bytes); + OCTET_INIT(&v0,2*bytes+1); + OCTET_INIT(&v1,2*bytes+1); + + ECP_KEY_PAIR_GENERATE(NULL,&epdom,&RNG,&u0,compress,&v0); + ECP_KEY_PAIR_GENERATE(NULL,&epdom,&RNG,&u1,compress,&v1); + + ECPSVDP_MQV(NULL,&epdom,&s0,&u0,&v0,&w1,&v1,&z); + ECPSVDP_MQV(NULL,&epdom,&s1,&u1,&v1,&w0,&v0,&z1); + + if (OCTET_COMPARE(&z,&z1)) + printf("ECPSVDP-MQV - OK\n"); + else + { + printf("*** ECPSVDP-MQV Failed\n"); + return 0; + } + + ECPSVDP_MQVC(NULL,&epdom,&s0,&u0,&v0,&w1,&v1,TRUE,&z2); + + if (OCTET_COMPARE(&z,&z2)) + printf("ECPSVDP_MQVC Compatibility Mode - OK\n"); + else + { + printf("*** ECPSVDP_MQVC Compatibility Mode Failed\n"); + return 0; + } + + ECPSVDP_MQVC(NULL,&epdom,&s0,&u0,&v0,&w1,&v1,FALSE,&z); + ECPSVDP_MQVC(NULL,&epdom,&s1,&u1,&v1,&w0,&v0,FALSE,&z1); + + if (OCTET_COMPARE(&z,&z1)) + printf("ECPSVDP-MQVC - OK\n"); + else + { + printf("*** ECPSVDP-MQVC Failed\n"); + return 0; + } + + OCTET_INIT(&s,bytes); + OCTET_INIT(&w,2*bytes+1); + + ECP_KEY_PAIR_GENERATE(NULL,&epdom,&RNG,&s,compress,&w); + res=ECP_PUBLIC_KEY_VALIDATE(NULL,&epdom,TRUE,&w); + + if (res!=0) + { + printf("ECP Public Key is invalid!\n"); + return 0; + } + + OCTET_INIT(&f,bytes); + OCTET_INIT(&f1,bytes); + OCTET_INIT(&c,bytes); + OCTET_INIT(&d,bytes); + + f.len=16; /* fake a message */ + for (i=0;i<16;i++) f.val[i]=i+1; + /* make sure its less than group order */ + + res=ECPSP_DSA(NULL,&epdom,&RNG,&s,&f,&c,&d); + res=ECPVP_DSA(NULL,&epdom,&w,&c,&d,&f); + + if (res==0) + printf("ECP DSA Signature - OK\n"); + else + { + printf("*** ECP DSA Signature Failed\n"); + return 0; + } + + res=ECPSP_NR(NULL,&epdom,&RNG,&s,&f,&c,&d); + res=ECPVP_NR(NULL,&epdom,&w,&c,&d,&f1); + + if (OCTET_COMPARE(&f,&f1)) + printf("ECP NR Signature - OK\n"); + else + { + printf("*** ECP NR Signature Failed\n"); + return 0; + } + + OCTET_INIT(&u,bytes); + OCTET_INIT(&v,bytes); + + res=ECPPSP_NR2PV(NULL,&epdom,&RNG,&u,&v); + res=ECPSP_NR2(NULL,&epdom,&s,&u,&v,&f,&c,&d); + res=ECPVP_NR2(NULL,&epdom,&w,&c,&d,&f1,&v1); + + if (OCTET_COMPARE(&f,&f1) && OCTET_COMPARE(&v,&v1)) + printf("ECP NR2 Signature - OK\n"); + else + { + printf("*** ECP NR2 Signature Failed\n"); + return 0; + } + + res=ECPPSP_NR2PV(NULL,&epdom,&RNG,&u,&v); + res=ECPSP_PV(NULL,&epdom,&s,&u,&f,&d); + res=ECPVP_PV(NULL,&epdom,&w,&f,&d,&v1); + + if (OCTET_COMPARE(&v,&v1)) + printf("ECP PV Signature - OK\n"); + else + { + printf("*** ECP PV Signature Failed\n"); + return 0; + } + + OCTET_KILL(&u); OCTET_KILL(&v); + OCTET_KILL(&s0); OCTET_KILL(&s1); + OCTET_KILL(&w0); OCTET_KILL(&w1); + OCTET_KILL(&z); + OCTET_KILL(&z1); OCTET_KILL(&z2); + OCTET_KILL(&u0); OCTET_KILL(&u1); + OCTET_KILL(&v0); OCTET_KILL(&v1); + OCTET_KILL(&s); + OCTET_KILL(&w); + OCTET_KILL(&f); OCTET_KILL(&f1); + OCTET_KILL(&c); OCTET_KILL(&d); + + ECP_DOMAIN_KILL(&epdom); + +/* Now test Elliptic Curves mod 2^m */ + + bytes=EC2_DOMAIN_INIT(&e2dom,"common2.ecs",NULL,precompute); + res=EC2_DOMAIN_VALIDATE(NULL,&e2dom); + if (res!=0) + { + printf("Domain parameters are invalid\n",res); + return 0; + } + + OCTET_INIT(&s0,bytes); + OCTET_INIT(&s1,bytes); + OCTET_INIT(&w0,2*bytes+1); + OCTET_INIT(&w1,2*bytes+1); + + EC2_KEY_PAIR_GENERATE(NULL,&e2dom,&RNG,&s0,compress,&w0); + EC2_KEY_PAIR_GENERATE(NULL,&e2dom,&RNG,&s1,compress,&w1); + + OCTET_INIT(&z,bytes); + OCTET_INIT(&z1,bytes); + OCTET_INIT(&z2,bytes); + + EC2SVDP_DH(NULL,&e2dom,&s0,&w1,&z); + EC2SVDP_DH(NULL,&e2dom,&s1,&w0,&z1); + + if (OCTET_COMPARE(&z,&z1)) + printf("EC2SVDP-DH - OK\n"); + else + { + printf("*** EC2SVDP-DH Failed\n"); + return 0; + } + + EC2SVDP_DHC(NULL,&e2dom,&s1,&w0,TRUE,&z2); + + if (OCTET_COMPARE(&z,&z2)) + printf("EC2SVDP-DHC Compatibility Mode - OK\n"); + else + { + printf("*** EC2SVDP-DHC Compatibility Mode Failed\n"); + return 0; + } + + EC2SVDP_DHC(NULL,&e2dom,&s0,&w1,FALSE,&z); + EC2SVDP_DHC(NULL,&e2dom,&s1,&w0,FALSE,&z1); + + if (OCTET_COMPARE(&z,&z1)) + printf("EC2SVDP-DHC - OK\n"); + else + { + printf("*** EC2SVDP-DHC Failed\n"); + return 0; + } + + OCTET_INIT(&u0,bytes); + OCTET_INIT(&u1,bytes); + OCTET_INIT(&v0,2*bytes+1); + OCTET_INIT(&v1,2*bytes+1); + + EC2_KEY_PAIR_GENERATE(NULL,&e2dom,&RNG,&u0,compress,&v0); + EC2_KEY_PAIR_GENERATE(NULL,&e2dom,&RNG,&u1,compress,&v1); + + EC2SVDP_MQV(NULL,&e2dom,&s0,&u0,&v0,&w1,&v1,&z); + EC2SVDP_MQV(NULL,&e2dom,&s1,&u1,&v1,&w0,&v0,&z1); + + if (OCTET_COMPARE(&z,&z1)) + printf("EC2SVDP-MQV - OK\n"); + else + { + printf("*** EC2SVDP-MQV Failed\n"); + return 0; + } + + EC2SVDP_MQVC(NULL,&e2dom,&s0,&u0,&v0,&w1,&v1,TRUE,&z2); + + if (OCTET_COMPARE(&z,&z2)) + printf("EC2SVDP_MQVC Compatibility Mode - OK\n"); + else + { + printf("*** EC2SVDP_MQVC Compatibility Mode Failed\n"); + return 0; + } + + EC2SVDP_MQVC(NULL,&e2dom,&s0,&u0,&v0,&w1,&v1,FALSE,&z); + EC2SVDP_MQVC(NULL,&e2dom,&s1,&u1,&v1,&w0,&v0,FALSE,&z1); + + if (OCTET_COMPARE(&z,&z1)) + printf("EC2SVDP-MQVC - OK\n"); + else + { + printf("*** EC2SVDP-MQVC Failed\n"); + return 0; + } + + OCTET_INIT(&s,bytes); + OCTET_INIT(&w,2*bytes+1); + + EC2_KEY_PAIR_GENERATE(NULL,&e2dom,&RNG,&s,compress,&w); + res=EC2_PUBLIC_KEY_VALIDATE(NULL,&e2dom,TRUE,&w); + + if (res!=0) + { + printf("EC2 Public Key is invalid!\n"); + return 0; + } + + OCTET_INIT(&f,bytes); + OCTET_INIT(&f1,bytes); + OCTET_INIT(&c,bytes); + OCTET_INIT(&d,bytes); + + f.len=16; /* fake a message */ + for (i=0;i<16;i++) f.val[i]=i+1; + /* make sure its less than group order */ + + res=EC2SP_DSA(NULL,&e2dom,&RNG,&s,&f,&c,&d); + res=EC2VP_DSA(NULL,&e2dom,&w,&c,&d,&f); + + if (res==0) + printf("EC2 DSA Signature - OK\n"); + else + { + printf("*** EC2 DSA Signature Failed\n"); + return 0; + } + + res=EC2SP_NR(NULL,&e2dom,&RNG,&s,&f,&c,&d); + res=EC2VP_NR(NULL,&e2dom,&w,&c,&d,&f1); + + if (OCTET_COMPARE(&f,&f1)) + printf("EC2 NR Signature - OK\n"); + else + { + printf("*** EC2 NR Signature Failed\n"); + return 0; + } + OCTET_INIT(&u,bytes); + OCTET_INIT(&v,bytes); + + res=EC2PSP_NR2PV(NULL,&e2dom,&RNG,&u,&v); + res=EC2SP_NR2(NULL,&e2dom,&s,&u,&v,&f,&c,&d); + res=EC2VP_NR2(NULL,&e2dom,&w,&c,&d,&f1,&v1); + + if (OCTET_COMPARE(&f,&f1) && OCTET_COMPARE(&v,&v1)) + printf("EC2 NR2 Signature - OK\n"); + else + { + printf("*** EC2 NR2 Signature Failed\n"); + return 0; + } + + res=EC2PSP_NR2PV(NULL,&e2dom,&RNG,&u,&v); + res=EC2SP_PV(NULL,&e2dom,&s,&u,&f,&d); + res=EC2VP_PV(NULL,&e2dom,&w,&f,&d,&v1); + + if (OCTET_COMPARE(&v,&v1)) + printf("EC2 PV Signature - OK\n"); + else + { + printf("*** EC2 PV Signature Failed\n"); + return 0; + } + + OCTET_KILL(&u); OCTET_KILL(&v); + OCTET_KILL(&s0); OCTET_KILL(&s1); + OCTET_KILL(&w0); OCTET_KILL(&w1); + OCTET_KILL(&z); + OCTET_KILL(&z1); OCTET_KILL(&z2); + OCTET_KILL(&u0); OCTET_KILL(&u1); + OCTET_KILL(&v0); OCTET_KILL(&v1); + OCTET_KILL(&s); + OCTET_KILL(&w); + OCTET_KILL(&f); OCTET_KILL(&f1); + OCTET_KILL(&c); OCTET_KILL(&d); + + EC2_DOMAIN_KILL(&e2dom); + + printf("Generating 1024-bit RSA Key Pair....\n"); + bytes=IF_KEY_PAIR(NULL,&RNG,1024,65537,&priv,&pub); + + OCTET_INIT(&f,bytes); + OCTET_INIT(&f1,bytes); + OCTET_INIT(&g,bytes); + + f.len=20; + for (i=0;i<20;i++) f.val[i]=i+1; /* fake a message */ + IFEP_RSA(NULL,&pub,&f,&g); + IFDP_RSA(NULL,&priv,&g,&f1); + + if (OCTET_COMPARE(&f,&f1)) + printf("RSA Encryption - OK\n"); + else + { + printf("RSA Encryption Failed\n"); + return 0; + } + + OCTET_INIT(&s,bytes); + OCTET_CLEAR(&f1); + + IFSP_RSA1(NULL,&priv,&f,&s); + IFVP_RSA1(NULL,&pub,&s,&f1); + + if (OCTET_COMPARE(&f,&f1)) + printf("RSA1 Signature - OK\n"); + else + { + printf("RSA1 Signature Failed\n"); + return 0; + } + + f.len=20; + for (i=0;i<20;i++) f.val[i]=i+1; /* fake a message */ + f.val[19]=12; /* =12 mod 16 */ + OCTET_CLEAR(&f1); + + IFSP_RSA2(NULL,&priv,&f,&s); + IFVP_RSA2(NULL,&pub,&s,&f1); + + if (OCTET_COMPARE(&f,&f1)) + printf("RSA2 Signature - OK\n"); + else + { + printf("RSA2 Signature Failed\n"); + return 0; + } + + IF_PUBLIC_KEY_KILL(&pub); + IF_PRIVATE_KEY_KILL(&priv); + + printf("Generating 1024-bit RW Key Pair....\n"); + IF_KEY_PAIR(NULL,&RNG,1024,2,&priv,&pub); + + OCTET_CLEAR(&f1); + IFSP_RW(NULL,&priv,&f,&s); + IFVP_RW(NULL,&pub,&s,&f1); + + if (OCTET_COMPARE(&f,&f1)) + printf("RW Signature - OK\n"); + else + { + printf("RW Signature Failed\n"); + return 0; + } + + printf("\nP1363 IFSSA Signature\n"); + OCTET_CLEAR(&g); + g.len=20; + for (i=0;i<20;i++) g.val[i]=i+1; + printf("Message is \n"); + OCTET_OUTPUT(&g); + mlen=1023; + if (!EMSA4_ENCODE(TRUE,SHA256,10,&RNG,mlen,&g,NULL,&f)) + { + printf("Failed to EMSA encode message\n"); + return 0; + } + + printf("Message Representative is\n"); + OCTET_OUTPUT(&f); + IFSP_RW(NULL,&priv,&f,&s); + printf("Signature is\n"); + OCTET_OUTPUT(&s); + printf("Verification\n"); + IFVP_RW(NULL,&pub,&s,&f1); + printf("Message Representative is\n"); + OCTET_OUTPUT(&f1); + result=EMSA4_DECODE(TRUE,SHA256,10,mlen,&f1,&g,NULL); + if (result && OCTET_COMPARE(&f,&f1)) + printf("IFSSA Signature - OK\n"); + else + { + printf("IFSSA Signature Failed\n"); + return 0; + } + + printf("\nP1363 IFSSR Signature with recovery\n"); + OCTET_CLEAR(&g); + g.len=20; + for (i=0;i<20;i++) g.val[i]=i+1; + printf("Message is \n"); + OCTET_OUTPUT(&g); + mlen=1023; + EMSR3_ENCODE(FALSE,SHA256,10,&RNG,mlen,&g,NULL,NULL,&f); + printf("Message Representative is\n"); + OCTET_OUTPUT(&f); + IFSP_RW(NULL,&priv,&f,&s); + OCTET_CLEAR(&g); + printf("Signature is\n"); + OCTET_OUTPUT(&s); + printf("Verification\n"); + + result=EMSR3_DECODE(FALSE,SHA256,10,1023,&f,NULL,NULL,&g); + printf("Recovered message= \n"); + OCTET_OUTPUT(&g); + if (result) + printf("IFSSR Signature with recovery - OK\n"); + else + { + printf("IFSSR Signature with recovery Failed\n"); + return 0; + } + + IF_PUBLIC_KEY_KILL(&pub); + IF_PRIVATE_KEY_KILL(&priv); + + OCTET_KILL(&f); OCTET_KILL(&f1); + OCTET_KILL(&g); OCTET_KILL(&s); + + printf("\nP1363 DLSSR Signature with message recovery\n"); + + + bytes=DL_DOMAIN_INIT(&dom,"common.dss",NULL,precompute); + res=DL_DOMAIN_VALIDATE(NULL,&dom); + if (res!=0) + { + printf("Domain parameters are invalid\n"); + return 0; + } + + OCTET_INIT(&s,bytes); + OCTET_INIT(&w,bytes); + OCTET_INIT(&u,bytes); + OCTET_INIT(&v,bytes); + OCTET_INIT(&v1,bytes); + OCTET_INIT(&c,bytes); + OCTET_INIT(&d,bytes); + OCTET_INIT(&f,bytes); + OCTET_INIT(&f1,bytes); + + OCTET_INIT(&m1,8); + + DL_KEY_PAIR_GENERATE(NULL,&dom,&RNG,&s,&w); + + res=DLPSP_NR2PV(NULL,&dom,&RNG,&u,&v); + bits=dom.rbits-1; + + m1.len=8; + for (i=0;i<8;i++) m1.val[i]=i+1; + + printf("recoverable message= "); + OCTET_OUTPUT(&m1); + + result=EMSR1_ENCODE(FALSE,10,20,&m1,NULL,NULL,bits,SHA1,&v,&f); + res=DLSP_NR2(NULL,&dom,&s,&u,&v,&f,&c,&d); + OCTET_CLEAR(&m1); + + printf("Signature= \n"); + OCTET_OUTPUT(&c); + OCTET_OUTPUT(&d); + res=DLVP_NR2(NULL,&dom,&w,&c,&d,&f1,&v1); + + result=EMSR1_DECODE(FALSE,10,20,&f,NULL,NULL,bits,SHA1,&v1,8,&m1); + printf("recovered message= "); + OCTET_OUTPUT(&m1); + if (result) + printf("DLSSR Signature with message recovery - OK\n"); + else + { + printf("*** DLSSR Signature with message recovery Failed\n"); + return 0; + } + + OCTET_KILL(&s); + OCTET_KILL(&w); + OCTET_KILL(&u); + OCTET_KILL(&v); + OCTET_KILL(&v1); + OCTET_KILL(&c); + OCTET_KILL(&d); + OCTET_KILL(&f); + OCTET_KILL(&f1); + OCTET_KILL(&m1); + + DL_DOMAIN_KILL(&dom); + + printf("\nP1363 DLSSR-PV Signature with message recovery\n"); + + + bytes=DL_DOMAIN_INIT(&dom,"common.dss",NULL,precompute); + res=DL_DOMAIN_VALIDATE(NULL,&dom); + if (res!=0) + { + printf("Domain parameters are invalid\n"); + return 0; + } + + OCTET_INIT(&s,bytes); + OCTET_INIT(&w,bytes); + OCTET_INIT(&u,bytes); + OCTET_INIT(&v,bytes); + OCTET_INIT(&m,bytes); + OCTET_INIT(&c,bytes); + OCTET_INIT(&h,bytes); + OCTET_INIT(&d,bytes); + + DL_KEY_PAIR_GENERATE(NULL,&dom,&RNG,&s,&w); + res=DLPSP_NR2PV(NULL,&dom,&RNG,&u,&v); + + m.len=20; + for (i=0;i<20;i++) m.val[i]=i+1; + printf("recoverable message= "); + OCTET_OUTPUT(&m); + + EMSR2_ENCODE(100,TRUE,SHA1,NULL,&m,&v,&c); + HASH(SHA1,&c,&h); + res=DLSP_PV(NULL,&dom,&s,&u,&h,&d); + OCTET_CLEAR(&m); + OCTET_CLEAR(&h); + OCTET_CLEAR(&v); + + printf("Signature= \n"); + OCTET_OUTPUT(&c); + OCTET_OUTPUT(&d); + + HASH(SHA1,&c,&h); + res=DLVP_PV(NULL,&dom,&w,&h,&d,&v); + result=EMSR2_DECODE(100,TRUE,SHA1,NULL,&c,&v,&m); + printf("recovered message= "); + OCTET_OUTPUT(&m); + if (result) + printf("DLSSR-PV Signature with message recovery - OK\n"); + else + { + printf("*** DLSSR-PV Signature with message recovery Failed\n"); + return 0; + } + + OCTET_KILL(&s); + OCTET_KILL(&w); + OCTET_KILL(&u); + OCTET_KILL(&v); + OCTET_KILL(&m); + OCTET_KILL(&c); + OCTET_KILL(&h); + OCTET_KILL(&d); + DL_DOMAIN_KILL(&dom); + + printf("\nP1363 ECIES Encryption/Decryption - DHAES mode\n"); + + dhaes=TRUE; /* Use DHAES mode */ + + + bytes=ECP_DOMAIN_INIT(&epdom,"common.ecs",NULL,precompute); + + OCTET_INIT(&m,20); OCTET_INIT(&c,32); /* round up to block size */ + OCTET_INIT(&k,32); OCTET_INIT(&s,bytes); + OCTET_INIT(&u,bytes); OCTET_INIT(&v,2*bytes+1); + OCTET_INIT(&w,2*bytes+1); + OCTET_INIT(&m1,20); + OCTET_INIT(&k1,16); OCTET_INIT(&k2,16); + OCTET_INIT(&tag,12); OCTET_INIT(&tag1,12); + OCTET_INIT(&z,bytes); OCTET_INIT(&vz,3*bytes+2); + OCTET_INIT(&p1,30); OCTET_INIT(&p2,30); + OCTET_INIT(&L2,8); OCTET_INIT(&C,300); + + OCTET_JOIN_STRING("Key Derivation Parameters",&p1); + OCTET_JOIN_STRING("Encoding Parameters",&p2); + + ECP_KEY_PAIR_GENERATE(NULL,&epdom,&RNG,&u,compress,&v); /* one time key pair */ + ECP_KEY_PAIR_GENERATE(NULL,&epdom,&RNG,&s,compress,&w); /* recipients key pair */ + + res=ECPSVDP_DH(NULL,&epdom,&u,&w,&z); + + if (dhaes) + { + OCTET_COPY(&v,&vz); + OCTET_JOIN_OCTET(&z,&vz); + } + else OCTET_COPY(&z,&vz); + + res=KDF2(&vz,&p1,32,SHA1,&k); + printf("Key is \n"); + OCTET_OUTPUT(&k); + + k1.len=k2.len=16; + for (i=0;i<16;i++) {k1.val[i]=k.val[i]; k2.val[i]=k.val[16+i];} + + printf("Encryption\n"); + + m.len=20; + for (i=0;i<20;i++) m.val[i]=i+1; /* fake a message */ + printf("Message is \n"); + OCTET_OUTPUT(&m); + + res=AES_CBC_IV0_ENCRYPT(&k1,&m,NULL,&c,NULL); + + printf("Ciphertext is \n"); + OCTET_OUTPUT(&c); + + if (dhaes) OCTET_JOIN_LONG((long)p2.len,8,&L2); + + OCTET_COPY(&c,&C); + OCTET_JOIN_OCTET(&p2,&C); + OCTET_JOIN_OCTET(&L2,&C); + + res=MAC1(&C,NULL,&k2,12,SHA256,&tag); + + printf("HMAC tag is \n"); + OCTET_OUTPUT(&tag); + +/* Note that "two passes" are required, one to encrypt, one + to calculate the MAC. */ + +/* Overall ciphertext is (v,c,tag) */ + + OCTET_CLEAR(&z); OCTET_CLEAR(&k); + OCTET_CLEAR(&k1); OCTET_CLEAR(&k2); + OCTET_CLEAR(&vz); OCTET_CLEAR(&C); + OCTET_CLEAR(&L2); + + printf("Decryption\n"); + + res=ECPSVDP_DH(NULL,&epdom,&s,&v,&z); + + if (dhaes) + { + OCTET_COPY(&v,&vz); + OCTET_JOIN_OCTET(&z,&vz); + } + + else OCTET_COPY(&z,&vz); + + res=KDF2(&vz,&p1,32,SHA1,&k); + k1.len=k2.len=16; + for (i=0;i<16;i++) {k1.val[i]=k.val[i]; k2.val[i]=k.val[16+i];} + + res=AES_CBC_IV0_DECRYPT(&k1,&c,NULL,&m1,NULL); + + printf("Message is \n"); + OCTET_OUTPUT(&m1); + + if (dhaes) OCTET_JOIN_LONG((long)p2.len,8,&L2); + + OCTET_COPY(&c,&C); + OCTET_JOIN_OCTET(&p2,&C); + OCTET_JOIN_OCTET(&L2,&C); + + res=MAC1(&C,NULL,&k2,12,SHA256,&tag1); + + printf("HMAC tag is \n"); + OCTET_OUTPUT(&tag1); + + if (OCTET_COMPARE(&m,&m1) && OCTET_COMPARE(&tag,&tag1)) + printf("ECIES Encryption/Decryption - OK\n"); + else + { + printf("ECIES Encryption/Decryption Failed\n"); + return 0; + } + + OCTET_KILL(&tag); OCTET_KILL(&tag1); + OCTET_KILL(&k1); OCTET_KILL(&k2); + OCTET_KILL(&m); OCTET_KILL(&c); + OCTET_KILL(&k); OCTET_KILL(&s); + OCTET_KILL(&u); OCTET_KILL(&v); + OCTET_KILL(&m1); OCTET_KILL(&w); + OCTET_KILL(&p1); OCTET_KILL(&p2); + OCTET_KILL(&L2); OCTET_KILL(&C); + + ECP_DOMAIN_KILL(&epdom); + OCTET_KILL(&z); OCTET_KILL(&vz); + + KILL_CSPRNG(&RNG); + return 0; +} + diff --git a/miracl/source/p1363/testecc.c b/miracl/source/p1363/testecc.c new file mode 100644 index 0000000..7669312 --- /dev/null +++ b/miracl/source/p1363/testecc.c @@ -0,0 +1,206 @@ +/*************************************************************************** + * +Copyright 2013 CertiVox UK Ltd. * + * +This file is part of CertiVox MIRACL Crypto SDK. * + * +The CertiVox MIRACL Crypto SDK provides developers with an * +extensive and efficient set of cryptographic functions. * +For further information about its features and functionalities please * +refer to http://www.certivox.com * + * +* The CertiVox MIRACL Crypto SDK is free software: you can * + redistribute it and/or modify it under the terms of the * + GNU Affero General Public License as published by the * + Free Software Foundation, either version 3 of the License, * + or (at your option) any later version. * + * +* The CertiVox MIRACL Crypto SDK is distributed in the hope * + that it will be useful, but WITHOUT ANY WARRANTY; without even the * + implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * + See the GNU Affero General Public License for more details. * + * +* You should have received a copy of the GNU Affero General Public * + License along with CertiVox MIRACL Crypto SDK. * + If not, see . * + * +You can be released from the requirements of the license by purchasing * +a commercial license. Buying such a license is mandatory as soon as you * +develop commercial activities involving the CertiVox MIRACL Crypto SDK * +without disclosing the source code of your own applications, or shipping * +the CertiVox MIRACL Crypto SDK with a closed source product. * + * +***************************************************************************/ + +/* This file implements a typical thread-safe API for MIRACL */ +/* Static build - requires no heap */ +/* See comments in ecdh.c for more details on the build */ +/* Derived from p1363.c code */ + +/* test driver and function exerciser for ECDH/ECIES/ECDSA Functions */ +/* cl /O2 testecc.c ecdh.c octet.c miracl.lib */ + +#include +#include +#include +#include +#include "ecdh.h" + +int main(int argc,char **argv) +{ + int i,res; + BOOL result; + char *pp="M0ng00se"; +/* These octets are automatically protected against buffer overflow attacks */ +/* Note salt must be big enough to include an appended word */ +/* Note ECIES ciphertext C must be big enough to include at least 1 appended block */ +/* Recall EFS is field size in bytes. So EFS=32 for 256-bit curve */ + char s0[EGS],s1[EGS],w0[2*EFS+1],w1[2*EFS+1],z0[EFS],z1[EFS],raw[100],key[EAS],salt[32],pw[20],b64[4+((8*EFS+4)/3)],p1[30],p2[30],v[2*EFS+1],m[32],c[64],t[32],cs[EGS],ds[EGS]; + octet S0={0,sizeof(s0),s0}; + octet S1={0,sizeof(s1),s1}; + octet W0={0,sizeof(w0),w0}; + octet W1={0,sizeof(w1),w1}; + octet Z0={0,sizeof(z0),z0}; + octet Z1={0,sizeof(z1),z1}; + octet RAW={0,sizeof(raw),raw}; + octet KEY={0,sizeof(key),key}; + octet SALT={0,sizeof(salt),salt}; + octet PW={0,sizeof(pw),pw}; + octet P1={0,sizeof(p1),p1}; + octet P2={0,sizeof(p2),p2}; + octet V={0,sizeof(v),v}; + octet M={0,sizeof(m),m}; + octet C={0,sizeof(c),c}; + octet T={0,sizeof(t),t}; + octet CS={0,sizeof(cs),cs}; + octet DS={0,sizeof(ds),ds}; + + ecp_domain epdom; + csprng RNG; /* Crypto Strong RNG */ + + RAW.len=100; /* fake random seed source */ + for (i=0;i<100;i++) RAW.val[i]=i+1; + + CREATE_CSPRNG(&RNG,&RAW); /* initialise strong RNG */ + + SALT.len=8; + for (i=0;i<8;i++) SALT.val[i]=i+1; // set Salt + + printf("Alice's Passphrase= %s\n",pp); + + OCTET_JOIN_STRING(pp,&PW); // set Password from string + +/* First set up Elliptic Curve from ROM data */ + + ECP_DOMAIN_INIT(&epdom,ecrom); + +/* private key S0 of size EGS bytes derived from Password and Salt */ + + PBKDF2(&PW,&SALT,1000,EGS,&S0); + OCTET_TO_BASE64(&S0,b64); + printf("Alices private key= %s\n",b64); + +/* Generate Key pair S/W */ + + ECP_KEY_PAIR_GENERATE(&epdom,NULL,&S0,&W0); + res=ECP_PUBLIC_KEY_VALIDATE(&epdom,TRUE,&W0); + if (res!=0) + { + printf("ECP Public Key is invalid!\n"); + return 0; + } + OCTET_TO_BASE64(&W0,b64); + printf("Alice's public key= %s\n",b64); + OCTET_FROM_BASE64(b64,&W0); + +/* Random private key for other party */ + + S1.len=3; S1.val[0]=0x01; S1.val[1]=0x23; S1.val[2]=0x45; + + ECP_KEY_PAIR_GENERATE(&epdom,NULL,&S1,&W1); + res=ECP_PUBLIC_KEY_VALIDATE(&epdom,TRUE,&W1); + if (res!=0) + { + printf("ECP Public Key is invalid!\n"); + return 0; + } + OCTET_TO_BASE64(&W1,b64); + printf("Servers public key= %s\n",b64); + OCTET_FROM_BASE64(b64,&W1); + +/* Calculate common key using DH - IEEE 1363 method */ + + ECPSVDP_DH(&epdom,&S0,&W1,&Z0); + ECPSVDP_DH(&epdom,&S1,&W0,&Z1); + + if (!OCTET_COMPARE(&Z0,&Z1)) + { + printf("*** ECPSVDP-DH Failed\n"); + return 0; + } + + KDF1(&Z0,EAS,&KEY); + printf("Alice's DH Key= "); for (i=0;i +#include +#include +#include "big.h" +#include "crt.h" + +using namespace std; + +Miracl precision(100,0); + +Big CRT(Big *p,Big *r) +{ // Chinese remainder theorem with 2 co-prime moduli + Crt chinese(2,p); + return chinese.eval(r); +} + +int main() +{ + Big lcm,c,m,d,n,n2,p,q,p2,q2,er[2],em[2]; + ifstream private_key("private.key"); + ifstream ciphertext("cipher.pal"); + miracl *mip=&precision; + int len; + char t[100]; + mip->IOBASE=16; + private_key >> p >> q; + n=p*q; + n2=n*n; + p2=p*p; + q2=q*q; + lcm=((p-1)*(q-1))/gcd(p-1,q-1); // LCM(p-1,q-1) + + em[0]=lcm; + em[1]=n; + er[0]=0; + er[1]=1; + d=CRT(em,er); + + ciphertext >> c; + + em[0]=p2; + em[1]=q2; + er[0]=pow(c,d%(p2-p),p2); // calculate mod p^2 and q^2 separately + er[1]=pow(c,d%(q2-q),q2); // .... and combine with CRT + m=CRT(em,er); + + m=(m-1)/n; // m=[(c^d mod n^2)-1]/n + + len=to_binary(m,100,t,FALSE); + t[len]=0; + + cout << "Message = \n" << t << endl; + return 0; +} + diff --git a/miracl/source/pal_enc.cpp b/miracl/source/pal_enc.cpp new file mode 100644 index 0000000..4e0fcd5 --- /dev/null +++ b/miracl/source/pal_enc.cpp @@ -0,0 +1,61 @@ +/* + * PAL_ENC.CPP + * + * Paillier Homomorphic Encryption + * See "Public key Cryptosystems based on Composite Degree Residue Classes", + * Eurocrypt 1999 + * + * NOTE: - This PK scheme is "Homomorphic" - E(m1+m2) = E(m1)*E(m2) - + * and probabilistic + * + * This program encrypts a short message to the file cipher.pal + * + * Uses standard 2-prime RSA key pair as private and public keys + * These are in public.key and private.key - or use genkey.c/cpp to + * generate a new pair. + * + * Requires: big.cpp + * + */ + +#include +#include +#include +#include "big.h" + +using namespace std; + +Miracl precision(100,0); + +int main() +{ + Big c,g,r,m,d,n,n2; + ifstream public_key("public.key"); + ofstream output_file("cipher.pal"); + miracl *mip=&precision; + long seed; + char t[100]; + mip->IOBASE=16; + public_key >> n; + n2=n*n; + + cout << "Enter 9 digit random number seed = "; + cin >> seed; + irand(seed); + + r=pow(rand(n2),n,n2); // off-line + + cout << "enter your message" << endl; + cin.get(); + cin.getline(t,100); + m=from_binary(strlen(t),t); // m +#include "miracl.h" + +BOOL rever(big x,big y) +{ /* reverse digits of x into y * + * returns TRUE if x is palindromic */ + int m,n; + int i,k,swaps; + BOOL palin; + copy(x,y); + palin=TRUE; + k=numdig(y)+1; + swaps=k/2; + for (i=1;i<=swaps;i++) + { + k--; + m=getdig(y,k); + n=getdig(y,i); + if (m!=n) palin=FALSE; + putdig(m,y,i); + putdig(n,y,k); + } + return palin; +} + +int main() +{ /* palindromic reversals */ + int iter; + big x,y; + mirsys(120,10); + x=mirvar(0); + y=mirvar(0); + printf("palindromic reversals program\n"); + printf("input number\n"); + innum(x,stdin); + iter=0; + while (!rever(x,y)) + { + iter++; + add(x,y,x); + otnum(x,stdout); + } + printf("palindromic after %d iterations\n",iter); + return 0; +} + diff --git a/miracl/source/palin.cpp b/miracl/source/palin.cpp new file mode 100644 index 0000000..2412c92 --- /dev/null +++ b/miracl/source/palin.cpp @@ -0,0 +1,55 @@ +/* + * Program to investigate palindromic reversals. + * Gruenberger F. Computer Recreations, Scientific American. April 1984. + * + * Requires: big.cpp + * + */ + +#include +#include "big.h" /* include MIRACL system */ + +using namespace std; + +Miracl precision(120,10); + +BOOL rever(Big &x,Big &y) +{ /* reverse digits of x into y * + * returns TRUE if x is palindromic */ + int m,n; + int i,k,swaps; + BOOL palin; + y=x; + palin=TRUE; + k=y.len()+1; + swaps=k/2; + for (i=1;i<=swaps;i++) + { + k--; + m=y.get(k); + n=y.get(i); + if (m!=n) palin=FALSE; + y.set(i,m); + y.set(k,n); + } + return palin; +} + +int main() +{ /* palindromic reversals */ + int iter; + Big x,y; + cout << "palindromic reversals program\n"; + cout << "input number\n"; + cin >> x; + iter=0; + while (!rever(x,y)) + { + iter++; + x+=y; + cout << x << endl; + } + cout << "palindromic after " << iter << " iterations\n"; + return 0; +} + diff --git a/miracl/source/pk-demo.c b/miracl/source/pk-demo.c new file mode 100644 index 0000000..30d7352 --- /dev/null +++ b/miracl/source/pk-demo.c @@ -0,0 +1,261 @@ +/* + * + * Example program demonstrates 1024 bit Diffie-Hellman, El Gamal and RSA + * and 168 bit Elliptic Curve Diffie-Hellman + * + */ + +#include +#include "miracl.h" +#include + +/* large 1024 bit prime p for which (p-1)/2 is also prime */ +char *primetext= +"155315526351482395991155996351231807220169644828378937433223838972232518351958838087073321845624756550146945246003790108045940383194773439496051917019892370102341378990113959561895891019716873290512815434724157588460613638202017020672756091067223336194394910765309830876066246480156617492164140095427773547319"; + +/* Use elliptic curve of the form y^2=x^3-3x+B */ + +/* NIST p192 bit elliptic curve prime 2#192-2#64-1 */ + +char *ecp="FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"; + +/* elliptic curve parameter B */ + +char *ecb="64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1"; + +/* elliptic curve - point of prime order (x,y) */ + +char *ecx="188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"; +char *ecy="07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"; + + +char *text="MIRACL - Best multi-precision library in the World!\n"; + +int main() +{ + int ia,ib; + time_t seed; + epoint *g,*ea,*eb; + big a,b,p,q,n,p1,q1,phi,pa,pb,key,e,d,dp,dq,t,m,c,x,y,k,inv; + big primes[2],pm[2]; + big_chinese ch; + miracl *mip; +#ifndef MR_NOFULLWIDTH + mip=mirsys(36,0); +#else + mip=mirsys(36,MAXBASE); +#endif + a=mirvar(0); + b=mirvar(0); + p=mirvar(0); + q=mirvar(0); + n=mirvar(0); + p1=mirvar(0); + q1=mirvar(0); + phi=mirvar(0); + pa=mirvar(0); + pb=mirvar(0); + key=mirvar(0); + e=mirvar(0); + d=mirvar(0); + dp=mirvar(0); + dq=mirvar(0); + t=mirvar(0); + m=mirvar(0); + c=mirvar(0); + pm[0]=mirvar(0); + pm[1]=mirvar(0); + x=mirvar(0); + y=mirvar(0); + k=mirvar(0); + inv=mirvar(0); + + time(&seed); + irand((unsigned long)seed); /* change parameter for different values */ + + printf("First Diffie-Hellman Key exchange .... \n"); + + cinstr(p,primetext); + +/* offline calculations could be done quicker using Comb method + - See brick.c. Note use of "truncated exponent" of 160 bits - + could be output of hash function SHA (see mrshs.c) */ + + printf("\nAlice's offline calculation\n"); + bigbits(160,a); + +/* 3 generates the sub-group of prime order (p-1)/2 */ + + powltr(3,a,p,pa); + + printf("Bob's offline calculation\n"); + bigbits(160,b); + powltr(3,b,p,pb); + + printf("Alice calculates Key=\n"); + powmod(pb,a,p,key); + cotnum(key,stdout); + + printf("Bob calculates Key=\n"); + powmod(pa,b,p,key); + cotnum(key,stdout); + + printf("Alice and Bob's keys should be the same!\n"); + +/* + Now Elliptic Curve version of the above. + Curve is y^2=x^3+Ax+B mod p, where A=-3, B and p as above + "Primitive root" is the point (x,y) above, which is of large prime order q. + In this case actually + q=FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831 + +*/ + + printf("\nLets try that again using elliptic curves .... \n"); + convert(-3,a); + mip->IOBASE=16; + cinstr(b,ecb); + cinstr(p,ecp); + ecurve_init(a,b,p,MR_BEST); /* Use PROJECTIVE if possible, else AFFINE coordinates */ + + g=epoint_init(); + cinstr(x,ecx); + cinstr(y,ecy); + mip->IOBASE=10; + epoint_set(x,y,0,g); + ea=epoint_init(); + eb=epoint_init(); + epoint_copy(g,ea); + epoint_copy(g,eb); + + printf("Alice's offline calculation\n"); + bigbits(160,a); + ecurve_mult(a,ea,ea); + ia=epoint_get(ea,pa,pa); /* is compressed form of public key */ + + printf("Bob's offline calculation\n"); + bigbits(160,b); + ecurve_mult(b,eb,eb); + ib=epoint_get(eb,pb,pb); /* is compressed form of public key */ + + printf("Alice calculates Key=\n"); + epoint_set(pb,pb,ib,eb); /* decompress eb */ + ecurve_mult(a,eb,eb); + epoint_get(eb,key,key); + cotnum(key,stdout); + + printf("Bob calculates Key=\n"); + epoint_set(pa,pa,ia,ea); /* decompress ea */ + ecurve_mult(b,ea,ea); + epoint_get(ea,key,key); + cotnum(key,stdout); + + printf("Alice and Bob's keys should be the same! (but much smaller)\n"); + + epoint_free(g); + epoint_free(ea); + epoint_free(eb); + +/* El Gamal's Method */ + + printf("\nTesting El Gamal's public key method\n"); + cinstr(p,primetext); + bigbits(160,x); /* x