From 343f28c02ba7ba3c8946c64848b10feac2886ad1 Mon Sep 17 00:00:00 2001 From: macmade Date: Thu, 7 Nov 2024 21:53:03 +0100 Subject: [PATCH] feat: Preparing for BigNum --- SRPXX-Tests/BigNum.cpp | 378 ++++++++++++++++++++++++++++++++ SRPXX.xcodeproj/project.pbxproj | 12 + SRPXX/include/SRPXX.hpp | 1 + SRPXX/include/SRPXX/BigNum.hpp | 85 +++++++ SRPXX/source/BigNum.cpp | 261 ++++++++++++++++++++++ 5 files changed, 737 insertions(+) create mode 100644 SRPXX-Tests/BigNum.cpp create mode 100644 SRPXX/include/SRPXX/BigNum.hpp create mode 100644 SRPXX/source/BigNum.cpp diff --git a/SRPXX-Tests/BigNum.cpp b/SRPXX-Tests/BigNum.cpp new file mode 100644 index 0000000..a5e6d11 --- /dev/null +++ b/SRPXX-Tests/BigNum.cpp @@ -0,0 +1,378 @@ +/******************************************************************************* + * The MIT License (MIT) + * + * Copyright (c) 2024 Jean-David Gadina - www.xs-labs.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include +#include + +XSTest( BigNum, FromString_Auto ) +{ + { + auto n1 = SRP::BigNum::fromString( "42", SRP::BigNum::StringFormat::Auto ); + auto n2 = SRP::BigNum::fromString( "-1", SRP::BigNum::StringFormat::Auto ); + auto n3 = SRP::BigNum::fromString( "42FF", SRP::BigNum::StringFormat::Auto ); + auto n4 = SRP::BigNum::fromString( "FF42", SRP::BigNum::StringFormat::Auto ); + auto n5 = SRP::BigNum::fromString( "42FFZZ", SRP::BigNum::StringFormat::Auto ); + auto n6 = SRP::BigNum::fromString( "ZZFF42", SRP::BigNum::StringFormat::Auto ); + + XSTestAssertTrue( n1.has_value() ); + XSTestAssertTrue( n2.has_value() ); + XSTestAssertTrue( n3.has_value() ); + XSTestAssertFalse( n4.has_value() ); + XSTestAssertTrue( n5.has_value() ); + XSTestAssertFalse( n6.has_value() ); + + XSTestAssertTrue( n1 == 42 ); + XSTestAssertTrue( n2 == SRP::BigNum( 1 ).negative() ); + XSTestAssertTrue( n3 == 42 ); + XSTestAssertTrue( n5 == 42 ); + } + + { + auto n1 = SRP::BigNum::fromString( "0x42", SRP::BigNum::StringFormat::Auto ); + auto n2 = SRP::BigNum::fromString( "-0x1", SRP::BigNum::StringFormat::Auto ); + auto n3 = SRP::BigNum::fromString( "0x42FF", SRP::BigNum::StringFormat::Auto ); + auto n4 = SRP::BigNum::fromString( "0xFF42", SRP::BigNum::StringFormat::Auto ); + auto n5 = SRP::BigNum::fromString( "0x42FFZZ", SRP::BigNum::StringFormat::Auto ); + auto n6 = SRP::BigNum::fromString( "0xZZFF42", SRP::BigNum::StringFormat::Auto ); + + XSTestAssertTrue( n1.has_value() ); + XSTestAssertTrue( n2.has_value() ); + XSTestAssertTrue( n3.has_value() ); + XSTestAssertTrue( n4.has_value() ); + XSTestAssertTrue( n5.has_value() ); + XSTestAssertFalse( n6.has_value() ); + + XSTestAssertTrue( n1 == 0x42 ); + XSTestAssertTrue( n2 == SRP::BigNum( 0x1 ).negative() ); + XSTestAssertTrue( n3 == 0x42FF ); + XSTestAssertTrue( n4 == 0xFF42 ); + XSTestAssertTrue( n5 == 0x42FF ); + } + + { + auto n1 = SRP::BigNum::fromString( "0X42", SRP::BigNum::StringFormat::Auto ); + auto n2 = SRP::BigNum::fromString( "-0X1", SRP::BigNum::StringFormat::Auto ); + auto n3 = SRP::BigNum::fromString( "0X42FF", SRP::BigNum::StringFormat::Auto ); + auto n4 = SRP::BigNum::fromString( "0XFF42", SRP::BigNum::StringFormat::Auto ); + auto n5 = SRP::BigNum::fromString( "0X42FFZZ", SRP::BigNum::StringFormat::Auto ); + auto n6 = SRP::BigNum::fromString( "0XZZFF42", SRP::BigNum::StringFormat::Auto ); + + XSTestAssertTrue( n1.has_value() ); + XSTestAssertTrue( n2.has_value() ); + XSTestAssertTrue( n3.has_value() ); + XSTestAssertTrue( n4.has_value() ); + XSTestAssertTrue( n5.has_value() ); + XSTestAssertFalse( n6.has_value() ); + + XSTestAssertTrue( n1 == 0x42 ); + XSTestAssertTrue( n2 == SRP::BigNum( 0x1 ).negative() ); + XSTestAssertTrue( n3 == 0x42FF ); + XSTestAssertTrue( n4 == 0xFF42 ); + XSTestAssertTrue( n5 == 0x42FF ); + } +} + +XSTest( BigNum, FromString_Decimal ) +{ + auto n1 = SRP::BigNum::fromString( "42", SRP::BigNum::StringFormat::Decimal ); + auto n2 = SRP::BigNum::fromString( "-1", SRP::BigNum::StringFormat::Decimal ); + auto n3 = SRP::BigNum::fromString( "42FF", SRP::BigNum::StringFormat::Decimal ); + auto n4 = SRP::BigNum::fromString( "FF42", SRP::BigNum::StringFormat::Decimal ); + + XSTestAssertTrue( n1.has_value() ); + XSTestAssertTrue( n2.has_value() ); + XSTestAssertTrue( n3.has_value() ); + XSTestAssertFalse( n4.has_value() ); + + XSTestAssertTrue( n1 == 42 ); + XSTestAssertTrue( n2 == SRP::BigNum( 1 ).negative() ); + XSTestAssertTrue( n3 == 42 ); +} + +XSTest( BigNum, FromString_Hexadecimal ) +{ + auto n1 = SRP::BigNum::fromString( "42", SRP::BigNum::StringFormat::Hexadecimal ); + auto n2 = SRP::BigNum::fromString( "-1", SRP::BigNum::StringFormat::Hexadecimal ); + auto n3 = SRP::BigNum::fromString( "42FF", SRP::BigNum::StringFormat::Hexadecimal ); + auto n4 = SRP::BigNum::fromString( "FF42", SRP::BigNum::StringFormat::Hexadecimal ); + auto n5 = SRP::BigNum::fromString( "42FFZZ", SRP::BigNum::StringFormat::Hexadecimal ); + auto n6 = SRP::BigNum::fromString( "ZZFF42", SRP::BigNum::StringFormat::Hexadecimal ); + + XSTestAssertTrue( n1.has_value() ); + XSTestAssertTrue( n2.has_value() ); + XSTestAssertTrue( n3.has_value() ); + XSTestAssertTrue( n4.has_value() ); + XSTestAssertTrue( n5.has_value() ); + XSTestAssertFalse( n6.has_value() ); + + XSTestAssertTrue( n1 == 0x42 ); + XSTestAssertTrue( n2 == SRP::BigNum( 0x1 ).negative() ); + XSTestAssertTrue( n3 == 0x42FF ); + XSTestAssertTrue( n4 == 0xFF42 ); + XSTestAssertTrue( n5 == 0x42FF ); +} + +XSTest( BigNum, CTOR ) +{ + XSTestAssertTrue( SRP::BigNum() == 0 ); +} + +XSTest( BigNum, CTOR_UInt64 ) +{ + XSTestAssertTrue( SRP::BigNum( 0 ) == 0 ); + XSTestAssertTrue( SRP::BigNum( 1 ) == 1 ); + XSTestAssertTrue( SRP::BigNum( INT64_MAX ) == INT64_MAX ); + XSTestAssertTrue( SRP::BigNum( static_cast< uint64_t >( -1 ) ) == static_cast< uint64_t >( -1 ) ); +} + +XSTest( BigNum, CCTOR ) +{ + SRP::BigNum n1( 42 ); + SRP::BigNum n2( n1 ); + + XSTestAssertTrue( n2 == 42 ); +} + +XSTest( BigNum, MCTOR ) +{ + SRP::BigNum n1( 42 ); + SRP::BigNum n2( std::move( n1 ) ); + + XSTestAssertTrue( n2 == 42 ); +} + +XSTest( BigNum, OperatorAssign ) +{ + SRP::BigNum n1( 42 ); + SRP::BigNum n2( 0 ); + + XSTestAssertTrue( n1 == 42 ); + XSTestAssertTrue( n2 == 0 ); + + n2 = n1; + + XSTestAssertTrue( n1 == 42 ); + XSTestAssertTrue( n2 == 42 ); +} + +XSTest( BigNum, OperatorAssign_UInt64 ) +{ + SRP::BigNum n( 0 ); + + XSTestAssertTrue( n == 0 ); + + n = 42; + + XSTestAssertTrue( n == 42 ); +} + +XSTest( BigNum, OperatorEqual ) +{ + SRP::BigNum n1( 42 ); + SRP::BigNum n2( 42 ); + SRP::BigNum n3( 0 ); + + XSTestAssertTrue( n1 == n1 ); + XSTestAssertTrue( n2 == n2 ); + XSTestAssertTrue( n3 == n3 ); + + XSTestAssertTrue( n1 == n2 ); + XSTestAssertTrue( n2 == n1 ); + + XSTestAssertFalse( n1 == n3 ); + XSTestAssertFalse( n2 == n3 ); + XSTestAssertFalse( n3 == n1 ); + XSTestAssertFalse( n3 == n2 ); +} + +XSTest( BigNum, OperatorEqual_UInt64 ) +{ + SRP::BigNum n( 42 ); + + XSTestAssertTrue( n == 42 ); + XSTestAssertFalse( n == 0 ); +} + +XSTest( BigNum, OperatorEqual_String ) +{ + XSTestAssertFalse( SRP::BigNum( 42 ) == "" ); + XSTestAssertFalse( SRP::BigNum( 0 ) == "" ); + XSTestAssertFalse( SRP::BigNum() == "" ); + + XSTestAssertTrue( SRP::BigNum( 42 ) == "42" ); + XSTestAssertTrue( SRP::BigNum( 42 ).negative() == "-42" ); + XSTestAssertTrue( SRP::BigNum( 0x42 ) == "0x42" ); + XSTestAssertTrue( SRP::BigNum( 0x42 ).negative() == "-0x42" ); + XSTestAssertTrue( SRP::BigNum( 0x42 ) == "0X42" ); + XSTestAssertTrue( SRP::BigNum( 0x42 ).negative() == "-0X42" ); + XSTestAssertTrue( SRP::BigNum( 0x42FF ) == "0X42FF" ); + XSTestAssertTrue( SRP::BigNum( 0x42FF ).negative() == "-0X42FF" ); + XSTestAssertTrue( SRP::BigNum( 0x42FF ) == "0x42FF" ); + XSTestAssertTrue( SRP::BigNum( 0x42FF ).negative() == "-0x42FF" ); + XSTestAssertTrue( SRP::BigNum( 0x42FF ) == "0x42ff" ); + XSTestAssertTrue( SRP::BigNum( 0x42FF ).negative() == "-0x42ff" ); + XSTestAssertTrue( SRP::BigNum( 0x42FF ) == "0X42ff" ); + XSTestAssertTrue( SRP::BigNum( 0x42FF ).negative() == "-0X42ff" ); +} + +XSTest( BigNum, OperatorNotEqual ) +{ + SRP::BigNum n1( 42 ); + SRP::BigNum n2( 42 ); + SRP::BigNum n3( 0 ); + + XSTestAssertFalse( n1 != n1 ); + XSTestAssertFalse( n2 != n2 ); + XSTestAssertFalse( n3 != n3 ); + + XSTestAssertFalse( n1 != n2 ); + XSTestAssertFalse( n2 != n1 ); + + XSTestAssertTrue( n1 != n3 ); + XSTestAssertTrue( n2 != n3 ); + XSTestAssertTrue( n3 != n1 ); + XSTestAssertTrue( n3 != n2 ); +} + +XSTest( BigNum, OperatorNotEqual_UInt64 ) +{ + SRP::BigNum n( 42 ); + + XSTestAssertFalse( n != 42 ); + XSTestAssertTrue( n != 0 ); +} + +XSTest( BigNum, OperatorNotEqual_String ) +{ + XSTestAssertTrue( SRP::BigNum( 42 ) != "" ); + XSTestAssertTrue( SRP::BigNum( 0 ) != "" ); + XSTestAssertTrue( SRP::BigNum() != "" ); + + XSTestAssertFalse( SRP::BigNum( 42 ) != "42" ); + XSTestAssertFalse( SRP::BigNum( 42 ).negative() != "-42" ); + XSTestAssertFalse( SRP::BigNum( 0x42 ) != "0x42" ); + XSTestAssertFalse( SRP::BigNum( 0x42 ).negative() != "-0x42" ); + XSTestAssertFalse( SRP::BigNum( 0x42 ) != "0X42" ); + XSTestAssertFalse( SRP::BigNum( 0x42 ).negative() != "-0X42" ); + XSTestAssertFalse( SRP::BigNum( 0x42FF ) != "0X42FF" ); + XSTestAssertFalse( SRP::BigNum( 0x42FF ).negative() != "-0X42FF" ); + XSTestAssertFalse( SRP::BigNum( 0x42FF ) != "0x42FF" ); + XSTestAssertFalse( SRP::BigNum( 0x42FF ).negative() != "-0x42FF" ); + XSTestAssertFalse( SRP::BigNum( 0x42FF ) != "0x42ff" ); + XSTestAssertFalse( SRP::BigNum( 0x42FF ).negative() != "-0x42ff" ); + XSTestAssertFalse( SRP::BigNum( 0x42FF ) != "0X42ff" ); + XSTestAssertFalse( SRP::BigNum( 0x42FF ).negative() != "-0X42ff" ); +} + +XSTest( BigNum, ToString ) +{ + XSTestAssertTrue( SRP::BigNum( 42 ).toString() == "42" ); + XSTestAssertTrue( SRP::BigNum( 42 ).negative().toString() == "-42" ); + + XSTestAssertTrue( SRP::BigNum( 42 ).toString( SRP::BigNum::StringFormat::Auto ) == "42" ); + XSTestAssertTrue( SRP::BigNum( 42 ).negative().toString( SRP::BigNum::StringFormat::Auto ) == "-42" ); + + XSTestAssertTrue( SRP::BigNum( 42 ).toString( SRP::BigNum::StringFormat::Decimal ) == "42" ); + XSTestAssertTrue( SRP::BigNum( 42 ).negative().toString( SRP::BigNum::StringFormat::Decimal ) == "-42" ); + + XSTestAssertTrue( SRP::BigNum( 0x42 ).toString( SRP::BigNum::StringFormat::Hexadecimal ) == "0x42" ); + XSTestAssertTrue( SRP::BigNum( 0x42 ).negative().toString( SRP::BigNum::StringFormat::Hexadecimal ) == "-0x42" ); + + XSTestAssertTrue( SRP::BigNum( 0xFF ).toString( SRP::BigNum::StringFormat::Hexadecimal ) == "0xff" ); + XSTestAssertTrue( SRP::BigNum( 0xFF ).negative().toString( SRP::BigNum::StringFormat::Hexadecimal ) == "-0xff" ); +} + +XSTest( BigNum, Negative ) +{ + SRP::BigNum n1( 42 ); + SRP::BigNum n2( n1.negative() ); + + XSTestAssertFalse( n1.isNegative() ); + XSTestAssertTrue( n2.isNegative() ); + + XSTestAssertTrue( n1 == 42 ); + XSTestAssertTrue( n2.positive() == 42 ); +} + +XSTest( BigNum, Positive ) +{ + SRP::BigNum n1( SRP::BigNum( 42 ).negative() ); + SRP::BigNum n2( n1.positive() ); + + XSTestAssertTrue( n1.isNegative() ); + XSTestAssertFalse( n2.isNegative() ); + + XSTestAssertTrue( n1 == SRP::BigNum( 42 ).negative() ); + XSTestAssertTrue( n2 == 42 ); +} + +XSTest( BigNum, IsNegative ) +{ + SRP::BigNum n1( 42 ); + SRP::BigNum n2( n1.negative() ); + + XSTestAssertFalse( n1.isNegative() ); + XSTestAssertTrue( n2.isNegative() ); +} + +XSTest( BigNum, IsPositive ) +{ + SRP::BigNum n1( 42 ); + SRP::BigNum n2( n1.negative() ); + + XSTestAssertTrue( n1.isPositive() ); + XSTestAssertFalse( n2.isPositive() ); +} + +XSTest( BigNum, IsOdd ) +{ + SRP::BigNum n1( 42 ); + SRP::BigNum n2( 43 ); + + XSTestAssertFalse( n1.isOdd() ); + XSTestAssertTrue( n2.isOdd() ); +} + +XSTest( BigNum, IsEven ) +{ + SRP::BigNum n1( 42 ); + SRP::BigNum n2( 43 ); + + XSTestAssertTrue( n1.isEven() ); + XSTestAssertFalse( n2.isEven() ); +} + +XSTest( BigNum, Swap ) +{ + SRP::BigNum n1( 42 ); + SRP::BigNum n2( 0 ); + + XSTestAssertTrue( n1 == 42 ); + XSTestAssertTrue( n2 == 0 ); + + swap( n1, n2 ); + + XSTestAssertTrue( n1 == 0 ); + XSTestAssertTrue( n2 == 42 ); +} diff --git a/SRPXX.xcodeproj/project.pbxproj b/SRPXX.xcodeproj/project.pbxproj index 758eb9a..247aa3a 100644 --- a/SRPXX.xcodeproj/project.pbxproj +++ b/SRPXX.xcodeproj/project.pbxproj @@ -11,6 +11,9 @@ 050961392CDD50B4008F4C59 /* SRPXX.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 050961332CDD50B4008F4C59 /* SRPXX.hpp */; }; 0509613A2CDD50B4008F4C59 /* String.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 050961352CDD50B4008F4C59 /* String.cpp */; }; 0509613D2CDD50C1008F4C59 /* String.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0509613B2CDD50C1008F4C59 /* String.cpp */; }; + 050961432CDD56B3008F4C59 /* BigNum.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 050961422CDD56B3008F4C59 /* BigNum.cpp */; }; + 050961452CDD56BB008F4C59 /* BigNum.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 050961442CDD56BB008F4C59 /* BigNum.hpp */; }; + 050961472CDD56C2008F4C59 /* BigNum.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 050961462CDD56C2008F4C59 /* BigNum.cpp */; }; 051F72C42CDD12600031F7FA /* libSRPXX.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 051F72B82CDD12480031F7FA /* libSRPXX.a */; }; 051F72DE2CDD13790031F7FA /* XSTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 051F72CF2CDD12AB0031F7FA /* XSTest.framework */; }; /* End PBXBuildFile section */ @@ -37,6 +40,9 @@ 050961332CDD50B4008F4C59 /* SRPXX.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SRPXX.hpp; sourceTree = ""; }; 050961352CDD50B4008F4C59 /* String.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = String.cpp; sourceTree = ""; }; 0509613B2CDD50C1008F4C59 /* String.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = String.cpp; sourceTree = ""; }; + 050961422CDD56B3008F4C59 /* BigNum.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = BigNum.cpp; sourceTree = ""; }; + 050961442CDD56BB008F4C59 /* BigNum.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = BigNum.hpp; sourceTree = ""; }; + 050961462CDD56C2008F4C59 /* BigNum.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = BigNum.cpp; sourceTree = ""; }; 051F72622CDD11CE0031F7FA /* CODE_OF_CONDUCT.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = CODE_OF_CONDUCT.md; sourceTree = ""; }; 051F72632CDD11CE0031F7FA /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; 051F72642CDD11CE0031F7FA /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; @@ -114,6 +120,7 @@ 050961322CDD50B4008F4C59 /* SRPXX */ = { isa = PBXGroup; children = ( + 050961442CDD56BB008F4C59 /* BigNum.hpp */, 050961312CDD50B4008F4C59 /* String.hpp */, ); path = SRPXX; @@ -131,6 +138,7 @@ 050961362CDD50B4008F4C59 /* source */ = { isa = PBXGroup; children = ( + 050961462CDD56C2008F4C59 /* BigNum.cpp */, 050961352CDD50B4008F4C59 /* String.cpp */, ); path = source; @@ -148,6 +156,7 @@ 0509613C2CDD50C1008F4C59 /* SRPXX-Tests */ = { isa = PBXGroup; children = ( + 050961422CDD56B3008F4C59 /* BigNum.cpp */, 0509613B2CDD50C1008F4C59 /* String.cpp */, ); path = "SRPXX-Tests"; @@ -325,6 +334,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 050961452CDD56BB008F4C59 /* BigNum.hpp in Headers */, 050961382CDD50B4008F4C59 /* String.hpp in Headers */, 050961392CDD50B4008F4C59 /* SRPXX.hpp in Headers */, ); @@ -442,6 +452,7 @@ buildActionMask = 2147483647; files = ( 0509613A2CDD50B4008F4C59 /* String.cpp in Sources */, + 050961472CDD56C2008F4C59 /* BigNum.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -450,6 +461,7 @@ buildActionMask = 2147483647; files = ( 0509613D2CDD50C1008F4C59 /* String.cpp in Sources */, + 050961432CDD56B3008F4C59 /* BigNum.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SRPXX/include/SRPXX.hpp b/SRPXX/include/SRPXX.hpp index 715f52c..6139a91 100644 --- a/SRPXX/include/SRPXX.hpp +++ b/SRPXX/include/SRPXX.hpp @@ -26,5 +26,6 @@ #define SRPXX_HPP #include +#include #endif /* SRPXX_HPP */ diff --git a/SRPXX/include/SRPXX/BigNum.hpp b/SRPXX/include/SRPXX/BigNum.hpp new file mode 100644 index 0000000..a110e06 --- /dev/null +++ b/SRPXX/include/SRPXX/BigNum.hpp @@ -0,0 +1,85 @@ +/******************************************************************************* + * The MIT License (MIT) + * + * Copyright (c) 2024 Jean-David Gadina - www.xs-labs.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#ifndef SRPXX_BIG_NUM_HPP +#define SRPXX_BIG_NUM_HPP + +#include +#include +#include +#include + +namespace SRP +{ + class BigNum + { + public: + + enum class StringFormat + { + Auto, + Decimal, + Hexadecimal + }; + + static std::optional< BigNum > fromString( const std::string & value, StringFormat format = StringFormat::Auto ); + + BigNum(); + BigNum( uint64_t value ); + BigNum( const BigNum & o ); + BigNum( BigNum && o ) noexcept; + ~BigNum(); + + BigNum & operator =( BigNum o ); + BigNum & operator =( uint64_t value ); + + bool operator ==( const BigNum & o ) const; + bool operator ==( uint64_t value ) const; + bool operator ==( const std::string & value ) const; + + bool operator !=( const BigNum & o ) const; + bool operator !=( uint64_t value ) const; + bool operator !=( const std::string & value ) const; + + std::string toString( StringFormat format = StringFormat::Auto ) const; + + BigNum negative() const; + BigNum positive() const; + + bool isNegative() const; + bool isPositive() const; + bool isOdd() const; + bool isEven() const; + + friend void swap( BigNum & o1, BigNum & o2 ) noexcept; + + private: + + class IMPL; + + std::unique_ptr< IMPL > impl; + }; +} + +#endif /* SRPXX_BIG_NUM_HPP */ diff --git a/SRPXX/source/BigNum.cpp b/SRPXX/source/BigNum.cpp new file mode 100644 index 0000000..b6aa5cc --- /dev/null +++ b/SRPXX/source/BigNum.cpp @@ -0,0 +1,261 @@ +/******************************************************************************* + * The MIT License (MIT) + * + * Copyright (c) 2024 Jean-David Gadina - www.xs-labs.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include +#include +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wold-style-cast" +#endif +#include +#include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace SRP +{ + class BigNum::IMPL + { + public: + + IMPL( BIGNUM * bn ); + IMPL( uint64_t value ); + IMPL( const BigNum & o ); + ~IMPL(); + + BIGNUM * _bn; + }; + + std::optional< BigNum > BigNum::fromString( const std::string & value, StringFormat format ) + { + BigNum n; + int r = 0; + + switch( format ) + { + case StringFormat::Auto: r = BN_asc2bn( &( n.impl->_bn ), value.c_str() ); break; + case StringFormat::Decimal: r = BN_dec2bn( &( n.impl->_bn ), value.c_str() ); break; + case StringFormat::Hexadecimal: r = BN_hex2bn( &( n.impl->_bn ), value.c_str() ); break; + } + + if( r != 0 ) + { + return n; + } + + return {}; + } + + BigNum::BigNum(): + BigNum( 0 ) + {} + + BigNum::BigNum( uint64_t value ): + impl( std::make_unique< IMPL >( value ) ) + {} + + BigNum::BigNum( const BigNum & o ): + impl( std::make_unique< IMPL >( o ) ) + {} + + BigNum::BigNum( BigNum && o ) noexcept: + impl( std::move( o.impl ) ) + {} + + BigNum::~BigNum() + {} + + BigNum & BigNum::operator =( BigNum o ) + { + swap( *( this ), o ); + + return *( this ); + } + + BigNum & BigNum::operator =( uint64_t value ) + { + return *( this ) = BigNum( value ); + } + + bool BigNum::operator ==( const BigNum & o ) const + { + return BN_cmp( this->impl->_bn, o.impl->_bn ) == 0; + } + + bool BigNum::operator ==( uint64_t value ) const + { + return *( this ) == BigNum( value ); + } + + bool BigNum::operator ==( const std::string & value ) const + { + if( value.length() == 0 ) + { + return false; + } + + StringFormat format = StringFormat::Decimal; + + if + ( + String::hasPrefix( value, "-0x" ) + || String::hasPrefix( value, "-0X" ) + || String::hasPrefix( value, "0x" ) + || String::hasPrefix( value, "0X" ) ) + { + format = StringFormat::Hexadecimal; + } + + std::string s1 = this->toString( format ); + std::string s2 = String::toLower( value ); + + return s1 == s2; + } + + bool BigNum::operator !=( const BigNum & o ) const + { + return !( *( this ) == o ); + } + + bool BigNum::operator !=( uint64_t value ) const + { + return !( *( this ) == value ); + } + + bool BigNum::operator !=( const std::string & value ) const + { + return !( *( this ) == value ); + } + + std::string BigNum::toString( StringFormat format ) const + { + BigNum abs = this->positive(); + char * cp = nullptr; + + switch( format ) + { + case StringFormat::Auto: cp = BN_bn2dec( abs.impl->_bn ); break; + case StringFormat::Decimal: cp = BN_bn2dec( abs.impl->_bn ); break; + case StringFormat::Hexadecimal: cp = BN_bn2hex( abs.impl->_bn ); break; + } + + if( cp == nullptr ) + { + return {}; + } + + std::string s( cp ); + + OPENSSL_free( cp ); + + if( format == StringFormat::Hexadecimal && this->isNegative() ) + { + s = "-0x" + s; + } + else if( format == StringFormat::Hexadecimal ) + { + s = "0x" + s; + } + else if( this->isNegative() ) + { + s = "-" + s; + } + + return String::toLower( s ); + } + + BigNum BigNum::negative() const + { + BigNum n = *( this ); + + if( BN_is_negative( n.impl->_bn ) == false ) + { + BN_set_negative( n.impl->_bn, 1 ); + } + + return n; + } + + BigNum BigNum::positive() const + { + BigNum n = *( this ); + + if( BN_is_negative( n.impl->_bn ) ) + { + BN_set_negative( n.impl->_bn, 0 ); + } + + return n; + } + + bool BigNum::isNegative() const + { + return BN_is_negative( this->impl->_bn ) == 1; + } + + bool BigNum::isPositive() const + { + return BN_is_negative( this->impl->_bn ) == 0; + } + + bool BigNum::isOdd() const + { + return BN_is_odd( this->impl->_bn ) == 1; + } + + bool BigNum::isEven() const + { + return BN_is_odd( this->impl->_bn ) == 0; + } + + void swap( BigNum & o1, BigNum & o2 ) noexcept + { + using std::swap; + + swap( o1.impl, o2.impl ); + } + + BigNum::IMPL::IMPL( BIGNUM * bn ): + _bn( bn ) + {} + + BigNum::IMPL::IMPL( uint64_t value ): + IMPL( BN_new() ) + { + BN_set_u64( this->_bn, value ); + } + + BigNum::IMPL::IMPL( const BigNum & o ): + IMPL( BN_dup( o.impl->_bn ) ) + {} + + BigNum::IMPL::~IMPL() + { + BN_free( this->_bn ); + } +}