Port monero-lws to wownero-lws

Adapts monero-lws for Wownero cryptocurrency:

- Rename all monero-lws-* binaries to wownero-lws-*
- Update submodule to point to official Wownero repo
- Use Wownero default ports (RPC: 34568, ZMQ: 34569)
- Update data directory to ~/.wownero/light_wallet_server
- Adapt next_difficulty() calls for Wownero API signature

Key technical changes for Wownero compatibility:

- BulletproofPlus (RCTTypeBulletproofPlus, type 8) commitment verification:
  Wownero stores BP+ commitments in 'divided by 8' form. Must call
  rct::scalarmult8() on outPk commitment before comparing with computed
  commitment (mask*G + amount*H). This is essential for amount decryption.

- Pass rct_type to decode_amount() for proper commitment handling

- Handle Wownero's ZMQ JSON format for ecdhTuple (32-byte mask/amount fields)

No fork of Wownero is required - uses official codeberg.org/wownero/wownero.
This commit is contained in:
jwinterm
2026-01-04 13:12:56 -05:00
parent f2b3534002
commit 3427c60315
35 changed files with 789 additions and 395 deletions

View File

@@ -28,9 +28,12 @@
#include "daemon_zmq.h"
#include <boost/optional/optional.hpp>
#include "misc_log_ex.h"
#include "string_tools.h"
#include "cryptonote_config.h" // monero/src
#include "crypto/crypto.h" // monero/src
#include "rpc/message_data_structs.h" // monero/src
#include "ringct/rctOps.h"
#include "wire/adapted/crypto.h"
#include "wire/json.h"
#include "wire/wrapper/array.h"
@@ -61,15 +64,23 @@ namespace
namespace rct
{
static void read_bytes(wire::json_reader& source, key& self)
{
source.binary(epee::as_mut_byte_span(self.bytes));
}
static void read_bytes(wire::json_reader& source, ctkey& self)
{
self.dest = {};
read_bytes(source, self.mask);
source.binary(epee::as_mut_byte_span(self.mask));
}
static void read_bytes(wire::json_reader& source, ecdhTuple& self)
{
wire::object(source, WIRE_FIELD(mask), WIRE_FIELD(amount));
wire::object(source,
WIRE_FIELD(mask),
WIRE_FIELD(amount)
);
}
static void read_bytes(wire::json_reader& source, clsag& self)
@@ -205,6 +216,11 @@ namespace rct
wire::optional_field("prunable", std::ref(prunable))
);
if (self.type != RCTTypeNull)
{
MDEBUG("Parsed rctSig: type=" << (int)self.type << " encrypted_count=" << self.ecdhInfo.size() << " commitments_count=" << self.outPk.size());
}
self.txnFee = 0;
if (self.type != RCTTypeNull)
{
@@ -213,7 +229,7 @@ namespace rct
self.txnFee = std::move(*txnFee);
}
else if (!self.ecdhInfo.empty() || !self.outPk.empty() || txnFee)
WIRE_DLOG_THROW(wire::error::schema::invalid_key, "Did not expected `encrypted`, `commitments`, or `fee`");
WIRE_DLOG_THROW(wire::error::schema::invalid_key, "Did not expect `encrypted`, `commitments`, or `fee`");
if (prunable)
{
@@ -289,30 +305,47 @@ namespace cryptonote
self.vin.reserve(default_inputs);
self.vout.reserve(default_outputs);
self.extra.reserve(default_txextra_size);
boost::optional<rct::rctSig> ringct;
wire::object(source,
WIRE_FIELD(version),
WIRE_FIELD(unlock_time),
wire::field("inputs", wire::array<max_inputs_per_tx>(std::ref(self.vin))),
wire::field("outputs", wire::array<max_outputs_per_tx>(std::ref(self.vout))),
WIRE_FIELD(extra),
WIRE_FIELD_ARRAY(signatures, max_inputs_per_tx),
wire::field("ringct", std::ref(self.rct_signatures))
wire::optional_field("signatures", wire::array<max_inputs_per_tx>(std::ref(self.signatures))),
wire::optional_field("ringct", std::ref(ringct))
);
if (ringct)
self.rct_signatures = std::move(*ringct);
}
static void read_bytes(wire::json_reader& source, block& self)
{
using min_hash_size = wire::min_element_sizeof<crypto::hash>;
self.tx_hashes.reserve(default_transaction_count);
boost::optional<crypto::signature> signature;
boost::optional<uint16_t> vote;
wire::object(source,
WIRE_FIELD(major_version),
WIRE_FIELD(minor_version),
WIRE_FIELD(timestamp),
WIRE_FIELD(miner_tx),
WIRE_FIELD_ARRAY(tx_hashes, min_hash_size),
WIRE_FIELD(prev_id),
WIRE_FIELD(nonce)
WIRE_FIELD(nonce),
wire::optional_field("signature", std::ref(signature)),
wire::optional_field("vote", std::ref(vote)),
WIRE_FIELD(miner_tx),
WIRE_FIELD_ARRAY(tx_hashes, min_hash_size)
);
if (signature)
self.signature = *signature;
if (vote)
self.vote = *vote;
}
static void read_bytes(wire::json_reader& source, std::vector<transaction>& self)