diff --git a/CMakeLists.txt b/CMakeLists.txt index 9316382..8ac03b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,7 +71,7 @@ doxygen_add_docs( ) # build common library -set(LIB_SOURCES src/model.cpp src/model.hpp) +set(LIB_SOURCES src/model.cpp src/model.hpp src/big_int.hpp src/big_int.cpp) add_library(oc-mint-lib ${LIB_SOURCES}) target_link_libraries(oc-mint-lib PUBLIC Crow::Crow) target_include_directories(oc-mint-lib PUBLIC ${expected_SOURCE_DIR}/include src) @@ -80,7 +80,7 @@ add_executable(oc-mint src/main.cpp) target_link_libraries(oc-mint PRIVATE oc-mint-lib INTERFACE tl::expected::expected) ## these are unittests that can be run on any platform -add_executable(tests test/test.cpp) +add_executable(tests test/test_big_int.cpp test/test.cpp) target_link_libraries(tests oc-mint-lib Catch2::Catch2WithMain) diff --git a/src/big_int.cpp b/src/big_int.cpp new file mode 100644 index 0000000..7c6ebb6 --- /dev/null +++ b/src/big_int.cpp @@ -0,0 +1,27 @@ +#include "big_int.hpp" +#include + +tl::expected +BigInt::from_string(const std::string& str) { + BigInt b; + std::cout << str << std::endl; + b.data = str; + return b; +} + +BigInt BigInt::from_int(uint64_t value) +{ + BigInt b; + b.data = std::to_string(value); + return b; +} + +std::string BigInt::to_string() const +{ + return data; +} + +bool operator == (const BigInt& rhs, const BigInt& lhs) +{ return rhs.data == lhs.data; } + + diff --git a/src/big_int.hpp b/src/big_int.hpp new file mode 100644 index 0000000..b396809 --- /dev/null +++ b/src/big_int.hpp @@ -0,0 +1,26 @@ +#ifndef BIG_INT_HPP +#define BIG_INT_HPP + +#include +#include "tl/expected.hpp" + +struct BigInt { + BigInt() : data() {} + virtual ~BigInt() {} + enum class eError { + PARSE_ERROR + }; + + + std::string data; + + static tl::expected from_string(const std::string& str); + static BigInt from_int(uint64_t value); + std::string to_string() const; +}; + +bool operator == (const BigInt& rhs, const BigInt& lhs); + +#endif // #ifndef #ifndef BIG_INT_HPP + + diff --git a/src/main.cpp b/src/main.cpp index 8d4c217..a45fa57 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -70,7 +70,8 @@ int main() { ResponseMint res; res.message_reference = req->message_reference; - auto minted = model->mint(req->transaction_reference, req->blinds); + /// \todo change argument transaction_reference to bigint + auto minted = model->mint(req->transaction_reference.to_string(), req->blinds); res.blind_signatures = minted; res.status_code = crow::status::OK; diff --git a/src/model.cpp b/src/model.cpp index a66de4d..b3abcfa 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -1,9 +1,11 @@ #include "model.hpp" #include "crow/json.h" +#include "tl/expected.hpp" -#define TO_JSON(name) r[#name] = name -#define TO_JSON_JSON(name) r[#name] = name.to_json() -#define TO_JSON_ARRAY(name) r[#name] = list_to_json(name) +#define TO_JSON(name) r[#name]=name +#define BIGINT_TO_JSON(name) r[#name]=name.to_string() +#define TO_JSON_JSON(name) r[#name]=name.to_json() +#define TO_JSON_ARRAY(name) r[#name]=list_to_json(name) template crow::json::wvalue list_to_json(const std::vector &array) { @@ -22,9 +24,9 @@ crow::json::wvalue list_to_json(const std::vector &array) { crow::json::wvalue PublicKey::to_json() const { crow::json::wvalue r; - TO_JSON(modulus); - TO_JSON(public_exponent); - r["type"] = "rsa public key"; + BIGINT_TO_JSON(modulus); + BIGINT_TO_JSON(public_exponent); + r["type"]="rsa public key"; return r; } @@ -48,7 +50,7 @@ crow::json::wvalue CDD::to_json() const { TO_JSON(currency_divisor); TO_JSON(currency_name); TO_JSON_ARRAY(denominations); - TO_JSON(id); + BIGINT_TO_JSON(id); TO_JSON_ARRAY(info_service); TO_JSON(issuer_cipher_suite); TO_JSON_JSON(issuer_public_master_key); @@ -75,8 +77,8 @@ crow::json::wvalue MintKey::to_json() const { TO_JSON(cdd_serial); TO_JSON(coins_expiry_date); TO_JSON(denomination); - TO_JSON(id); - TO_JSON(issuer_id); + BIGINT_TO_JSON(id); + BIGINT_TO_JSON(issuer_id); TO_JSON_JSON(public_mint_key); TO_JSON(sign_coins_not_after); @@ -177,8 +179,13 @@ RequestMKCs::from_string(const std::string &str) { if (mint_key_ids.t() != crow::json::type::List) { return tl::make_unexpected(eError::JSON_WRONG_REQUEST_TYPE); } else { - for (auto k : mint_key_ids.lo()) { - r.mint_key_ids.push_back(k.u()); + for (auto k: mint_key_ids.lo()) { + auto kv = BigInt::from_string(k.s()); + if (!kv.has_value()) { + return tl::make_unexpected(eError::JSON_PARSE_ERROR); + } else { + r.mint_key_ids.push_back(*kv); + } } } return r; @@ -194,23 +201,38 @@ crow::json::wvalue ResponseMKCs::to_json() const { crow::json::wvalue Blind::to_json() const { crow::json::wvalue r; - TO_JSON(blinded_payload_hash); - TO_JSON(mint_key_id); + BIGINT_TO_JSON(blinded_payload_hash); + BIGINT_TO_JSON(mint_key_id); TO_JSON(reference); r["type"] = "blinded payload hash"; return r; } tl::expected Blind::from_json(const crow::json::rvalue &json) { - if (!(json.has("type") && json.has("blinded_payload_hash") && - json.has("mint_key_id") && json.has("reference"))) { + if (!(json.has("type") + && json.has("blinded_payload_hash") + && json.has("mint_key_id") + && json.has("reference"))) { return tl::make_unexpected(eError::JSON_ERROR); } else if (json["type"] != "blinded payload hash") { return tl::make_unexpected(eError::JSON_ERROR); } else { Blind r; - r.blinded_payload_hash = json["blinded_payload_hash"].s(); - r.mint_key_id = json["mint_key_id"].s(); + + auto hash = BigInt::from_string(json["blinded_payload_hash"].s()); + if (!hash) { + std::cout << "invalid hash : " << json["blinded_payload_hash"].s() + << std::endl; + return tl::make_unexpected(eError::JSON_PARSE_ERROR); + } + r.blinded_payload_hash = hash.value(); + + auto key_id = BigInt::from_string(json["mint_key_id"].s()); + if (!key_id) { + printf("invalid key_id"); + return tl::make_unexpected(eError::JSON_PARSE_ERROR); + } + r.mint_key_id = key_id.value(); r.reference = json["reference"].s(); return r; } @@ -218,7 +240,7 @@ tl::expected Blind::from_json(const crow::json::rvalue &json) { crow::json::wvalue BlindSignature::to_json() const { crow::json::wvalue r; - TO_JSON(blind_signature); + BIGINT_TO_JSON(blind_signature); TO_JSON(reference); r["type"] = "blind signature"; return r; @@ -238,9 +260,13 @@ RequestMint::from_string(const std::string &str) { return tl::make_unexpected(eError::JSON_ERROR); } else { RequestMint r; - r.message_reference = json["message_reference"].u(); - r.transaction_reference = json["transaction_reference"].s(); - if (json["blinds"].t() != crow::json::type::List) { + r.message_reference= json["message_reference"].u(); + auto tr = BigInt::from_string(json["transaction_reference"].s()); + if (!tr) + return tl::make_unexpected(eError::JSON_PARSE_ERROR); + + r.transaction_reference = *tr; + if (json["blinds"].t()!=crow::json::type::List) { return tl::make_unexpected(eError::JSON_WRONG_VALUE_TYPE); } @@ -267,10 +293,10 @@ crow::json::wvalue Coin::Payload::to_json() const { crow::json::wvalue r; TO_JSON(cdd_location); TO_JSON(denomination); - TO_JSON(issuer_id); - TO_JSON(mint_key_id); + BIGINT_TO_JSON(issuer_id); + BIGINT_TO_JSON(mint_key_id); TO_JSON(protocol_version); - TO_JSON(serial); + BIGINT_TO_JSON(serial); r["type"] = "payload"; return r; @@ -297,10 +323,20 @@ Coin::Payload::from_json(const crow::json::rvalue &json) { Coin::Payload payload; payload.cdd_location = json["cdd_location"].s(); payload.denomination = json["denomination"].u(); - payload.issuer_id = json["issuer_id"].s(); - payload.mint_key_id = json["mint_key_id"].s(); + auto id = BigInt::from_string(json["issuer_id"].s()); + if (!id) + tl::make_unexpected(eError::JSON_PARSE_ERROR); + payload.issuer_id = *id; + + id = BigInt::from_string(json["mint_key_id"].s()); + if (!id) + tl::make_unexpected(eError::JSON_PARSE_ERROR); + payload.mint_key_id = *id; payload.protocol_version = json["protocol_version"].s(); - payload.serial = json["serial"].s(); + id = BigInt::from_string(json["serial"].s()); + if (!id) + tl::make_unexpected(eError::JSON_PARSE_ERROR); + payload.serial = *id; return payload; } } @@ -392,7 +428,10 @@ RequestResume::from_string(const std::string &str) { } else { RequestResume r; r.message_reference = json["message_reference"].u(); - r.transaction_reference = json["transaction_reference"].s(); + auto tr = BigInt::from_string(json["transaction_reference"].s()); + if (!tr) + return tl::make_unexpected(eError::JSON_PARSE_ERROR); + r.transaction_reference = *tr; return r; } } @@ -451,7 +490,7 @@ public: return &m_cddc; } - std::vector mint(const std::string &transaction_reference, + std::vector mint(const std::string& transaction_reference, const std::vector &blinds) override { std::vector res; cout << __FUNCTION__ << "(" @@ -462,7 +501,7 @@ public: const std::vector getMKCs(const std::vector &denominations, - const std::vector &mint_key_ids) override { + const std::vector &mint_key_ids) override { std::vector res; cout << __FUNCTION__ << endl; return res; diff --git a/src/model.hpp b/src/model.hpp index e4bb52c..584581c 100644 --- a/src/model.hpp +++ b/src/model.hpp @@ -9,10 +9,11 @@ #include "crow/json.h" #include "tl/expected.hpp" +#include "big_int.hpp" struct PublicKey { - std::string modulus; //: "daaa63ddda38c189b8c49020c8276adbe0a695685a...", - std::string public_exponent; //: 65537, + BigInt modulus; //: "daaa63ddda38c189b8c49020c8276adbe0a695685a...", + BigInt public_exponent;//: 65537, crow::json::wvalue to_json() const; }; @@ -28,15 +29,16 @@ struct WeightedUrl { struct CDD { std::string additional_info; - time_t cdd_expiry_date; //: 2023-07-22T15:45:53.164685 - std::string cdd_location; //: https://opencent.org, - size_t cdd_serial; //: 1, - time_t cdd_signing_date; //: 2022-07-22T15:45:53.164685, - size_t currency_divisor; //: 100, - std::string currency_name; //: OpenCent, - std::vector denominations; //: [1, 2, 5], - std::string id; //: 23ed956e629ba35f0002eaf833ea436aea7db5c2, - std::vector info_service; + time_t cdd_expiry_date;//: 2023-07-22T15:45:53.164685 + std::string cdd_location;//: https://opencent.org, + size_t cdd_serial;//: 1, + time_t cdd_signing_date;//: 2022-07-22T15:45:53.164685, + size_t currency_divisor;//: 100, + std::string currency_name;//: OpenCent, + std::vector denominations;//: [1, 2, 5], + BigInt id;//: 23ed956e629ba35f0002eaf833ea436aea7db5c2, + +std::vector info_service; /* eCipherSuite*/ std::string issuer_cipher_suite; //: RSA-SHA256-PSS-CHAUM82, PublicKey issuer_public_master_key; //: { @@ -63,9 +65,9 @@ struct CDDC { struct MintKey { unsigned int cdd_serial; std::string coins_expiry_date; //": "2023-10-30T15:45:53.164685", - unsigned int denomination; //": 1, - std::string id; // "1ceb977bb531c65f133ab8b0d60862b17369d96", - std::string issuer_id; //": "23ed956e629ba35f0002eaf833ea436aea7db5c2", + unsigned int denomination; //": 1, + BigInt id; // "1ceb977bb531c65f133ab8b0d60862b17369d96", + BigInt issuer_id; //": "23ed956e629ba35f0002eaf833ea436aea7db5c2", PublicKey public_mint_key; std::string sign_coins_not_after; @@ -128,7 +130,7 @@ struct RequestMKCs { std::vector denominations; unsigned int message_reference; /// Client internal message reference. /// (Integer) - std::vector mint_key_ids; + std::vector mint_key_ids; // "type": "request mint key certificates" static tl::expected from_string(const std::string &str); }; @@ -140,15 +142,15 @@ struct ResponseMKCs : Response { }; struct Blind { - std::string blinded_payload_hash; // bigint - std::string mint_key_id; // bigint + BigInt blinded_payload_hash; //bigint + BigInt mint_key_id; //bigint std::string reference; crow::json::wvalue to_json() const; static tl::expected from_json(const crow::json::rvalue &json); }; struct BlindSignature { - std::string blind_signature; + BigInt blind_signature; std::string reference; crow::json::wvalue to_json() const; }; @@ -156,7 +158,7 @@ struct BlindSignature { struct RequestMint { unsigned int message_reference; /// Client internal message reference. /// (Integer) - std::string transaction_reference; + BigInt transaction_reference; std::vector blinds; // "type": "request mint" static tl::expected from_string(const std::string &str); @@ -172,14 +174,13 @@ struct Coin { struct Payload { std::string cdd_location; unsigned int denomination; - std::string issuer_id; - std::string mint_key_id; + BigInt issuer_id; + BigInt mint_key_id; std::string protocol_version; - std::string serial; - - crow::json::wvalue to_json() const; - static tl::expected - from_json(const crow::json::rvalue &json); + BigInt serial; + + crow::json::wvalue to_json() const; + static tl::expected from_json(const crow::json::rvalue& json); }; Payload payload; @@ -213,7 +214,7 @@ struct ResponseDelay : Response { struct RequestResume { unsigned int message_reference; /// Client internal message reference. /// (Integer) - std::string transaction_reference; + BigInt transaction_reference; // "type": "request resume" static tl::expected from_string(const std::string &str); @@ -241,10 +242,10 @@ public: virtual const std::vector getMKCs(const std::vector &denominations, - const std::vector &mint_key_ids) = 0; + const std::vector &mint_key_ids) = 0; virtual std::vector - mint(const std::string &transaction_reference, + mint(std::string const& transaction_reference, const std::vector &blinds) = 0; virtual bool redeem(const std::vector &coins) = 0; diff --git a/test/test.cpp b/test/test.cpp index d4b88b9..3a3f819 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -2,15 +2,17 @@ #include "model.hpp" #include -TEST_CASE("PublicKey::to_json", "[to_json]") { - PublicKey k{"daaa63ddda38c189b8c49020c8276adbe0a695685a...", "65537"}; - +TEST_CASE( "PublicKey::to_json", "[to_json]" ) { + + PublicKey k //{ BigInt::from_string("daaa63ddda38c189b8c49020c8276adbe0a695685a...").value(), + // BigInt::from_int(65537UL) }; + ; auto json = k.to_json(); - REQUIRE(json["modulus"].dump() == "\"" + k.modulus + "\""); - REQUIRE(json["public_exponent"].dump() == "\"" + k.public_exponent + "\""); - REQUIRE(json["type"].dump() == "\"rsa public key\""); - REQUIRE(json.keys().size() == 3); + REQUIRE( json["modulus"].dump() == "\"" + k.modulus.to_string() + "\"" ); + REQUIRE( json["public_exponent"].dump() == "\"" + k.public_exponent.to_string()+"\"" ); + REQUIRE( json["type"].dump() == "\"rsa public key\"" ); + REQUIRE( json.keys().size() == 3 ); } TEST_CASE("RequestCDDSerial::from_string", "[from_string]") { @@ -76,15 +78,14 @@ TEST_CASE("RequestCDDC::from_string", "[from_string]") { TEST_CASE("RequestMKCs::from_string", "[from_string]") { // good case - auto res = - RequestMKCs::from_string("{" - "\"denominations\": [1, 2, 5]," - "\"message_reference\": 100002," - "\"mint_key_ids\": []," - "\"type\": \"request mint key certificates\"" - "}"); - const std::vector EXPECTED_DENOMINATIONS = {1, 2, 5}; - const std::vector EXPECTED_MINT_KEY_IDS = {}; + auto res = RequestMKCs::from_string( "{" + "\"denominations\": [1, 2, 5]," + "\"message_reference\": 100002," + "\"mint_key_ids\": []," + "\"type\": \"request mint key certificates\"" + "}"); + const std::vector EXPECTED_DENOMINATIONS = {1,2,5}; + const std::vector EXPECTED_MINT_KEY_IDS = {}; REQUIRE(res.has_value() == true); REQUIRE(res->denominations == EXPECTED_DENOMINATIONS); @@ -136,15 +137,15 @@ TEST_CASE("Blind::from_json", "[from_string]") { "}"); auto res = Blind::from_json(good); - REQUIRE(res.has_value() == true); - REQUIRE(res->blinded_payload_hash == - "924edb672c3345492f38341ff86b57181da4c673ef..."); - REQUIRE(res->mint_key_id == "1ceb977bb531c65f133ab8b0d60862b17369d96"); - REQUIRE(res->reference == "a0"); - // bad cases - // wrong_type["blinded_payload_hash"]= - // "924edb672c3345492f38341ff86b57181da4c673ef..."; wrong_type["mint_key_id"]= - // "1ceb977bb531c65f133ab8b0d60862b17369d96"; wrong_type["reference"] = "a0"; + REQUIRE(res.has_value()==true); + REQUIRE(res->blinded_payload_hash.to_string()== + "924edb672c3345492f38341ff86b57181da4c673ef..."); + REQUIRE(res->mint_key_id.to_string()=="1ceb977bb531c65f133ab8b0d60862b17369d96"); + REQUIRE(res->reference=="a0"); + // bad cases + // wrong_type["blinded_payload_hash"]= "924edb672c3345492f38341ff86b57181da4c673ef..."; + // wrong_type["mint_key_id"]= "1ceb977bb531c65f133ab8b0d60862b17369d96"; + // wrong_type["reference"] = "a0"; // wrong_type["type"]= "wrong type"; // res = Blind::from_json(wrong_type); @@ -152,39 +153,35 @@ TEST_CASE("Blind::from_json", "[from_string]") { TEST_CASE("RequestMint::from_string", "[from_string]") { // good case - auto res = RequestMint::from_string( - "{" - "\"blinds\": [" - "{" - "\"blinded_payload_hash\": " - "\"924edb672c3345492f38341ff86b57181da4c673ef...\"," - "\"mint_key_id\": \"1ceb977bb531c65f133ab8b0d60862b17369d96\"," - "\"reference\": \"a0\"," - "\"type\": \"blinded payload hash\"" - "}," - "{" - "\"blinded_payload_hash\": " - "\"95db92e1c46ebea5edec5e508a831263de6fb78b4c...\"," - "\"mint_key_id\": \"f2864e5cd937dbaa4825e73a81062de162143682\"," - "\"reference\": \"a1\"," - "\"type\": \"blinded payload hash\"" - "}," - "{" - "\"blinded_payload_hash\": " - "\"10afac98ac43eb40e996c621d5db4d2238348e3f74...\"," - "\"mint_key_id\": \"897a16bf12bd9ba474ef7be0e3a53553a7b4ece8\"," - "\"reference\": \"a2\"," - "\"type\": \"blinded payload hash\"" - "}" - "]," - "\"message_reference\": 100003," - "\"transaction_reference\": \"b2221a58008a05a6c4647159c324c985\"," - "\"type\": \"request mint\"" - "}"); + auto res = RequestMint::from_string( "{" + "\"blinds\": [" + "{" + "\"blinded_payload_hash\": \"924edb672c3345492f38341ff86b57181da4c673ef...\"," + "\"mint_key_id\": \"1ceb977bb531c65f133ab8b0d60862b17369d96\"," + "\"reference\": \"a0\"," + "\"type\": \"blinded payload hash\"" + "}," + "{" + "\"blinded_payload_hash\": \"95db92e1c46ebea5edec5e508a831263de6fb78b4c...\"," + "\"mint_key_id\": \"f2864e5cd937dbaa4825e73a81062de162143682\"," + "\"reference\": \"a1\"," + "\"type\": \"blinded payload hash\"" + "}," + "{" + "\"blinded_payload_hash\": \"10afac98ac43eb40e996c621d5db4d2238348e3f74...\"," + "\"mint_key_id\": \"897a16bf12bd9ba474ef7be0e3a53553a7b4ece8\"," + "\"reference\": \"a2\"," + "\"type\": \"blinded payload hash\"" + "}" + "]," + "\"message_reference\": 100003," + "\"transaction_reference\": \"b2221a58008a05a6c4647159c324c985\"," + "\"type\": \"request mint\"" + "}"); - REQUIRE(res.has_value() == true); - REQUIRE(res->message_reference == 100003); - REQUIRE(res->transaction_reference == "b2221a58008a05a6c4647159c324c985"); + REQUIRE(res.has_value()==true); + REQUIRE(res->message_reference==100003); + REQUIRE(res->transaction_reference.to_string() == "b2221a58008a05a6c4647159c324c985"); /// \todo check blinds // bad cases @@ -280,17 +277,16 @@ TEST_CASE("RequestRenew::from_string", "[from_string]") { TEST_CASE("RequestResume::from_string", "[from_string]") { // good case - auto res = RequestResume::from_string( - "{" - "\"message_reference\": 100005," - "\"transaction_reference\": \"ad45f23d3b1a11df587fd2803bab6c39\"," - "\"type\": \"request resume\"" - "}"); - - REQUIRE(res.has_value() == true); - REQUIRE(res->message_reference == 100005); - REQUIRE(res->transaction_reference == "ad45f23d3b1a11df587fd2803bab6c39"); + auto res = RequestResume::from_string( "{" + "\"message_reference\": 100005," + "\"transaction_reference\": \"ad45f23d3b1a11df587fd2803bab6c39\"," + "\"type\": \"request resume\"" + "}"); + REQUIRE(res.has_value()==true); + REQUIRE(res->message_reference==100005); + REQUIRE(res->transaction_reference.to_string()=="ad45f23d3b1a11df587fd2803bab6c39"); + // bad cases res = RequestResume::from_string(""); REQUIRE(res.has_value() == false); diff --git a/test/test_big_int.cpp b/test/test_big_int.cpp new file mode 100644 index 0000000..efdcd0f --- /dev/null +++ b/test/test_big_int.cpp @@ -0,0 +1,17 @@ +#include "big_int.hpp" +#include + +TEST_CASE("BigInt::from_string", "[big_int]") { + auto valid_hex = "aabbcc"; + { + auto b = BigInt::from_string(valid_hex); + REQUIRE(b.has_value()); + + REQUIRE(b->data == valid_hex); + } +} + +TEST_CASE("BigInt::from_int", "[big_int]") { + auto b = BigInt::from_int(0xaabbcc); + REQUIRE(b.data=="aabbcc"); +}