LCOV - code coverage report
Current view: top level - utils - monero_c_utils.cpp (source / functions) Hit Total Coverage
Test: monero-c coverage @ 3fdc3a1 Lines: 142 142 100.0 %
Date: 2026-10-18 16:42:22 Functions: 55 55 100.0 %

          Line data    Source code
       1             : /**
       2             :  * Copyright (c) Libmonero
       3             :  *
       4             :  * Permission is hereby granted, free of charge, to any person obtaining a copy
       5             :  * of this software and associated documentation files (the "Software"), to deal
       6             :  * in the Software without restriction, including without limitation the rights
       7             :  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
       8             :  * copies of the Software, and to permit persons to whom the Software is
       9             :  * furnished to do so, subject to the following conditions:
      10             :  *
      11             :  * The above copyright notice and this permission notice shall be included in all
      12             :  * copies or substantial portions of the Software.
      13             :  *
      14             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      15             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      16             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      17             :  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      18             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      19             :  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      20             :  * SOFTWARE.
      21             :  *
      22             :  * Parts of this file are originally copyright (c) woodser
      23             :  *
      24             :  * Parts of this file are originally copyright (c) 2014-2019, The Monero Project
      25             :  *
      26             :  * Redistribution and use in source and binary forms, with or without modification, are
      27             :  * permitted provided that the following conditions are met:
      28             :  *
      29             :  * All rights reserved.
      30             :  *
      31             :  * 1. Redistributions of source code must retain the above copyright notice, this list of
      32             :  *    conditions and the following disclaimer.
      33             :  *
      34             :  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
      35             :  *    of conditions and the following disclaimer in the documentation and/or other
      36             :  *    materials provided with the distribution.
      37             :  *
      38             :  * 3. Neither the name of the copyright holder nor the names of its contributors may be
      39             :  *    used to endorse or promote products derived from this software without specific
      40             :  *    prior written permission.
      41             :  *
      42             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
      43             :  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
      44             :  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
      45             :  * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      46             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      47             :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
      48             :  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
      49             :  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
      50             :  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      51             :  *
      52             :  * Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers
      53             :  */
      54             : 
      55             : #include "monero_c_utils.h"
      56             : #include "common/monero_c_common.h"
      57             : #include "utils/monero_utils.h"
      58             : #include "crypto/hash.h"
      59             : #include <cstdlib>
      60             : #include <cstring>
      61             : #include <memory>
      62             : #include <mutex>
      63             : #include <new>
      64             : #include <stdexcept>
      65             : #include <string>
      66             : 
      67             : namespace {
      68             : 
      69             : using monero_c::check_json_depth;
      70             : using monero_c::check_mnemonic_length;
      71             : using monero_c::MAX_MNEMONIC_LENGTH;
      72             : using monero_c::dup_buffer;
      73             : using monero_c::dup_string;
      74             : using monero_c::guard;
      75             : using monero_c::network_of;
      76             : using monero_c::require;
      77             : using monero_c::reset_out;
      78             : using monero_c::safe_str;
      79             : using monero_c::to_network_type;
      80             : 
      81             : // the logging of monero-project is one global state, and two threads that change it together crash
      82        1212 : std::mutex& logging_mutex() {
      83             :   static std::mutex mutex;
      84        1212 :   return mutex;
      85             : }
      86             : 
      87        1517 : std::string safe_bin(const uint8_t* data, size_t len) {
      88        1517 :   return data ? std::string(reinterpret_cast<const char*>(data), len) : std::string();
      89             : }
      90             : 
      91             : using binary_to_json_fn = void (*)(const std::string&, std::string&);
      92             : 
      93             : // shared by the monero_utils_binary*_to_json wrappers below, which differ
      94             : // only in which monero_utils converter they call
      95        1523 : monero_result binary_to_json_impl(binary_to_json_fn fn, const uint8_t* data, size_t len, char** out_json) {
      96        1523 :   reset_out(out_json);
      97        1523 :   if (!require(out_json, "out_json")) return MONERO_ERROR;
      98        3034 :   return guard([&] {
      99        1517 :     std::string json;
     100        1768 :     fn(safe_bin(data, len), json);
     101        1266 :     *out_json = dup_string(json);
     102        3034 :   });
     103             : }
     104             : 
     105             : } // namespace
     106             : 
     107             : extern "C" {
     108             : 
     109             : // ---------------------------- ERROR / MEMORY --------------------------------
     110             : 
     111       38319 : const char* monero_last_error(void) {
     112       38319 :   return monero_c::last_error().c_str();
     113             : }
     114             : 
     115        7129 : void monero_utils_free(void* ptr) {
     116        7129 :   std::free(ptr);
     117        7129 : }
     118             : 
     119             : // ---------------------------------- VERSION ---------------------------------
     120             : 
     121          12 : monero_result monero_utils_get_abi_version(uint32_t* out_major, uint32_t* out_minor, uint32_t* out_patch) {
     122          12 :   if (!require(out_major, "out_major") || !require(out_minor, "out_minor") || !require(out_patch, "out_patch")) return MONERO_ERROR;
     123           4 :   *out_major = MONERO_C_ABI_VERSION_MAJOR;
     124           4 :   *out_minor = MONERO_C_ABI_VERSION_MINOR;
     125           4 :   *out_patch = MONERO_C_ABI_VERSION_PATCH;
     126           4 :   return MONERO_OK;
     127             : }
     128             : 
     129             : // --------------------------------- LOGGING ----------------------------------
     130             : 
     131         403 : void monero_utils_set_log_level(int32_t level) {
     132         403 :   std::lock_guard<std::mutex> lock(logging_mutex());
     133         403 :   monero_utils::set_log_level(static_cast<int>(level));
     134         403 : }
     135             : 
     136         404 : void monero_utils_set_log_categories(const char* categories) {
     137         404 :   std::lock_guard<std::mutex> lock(logging_mutex());
     138         404 :   monero_utils::set_log_categories(safe_str(categories));
     139         404 : }
     140             : 
     141         405 : void monero_utils_configure_logging(const char* path, bool console) {
     142         405 :   std::lock_guard<std::mutex> lock(logging_mutex());
     143         405 :   monero_utils::configure_logging(safe_str(path), console);
     144         405 : }
     145             : 
     146             : // -------------------------------- VALIDATION --------------------------------
     147             : 
     148        2268 : bool monero_utils_is_valid_address(const char* address, int32_t network_type) {
     149             :   monero_network_type nt;
     150        2268 :   if (!to_network_type(network_type, nt)) return false;
     151        2267 :   return monero_utils::is_valid_address(safe_str(address), nt);
     152             : }
     153             : 
     154        1360 : bool monero_utils_is_valid_private_view_key(const char* private_view_key) {
     155        1360 :   return monero_utils::is_valid_private_view_key(safe_str(private_view_key));
     156             : }
     157             : 
     158         457 : bool monero_utils_is_valid_private_spend_key(const char* private_spend_key) {
     159         457 :   return monero_utils::is_valid_private_spend_key(safe_str(private_spend_key));
     160             : }
     161             : 
     162         457 : bool monero_utils_is_valid_public_view_key(const char* public_view_key) {
     163         457 :   return monero_utils::is_valid_public_view_key(safe_str(public_view_key));
     164             : }
     165             : 
     166         457 : bool monero_utils_is_valid_public_spend_key(const char* public_spend_key) {
     167         457 :   return monero_utils::is_valid_public_spend_key(safe_str(public_spend_key));
     168             : }
     169             : 
     170         469 : bool monero_utils_is_valid_payment_id(const char* payment_id) {
     171         469 :   return monero_utils::is_valid_payment_id(safe_str(payment_id));
     172             : }
     173             : 
     174        2715 : bool monero_utils_is_valid_mnemonic(const char* mnemonic, const char* language) {
     175        2715 :   std::string text = safe_str(mnemonic);
     176        5430 :   return text.size() <= MAX_MNEMONIC_LENGTH && monero_utils::is_valid_mnemonic(text, safe_str(language));
     177        2715 : }
     178             : 
     179         461 : bool monero_utils_is_valid_language(const char* language) {
     180         461 :   return monero_utils::is_valid_language(safe_str(language));
     181             : }
     182             : 
     183         459 : monero_result monero_utils_validate_address(const char* address, int32_t network_type) {
     184         918 :   return guard([&] { monero_utils::validate_address(safe_str(address), network_of<monero_network_type>(network_type)); });
     185             : }
     186             : 
     187         456 : monero_result monero_utils_validate_private_view_key(const char* private_view_key) {
     188         912 :   return guard([&] { monero_utils::validate_private_view_key(safe_str(private_view_key)); });
     189             : }
     190             : 
     191         457 : monero_result monero_utils_validate_private_spend_key(const char* private_spend_key) {
     192         914 :   return guard([&] { monero_utils::validate_private_spend_key(safe_str(private_spend_key)); });
     193             : }
     194             : 
     195         456 : monero_result monero_utils_validate_public_view_key(const char* public_view_key) {
     196         912 :   return guard([&] { monero_utils::validate_public_view_key(safe_str(public_view_key)); });
     197             : }
     198             : 
     199         456 : monero_result monero_utils_validate_public_spend_key(const char* public_spend_key) {
     200         912 :   return guard([&] { monero_utils::validate_public_spend_key(safe_str(public_spend_key)); });
     201             : }
     202             : 
     203         468 : monero_result monero_utils_validate_payment_id(const char* payment_id) {
     204         936 :   return guard([&] { monero_utils::validate_payment_id(safe_str(payment_id)); });
     205             : }
     206             : 
     207         460 : monero_result monero_utils_validate_mnemonic(const char* mnemonic, const char* language) {
     208         920 :   return guard([&] {
     209         460 :     std::string text = safe_str(mnemonic);
     210         460 :     check_mnemonic_length(text);
     211         783 :     monero_utils::validate_mnemonic(text, safe_str(language));
     212        1380 :   });
     213             : }
     214             : 
     215             : // --------------------------- INTEGRATED ADDRESS / URIS ----------------------
     216             : 
     217        2112 : monero_result monero_utils_get_integrated_address(int32_t network_type, const char* standard_address, const char* payment_id, char** out_json) {
     218        2112 :   reset_out(out_json);
     219        2112 :   if (!require(out_json, "out_json")) return MONERO_ERROR;
     220        3320 :   return guard([&] {
     221        1660 :     monero_network_type nt = network_of<monero_network_type>(network_type);
     222        1754 :     monero_integrated_address addr = monero_utils::get_integrated_address(nt, safe_str(standard_address), safe_str(payment_id));
     223         935 :     *out_json = dup_string(addr.serialize());
     224        2595 :   });
     225             : }
     226             : 
     227         160 : monero_result monero_utils_get_payment_uri(const char* tx_config_json, int32_t network_type, char** out_uri) {
     228         160 :   reset_out(out_uri);
     229         160 :   if (!require(out_uri, "out_uri")) return MONERO_ERROR;
     230         316 :   return guard([&] {
     231         158 :     monero_network_type nt = network_of<monero_network_type>(network_type);
     232         156 :     std::string json = safe_str(tx_config_json);
     233         156 :     check_json_depth(json);
     234         154 :     std::shared_ptr<monero_tx_config> config = monero_tx_config::deserialize(json);
     235          48 :     *out_uri = dup_string(monero_utils::get_payment_uri(*config, nt));
     236         360 :   });
     237             : }
     238             : 
     239         159 : monero_result monero_utils_parse_payment_uri(const char* uri, int32_t network_type, char** out_tx_config_json) {
     240         159 :   reset_out(out_tx_config_json);
     241         159 :   if (!require(out_tx_config_json, "out_tx_config_json")) return MONERO_ERROR;
     242         314 :   return guard([&] {
     243         157 :     monero_network_type nt = network_of<monero_network_type>(network_type);
     244         282 :     std::shared_ptr<monero_tx_config> config = monero_utils::parse_payment_uri(safe_str(uri), nt);
     245          28 :     *out_tx_config_json = dup_string(config->serialize());
     246         185 :   });
     247             : }
     248             : 
     249             : // ----------------------------- JSON / BINARY RPC ----------------------------
     250             : 
     251        1514 : monero_result monero_utils_json_to_binary(const char* json, uint8_t** out_data, size_t* out_len) {
     252        1514 :   reset_out(out_data);
     253        1514 :   reset_out(out_len);
     254        1514 :   if (!require(out_data, "out_data") || !require(out_len, "out_len")) return MONERO_ERROR;
     255        3018 :   return guard([&] {
     256        1509 :     std::string text = safe_str(json);
     257        1509 :     check_json_depth(text);
     258        1501 :     std::string bin;
     259        1501 :     monero_utils::json_to_binary(text, bin);
     260        1501 :     *out_data = dup_buffer(bin, out_len);
     261        3018 :   });
     262             : }
     263             : 
     264        1203 : monero_result monero_utils_binary_to_json(const uint8_t* data, size_t len, char** out_json) {
     265        1203 :   return binary_to_json_impl(monero_utils::binary_to_json, data, len, out_json);
     266             : }
     267             : 
     268         160 : monero_result monero_utils_binary_blocks_to_json(const uint8_t* data, size_t len, char** out_json) {
     269         160 :   return binary_to_json_impl(monero_utils::binary_blocks_to_json, data, len, out_json);
     270             : }
     271             : 
     272         160 : monero_result monero_utils_binary_blocks_fast_to_json(const uint8_t* data, size_t len, char** out_json) {
     273         160 :   return binary_to_json_impl(monero_utils::binary_blocks_fast_to_json, data, len, out_json);
     274             : }
     275             : 
     276             : // -------------------------------- AMOUNTS / IDS -----------------------------
     277             : 
     278          19 : monero_result monero_utils_xmr_to_atomic_units(double amount_xmr, uint64_t* out_atomic_units) {
     279          19 :   if (!require(out_atomic_units, "out_atomic_units")) return MONERO_ERROR;
     280          34 :   return guard([&] { *out_atomic_units = monero_utils::xmr_to_atomic_units(amount_xmr); });
     281             : }
     282             : 
     283           6 : double monero_utils_atomic_units_to_xmr(uint64_t amount_atomic_units) {
     284           6 :   return monero_utils::atomic_units_to_xmr(amount_atomic_units);
     285             : }
     286             : 
     287         458 : bool monero_utils_parse_payment_id_long(const char* payment_id_str, uint8_t out_payment_id[32]) {
     288             :   static_assert(sizeof(crypto::hash) == 32, "crypto::hash is expected to be 32 bytes");
     289             :   crypto::hash h;
     290         458 :   if (!monero_utils::parse_payment_id_long(safe_str(payment_id_str), h)) return false;
     291          10 :   if (out_payment_id != nullptr) std::memcpy(out_payment_id, &h, sizeof(h));
     292          10 :   return true;
     293             : }
     294             : 
     295         458 : bool monero_utils_parse_payment_id_short(const char* payment_id_str, uint8_t out_payment_id[8]) {
     296             :   static_assert(sizeof(crypto::hash8) == 8, "crypto::hash8 is expected to be 8 bytes");
     297             :   crypto::hash8 h;
     298         458 :   if (!monero_utils::parse_payment_id_short(safe_str(payment_id_str), h)) return false;
     299           4 :   if (out_payment_id != nullptr) std::memcpy(out_payment_id, &h, sizeof(h));
     300           4 :   return true;
     301             : }
     302             : 
     303             : // monero-cpp only exposes parse_payment_id_long/short, which return a bool and an out-ref.
     304             : // the is_valid_ and validate_ wrappers match the checks of downstream bindings such as
     305             : // monero-python's PyMoneroUtils, including the "Invalid {long,short} payment id" messages
     306             : 
     307         459 : bool monero_utils_is_valid_payment_id_long(const char* payment_id_str) {
     308             :   crypto::hash h;
     309         459 :   return monero_utils::parse_payment_id_long(safe_str(payment_id_str), h);
     310             : }
     311             : 
     312         458 : bool monero_utils_is_valid_payment_id_short(const char* payment_id_str) {
     313             :   crypto::hash8 h;
     314         458 :   return monero_utils::parse_payment_id_short(safe_str(payment_id_str), h);
     315             : }
     316             : 
     317         458 : monero_result monero_utils_validate_payment_id_long(const char* payment_id_str) {
     318         916 :   return guard([&] {
     319             :     crypto::hash h;
     320         458 :     if (!monero_utils::parse_payment_id_long(safe_str(payment_id_str), h)) throw std::runtime_error("Invalid long payment id");
     321         926 :   });
     322             : }
     323             : 
     324         457 : monero_result monero_utils_validate_payment_id_short(const char* payment_id_str) {
     325         914 :   return guard([&] {
     326             :     crypto::hash8 h;
     327         457 :     if (!monero_utils::parse_payment_id_short(safe_str(payment_id_str), h)) throw std::runtime_error("Invalid short payment id");
     328         917 :   });
     329             : }
     330             : 
     331           5 : int32_t monero_utils_get_ring_size(void) {
     332           5 :   return monero_utils::RING_SIZE;
     333             : }
     334             : 
     335             : } // extern "C"

Generated by: LCOV version 1.16